texture_layer.cc revision 3551c9c881056c480085172ff9840cab31610854
1// Copyright 2010 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "cc/layers/texture_layer.h" 6 7#include "base/bind.h" 8#include "base/location.h" 9#include "base/message_loop/message_loop_proxy.h" 10#include "cc/layers/texture_layer_client.h" 11#include "cc/layers/texture_layer_impl.h" 12#include "cc/trees/layer_tree_host.h" 13#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" 14 15namespace cc { 16 17scoped_refptr<TextureLayer> TextureLayer::Create(TextureLayerClient* client) { 18 return scoped_refptr<TextureLayer>(new TextureLayer(client, false)); 19} 20 21scoped_refptr<TextureLayer> TextureLayer::CreateForMailbox( 22 TextureLayerClient* client) { 23 return scoped_refptr<TextureLayer>(new TextureLayer(client, true)); 24} 25 26TextureLayer::TextureLayer(TextureLayerClient* client, bool uses_mailbox) 27 : Layer(), 28 client_(client), 29 uses_mailbox_(uses_mailbox), 30 flipped_(true), 31 uv_top_left_(0.f, 0.f), 32 uv_bottom_right_(1.f, 1.f), 33 premultiplied_alpha_(true), 34 blend_background_color_(false), 35 rate_limit_context_(false), 36 content_committed_(false), 37 texture_id_(0), 38 needs_set_mailbox_(false) { 39 vertex_opacity_[0] = 1.0f; 40 vertex_opacity_[1] = 1.0f; 41 vertex_opacity_[2] = 1.0f; 42 vertex_opacity_[3] = 1.0f; 43} 44 45TextureLayer::~TextureLayer() { 46} 47 48void TextureLayer::ClearClient() { 49 if (rate_limit_context_ && client_ && layer_tree_host()) 50 layer_tree_host()->StopRateLimiter(client_->Context3d()); 51 client_ = NULL; 52 if (uses_mailbox_) 53 SetTextureMailbox(TextureMailbox()); 54 else 55 SetTextureId(0); 56} 57 58scoped_ptr<LayerImpl> TextureLayer::CreateLayerImpl(LayerTreeImpl* tree_impl) { 59 return TextureLayerImpl::Create(tree_impl, id(), uses_mailbox_). 60 PassAs<LayerImpl>(); 61} 62 63void TextureLayer::SetFlipped(bool flipped) { 64 if (flipped_ == flipped) 65 return; 66 flipped_ = flipped; 67 SetNeedsCommit(); 68} 69 70void TextureLayer::SetUV(gfx::PointF top_left, gfx::PointF bottom_right) { 71 if (uv_top_left_ == top_left && uv_bottom_right_ == bottom_right) 72 return; 73 uv_top_left_ = top_left; 74 uv_bottom_right_ = bottom_right; 75 SetNeedsCommit(); 76} 77 78void TextureLayer::SetVertexOpacity(float bottom_left, 79 float top_left, 80 float top_right, 81 float bottom_right) { 82 // Indexing according to the quad vertex generation: 83 // 1--2 84 // | | 85 // 0--3 86 if (vertex_opacity_[0] == bottom_left && 87 vertex_opacity_[1] == top_left && 88 vertex_opacity_[2] == top_right && 89 vertex_opacity_[3] == bottom_right) 90 return; 91 vertex_opacity_[0] = bottom_left; 92 vertex_opacity_[1] = top_left; 93 vertex_opacity_[2] = top_right; 94 vertex_opacity_[3] = bottom_right; 95 SetNeedsCommit(); 96} 97 98void TextureLayer::SetPremultipliedAlpha(bool premultiplied_alpha) { 99 if (premultiplied_alpha_ == premultiplied_alpha) 100 return; 101 premultiplied_alpha_ = premultiplied_alpha; 102 SetNeedsCommit(); 103} 104 105void TextureLayer::SetBlendBackgroundColor(bool blend) { 106 if (blend_background_color_ == blend) 107 return; 108 blend_background_color_ = blend; 109 SetNeedsCommit(); 110} 111 112void TextureLayer::SetRateLimitContext(bool rate_limit) { 113 if (!rate_limit && rate_limit_context_ && client_ && layer_tree_host()) 114 layer_tree_host()->StopRateLimiter(client_->Context3d()); 115 116 rate_limit_context_ = rate_limit; 117} 118 119void TextureLayer::SetTextureId(unsigned id) { 120 DCHECK(!uses_mailbox_); 121 if (texture_id_ == id) 122 return; 123 if (texture_id_ && layer_tree_host()) 124 layer_tree_host()->AcquireLayerTextures(); 125 texture_id_ = id; 126 SetNeedsCommit(); 127} 128 129void TextureLayer::SetTextureMailbox(const TextureMailbox& mailbox) { 130 DCHECK(uses_mailbox_); 131 DCHECK(!mailbox.IsValid() || !holder_ref_ || 132 !mailbox.Equals(holder_ref_->holder()->mailbox())); 133 // If we never commited the mailbox, we need to release it here. 134 if (mailbox.IsValid()) 135 holder_ref_ = MailboxHolder::Create(mailbox); 136 else 137 holder_ref_.reset(); 138 needs_set_mailbox_ = true; 139 SetNeedsCommit(); 140} 141 142void TextureLayer::WillModifyTexture() { 143 if (layer_tree_host() && (DrawsContent() || content_committed_)) { 144 layer_tree_host()->AcquireLayerTextures(); 145 content_committed_ = false; 146 } 147} 148 149void TextureLayer::SetNeedsDisplayRect(const gfx::RectF& dirty_rect) { 150 Layer::SetNeedsDisplayRect(dirty_rect); 151 152 if (rate_limit_context_ && client_ && layer_tree_host() && DrawsContent()) 153 layer_tree_host()->StartRateLimiter(client_->Context3d()); 154} 155 156void TextureLayer::SetLayerTreeHost(LayerTreeHost* host) { 157 if (layer_tree_host() == host) { 158 Layer::SetLayerTreeHost(host); 159 return; 160 } 161 162 if (layer_tree_host()) { 163 if (texture_id_) 164 layer_tree_host()->AcquireLayerTextures(); 165 if (rate_limit_context_ && client_) 166 layer_tree_host()->StopRateLimiter(client_->Context3d()); 167 } 168 // If we're removed from the tree, the TextureLayerImpl will be destroyed, and 169 // we will need to set the mailbox again on a new TextureLayerImpl the next 170 // time we push. 171 if (!host && uses_mailbox_ && holder_ref_) 172 needs_set_mailbox_ = true; 173 Layer::SetLayerTreeHost(host); 174} 175 176bool TextureLayer::DrawsContent() const { 177 return (client_ || texture_id_ || holder_ref_) && Layer::DrawsContent(); 178} 179 180bool TextureLayer::Update(ResourceUpdateQueue* queue, 181 const OcclusionTracker* occlusion) { 182 bool updated = Layer::Update(queue, occlusion); 183 if (client_) { 184 if (uses_mailbox_) { 185 TextureMailbox mailbox; 186 if (client_->PrepareTextureMailbox( 187 &mailbox, layer_tree_host()->UsingSharedMemoryResources())) { 188 SetTextureMailbox(mailbox); 189 updated = true; 190 } 191 } else { 192 texture_id_ = client_->PrepareTexture(); 193 DCHECK_EQ(!!texture_id_, !!client_->Context3d()); 194 if (client_->Context3d() && 195 client_->Context3d()->getGraphicsResetStatusARB() != GL_NO_ERROR) 196 texture_id_ = 0; 197 updated = true; 198 } 199 } 200 201 // SetTextureMailbox could be called externally and the same mailbox used for 202 // different textures. Such callers notify this layer that the texture has 203 // changed by calling SetNeedsDisplay, so check for that here. 204 return updated || !update_rect_.IsEmpty(); 205} 206 207void TextureLayer::PushPropertiesTo(LayerImpl* layer) { 208 Layer::PushPropertiesTo(layer); 209 210 TextureLayerImpl* texture_layer = static_cast<TextureLayerImpl*>(layer); 211 texture_layer->set_flipped(flipped_); 212 texture_layer->set_uv_top_left(uv_top_left_); 213 texture_layer->set_uv_bottom_right(uv_bottom_right_); 214 texture_layer->set_vertex_opacity(vertex_opacity_); 215 texture_layer->set_premultiplied_alpha(premultiplied_alpha_); 216 texture_layer->set_blend_background_color(blend_background_color_); 217 if (uses_mailbox_ && needs_set_mailbox_) { 218 TextureMailbox texture_mailbox; 219 if (holder_ref_) { 220 MailboxHolder* holder = holder_ref_->holder(); 221 TextureMailbox::ReleaseCallback callback = 222 holder->GetCallbackForImplThread(); 223 texture_mailbox = holder->mailbox().CopyWithNewCallback(callback); 224 } 225 texture_layer->SetTextureMailbox(texture_mailbox); 226 needs_set_mailbox_ = false; 227 } else { 228 texture_layer->set_texture_id(texture_id_); 229 } 230 content_committed_ = DrawsContent(); 231} 232 233Region TextureLayer::VisibleContentOpaqueRegion() const { 234 if (contents_opaque()) 235 return visible_content_rect(); 236 237 if (blend_background_color_ && (SkColorGetA(background_color()) == 0xFF)) 238 return visible_content_rect(); 239 240 return Region(); 241} 242 243bool TextureLayer::BlocksPendingCommit() const { 244 // Double-buffered texture layers need to be blocked until they can be made 245 // triple-buffered. Single-buffered layers already prevent draws, so 246 // can block too for simplicity. 247 return DrawsContent(); 248} 249 250bool TextureLayer::CanClipSelf() const { 251 return true; 252} 253 254TextureLayer::MailboxHolder::MainThreadReference::MainThreadReference( 255 MailboxHolder* holder) 256 : holder_(holder) { 257 holder_->InternalAddRef(); 258} 259 260TextureLayer::MailboxHolder::MainThreadReference::~MainThreadReference() { 261 holder_->InternalRelease(); 262} 263 264TextureLayer::MailboxHolder::MailboxHolder(const TextureMailbox& mailbox) 265 : message_loop_(base::MessageLoopProxy::current()), 266 internal_references_(0), 267 mailbox_(mailbox), 268 sync_point_(mailbox.sync_point()), 269 is_lost_(false) { 270} 271 272TextureLayer::MailboxHolder::~MailboxHolder() { 273 DCHECK_EQ(0u, internal_references_); 274} 275 276scoped_ptr<TextureLayer::MailboxHolder::MainThreadReference> 277TextureLayer::MailboxHolder::Create(const TextureMailbox& mailbox) { 278 return scoped_ptr<MainThreadReference>(new MainThreadReference( 279 new MailboxHolder(mailbox))); 280} 281 282void TextureLayer::MailboxHolder::Return(unsigned sync_point, bool is_lost) { 283 sync_point_ = sync_point; 284 is_lost_ = is_lost; 285} 286 287TextureMailbox::ReleaseCallback 288TextureLayer::MailboxHolder::GetCallbackForImplThread() { 289 // We can't call GetCallbackForImplThread if we released the main thread 290 // reference. 291 DCHECK_GT(internal_references_, 0u); 292 InternalAddRef(); 293 return base::Bind(&MailboxHolder::ReturnAndReleaseOnImplThread, this); 294} 295 296void TextureLayer::MailboxHolder::InternalAddRef() { 297 ++internal_references_; 298} 299 300void TextureLayer::MailboxHolder::InternalRelease() { 301 DCHECK(message_loop_->BelongsToCurrentThread()); 302 if (!--internal_references_) { 303 mailbox_.RunReleaseCallback(sync_point_, is_lost_); 304 mailbox_ = TextureMailbox(); 305 } 306} 307 308void TextureLayer::MailboxHolder::ReturnAndReleaseOnMainThread( 309 unsigned sync_point, bool is_lost) { 310 DCHECK(message_loop_->BelongsToCurrentThread()); 311 Return(sync_point, is_lost); 312 InternalRelease(); 313} 314 315void TextureLayer::MailboxHolder::ReturnAndReleaseOnImplThread( 316 unsigned sync_point, bool is_lost) { 317 message_loop_->PostTask(FROM_HERE, base::Bind( 318 &MailboxHolder::ReturnAndReleaseOnMainThread, 319 this, sync_point, is_lost)); 320} 321 322} // namespace cc 323