• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 namespace cc {
18 
Create(TextureLayerClient * client)19 scoped_refptr<TextureLayer> TextureLayer::Create(TextureLayerClient* client) {
20   return scoped_refptr<TextureLayer>(new TextureLayer(client, false));
21 }
22 
CreateForMailbox(TextureLayerClient * client)23 scoped_refptr<TextureLayer> TextureLayer::CreateForMailbox(
24     TextureLayerClient* client) {
25   return scoped_refptr<TextureLayer>(new TextureLayer(client, true));
26 }
27 
TextureLayer(TextureLayerClient * client,bool uses_mailbox)28 TextureLayer::TextureLayer(TextureLayerClient* client, bool uses_mailbox)
29     : Layer(),
30       client_(client),
31       uses_mailbox_(uses_mailbox),
32       flipped_(true),
33       uv_top_left_(0.f, 0.f),
34       uv_bottom_right_(1.f, 1.f),
35       premultiplied_alpha_(true),
36       blend_background_color_(false),
37       rate_limit_context_(false),
38       content_committed_(false),
39       texture_id_(0),
40       needs_set_mailbox_(false) {
41   vertex_opacity_[0] = 1.0f;
42   vertex_opacity_[1] = 1.0f;
43   vertex_opacity_[2] = 1.0f;
44   vertex_opacity_[3] = 1.0f;
45 }
46 
~TextureLayer()47 TextureLayer::~TextureLayer() {
48 }
49 
ClearClient()50 void TextureLayer::ClearClient() {
51   if (rate_limit_context_ && client_ && layer_tree_host())
52     layer_tree_host()->StopRateLimiter();
53   client_ = NULL;
54   if (uses_mailbox_)
55     SetTextureMailbox(TextureMailbox(), scoped_ptr<SingleReleaseCallback>());
56   else
57     SetTextureId(0);
58 }
59 
CreateLayerImpl(LayerTreeImpl * tree_impl)60 scoped_ptr<LayerImpl> TextureLayer::CreateLayerImpl(LayerTreeImpl* tree_impl) {
61   return TextureLayerImpl::Create(tree_impl, id(), uses_mailbox_).
62       PassAs<LayerImpl>();
63 }
64 
SetFlipped(bool flipped)65 void TextureLayer::SetFlipped(bool flipped) {
66   if (flipped_ == flipped)
67     return;
68   flipped_ = flipped;
69   SetNeedsCommit();
70 }
71 
SetUV(gfx::PointF top_left,gfx::PointF bottom_right)72 void TextureLayer::SetUV(gfx::PointF top_left, gfx::PointF bottom_right) {
73   if (uv_top_left_ == top_left && uv_bottom_right_ == bottom_right)
74     return;
75   uv_top_left_ = top_left;
76   uv_bottom_right_ = bottom_right;
77   SetNeedsCommit();
78 }
79 
SetVertexOpacity(float bottom_left,float top_left,float top_right,float bottom_right)80 void TextureLayer::SetVertexOpacity(float bottom_left,
81                                     float top_left,
82                                     float top_right,
83                                     float bottom_right) {
84   // Indexing according to the quad vertex generation:
85   // 1--2
86   // |  |
87   // 0--3
88   if (vertex_opacity_[0] == bottom_left &&
89       vertex_opacity_[1] == top_left &&
90       vertex_opacity_[2] == top_right &&
91       vertex_opacity_[3] == bottom_right)
92     return;
93   vertex_opacity_[0] = bottom_left;
94   vertex_opacity_[1] = top_left;
95   vertex_opacity_[2] = top_right;
96   vertex_opacity_[3] = bottom_right;
97   SetNeedsCommit();
98 }
99 
SetPremultipliedAlpha(bool premultiplied_alpha)100 void TextureLayer::SetPremultipliedAlpha(bool premultiplied_alpha) {
101   if (premultiplied_alpha_ == premultiplied_alpha)
102     return;
103   premultiplied_alpha_ = premultiplied_alpha;
104   SetNeedsCommit();
105 }
106 
SetBlendBackgroundColor(bool blend)107 void TextureLayer::SetBlendBackgroundColor(bool blend) {
108   if (blend_background_color_ == blend)
109     return;
110   blend_background_color_ = blend;
111   SetNeedsCommit();
112 }
113 
SetRateLimitContext(bool rate_limit)114 void TextureLayer::SetRateLimitContext(bool rate_limit) {
115   if (!rate_limit && rate_limit_context_ && client_ && layer_tree_host())
116     layer_tree_host()->StopRateLimiter();
117 
118   rate_limit_context_ = rate_limit;
119 }
120 
SetTextureId(unsigned id)121 void TextureLayer::SetTextureId(unsigned id) {
122   DCHECK(!uses_mailbox_);
123   if (texture_id_ == id)
124     return;
125   if (texture_id_ && layer_tree_host())
126     layer_tree_host()->AcquireLayerTextures();
127   texture_id_ = id;
128   SetNeedsCommit();
129   // The texture id needs to be removed from the active tree before the
130   // commit is called complete.
131   SetNextCommitWaitsForActivation();
132 }
133 
SetTextureMailboxInternal(const TextureMailbox & mailbox,scoped_ptr<SingleReleaseCallback> release_callback,bool requires_commit)134 void TextureLayer::SetTextureMailboxInternal(
135     const TextureMailbox& mailbox,
136     scoped_ptr<SingleReleaseCallback> release_callback,
137     bool requires_commit) {
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   // If we are within a commit, no need to do it again immediately after.
150   if (requires_commit)
151     SetNeedsCommit();
152   else
153     SetNeedsPushProperties();
154 
155   // The active frame needs to be replaced and the mailbox returned before the
156   // commit is called complete.
157   SetNextCommitWaitsForActivation();
158 }
159 
SetTextureMailbox(const TextureMailbox & mailbox,scoped_ptr<SingleReleaseCallback> release_callback)160 void TextureLayer::SetTextureMailbox(
161     const TextureMailbox& mailbox,
162     scoped_ptr<SingleReleaseCallback> release_callback) {
163   SetTextureMailboxInternal(
164       mailbox,
165       release_callback.Pass(),
166       true /* requires_commit */);
167 }
168 
WillModifyTexture()169 void TextureLayer::WillModifyTexture() {
170   if (!uses_mailbox_ && layer_tree_host() && (DrawsContent() ||
171       content_committed_)) {
172     layer_tree_host()->AcquireLayerTextures();
173     content_committed_ = false;
174   }
175 }
176 
SetNeedsDisplayRect(const gfx::RectF & dirty_rect)177 void 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();
182 }
183 
SetLayerTreeHost(LayerTreeHost * host)184 void 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();
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 
DrawsContent() const212 bool TextureLayer::DrawsContent() const {
213   return (client_ || texture_id_ || holder_ref_) && Layer::DrawsContent();
214 }
215 
Update(ResourceUpdateQueue * queue,const OcclusionTracker * occlusion)216 bool 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       updated = true;
237       SetNeedsPushProperties();
238       // The texture id needs to be removed from the active tree before the
239       // commit is called complete.
240       SetNextCommitWaitsForActivation();
241     }
242   }
243 
244   // SetTextureMailbox could be called externally and the same mailbox used for
245   // different textures.  Such callers notify this layer that the texture has
246   // changed by calling SetNeedsDisplay, so check for that here.
247   return updated || !update_rect_.IsEmpty();
248 }
249 
PushPropertiesTo(LayerImpl * layer)250 void TextureLayer::PushPropertiesTo(LayerImpl* layer) {
251   Layer::PushPropertiesTo(layer);
252 
253   TextureLayerImpl* texture_layer = static_cast<TextureLayerImpl*>(layer);
254   texture_layer->set_flipped(flipped_);
255   texture_layer->set_uv_top_left(uv_top_left_);
256   texture_layer->set_uv_bottom_right(uv_bottom_right_);
257   texture_layer->set_vertex_opacity(vertex_opacity_);
258   texture_layer->set_premultiplied_alpha(premultiplied_alpha_);
259   texture_layer->set_blend_background_color(blend_background_color_);
260   if (uses_mailbox_ && needs_set_mailbox_) {
261     TextureMailbox texture_mailbox;
262     scoped_ptr<SingleReleaseCallback> release_callback;
263     if (holder_ref_) {
264       MailboxHolder* holder = holder_ref_->holder();
265       texture_mailbox = holder->mailbox();
266       release_callback = holder->GetCallbackForImplThread();
267     }
268     texture_layer->SetTextureMailbox(texture_mailbox, release_callback.Pass());
269     needs_set_mailbox_ = false;
270   } else {
271     texture_layer->set_texture_id(texture_id_);
272     content_committed_ = DrawsContent();
273   }
274 }
275 
VisibleContentOpaqueRegion() const276 Region TextureLayer::VisibleContentOpaqueRegion() const {
277   if (contents_opaque())
278     return visible_content_rect();
279 
280   if (blend_background_color_ && (SkColorGetA(background_color()) == 0xFF))
281     return visible_content_rect();
282 
283   return Region();
284 }
285 
MainThreadReference(MailboxHolder * holder)286 TextureLayer::MailboxHolder::MainThreadReference::MainThreadReference(
287     MailboxHolder* holder)
288     : holder_(holder) {
289   holder_->InternalAddRef();
290 }
291 
~MainThreadReference()292 TextureLayer::MailboxHolder::MainThreadReference::~MainThreadReference() {
293   holder_->InternalRelease();
294 }
295 
MailboxHolder(const TextureMailbox & mailbox,scoped_ptr<SingleReleaseCallback> release_callback)296 TextureLayer::MailboxHolder::MailboxHolder(
297     const TextureMailbox& mailbox,
298     scoped_ptr<SingleReleaseCallback> release_callback)
299     : message_loop_(BlockingTaskRunner::current()),
300       internal_references_(0),
301       mailbox_(mailbox),
302       release_callback_(release_callback.Pass()),
303       sync_point_(mailbox.sync_point()),
304       is_lost_(false) {
305 }
306 
~MailboxHolder()307 TextureLayer::MailboxHolder::~MailboxHolder() {
308   DCHECK_EQ(0u, internal_references_);
309 }
310 
311 scoped_ptr<TextureLayer::MailboxHolder::MainThreadReference>
Create(const TextureMailbox & mailbox,scoped_ptr<SingleReleaseCallback> release_callback)312 TextureLayer::MailboxHolder::Create(
313     const TextureMailbox& mailbox,
314     scoped_ptr<SingleReleaseCallback> release_callback) {
315   return scoped_ptr<MainThreadReference>(new MainThreadReference(
316       new MailboxHolder(mailbox, release_callback.Pass())));
317 }
318 
Return(unsigned sync_point,bool is_lost)319 void TextureLayer::MailboxHolder::Return(unsigned sync_point, bool is_lost) {
320   base::AutoLock lock(arguments_lock_);
321   sync_point_ = sync_point;
322   is_lost_ = is_lost;
323 }
324 
325 scoped_ptr<SingleReleaseCallback>
GetCallbackForImplThread()326 TextureLayer::MailboxHolder::GetCallbackForImplThread() {
327   // We can't call GetCallbackForImplThread if we released the main thread
328   // reference.
329   DCHECK_GT(internal_references_, 0u);
330   InternalAddRef();
331   return SingleReleaseCallback::Create(
332       base::Bind(&MailboxHolder::ReturnAndReleaseOnImplThread, this));
333 }
334 
InternalAddRef()335 void TextureLayer::MailboxHolder::InternalAddRef() {
336   ++internal_references_;
337 }
338 
InternalRelease()339 void TextureLayer::MailboxHolder::InternalRelease() {
340   DCHECK(message_loop_->BelongsToCurrentThread());
341   if (!--internal_references_) {
342     release_callback_->Run(sync_point_, is_lost_);
343     mailbox_ = TextureMailbox();
344     release_callback_.reset();
345   }
346 }
347 
ReturnAndReleaseOnImplThread(unsigned sync_point,bool is_lost)348 void TextureLayer::MailboxHolder::ReturnAndReleaseOnImplThread(
349     unsigned sync_point, bool is_lost) {
350   Return(sync_point, is_lost);
351   message_loop_->PostTask(FROM_HERE,
352                           base::Bind(&MailboxHolder::InternalRelease, this));
353 }
354 
355 }  // namespace cc
356