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/resources/single_release_callback_impl.h"
16 #include "cc/trees/blocking_task_runner.h"
17 #include "cc/trees/layer_tree_host.h"
21 scoped_refptr
<TextureLayer
> TextureLayer::CreateForMailbox(
22 TextureLayerClient
* client
) {
23 return scoped_refptr
<TextureLayer
>(new TextureLayer(client
));
26 TextureLayer::TextureLayer(TextureLayerClient
* client
)
30 nearest_neighbor_(false),
31 uv_top_left_(0.f
, 0.f
),
32 uv_bottom_right_(1.f
, 1.f
),
33 premultiplied_alpha_(true),
34 blend_background_color_(false),
35 rate_limit_context_(false),
36 needs_set_mailbox_(false) {
37 vertex_opacity_
[0] = 1.0f
;
38 vertex_opacity_
[1] = 1.0f
;
39 vertex_opacity_
[2] = 1.0f
;
40 vertex_opacity_
[3] = 1.0f
;
43 TextureLayer::~TextureLayer() {
46 void TextureLayer::ClearClient() {
47 if (rate_limit_context_
&& client_
&& layer_tree_host())
48 layer_tree_host()->StopRateLimiter();
51 UpdateDrawsContent(HasDrawableContent());
54 void TextureLayer::ClearTexture() {
55 SetTextureMailbox(TextureMailbox(), nullptr);
58 scoped_ptr
<LayerImpl
> TextureLayer::CreateLayerImpl(LayerTreeImpl
* tree_impl
) {
59 return TextureLayerImpl::Create(tree_impl
, id());
62 void TextureLayer::SetFlipped(bool flipped
) {
63 if (flipped_
== flipped
)
69 void TextureLayer::SetNearestNeighbor(bool nearest_neighbor
) {
70 if (nearest_neighbor_
== nearest_neighbor
)
72 nearest_neighbor_
= nearest_neighbor
;
76 void TextureLayer::SetUV(const gfx::PointF
& top_left
,
77 const gfx::PointF
& bottom_right
) {
78 if (uv_top_left_
== top_left
&& uv_bottom_right_
== bottom_right
)
80 uv_top_left_
= top_left
;
81 uv_bottom_right_
= bottom_right
;
85 void TextureLayer::SetVertexOpacity(float bottom_left
,
89 // Indexing according to the quad vertex generation:
93 if (vertex_opacity_
[0] == bottom_left
&&
94 vertex_opacity_
[1] == top_left
&&
95 vertex_opacity_
[2] == top_right
&&
96 vertex_opacity_
[3] == bottom_right
)
98 vertex_opacity_
[0] = bottom_left
;
99 vertex_opacity_
[1] = top_left
;
100 vertex_opacity_
[2] = top_right
;
101 vertex_opacity_
[3] = bottom_right
;
105 void TextureLayer::SetPremultipliedAlpha(bool premultiplied_alpha
) {
106 if (premultiplied_alpha_
== premultiplied_alpha
)
108 premultiplied_alpha_
= premultiplied_alpha
;
112 void TextureLayer::SetBlendBackgroundColor(bool blend
) {
113 if (blend_background_color_
== blend
)
115 blend_background_color_
= blend
;
119 void TextureLayer::SetRateLimitContext(bool rate_limit
) {
120 if (!rate_limit
&& rate_limit_context_
&& client_
&& layer_tree_host())
121 layer_tree_host()->StopRateLimiter();
123 rate_limit_context_
= rate_limit
;
126 void TextureLayer::SetTextureMailboxInternal(
127 const TextureMailbox
& mailbox
,
128 scoped_ptr
<SingleReleaseCallback
> release_callback
,
129 bool requires_commit
,
130 bool allow_mailbox_reuse
) {
131 DCHECK(!mailbox
.IsValid() || !holder_ref_
||
132 !mailbox
.Equals(holder_ref_
->holder()->mailbox()) ||
133 allow_mailbox_reuse
);
134 DCHECK_EQ(mailbox
.IsValid(), !!release_callback
);
136 // If we never commited the mailbox, we need to release it here.
137 if (mailbox
.IsValid()) {
139 TextureMailboxHolder::Create(mailbox
, release_callback
.Pass());
141 holder_ref_
= nullptr;
143 needs_set_mailbox_
= true;
144 // If we are within a commit, no need to do it again immediately after.
148 SetNeedsPushProperties();
150 UpdateDrawsContent(HasDrawableContent());
151 // The active frame needs to be replaced and the mailbox returned before the
152 // commit is called complete.
153 SetNextCommitWaitsForActivation();
156 void TextureLayer::SetTextureMailbox(
157 const TextureMailbox
& mailbox
,
158 scoped_ptr
<SingleReleaseCallback
> release_callback
) {
159 bool requires_commit
= true;
160 bool allow_mailbox_reuse
= false;
161 SetTextureMailboxInternal(
162 mailbox
, release_callback
.Pass(), requires_commit
, allow_mailbox_reuse
);
165 static void IgnoreReleaseCallback(uint32 sync_point
, bool lost
) {}
167 void TextureLayer::SetTextureMailboxWithoutReleaseCallback(
168 const TextureMailbox
& mailbox
) {
169 // We allow reuse of the mailbox if there is a new sync point signalling new
170 // content, and the release callback goes nowhere since we'll be calling it
171 // multiple times for the same mailbox.
172 DCHECK(!mailbox
.IsValid() || !holder_ref_
||
173 !mailbox
.Equals(holder_ref_
->holder()->mailbox()) ||
174 mailbox
.sync_point() != holder_ref_
->holder()->mailbox().sync_point());
175 scoped_ptr
<SingleReleaseCallback
> release
;
176 bool requires_commit
= true;
177 bool allow_mailbox_reuse
= true;
178 if (mailbox
.IsValid())
179 release
= SingleReleaseCallback::Create(base::Bind(&IgnoreReleaseCallback
));
180 SetTextureMailboxInternal(
181 mailbox
, release
.Pass(), requires_commit
, allow_mailbox_reuse
);
184 void TextureLayer::SetNeedsDisplayRect(const gfx::Rect
& dirty_rect
) {
185 Layer::SetNeedsDisplayRect(dirty_rect
);
187 if (rate_limit_context_
&& client_
&& layer_tree_host() && DrawsContent())
188 layer_tree_host()->StartRateLimiter();
191 void TextureLayer::SetLayerTreeHost(LayerTreeHost
* host
) {
192 if (layer_tree_host() == host
) {
193 Layer::SetLayerTreeHost(host
);
197 if (layer_tree_host()) {
198 if (rate_limit_context_
&& client_
)
199 layer_tree_host()->StopRateLimiter();
201 // If we're removed from the tree, the TextureLayerImpl will be destroyed, and
202 // we will need to set the mailbox again on a new TextureLayerImpl the next
204 if (!host
&& holder_ref_
) {
205 needs_set_mailbox_
= true;
206 // The active frame needs to be replaced and the mailbox returned before the
207 // commit is called complete.
208 SetNextCommitWaitsForActivation();
210 Layer::SetLayerTreeHost(host
);
213 bool TextureLayer::HasDrawableContent() const {
214 return (client_
|| holder_ref_
) && Layer::HasDrawableContent();
217 bool TextureLayer::Update(ResourceUpdateQueue
* queue
,
218 const OcclusionTracker
<Layer
>* occlusion
) {
219 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 bool requires_commit
= false;
229 bool allow_mailbox_reuse
= false;
230 SetTextureMailboxInternal(mailbox
,
231 release_callback
.Pass(),
233 allow_mailbox_reuse
);
238 // SetTextureMailbox could be called externally and the same mailbox used for
239 // different textures. Such callers notify this layer that the texture has
240 // changed by calling SetNeedsDisplay, so check for that here.
241 return updated
|| !update_rect_
.IsEmpty();
244 void TextureLayer::PushPropertiesTo(LayerImpl
* layer
) {
245 Layer::PushPropertiesTo(layer
);
247 TextureLayerImpl
* texture_layer
= static_cast<TextureLayerImpl
*>(layer
);
248 texture_layer
->SetFlipped(flipped_
);
249 texture_layer
->SetNearestNeighbor(nearest_neighbor_
);
250 texture_layer
->SetUVTopLeft(uv_top_left_
);
251 texture_layer
->SetUVBottomRight(uv_bottom_right_
);
252 texture_layer
->SetVertexOpacity(vertex_opacity_
);
253 texture_layer
->SetPremultipliedAlpha(premultiplied_alpha_
);
254 texture_layer
->SetBlendBackgroundColor(blend_background_color_
);
255 if (needs_set_mailbox_
) {
256 TextureMailbox texture_mailbox
;
257 scoped_ptr
<SingleReleaseCallbackImpl
> release_callback_impl
;
259 TextureMailboxHolder
* holder
= holder_ref_
->holder();
260 texture_mailbox
= holder
->mailbox();
261 release_callback_impl
= holder
->GetCallbackForImplThread();
263 texture_layer
->SetTextureMailbox(texture_mailbox
,
264 release_callback_impl
.Pass());
265 needs_set_mailbox_
= false;
269 SimpleEnclosedRegion
TextureLayer::VisibleContentOpaqueRegion() const {
270 if (contents_opaque())
271 return SimpleEnclosedRegion(visible_content_rect());
273 if (blend_background_color_
&& (SkColorGetA(background_color()) == 0xFF))
274 return SimpleEnclosedRegion(visible_content_rect());
276 return SimpleEnclosedRegion();
279 TextureLayer::TextureMailboxHolder::MainThreadReference::MainThreadReference(
280 TextureMailboxHolder
* holder
)
282 holder_
->InternalAddRef();
285 TextureLayer::TextureMailboxHolder::MainThreadReference::
286 ~MainThreadReference() {
287 holder_
->InternalRelease();
290 TextureLayer::TextureMailboxHolder::TextureMailboxHolder(
291 const TextureMailbox
& mailbox
,
292 scoped_ptr
<SingleReleaseCallback
> release_callback
)
293 : internal_references_(0),
295 release_callback_(release_callback
.Pass()),
296 sync_point_(mailbox
.sync_point()),
300 TextureLayer::TextureMailboxHolder::~TextureMailboxHolder() {
301 DCHECK_EQ(0u, internal_references_
);
304 scoped_ptr
<TextureLayer::TextureMailboxHolder::MainThreadReference
>
305 TextureLayer::TextureMailboxHolder::Create(
306 const TextureMailbox
& mailbox
,
307 scoped_ptr
<SingleReleaseCallback
> release_callback
) {
308 return make_scoped_ptr(new MainThreadReference(
309 new TextureMailboxHolder(mailbox
, release_callback
.Pass())));
312 void TextureLayer::TextureMailboxHolder::Return(uint32 sync_point
,
314 base::AutoLock
lock(arguments_lock_
);
315 sync_point_
= sync_point
;
319 scoped_ptr
<SingleReleaseCallbackImpl
>
320 TextureLayer::TextureMailboxHolder::GetCallbackForImplThread() {
321 // We can't call GetCallbackForImplThread if we released the main thread
323 DCHECK_GT(internal_references_
, 0u);
325 return SingleReleaseCallbackImpl::Create(
326 base::Bind(&TextureMailboxHolder::ReturnAndReleaseOnImplThread
, this));
329 void TextureLayer::TextureMailboxHolder::InternalAddRef() {
330 ++internal_references_
;
333 void TextureLayer::TextureMailboxHolder::InternalRelease() {
334 DCHECK(main_thread_checker_
.CalledOnValidThread());
335 if (!--internal_references_
) {
336 release_callback_
->Run(sync_point_
, is_lost_
);
337 mailbox_
= TextureMailbox();
338 release_callback_
= nullptr;
342 void TextureLayer::TextureMailboxHolder::ReturnAndReleaseOnImplThread(
345 BlockingTaskRunner
* main_thread_task_runner
) {
346 Return(sync_point
, is_lost
);
347 main_thread_task_runner
->PostTask(
348 FROM_HERE
, base::Bind(&TextureMailboxHolder::InternalRelease
, this));