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