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