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