texture_layer.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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::SetTextureMailbox(
136    const TextureMailbox& mailbox,
137    scoped_ptr<SingleReleaseCallback> release_callback) {
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  SetNeedsCommit();
150  // The active frame needs to be replaced and the mailbox returned before the
151  // commit is called complete.
152  SetNextCommitWaitsForActivation();
153}
154
155void TextureLayer::WillModifyTexture() {
156  if (layer_tree_host() && (DrawsContent() || content_committed_)) {
157    layer_tree_host()->AcquireLayerTextures();
158    content_committed_ = false;
159  }
160}
161
162void TextureLayer::SetNeedsDisplayRect(const gfx::RectF& dirty_rect) {
163  Layer::SetNeedsDisplayRect(dirty_rect);
164
165  if (rate_limit_context_ && client_ && layer_tree_host() && DrawsContent())
166    layer_tree_host()->StartRateLimiter(client_->Context3d());
167}
168
169void TextureLayer::SetLayerTreeHost(LayerTreeHost* host) {
170  if (layer_tree_host() == host) {
171    Layer::SetLayerTreeHost(host);
172    return;
173  }
174
175  if (layer_tree_host()) {
176    if (texture_id_) {
177      layer_tree_host()->AcquireLayerTextures();
178      // The texture id needs to be removed from the active tree before the
179      // commit is called complete.
180      SetNextCommitWaitsForActivation();
181    }
182    if (rate_limit_context_ && client_)
183      layer_tree_host()->StopRateLimiter(client_->Context3d());
184  }
185  // If we're removed from the tree, the TextureLayerImpl will be destroyed, and
186  // we will need to set the mailbox again on a new TextureLayerImpl the next
187  // time we push.
188  if (!host && uses_mailbox_ && holder_ref_) {
189    needs_set_mailbox_ = true;
190    // The active frame needs to be replaced and the mailbox returned before the
191    // commit is called complete.
192    SetNextCommitWaitsForActivation();
193  }
194  Layer::SetLayerTreeHost(host);
195}
196
197bool TextureLayer::DrawsContent() const {
198  return (client_ || texture_id_ || holder_ref_) && Layer::DrawsContent();
199}
200
201bool TextureLayer::Update(ResourceUpdateQueue* queue,
202                          const OcclusionTracker* occlusion) {
203  bool updated = Layer::Update(queue, occlusion);
204  if (client_) {
205    if (uses_mailbox_) {
206      TextureMailbox mailbox;
207      scoped_ptr<SingleReleaseCallback> release_callback;
208      if (client_->PrepareTextureMailbox(
209              &mailbox,
210              &release_callback,
211              layer_tree_host()->UsingSharedMemoryResources())) {
212        SetTextureMailbox(mailbox, release_callback.Pass());
213        updated = true;
214      }
215    } else {
216      texture_id_ = client_->PrepareTexture();
217      DCHECK_EQ(!!texture_id_, !!client_->Context3d());
218      if (client_->Context3d() &&
219          client_->Context3d()->getGraphicsResetStatusARB() != GL_NO_ERROR)
220        texture_id_ = 0;
221      updated = true;
222      SetNeedsPushProperties();
223      // The texture id needs to be removed from the active tree before the
224      // commit is called complete.
225      SetNextCommitWaitsForActivation();
226    }
227  }
228
229  // SetTextureMailbox could be called externally and the same mailbox used for
230  // different textures.  Such callers notify this layer that the texture has
231  // changed by calling SetNeedsDisplay, so check for that here.
232  return updated || !update_rect_.IsEmpty();
233}
234
235void TextureLayer::PushPropertiesTo(LayerImpl* layer) {
236  Layer::PushPropertiesTo(layer);
237
238  TextureLayerImpl* texture_layer = static_cast<TextureLayerImpl*>(layer);
239  texture_layer->set_flipped(flipped_);
240  texture_layer->set_uv_top_left(uv_top_left_);
241  texture_layer->set_uv_bottom_right(uv_bottom_right_);
242  texture_layer->set_vertex_opacity(vertex_opacity_);
243  texture_layer->set_premultiplied_alpha(premultiplied_alpha_);
244  texture_layer->set_blend_background_color(blend_background_color_);
245  if (uses_mailbox_ && needs_set_mailbox_) {
246    TextureMailbox texture_mailbox;
247    scoped_ptr<SingleReleaseCallback> release_callback;
248    if (holder_ref_) {
249      MailboxHolder* holder = holder_ref_->holder();
250      texture_mailbox = holder->mailbox();
251      release_callback = holder->GetCallbackForImplThread();
252    }
253    texture_layer->SetTextureMailbox(texture_mailbox, release_callback.Pass());
254    needs_set_mailbox_ = false;
255  } else {
256    texture_layer->set_texture_id(texture_id_);
257  }
258  content_committed_ = DrawsContent();
259}
260
261Region TextureLayer::VisibleContentOpaqueRegion() const {
262  if (contents_opaque())
263    return visible_content_rect();
264
265  if (blend_background_color_ && (SkColorGetA(background_color()) == 0xFF))
266    return visible_content_rect();
267
268  return Region();
269}
270
271TextureLayer::MailboxHolder::MainThreadReference::MainThreadReference(
272    MailboxHolder* holder)
273    : holder_(holder) {
274  holder_->InternalAddRef();
275}
276
277TextureLayer::MailboxHolder::MainThreadReference::~MainThreadReference() {
278  holder_->InternalRelease();
279}
280
281TextureLayer::MailboxHolder::MailboxHolder(
282    const TextureMailbox& mailbox,
283    scoped_ptr<SingleReleaseCallback> release_callback)
284    : message_loop_(BlockingTaskRunner::current()),
285      internal_references_(0),
286      mailbox_(mailbox),
287      release_callback_(release_callback.Pass()),
288      sync_point_(mailbox.sync_point()),
289      is_lost_(false) {
290}
291
292TextureLayer::MailboxHolder::~MailboxHolder() {
293  DCHECK_EQ(0u, internal_references_);
294}
295
296scoped_ptr<TextureLayer::MailboxHolder::MainThreadReference>
297TextureLayer::MailboxHolder::Create(
298    const TextureMailbox& mailbox,
299    scoped_ptr<SingleReleaseCallback> release_callback) {
300  return scoped_ptr<MainThreadReference>(new MainThreadReference(
301      new MailboxHolder(mailbox, release_callback.Pass())));
302}
303
304void TextureLayer::MailboxHolder::Return(unsigned sync_point, bool is_lost) {
305  base::AutoLock lock(arguments_lock_);
306  sync_point_ = sync_point;
307  is_lost_ = is_lost;
308}
309
310scoped_ptr<SingleReleaseCallback>
311TextureLayer::MailboxHolder::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 SingleReleaseCallback::Create(
317      base::Bind(&MailboxHolder::ReturnAndReleaseOnImplThread, this));
318}
319
320void TextureLayer::MailboxHolder::InternalAddRef() {
321  ++internal_references_;
322}
323
324void TextureLayer::MailboxHolder::InternalRelease() {
325  DCHECK(message_loop_->BelongsToCurrentThread());
326  if (!--internal_references_) {
327    release_callback_->Run(sync_point_, is_lost_);
328    mailbox_ = TextureMailbox();
329    release_callback_.reset();
330  }
331}
332
333void TextureLayer::MailboxHolder::ReturnAndReleaseOnImplThread(
334    unsigned sync_point, bool is_lost) {
335  Return(sync_point, is_lost);
336  message_loop_->PostTask(FROM_HERE,
337                          base::Bind(&MailboxHolder::InternalRelease, this));
338}
339
340}  // namespace cc
341