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
19namespace cc {
20
21scoped_refptr<TextureLayer> TextureLayer::CreateForMailbox(
22    TextureLayerClient* client) {
23  return scoped_refptr<TextureLayer>(new TextureLayer(client));
24}
25
26TextureLayer::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
42TextureLayer::~TextureLayer() {
43}
44
45void 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
53void TextureLayer::ClearTexture() {
54  SetTextureMailbox(TextureMailbox(), scoped_ptr<SingleReleaseCallback>());
55}
56
57scoped_ptr<LayerImpl> TextureLayer::CreateLayerImpl(LayerTreeImpl* tree_impl) {
58  return TextureLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
59}
60
61void TextureLayer::SetFlipped(bool flipped) {
62  if (flipped_ == flipped)
63    return;
64  flipped_ = flipped;
65  SetNeedsCommit();
66}
67
68void 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
77void 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
97void TextureLayer::SetPremultipliedAlpha(bool premultiplied_alpha) {
98  if (premultiplied_alpha_ == premultiplied_alpha)
99    return;
100  premultiplied_alpha_ = premultiplied_alpha;
101  SetNeedsCommit();
102}
103
104void TextureLayer::SetBlendBackgroundColor(bool blend) {
105  if (blend_background_color_ == blend)
106    return;
107  blend_background_color_ = blend;
108  SetNeedsCommit();
109}
110
111void 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
118void 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
148void 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
157static void IgnoreReleaseCallback(uint32 sync_point, bool lost) {}
158
159void 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
176void 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
183void 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
205bool TextureLayer::HasDrawableContent() const {
206  return (client_ || holder_ref_) && Layer::HasDrawableContent();
207}
208
209bool 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
236void 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
260SimpleEnclosedRegion 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
270TextureLayer::TextureMailboxHolder::MainThreadReference::MainThreadReference(
271    TextureMailboxHolder* holder)
272    : holder_(holder) {
273  holder_->InternalAddRef();
274}
275
276TextureLayer::TextureMailboxHolder::MainThreadReference::
277    ~MainThreadReference() {
278  holder_->InternalRelease();
279}
280
281TextureLayer::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
291TextureLayer::TextureMailboxHolder::~TextureMailboxHolder() {
292  DCHECK_EQ(0u, internal_references_);
293}
294
295scoped_ptr<TextureLayer::TextureMailboxHolder::MainThreadReference>
296TextureLayer::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
303void 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
310scoped_ptr<SingleReleaseCallbackImpl>
311TextureLayer::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
320void TextureLayer::TextureMailboxHolder::InternalAddRef() {
321  ++internal_references_;
322}
323
324void 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
333void 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