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