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/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"
19 scoped_refptr
<TextureLayer
> TextureLayer::Create(TextureLayerClient
* client
) {
20 return scoped_refptr
<TextureLayer
>(new TextureLayer(client
, false));
23 scoped_refptr
<TextureLayer
> TextureLayer::CreateForMailbox(
24 TextureLayerClient
* client
) {
25 return scoped_refptr
<TextureLayer
>(new TextureLayer(client
, true));
28 TextureLayer::TextureLayer(TextureLayerClient
* client
, bool uses_mailbox
)
31 uses_mailbox_(uses_mailbox
),
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),
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
;
47 TextureLayer::~TextureLayer() {
50 void TextureLayer::ClearClient() {
51 if (rate_limit_context_
&& client_
&& layer_tree_host())
52 layer_tree_host()->StopRateLimiter();
55 SetTextureMailbox(TextureMailbox(), scoped_ptr
<SingleReleaseCallback
>());
60 scoped_ptr
<LayerImpl
> TextureLayer::CreateLayerImpl(LayerTreeImpl
* tree_impl
) {
61 return TextureLayerImpl::Create(tree_impl
, id(), uses_mailbox_
).
65 void TextureLayer::SetFlipped(bool flipped
) {
66 if (flipped_
== flipped
)
72 void TextureLayer::SetUV(gfx::PointF top_left
, gfx::PointF bottom_right
) {
73 if (uv_top_left_
== top_left
&& uv_bottom_right_
== bottom_right
)
75 uv_top_left_
= top_left
;
76 uv_bottom_right_
= bottom_right
;
80 void TextureLayer::SetVertexOpacity(float bottom_left
,
84 // Indexing according to the quad vertex generation:
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
)
93 vertex_opacity_
[0] = bottom_left
;
94 vertex_opacity_
[1] = top_left
;
95 vertex_opacity_
[2] = top_right
;
96 vertex_opacity_
[3] = bottom_right
;
100 void TextureLayer::SetPremultipliedAlpha(bool premultiplied_alpha
) {
101 if (premultiplied_alpha_
== premultiplied_alpha
)
103 premultiplied_alpha_
= premultiplied_alpha
;
107 void TextureLayer::SetBlendBackgroundColor(bool blend
) {
108 if (blend_background_color_
== blend
)
110 blend_background_color_
= blend
;
114 void TextureLayer::SetRateLimitContext(bool rate_limit
) {
115 if (!rate_limit
&& rate_limit_context_
&& client_
&& layer_tree_host())
116 layer_tree_host()->StopRateLimiter();
118 rate_limit_context_
= rate_limit
;
121 void TextureLayer::SetTextureId(unsigned id
) {
122 DCHECK(!uses_mailbox_
);
123 if (texture_id_
== id
)
125 if (texture_id_
&& layer_tree_host())
126 layer_tree_host()->AcquireLayerTextures();
129 // The texture id needs to be removed from the active tree before the
130 // commit is called complete.
131 SetNextCommitWaitsForActivation();
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
);
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());
148 needs_set_mailbox_
= true;
149 // If we are within a commit, no need to do it again immediately after.
153 SetNeedsPushProperties();
155 // The active frame needs to be replaced and the mailbox returned before the
156 // commit is called complete.
157 SetNextCommitWaitsForActivation();
160 void TextureLayer::SetTextureMailbox(
161 const TextureMailbox
& mailbox
,
162 scoped_ptr
<SingleReleaseCallback
> release_callback
) {
163 SetTextureMailboxInternal(
165 release_callback
.Pass(),
166 true /* requires_commit */);
169 void TextureLayer::WillModifyTexture() {
170 if (!uses_mailbox_
&& layer_tree_host() && (DrawsContent() ||
171 content_committed_
)) {
172 layer_tree_host()->AcquireLayerTextures();
173 content_committed_
= false;
177 void TextureLayer::SetNeedsDisplayRect(const gfx::RectF
& dirty_rect
) {
178 Layer::SetNeedsDisplayRect(dirty_rect
);
180 if (rate_limit_context_
&& client_
&& layer_tree_host() && DrawsContent())
181 layer_tree_host()->StartRateLimiter();
184 void TextureLayer::SetLayerTreeHost(LayerTreeHost
* host
) {
185 if (layer_tree_host() == host
) {
186 Layer::SetLayerTreeHost(host
);
190 if (layer_tree_host()) {
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();
197 if (rate_limit_context_
&& client_
)
198 layer_tree_host()->StopRateLimiter();
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
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();
209 Layer::SetLayerTreeHost(host
);
212 bool TextureLayer::DrawsContent() const {
213 return (client_
|| texture_id_
|| holder_ref_
) && Layer::DrawsContent();
216 bool TextureLayer::Update(ResourceUpdateQueue
* queue
,
217 const OcclusionTracker
* occlusion
) {
218 bool updated
= Layer::Update(queue
, occlusion
);
221 TextureMailbox mailbox
;
222 scoped_ptr
<SingleReleaseCallback
> release_callback
;
223 if (client_
->PrepareTextureMailbox(
226 layer_tree_host()->UsingSharedMemoryResources())) {
227 // Already within a commit, no need to do another one immediately.
228 SetTextureMailboxInternal(
230 release_callback
.Pass(),
231 false /* requires_commit */);
235 texture_id_
= client_
->PrepareTexture();
237 SetNeedsPushProperties();
238 // The texture id needs to be removed from the active tree before the
239 // commit is called complete.
240 SetNextCommitWaitsForActivation();
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();
250 void TextureLayer::PushPropertiesTo(LayerImpl
* layer
) {
251 Layer::PushPropertiesTo(layer
);
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
;
264 MailboxHolder
* holder
= holder_ref_
->holder();
265 texture_mailbox
= holder
->mailbox();
266 release_callback
= holder
->GetCallbackForImplThread();
268 texture_layer
->SetTextureMailbox(texture_mailbox
, release_callback
.Pass());
269 needs_set_mailbox_
= false;
271 texture_layer
->set_texture_id(texture_id_
);
272 content_committed_
= DrawsContent();
276 Region
TextureLayer::VisibleContentOpaqueRegion() const {
277 if (contents_opaque())
278 return visible_content_rect();
280 if (blend_background_color_
&& (SkColorGetA(background_color()) == 0xFF))
281 return visible_content_rect();
286 TextureLayer::MailboxHolder::MainThreadReference::MainThreadReference(
287 MailboxHolder
* holder
)
289 holder_
->InternalAddRef();
292 TextureLayer::MailboxHolder::MainThreadReference::~MainThreadReference() {
293 holder_
->InternalRelease();
296 TextureLayer::MailboxHolder::MailboxHolder(
297 const TextureMailbox
& mailbox
,
298 scoped_ptr
<SingleReleaseCallback
> release_callback
)
299 : message_loop_(BlockingTaskRunner::current()),
300 internal_references_(0),
302 release_callback_(release_callback
.Pass()),
303 sync_point_(mailbox
.sync_point()),
307 TextureLayer::MailboxHolder::~MailboxHolder() {
308 DCHECK_EQ(0u, internal_references_
);
311 scoped_ptr
<TextureLayer::MailboxHolder::MainThreadReference
>
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())));
319 void TextureLayer::MailboxHolder::Return(unsigned sync_point
, bool is_lost
) {
320 base::AutoLock
lock(arguments_lock_
);
321 sync_point_
= sync_point
;
325 scoped_ptr
<SingleReleaseCallback
>
326 TextureLayer::MailboxHolder::GetCallbackForImplThread() {
327 // We can't call GetCallbackForImplThread if we released the main thread
329 DCHECK_GT(internal_references_
, 0u);
331 return SingleReleaseCallback::Create(
332 base::Bind(&MailboxHolder::ReturnAndReleaseOnImplThread
, this));
335 void TextureLayer::MailboxHolder::InternalAddRef() {
336 ++internal_references_
;
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();
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));