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