texture_layer.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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::SetTextureMailbox( 136 const TextureMailbox& mailbox, 137 scoped_ptr<SingleReleaseCallback> release_callback) { 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 SetNeedsCommit(); 150 // The active frame needs to be replaced and the mailbox returned before the 151 // commit is called complete. 152 SetNextCommitWaitsForActivation(); 153} 154 155void TextureLayer::WillModifyTexture() { 156 if (layer_tree_host() && (DrawsContent() || content_committed_)) { 157 layer_tree_host()->AcquireLayerTextures(); 158 content_committed_ = false; 159 } 160} 161 162void TextureLayer::SetNeedsDisplayRect(const gfx::RectF& dirty_rect) { 163 Layer::SetNeedsDisplayRect(dirty_rect); 164 165 if (rate_limit_context_ && client_ && layer_tree_host() && DrawsContent()) 166 layer_tree_host()->StartRateLimiter(client_->Context3d()); 167} 168 169void TextureLayer::SetLayerTreeHost(LayerTreeHost* host) { 170 if (layer_tree_host() == host) { 171 Layer::SetLayerTreeHost(host); 172 return; 173 } 174 175 if (layer_tree_host()) { 176 if (texture_id_) { 177 layer_tree_host()->AcquireLayerTextures(); 178 // The texture id needs to be removed from the active tree before the 179 // commit is called complete. 180 SetNextCommitWaitsForActivation(); 181 } 182 if (rate_limit_context_ && client_) 183 layer_tree_host()->StopRateLimiter(client_->Context3d()); 184 } 185 // If we're removed from the tree, the TextureLayerImpl will be destroyed, and 186 // we will need to set the mailbox again on a new TextureLayerImpl the next 187 // time we push. 188 if (!host && uses_mailbox_ && holder_ref_) { 189 needs_set_mailbox_ = true; 190 // The active frame needs to be replaced and the mailbox returned before the 191 // commit is called complete. 192 SetNextCommitWaitsForActivation(); 193 } 194 Layer::SetLayerTreeHost(host); 195} 196 197bool TextureLayer::DrawsContent() const { 198 return (client_ || texture_id_ || holder_ref_) && Layer::DrawsContent(); 199} 200 201bool TextureLayer::Update(ResourceUpdateQueue* queue, 202 const OcclusionTracker* occlusion) { 203 bool updated = Layer::Update(queue, occlusion); 204 if (client_) { 205 if (uses_mailbox_) { 206 TextureMailbox mailbox; 207 scoped_ptr<SingleReleaseCallback> release_callback; 208 if (client_->PrepareTextureMailbox( 209 &mailbox, 210 &release_callback, 211 layer_tree_host()->UsingSharedMemoryResources())) { 212 SetTextureMailbox(mailbox, release_callback.Pass()); 213 updated = true; 214 } 215 } else { 216 texture_id_ = client_->PrepareTexture(); 217 DCHECK_EQ(!!texture_id_, !!client_->Context3d()); 218 if (client_->Context3d() && 219 client_->Context3d()->getGraphicsResetStatusARB() != GL_NO_ERROR) 220 texture_id_ = 0; 221 updated = true; 222 SetNeedsPushProperties(); 223 // The texture id needs to be removed from the active tree before the 224 // commit is called complete. 225 SetNextCommitWaitsForActivation(); 226 } 227 } 228 229 // SetTextureMailbox could be called externally and the same mailbox used for 230 // different textures. Such callers notify this layer that the texture has 231 // changed by calling SetNeedsDisplay, so check for that here. 232 return updated || !update_rect_.IsEmpty(); 233} 234 235void TextureLayer::PushPropertiesTo(LayerImpl* layer) { 236 Layer::PushPropertiesTo(layer); 237 238 TextureLayerImpl* texture_layer = static_cast<TextureLayerImpl*>(layer); 239 texture_layer->set_flipped(flipped_); 240 texture_layer->set_uv_top_left(uv_top_left_); 241 texture_layer->set_uv_bottom_right(uv_bottom_right_); 242 texture_layer->set_vertex_opacity(vertex_opacity_); 243 texture_layer->set_premultiplied_alpha(premultiplied_alpha_); 244 texture_layer->set_blend_background_color(blend_background_color_); 245 if (uses_mailbox_ && needs_set_mailbox_) { 246 TextureMailbox texture_mailbox; 247 scoped_ptr<SingleReleaseCallback> release_callback; 248 if (holder_ref_) { 249 MailboxHolder* holder = holder_ref_->holder(); 250 texture_mailbox = holder->mailbox(); 251 release_callback = holder->GetCallbackForImplThread(); 252 } 253 texture_layer->SetTextureMailbox(texture_mailbox, release_callback.Pass()); 254 needs_set_mailbox_ = false; 255 } else { 256 texture_layer->set_texture_id(texture_id_); 257 } 258 content_committed_ = DrawsContent(); 259} 260 261Region TextureLayer::VisibleContentOpaqueRegion() const { 262 if (contents_opaque()) 263 return visible_content_rect(); 264 265 if (blend_background_color_ && (SkColorGetA(background_color()) == 0xFF)) 266 return visible_content_rect(); 267 268 return Region(); 269} 270 271TextureLayer::MailboxHolder::MainThreadReference::MainThreadReference( 272 MailboxHolder* holder) 273 : holder_(holder) { 274 holder_->InternalAddRef(); 275} 276 277TextureLayer::MailboxHolder::MainThreadReference::~MainThreadReference() { 278 holder_->InternalRelease(); 279} 280 281TextureLayer::MailboxHolder::MailboxHolder( 282 const TextureMailbox& mailbox, 283 scoped_ptr<SingleReleaseCallback> release_callback) 284 : message_loop_(BlockingTaskRunner::current()), 285 internal_references_(0), 286 mailbox_(mailbox), 287 release_callback_(release_callback.Pass()), 288 sync_point_(mailbox.sync_point()), 289 is_lost_(false) { 290} 291 292TextureLayer::MailboxHolder::~MailboxHolder() { 293 DCHECK_EQ(0u, internal_references_); 294} 295 296scoped_ptr<TextureLayer::MailboxHolder::MainThreadReference> 297TextureLayer::MailboxHolder::Create( 298 const TextureMailbox& mailbox, 299 scoped_ptr<SingleReleaseCallback> release_callback) { 300 return scoped_ptr<MainThreadReference>(new MainThreadReference( 301 new MailboxHolder(mailbox, release_callback.Pass()))); 302} 303 304void TextureLayer::MailboxHolder::Return(unsigned sync_point, bool is_lost) { 305 base::AutoLock lock(arguments_lock_); 306 sync_point_ = sync_point; 307 is_lost_ = is_lost; 308} 309 310scoped_ptr<SingleReleaseCallback> 311TextureLayer::MailboxHolder::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 SingleReleaseCallback::Create( 317 base::Bind(&MailboxHolder::ReturnAndReleaseOnImplThread, this)); 318} 319 320void TextureLayer::MailboxHolder::InternalAddRef() { 321 ++internal_references_; 322} 323 324void TextureLayer::MailboxHolder::InternalRelease() { 325 DCHECK(message_loop_->BelongsToCurrentThread()); 326 if (!--internal_references_) { 327 release_callback_->Run(sync_point_, is_lost_); 328 mailbox_ = TextureMailbox(); 329 release_callback_.reset(); 330 } 331} 332 333void TextureLayer::MailboxHolder::ReturnAndReleaseOnImplThread( 334 unsigned sync_point, bool is_lost) { 335 Return(sync_point, is_lost); 336 message_loop_->PostTask(FROM_HERE, 337 base::Bind(&MailboxHolder::InternalRelease, this)); 338} 339 340} // namespace cc 341