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