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::CreateForMailbox(
20 TextureLayerClient* client) {
21 return scoped_refptr<TextureLayer>(new TextureLayer(client));
24 TextureLayer::TextureLayer(TextureLayerClient* client)
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;
40 TextureLayer::~TextureLayer() {
43 void TextureLayer::ClearClient() {
44 if (rate_limit_context_ && client_ && layer_tree_host())
45 layer_tree_host()->StopRateLimiter();
48 UpdateDrawsContent(HasDrawableContent());
51 void TextureLayer::ClearTexture() {
52 SetTextureMailbox(TextureMailbox(), scoped_ptr<SingleReleaseCallback>());
55 scoped_ptr<LayerImpl> TextureLayer::CreateLayerImpl(LayerTreeImpl* tree_impl) {
56 return TextureLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
59 void TextureLayer::SetFlipped(bool flipped) {
60 if (flipped_ == flipped)
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)
70 uv_top_left_ = top_left;
71 uv_bottom_right_ = bottom_right;
75 void TextureLayer::SetVertexOpacity(float bottom_left,
79 // Indexing according to the quad vertex generation:
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)
88 vertex_opacity_[0] = bottom_left;
89 vertex_opacity_[1] = top_left;
90 vertex_opacity_[2] = top_right;
91 vertex_opacity_[3] = bottom_right;
95 void TextureLayer::SetPremultipliedAlpha(bool premultiplied_alpha) {
96 if (premultiplied_alpha_ == premultiplied_alpha)
98 premultiplied_alpha_ = premultiplied_alpha;
102 void TextureLayer::SetBlendBackgroundColor(bool blend) {
103 if (blend_background_color_ == blend)
105 blend_background_color_ = blend;
109 void TextureLayer::SetRateLimitContext(bool rate_limit) {
110 if (!rate_limit && rate_limit_context_ && client_ && layer_tree_host())
111 layer_tree_host()->StopRateLimiter();
113 rate_limit_context_ = rate_limit;
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);
126 // If we never commited the mailbox, we need to release it here.
127 if (mailbox.IsValid()) {
129 TextureMailboxHolder::Create(mailbox, release_callback.Pass());
133 needs_set_mailbox_ = true;
134 // If we are within a commit, no need to do it again immediately after.
138 SetNeedsPushProperties();
140 UpdateDrawsContent(HasDrawableContent());
141 // The active frame needs to be replaced and the mailbox returned before the
142 // commit is called complete.
143 SetNextCommitWaitsForActivation();
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);
155 static void IgnoreReleaseCallback(uint32 sync_point, bool lost) {}
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);
174 void TextureLayer::SetNeedsDisplayRect(const gfx::RectF& dirty_rect) {
175 Layer::SetNeedsDisplayRect(dirty_rect);
177 if (rate_limit_context_ && client_ && layer_tree_host() && DrawsContent())
178 layer_tree_host()->StartRateLimiter();
181 void TextureLayer::SetLayerTreeHost(LayerTreeHost* host) {
182 if (layer_tree_host() == host) {
183 Layer::SetLayerTreeHost(host);
187 if (layer_tree_host()) {
188 if (rate_limit_context_ && client_)
189 layer_tree_host()->StopRateLimiter();
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
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();
200 Layer::SetLayerTreeHost(host);
203 bool TextureLayer::HasDrawableContent() const {
204 return (client_ || holder_ref_) && Layer::HasDrawableContent();
207 bool TextureLayer::Update(ResourceUpdateQueue* queue,
208 const OcclusionTracker<Layer>* occlusion) {
209 bool updated = Layer::Update(queue, occlusion);
211 TextureMailbox mailbox;
212 scoped_ptr<SingleReleaseCallback> release_callback;
213 if (client_->PrepareTextureMailbox(
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(),
223 allow_mailbox_reuse);
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();
234 void TextureLayer::PushPropertiesTo(LayerImpl* layer) {
235 Layer::PushPropertiesTo(layer);
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;
248 TextureMailboxHolder* holder = holder_ref_->holder();
249 texture_mailbox = holder->mailbox();
250 release_callback = holder->GetCallbackForImplThread();
252 texture_layer->SetTextureMailbox(texture_mailbox, release_callback.Pass());
253 needs_set_mailbox_ = false;
257 Region TextureLayer::VisibleContentOpaqueRegion() const {
258 if (contents_opaque())
259 return visible_content_rect();
261 if (blend_background_color_ && (SkColorGetA(background_color()) == 0xFF))
262 return visible_content_rect();
267 TextureLayer::TextureMailboxHolder::MainThreadReference::MainThreadReference(
268 TextureMailboxHolder* holder)
270 holder_->InternalAddRef();
273 TextureLayer::TextureMailboxHolder::MainThreadReference::
274 ~MainThreadReference() {
275 holder_->InternalRelease();
278 TextureLayer::TextureMailboxHolder::TextureMailboxHolder(
279 const TextureMailbox& mailbox,
280 scoped_ptr<SingleReleaseCallback> release_callback)
281 : message_loop_(BlockingTaskRunner::current()),
282 internal_references_(0),
284 release_callback_(release_callback.Pass()),
285 sync_point_(mailbox.sync_point()),
288 TextureLayer::TextureMailboxHolder::~TextureMailboxHolder() {
289 DCHECK_EQ(0u, internal_references_);
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())));
300 void TextureLayer::TextureMailboxHolder::Return(uint32 sync_point,
302 base::AutoLock lock(arguments_lock_);
303 sync_point_ = sync_point;
307 scoped_ptr<SingleReleaseCallback>
308 TextureLayer::TextureMailboxHolder::GetCallbackForImplThread() {
309 // We can't call GetCallbackForImplThread if we released the main thread
311 DCHECK_GT(internal_references_, 0u);
313 return SingleReleaseCallback::Create(
314 base::Bind(&TextureMailboxHolder::ReturnAndReleaseOnImplThread, this));
317 void TextureLayer::TextureMailboxHolder::InternalAddRef() {
318 ++internal_references_;
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();
330 void TextureLayer::TextureMailboxHolder::ReturnAndReleaseOnImplThread(
333 Return(sync_point, is_lost);
334 message_loop_->PostTask(
335 FROM_HERE, base::Bind(&TextureMailboxHolder::InternalRelease, this));