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