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.
5 #include "cc/layers/texture_layer.h"
8 #include "base/callback_helpers.h"
9 #include "base/location.h"
10 #include "base/synchronization/lock.h"
11 #include "cc/base/simple_enclosed_region.h"
12 #include "cc/layers/texture_layer_client.h"
13 #include "cc/layers/texture_layer_impl.h"
14 #include "cc/resources/single_release_callback.h"
15 #include "cc/trees/blocking_task_runner.h"
16 #include "cc/trees/layer_tree_host.h"
20 scoped_refptr
<TextureLayer
> TextureLayer::CreateForMailbox(
21 TextureLayerClient
* client
) {
22 return scoped_refptr
<TextureLayer
>(new TextureLayer(client
));
25 TextureLayer::TextureLayer(TextureLayerClient
* client
)
29 uv_top_left_(0.f
, 0.f
),
30 uv_bottom_right_(1.f
, 1.f
),
31 premultiplied_alpha_(true),
32 blend_background_color_(false),
33 rate_limit_context_(false),
34 needs_set_mailbox_(false) {
35 vertex_opacity_
[0] = 1.0f
;
36 vertex_opacity_
[1] = 1.0f
;
37 vertex_opacity_
[2] = 1.0f
;
38 vertex_opacity_
[3] = 1.0f
;
41 TextureLayer::~TextureLayer() {
44 void TextureLayer::ClearClient() {
45 if (rate_limit_context_
&& client_
&& layer_tree_host())
46 layer_tree_host()->StopRateLimiter();
49 UpdateDrawsContent(HasDrawableContent());
52 void TextureLayer::ClearTexture() {
53 SetTextureMailbox(TextureMailbox(), scoped_ptr
<SingleReleaseCallback
>());
56 scoped_ptr
<LayerImpl
> TextureLayer::CreateLayerImpl(LayerTreeImpl
* tree_impl
) {
57 return TextureLayerImpl::Create(tree_impl
, id()).PassAs
<LayerImpl
>();
60 void TextureLayer::SetFlipped(bool flipped
) {
61 if (flipped_
== flipped
)
67 void TextureLayer::SetUV(const gfx::PointF
& top_left
,
68 const gfx::PointF
& bottom_right
) {
69 if (uv_top_left_
== top_left
&& uv_bottom_right_
== bottom_right
)
71 uv_top_left_
= top_left
;
72 uv_bottom_right_
= bottom_right
;
76 void TextureLayer::SetVertexOpacity(float bottom_left
,
80 // Indexing according to the quad vertex generation:
84 if (vertex_opacity_
[0] == bottom_left
&&
85 vertex_opacity_
[1] == top_left
&&
86 vertex_opacity_
[2] == top_right
&&
87 vertex_opacity_
[3] == bottom_right
)
89 vertex_opacity_
[0] = bottom_left
;
90 vertex_opacity_
[1] = top_left
;
91 vertex_opacity_
[2] = top_right
;
92 vertex_opacity_
[3] = bottom_right
;
96 void TextureLayer::SetPremultipliedAlpha(bool premultiplied_alpha
) {
97 if (premultiplied_alpha_
== premultiplied_alpha
)
99 premultiplied_alpha_
= premultiplied_alpha
;
103 void TextureLayer::SetBlendBackgroundColor(bool blend
) {
104 if (blend_background_color_
== blend
)
106 blend_background_color_
= blend
;
110 void TextureLayer::SetRateLimitContext(bool rate_limit
) {
111 if (!rate_limit
&& rate_limit_context_
&& client_
&& layer_tree_host())
112 layer_tree_host()->StopRateLimiter();
114 rate_limit_context_
= rate_limit
;
117 void TextureLayer::SetTextureMailboxInternal(
118 const TextureMailbox
& mailbox
,
119 scoped_ptr
<SingleReleaseCallback
> release_callback
,
120 bool requires_commit
,
121 bool allow_mailbox_reuse
) {
122 DCHECK(!mailbox
.IsValid() || !holder_ref_
||
123 !mailbox
.Equals(holder_ref_
->holder()->mailbox()) ||
124 allow_mailbox_reuse
);
125 DCHECK_EQ(mailbox
.IsValid(), !!release_callback
);
127 // If we never commited the mailbox, we need to release it here.
128 if (mailbox
.IsValid()) {
130 TextureMailboxHolder::Create(mailbox
, release_callback
.Pass());
134 needs_set_mailbox_
= true;
135 // If we are within a commit, no need to do it again immediately after.
139 SetNeedsPushProperties();
141 UpdateDrawsContent(HasDrawableContent());
142 // The active frame needs to be replaced and the mailbox returned before the
143 // commit is called complete.
144 SetNextCommitWaitsForActivation();
147 void TextureLayer::SetTextureMailbox(
148 const TextureMailbox
& mailbox
,
149 scoped_ptr
<SingleReleaseCallback
> release_callback
) {
150 bool requires_commit
= true;
151 bool allow_mailbox_reuse
= false;
152 SetTextureMailboxInternal(
153 mailbox
, release_callback
.Pass(), requires_commit
, allow_mailbox_reuse
);
156 static void IgnoreReleaseCallback(uint32 sync_point
, bool lost
) {}
158 void TextureLayer::SetTextureMailboxWithoutReleaseCallback(
159 const TextureMailbox
& mailbox
) {
160 // We allow reuse of the mailbox if there is a new sync point signalling new
161 // content, and the release callback goes nowhere since we'll be calling it
162 // multiple times for the same mailbox.
163 DCHECK(!mailbox
.IsValid() || !holder_ref_
||
164 !mailbox
.Equals(holder_ref_
->holder()->mailbox()) ||
165 mailbox
.sync_point() != holder_ref_
->holder()->mailbox().sync_point());
166 scoped_ptr
<SingleReleaseCallback
> release
;
167 bool requires_commit
= true;
168 bool allow_mailbox_reuse
= true;
169 if (mailbox
.IsValid())
170 release
= SingleReleaseCallback::Create(base::Bind(&IgnoreReleaseCallback
));
171 SetTextureMailboxInternal(
172 mailbox
, release
.Pass(), requires_commit
, allow_mailbox_reuse
);
175 void TextureLayer::SetNeedsDisplayRect(const gfx::RectF
& dirty_rect
) {
176 Layer::SetNeedsDisplayRect(dirty_rect
);
178 if (rate_limit_context_
&& client_
&& layer_tree_host() && DrawsContent())
179 layer_tree_host()->StartRateLimiter();
182 void TextureLayer::SetLayerTreeHost(LayerTreeHost
* host
) {
183 if (layer_tree_host() == host
) {
184 Layer::SetLayerTreeHost(host
);
188 if (layer_tree_host()) {
189 if (rate_limit_context_
&& client_
)
190 layer_tree_host()->StopRateLimiter();
192 // If we're removed from the tree, the TextureLayerImpl will be destroyed, and
193 // we will need to set the mailbox again on a new TextureLayerImpl the next
195 if (!host
&& holder_ref_
) {
196 needs_set_mailbox_
= true;
197 // The active frame needs to be replaced and the mailbox returned before the
198 // commit is called complete.
199 SetNextCommitWaitsForActivation();
201 Layer::SetLayerTreeHost(host
);
204 bool TextureLayer::HasDrawableContent() const {
205 return (client_
|| holder_ref_
) && Layer::HasDrawableContent();
208 bool TextureLayer::Update(ResourceUpdateQueue
* queue
,
209 const OcclusionTracker
<Layer
>* occlusion
) {
210 bool updated
= Layer::Update(queue
, occlusion
);
212 TextureMailbox mailbox
;
213 scoped_ptr
<SingleReleaseCallback
> release_callback
;
214 if (client_
->PrepareTextureMailbox(
217 layer_tree_host()->UsingSharedMemoryResources())) {
218 // Already within a commit, no need to do another one immediately.
219 bool requires_commit
= false;
220 bool allow_mailbox_reuse
= false;
221 SetTextureMailboxInternal(mailbox
,
222 release_callback
.Pass(),
224 allow_mailbox_reuse
);
229 // SetTextureMailbox could be called externally and the same mailbox used for
230 // different textures. Such callers notify this layer that the texture has
231 // changed by calling SetNeedsDisplay, so check for that here.
232 return updated
|| !update_rect_
.IsEmpty();
235 void TextureLayer::PushPropertiesTo(LayerImpl
* layer
) {
236 Layer::PushPropertiesTo(layer
);
238 TextureLayerImpl
* texture_layer
= static_cast<TextureLayerImpl
*>(layer
);
239 texture_layer
->SetFlipped(flipped_
);
240 texture_layer
->SetUVTopLeft(uv_top_left_
);
241 texture_layer
->SetUVBottomRight(uv_bottom_right_
);
242 texture_layer
->SetVertexOpacity(vertex_opacity_
);
243 texture_layer
->SetPremultipliedAlpha(premultiplied_alpha_
);
244 texture_layer
->SetBlendBackgroundColor(blend_background_color_
);
245 if (needs_set_mailbox_
) {
246 TextureMailbox texture_mailbox
;
247 scoped_ptr
<SingleReleaseCallback
> release_callback
;
249 TextureMailboxHolder
* holder
= holder_ref_
->holder();
250 texture_mailbox
= holder
->mailbox();
251 release_callback
= holder
->GetCallbackForImplThread();
253 texture_layer
->SetTextureMailbox(texture_mailbox
, release_callback
.Pass());
254 needs_set_mailbox_
= false;
258 SimpleEnclosedRegion
TextureLayer::VisibleContentOpaqueRegion() const {
259 if (contents_opaque())
260 return SimpleEnclosedRegion(visible_content_rect());
262 if (blend_background_color_
&& (SkColorGetA(background_color()) == 0xFF))
263 return SimpleEnclosedRegion(visible_content_rect());
265 return SimpleEnclosedRegion();
268 TextureLayer::TextureMailboxHolder::MainThreadReference::MainThreadReference(
269 TextureMailboxHolder
* holder
)
271 holder_
->InternalAddRef();
274 TextureLayer::TextureMailboxHolder::MainThreadReference::
275 ~MainThreadReference() {
276 holder_
->InternalRelease();
279 TextureLayer::TextureMailboxHolder::TextureMailboxHolder(
280 const TextureMailbox
& mailbox
,
281 scoped_ptr
<SingleReleaseCallback
> release_callback
)
282 : message_loop_(BlockingTaskRunner::current()),
283 internal_references_(0),
285 release_callback_(release_callback
.Pass()),
286 sync_point_(mailbox
.sync_point()),
289 TextureLayer::TextureMailboxHolder::~TextureMailboxHolder() {
290 DCHECK_EQ(0u, internal_references_
);
293 scoped_ptr
<TextureLayer::TextureMailboxHolder::MainThreadReference
>
294 TextureLayer::TextureMailboxHolder::Create(
295 const TextureMailbox
& mailbox
,
296 scoped_ptr
<SingleReleaseCallback
> release_callback
) {
297 return scoped_ptr
<MainThreadReference
>(new MainThreadReference(
298 new TextureMailboxHolder(mailbox
, release_callback
.Pass())));
301 void TextureLayer::TextureMailboxHolder::Return(uint32 sync_point
,
303 base::AutoLock
lock(arguments_lock_
);
304 sync_point_
= sync_point
;
308 scoped_ptr
<SingleReleaseCallback
>
309 TextureLayer::TextureMailboxHolder::GetCallbackForImplThread() {
310 // We can't call GetCallbackForImplThread if we released the main thread
312 DCHECK_GT(internal_references_
, 0u);
314 return SingleReleaseCallback::Create(
315 base::Bind(&TextureMailboxHolder::ReturnAndReleaseOnImplThread
, this));
318 void TextureLayer::TextureMailboxHolder::InternalAddRef() {
319 ++internal_references_
;
322 void TextureLayer::TextureMailboxHolder::InternalRelease() {
323 DCHECK(message_loop_
->BelongsToCurrentThread());
324 if (!--internal_references_
) {
325 release_callback_
->Run(sync_point_
, is_lost_
);
326 mailbox_
= TextureMailbox();
327 release_callback_
.reset();
331 void TextureLayer::TextureMailboxHolder::ReturnAndReleaseOnImplThread(
334 Return(sync_point
, is_lost
);
335 message_loop_
->PostTask(
336 FROM_HERE
, base::Bind(&TextureMailboxHolder::InternalRelease
, this));