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