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