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