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