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