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