texture_layer.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
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#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
17
18namespace cc {
19
20scoped_refptr<TextureLayer> TextureLayer::Create(TextureLayerClient* client) {
21  return scoped_refptr<TextureLayer>(new TextureLayer(client, false));
22}
23
24scoped_refptr<TextureLayer> TextureLayer::CreateForMailbox(
25    TextureLayerClient* client) {
26  return scoped_refptr<TextureLayer>(new TextureLayer(client, true));
27}
28
29TextureLayer::TextureLayer(TextureLayerClient* client, bool uses_mailbox)
30    : Layer(),
31      client_(client),
32      uses_mailbox_(uses_mailbox),
33      flipped_(true),
34      uv_top_left_(0.f, 0.f),
35      uv_bottom_right_(1.f, 1.f),
36      premultiplied_alpha_(true),
37      blend_background_color_(false),
38      rate_limit_context_(false),
39      content_committed_(false),
40      texture_id_(0),
41      needs_set_mailbox_(false) {
42  vertex_opacity_[0] = 1.0f;
43  vertex_opacity_[1] = 1.0f;
44  vertex_opacity_[2] = 1.0f;
45  vertex_opacity_[3] = 1.0f;
46}
47
48TextureLayer::~TextureLayer() {
49}
50
51void TextureLayer::ClearClient() {
52  if (rate_limit_context_ && client_ && layer_tree_host())
53    layer_tree_host()->StopRateLimiter(client_->Context3d());
54  client_ = NULL;
55  if (uses_mailbox_)
56    SetTextureMailbox(TextureMailbox(), scoped_ptr<SingleReleaseCallback>());
57  else
58    SetTextureId(0);
59}
60
61scoped_ptr<LayerImpl> TextureLayer::CreateLayerImpl(LayerTreeImpl* tree_impl) {
62  return TextureLayerImpl::Create(tree_impl, id(), uses_mailbox_).
63      PassAs<LayerImpl>();
64}
65
66void TextureLayer::SetFlipped(bool flipped) {
67  if (flipped_ == flipped)
68    return;
69  flipped_ = flipped;
70  SetNeedsCommit();
71}
72
73void TextureLayer::SetUV(gfx::PointF top_left, 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(client_->Context3d());
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_ = MailboxHolder::Create(mailbox, release_callback.Pass());
147  else
148    holder_ref_.reset();
149  needs_set_mailbox_ = true;
150  // If we are within a commit, no need to do it again immediately after.
151  if (requires_commit)
152    SetNeedsCommit();
153  else
154    SetNeedsPushProperties();
155
156  // The active frame needs to be replaced and the mailbox returned before the
157  // commit is called complete.
158  SetNextCommitWaitsForActivation();
159}
160
161void TextureLayer::SetTextureMailbox(
162    const TextureMailbox& mailbox,
163    scoped_ptr<SingleReleaseCallback> release_callback) {
164  SetTextureMailboxInternal(
165      mailbox,
166      release_callback.Pass(),
167      true /* requires_commit */);
168}
169
170void TextureLayer::WillModifyTexture() {
171  if (layer_tree_host() && (DrawsContent() || content_committed_)) {
172    layer_tree_host()->AcquireLayerTextures();
173    content_committed_ = false;
174  }
175}
176
177void 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(client_->Context3d());
182}
183
184void 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(client_->Context3d());
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
212bool TextureLayer::DrawsContent() const {
213  return (client_ || texture_id_ || holder_ref_) && Layer::DrawsContent();
214}
215
216bool 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      DCHECK_EQ(!!texture_id_, !!client_->Context3d());
237      if (client_->Context3d() &&
238          client_->Context3d()->getGraphicsResetStatusARB() != GL_NO_ERROR)
239        texture_id_ = 0;
240      updated = true;
241      SetNeedsPushProperties();
242      // The texture id needs to be removed from the active tree before the
243      // commit is called complete.
244      SetNextCommitWaitsForActivation();
245    }
246  }
247
248  // SetTextureMailbox could be called externally and the same mailbox used for
249  // different textures.  Such callers notify this layer that the texture has
250  // changed by calling SetNeedsDisplay, so check for that here.
251  return updated || !update_rect_.IsEmpty();
252}
253
254void TextureLayer::PushPropertiesTo(LayerImpl* layer) {
255  Layer::PushPropertiesTo(layer);
256
257  TextureLayerImpl* texture_layer = static_cast<TextureLayerImpl*>(layer);
258  texture_layer->set_flipped(flipped_);
259  texture_layer->set_uv_top_left(uv_top_left_);
260  texture_layer->set_uv_bottom_right(uv_bottom_right_);
261  texture_layer->set_vertex_opacity(vertex_opacity_);
262  texture_layer->set_premultiplied_alpha(premultiplied_alpha_);
263  texture_layer->set_blend_background_color(blend_background_color_);
264  if (uses_mailbox_ && needs_set_mailbox_) {
265    TextureMailbox texture_mailbox;
266    scoped_ptr<SingleReleaseCallback> release_callback;
267    if (holder_ref_) {
268      MailboxHolder* holder = holder_ref_->holder();
269      texture_mailbox = holder->mailbox();
270      release_callback = holder->GetCallbackForImplThread();
271    }
272    texture_layer->SetTextureMailbox(texture_mailbox, release_callback.Pass());
273    needs_set_mailbox_ = false;
274  } else {
275    texture_layer->set_texture_id(texture_id_);
276  }
277  content_committed_ = DrawsContent();
278}
279
280Region TextureLayer::VisibleContentOpaqueRegion() const {
281  if (contents_opaque())
282    return visible_content_rect();
283
284  if (blend_background_color_ && (SkColorGetA(background_color()) == 0xFF))
285    return visible_content_rect();
286
287  return Region();
288}
289
290TextureLayer::MailboxHolder::MainThreadReference::MainThreadReference(
291    MailboxHolder* holder)
292    : holder_(holder) {
293  holder_->InternalAddRef();
294}
295
296TextureLayer::MailboxHolder::MainThreadReference::~MainThreadReference() {
297  holder_->InternalRelease();
298}
299
300TextureLayer::MailboxHolder::MailboxHolder(
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}
310
311TextureLayer::MailboxHolder::~MailboxHolder() {
312  DCHECK_EQ(0u, internal_references_);
313}
314
315scoped_ptr<TextureLayer::MailboxHolder::MainThreadReference>
316TextureLayer::MailboxHolder::Create(
317    const TextureMailbox& mailbox,
318    scoped_ptr<SingleReleaseCallback> release_callback) {
319  return scoped_ptr<MainThreadReference>(new MainThreadReference(
320      new MailboxHolder(mailbox, release_callback.Pass())));
321}
322
323void TextureLayer::MailboxHolder::Return(unsigned sync_point, 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::MailboxHolder::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(&MailboxHolder::ReturnAndReleaseOnImplThread, this));
337}
338
339void TextureLayer::MailboxHolder::InternalAddRef() {
340  ++internal_references_;
341}
342
343void TextureLayer::MailboxHolder::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::MailboxHolder::ReturnAndReleaseOnImplThread(
353    unsigned sync_point, bool is_lost) {
354  Return(sync_point, is_lost);
355  message_loop_->PostTask(FROM_HERE,
356                          base::Bind(&MailboxHolder::InternalRelease, this));
357}
358
359}  // namespace cc
360