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