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 15 namespace cc { 16 17 scoped_refptr<TextureLayer> TextureLayer::Create(TextureLayerClient* client) { 18 return scoped_refptr<TextureLayer>(new TextureLayer(client, false)); 19 } 20 21 scoped_refptr<TextureLayer> TextureLayer::CreateForMailbox( 22 TextureLayerClient* client) { 23 return scoped_refptr<TextureLayer>(new TextureLayer(client, true)); 24 } 25 26 TextureLayer::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 45 TextureLayer::~TextureLayer() { 46 } 47 48 void 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 58 scoped_ptr<LayerImpl> TextureLayer::CreateLayerImpl(LayerTreeImpl* tree_impl) { 59 return TextureLayerImpl::Create(tree_impl, id(), uses_mailbox_). 60 PassAs<LayerImpl>(); 61 } 62 63 void TextureLayer::SetFlipped(bool flipped) { 64 if (flipped_ == flipped) 65 return; 66 flipped_ = flipped; 67 SetNeedsCommit(); 68 } 69 70 void 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 78 void 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 98 void TextureLayer::SetPremultipliedAlpha(bool premultiplied_alpha) { 99 if (premultiplied_alpha_ == premultiplied_alpha) 100 return; 101 premultiplied_alpha_ = premultiplied_alpha; 102 SetNeedsCommit(); 103 } 104 105 void TextureLayer::SetBlendBackgroundColor(bool blend) { 106 if (blend_background_color_ == blend) 107 return; 108 blend_background_color_ = blend; 109 SetNeedsCommit(); 110 } 111 112 void 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 119 void 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 129 void 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 142 void TextureLayer::WillModifyTexture() { 143 if (layer_tree_host() && (DrawsContent() || content_committed_)) { 144 layer_tree_host()->AcquireLayerTextures(); 145 content_committed_ = false; 146 } 147 } 148 149 void 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 156 void 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 176 bool TextureLayer::DrawsContent() const { 177 return (client_ || texture_id_ || holder_ref_) && Layer::DrawsContent(); 178 } 179 180 bool 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 DCHECK(client_->Context3d()); 193 texture_id_ = client_->PrepareTexture(); 194 if (client_->Context3d() && 195 client_->Context3d()->getGraphicsResetStatusARB() != GL_NO_ERROR) 196 texture_id_ = 0; 197 updated = true; 198 SetNeedsPushProperties(); 199 } 200 } 201 202 // SetTextureMailbox could be called externally and the same mailbox used for 203 // different textures. Such callers notify this layer that the texture has 204 // changed by calling SetNeedsDisplay, so check for that here. 205 return updated || !update_rect_.IsEmpty(); 206 } 207 208 void TextureLayer::PushPropertiesTo(LayerImpl* layer) { 209 Layer::PushPropertiesTo(layer); 210 211 TextureLayerImpl* texture_layer = static_cast<TextureLayerImpl*>(layer); 212 texture_layer->set_flipped(flipped_); 213 texture_layer->set_uv_top_left(uv_top_left_); 214 texture_layer->set_uv_bottom_right(uv_bottom_right_); 215 texture_layer->set_vertex_opacity(vertex_opacity_); 216 texture_layer->set_premultiplied_alpha(premultiplied_alpha_); 217 texture_layer->set_blend_background_color(blend_background_color_); 218 if (uses_mailbox_ && needs_set_mailbox_) { 219 TextureMailbox texture_mailbox; 220 if (holder_ref_) { 221 MailboxHolder* holder = holder_ref_->holder(); 222 TextureMailbox::ReleaseCallback callback = 223 holder->GetCallbackForImplThread(); 224 texture_mailbox = holder->mailbox().CopyWithNewCallback(callback); 225 } 226 texture_layer->SetTextureMailbox(texture_mailbox); 227 needs_set_mailbox_ = false; 228 } else { 229 texture_layer->set_texture_id(texture_id_); 230 } 231 content_committed_ = DrawsContent(); 232 } 233 234 Region TextureLayer::VisibleContentOpaqueRegion() const { 235 if (contents_opaque()) 236 return visible_content_rect(); 237 238 if (blend_background_color_ && (SkColorGetA(background_color()) == 0xFF)) 239 return visible_content_rect(); 240 241 return Region(); 242 } 243 244 bool TextureLayer::BlocksPendingCommit() const { 245 // Double-buffered texture layers need to be blocked until they can be made 246 // triple-buffered. Single-buffered layers already prevent draws, so 247 // can block too for simplicity. 248 return DrawsContent(); 249 } 250 251 bool TextureLayer::CanClipSelf() const { 252 return true; 253 } 254 255 TextureLayer::MailboxHolder::MainThreadReference::MainThreadReference( 256 MailboxHolder* holder) 257 : holder_(holder) { 258 holder_->InternalAddRef(); 259 } 260 261 TextureLayer::MailboxHolder::MainThreadReference::~MainThreadReference() { 262 holder_->InternalRelease(); 263 } 264 265 TextureLayer::MailboxHolder::MailboxHolder(const TextureMailbox& mailbox) 266 : message_loop_(base::MessageLoopProxy::current()), 267 internal_references_(0), 268 mailbox_(mailbox), 269 sync_point_(mailbox.sync_point()), 270 is_lost_(false) { 271 } 272 273 TextureLayer::MailboxHolder::~MailboxHolder() { 274 DCHECK_EQ(0u, internal_references_); 275 } 276 277 scoped_ptr<TextureLayer::MailboxHolder::MainThreadReference> 278 TextureLayer::MailboxHolder::Create(const TextureMailbox& mailbox) { 279 return scoped_ptr<MainThreadReference>(new MainThreadReference( 280 new MailboxHolder(mailbox))); 281 } 282 283 void TextureLayer::MailboxHolder::Return(unsigned sync_point, bool is_lost) { 284 sync_point_ = sync_point; 285 is_lost_ = is_lost; 286 } 287 288 TextureMailbox::ReleaseCallback 289 TextureLayer::MailboxHolder::GetCallbackForImplThread() { 290 // We can't call GetCallbackForImplThread if we released the main thread 291 // reference. 292 DCHECK_GT(internal_references_, 0u); 293 InternalAddRef(); 294 return base::Bind(&MailboxHolder::ReturnAndReleaseOnImplThread, this); 295 } 296 297 void TextureLayer::MailboxHolder::InternalAddRef() { 298 ++internal_references_; 299 } 300 301 void TextureLayer::MailboxHolder::InternalRelease() { 302 DCHECK(message_loop_->BelongsToCurrentThread()); 303 if (!--internal_references_) { 304 mailbox_.RunReleaseCallback(sync_point_, is_lost_); 305 mailbox_ = TextureMailbox(); 306 } 307 } 308 309 void TextureLayer::MailboxHolder::ReturnAndReleaseOnMainThread( 310 unsigned sync_point, bool is_lost) { 311 DCHECK(message_loop_->BelongsToCurrentThread()); 312 Return(sync_point, is_lost); 313 InternalRelease(); 314 } 315 316 void TextureLayer::MailboxHolder::ReturnAndReleaseOnImplThread( 317 unsigned sync_point, bool is_lost) { 318 message_loop_->PostTask(FROM_HERE, base::Bind( 319 &MailboxHolder::ReturnAndReleaseOnMainThread, 320 this, sync_point, is_lost)); 321 } 322 323 } // namespace cc 324