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