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