texture_layer.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
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#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" 17 18namespace cc { 19 20scoped_refptr<TextureLayer> TextureLayer::Create(TextureLayerClient* client) { 21 return scoped_refptr<TextureLayer>(new TextureLayer(client, false)); 22} 23 24scoped_refptr<TextureLayer> TextureLayer::CreateForMailbox( 25 TextureLayerClient* client) { 26 return scoped_refptr<TextureLayer>(new TextureLayer(client, true)); 27} 28 29TextureLayer::TextureLayer(TextureLayerClient* client, bool uses_mailbox) 30 : Layer(), 31 client_(client), 32 uses_mailbox_(uses_mailbox), 33 flipped_(true), 34 uv_top_left_(0.f, 0.f), 35 uv_bottom_right_(1.f, 1.f), 36 premultiplied_alpha_(true), 37 blend_background_color_(false), 38 rate_limit_context_(false), 39 content_committed_(false), 40 texture_id_(0), 41 needs_set_mailbox_(false) { 42 vertex_opacity_[0] = 1.0f; 43 vertex_opacity_[1] = 1.0f; 44 vertex_opacity_[2] = 1.0f; 45 vertex_opacity_[3] = 1.0f; 46} 47 48TextureLayer::~TextureLayer() { 49} 50 51void TextureLayer::ClearClient() { 52 if (rate_limit_context_ && client_ && layer_tree_host()) 53 layer_tree_host()->StopRateLimiter(client_->Context3d()); 54 client_ = NULL; 55 if (uses_mailbox_) 56 SetTextureMailbox(TextureMailbox(), scoped_ptr<SingleReleaseCallback>()); 57 else 58 SetTextureId(0); 59} 60 61scoped_ptr<LayerImpl> TextureLayer::CreateLayerImpl(LayerTreeImpl* tree_impl) { 62 return TextureLayerImpl::Create(tree_impl, id(), uses_mailbox_). 63 PassAs<LayerImpl>(); 64} 65 66void TextureLayer::SetFlipped(bool flipped) { 67 if (flipped_ == flipped) 68 return; 69 flipped_ = flipped; 70 SetNeedsCommit(); 71} 72 73void TextureLayer::SetUV(gfx::PointF top_left, 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(client_->Context3d()); 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_ = MailboxHolder::Create(mailbox, release_callback.Pass()); 147 else 148 holder_ref_.reset(); 149 needs_set_mailbox_ = true; 150 // If we are within a commit, no need to do it again immediately after. 151 if (requires_commit) 152 SetNeedsCommit(); 153 else 154 SetNeedsPushProperties(); 155 156 // The active frame needs to be replaced and the mailbox returned before the 157 // commit is called complete. 158 SetNextCommitWaitsForActivation(); 159} 160 161void TextureLayer::SetTextureMailbox( 162 const TextureMailbox& mailbox, 163 scoped_ptr<SingleReleaseCallback> release_callback) { 164 SetTextureMailboxInternal( 165 mailbox, 166 release_callback.Pass(), 167 true /* requires_commit */); 168} 169 170void TextureLayer::WillModifyTexture() { 171 if (layer_tree_host() && (DrawsContent() || content_committed_)) { 172 layer_tree_host()->AcquireLayerTextures(); 173 content_committed_ = false; 174 } 175} 176 177void 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(client_->Context3d()); 182} 183 184void 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(client_->Context3d()); 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 212bool TextureLayer::DrawsContent() const { 213 return (client_ || texture_id_ || holder_ref_) && Layer::DrawsContent(); 214} 215 216bool 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 DCHECK_EQ(!!texture_id_, !!client_->Context3d()); 237 if (client_->Context3d() && 238 client_->Context3d()->getGraphicsResetStatusARB() != GL_NO_ERROR) 239 texture_id_ = 0; 240 updated = true; 241 SetNeedsPushProperties(); 242 // The texture id needs to be removed from the active tree before the 243 // commit is called complete. 244 SetNextCommitWaitsForActivation(); 245 } 246 } 247 248 // SetTextureMailbox could be called externally and the same mailbox used for 249 // different textures. Such callers notify this layer that the texture has 250 // changed by calling SetNeedsDisplay, so check for that here. 251 return updated || !update_rect_.IsEmpty(); 252} 253 254void TextureLayer::PushPropertiesTo(LayerImpl* layer) { 255 Layer::PushPropertiesTo(layer); 256 257 TextureLayerImpl* texture_layer = static_cast<TextureLayerImpl*>(layer); 258 texture_layer->set_flipped(flipped_); 259 texture_layer->set_uv_top_left(uv_top_left_); 260 texture_layer->set_uv_bottom_right(uv_bottom_right_); 261 texture_layer->set_vertex_opacity(vertex_opacity_); 262 texture_layer->set_premultiplied_alpha(premultiplied_alpha_); 263 texture_layer->set_blend_background_color(blend_background_color_); 264 if (uses_mailbox_ && needs_set_mailbox_) { 265 TextureMailbox texture_mailbox; 266 scoped_ptr<SingleReleaseCallback> release_callback; 267 if (holder_ref_) { 268 MailboxHolder* holder = holder_ref_->holder(); 269 texture_mailbox = holder->mailbox(); 270 release_callback = holder->GetCallbackForImplThread(); 271 } 272 texture_layer->SetTextureMailbox(texture_mailbox, release_callback.Pass()); 273 needs_set_mailbox_ = false; 274 } else { 275 texture_layer->set_texture_id(texture_id_); 276 } 277 content_committed_ = DrawsContent(); 278} 279 280Region TextureLayer::VisibleContentOpaqueRegion() const { 281 if (contents_opaque()) 282 return visible_content_rect(); 283 284 if (blend_background_color_ && (SkColorGetA(background_color()) == 0xFF)) 285 return visible_content_rect(); 286 287 return Region(); 288} 289 290TextureLayer::MailboxHolder::MainThreadReference::MainThreadReference( 291 MailboxHolder* holder) 292 : holder_(holder) { 293 holder_->InternalAddRef(); 294} 295 296TextureLayer::MailboxHolder::MainThreadReference::~MainThreadReference() { 297 holder_->InternalRelease(); 298} 299 300TextureLayer::MailboxHolder::MailboxHolder( 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} 310 311TextureLayer::MailboxHolder::~MailboxHolder() { 312 DCHECK_EQ(0u, internal_references_); 313} 314 315scoped_ptr<TextureLayer::MailboxHolder::MainThreadReference> 316TextureLayer::MailboxHolder::Create( 317 const TextureMailbox& mailbox, 318 scoped_ptr<SingleReleaseCallback> release_callback) { 319 return scoped_ptr<MainThreadReference>(new MainThreadReference( 320 new MailboxHolder(mailbox, release_callback.Pass()))); 321} 322 323void TextureLayer::MailboxHolder::Return(unsigned sync_point, 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::MailboxHolder::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(&MailboxHolder::ReturnAndReleaseOnImplThread, this)); 337} 338 339void TextureLayer::MailboxHolder::InternalAddRef() { 340 ++internal_references_; 341} 342 343void TextureLayer::MailboxHolder::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::MailboxHolder::ReturnAndReleaseOnImplThread( 353 unsigned sync_point, bool is_lost) { 354 Return(sync_point, is_lost); 355 message_loop_->PostTask(FROM_HERE, 356 base::Bind(&MailboxHolder::InternalRelease, this)); 357} 358 359} // namespace cc 360