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