don't explicitly create SkDevice, as it is intended to be private. Skia now has ways...
[chromium-blink-merge.git] / cc / layers / texture_layer.cc
blobbc6b58a0342145bce3130c02d6983591f33855f9
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"
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"
17 namespace cc {
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)
29 : Layer(),
30 client_(client),
31 uses_mailbox_(uses_mailbox),
32 flipped_(true),
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),
39 texture_id_(0),
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();
53 client_ = NULL;
54 if (uses_mailbox_)
55 SetTextureMailbox(TextureMailbox(), scoped_ptr<SingleReleaseCallback>());
56 else
57 SetTextureId(0);
60 scoped_ptr<LayerImpl> TextureLayer::CreateLayerImpl(LayerTreeImpl* tree_impl) {
61 return TextureLayerImpl::Create(tree_impl, id(), uses_mailbox_).
62 PassAs<LayerImpl>();
65 void TextureLayer::SetFlipped(bool flipped) {
66 if (flipped_ == flipped)
67 return;
68 flipped_ = flipped;
69 SetNeedsCommit();
72 void TextureLayer::SetUV(const gfx::PointF& top_left,
73 const 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();
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();
101 void TextureLayer::SetPremultipliedAlpha(bool premultiplied_alpha) {
102 if (premultiplied_alpha_ == premultiplied_alpha)
103 return;
104 premultiplied_alpha_ = premultiplied_alpha;
105 SetNeedsCommit();
108 void TextureLayer::SetBlendBackgroundColor(bool blend) {
109 if (blend_background_color_ == blend)
110 return;
111 blend_background_color_ = blend;
112 SetNeedsCommit();
115 void TextureLayer::SetRateLimitContext(bool rate_limit) {
116 if (!rate_limit && rate_limit_context_ && client_ && layer_tree_host())
117 layer_tree_host()->StopRateLimiter();
119 rate_limit_context_ = rate_limit;
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();
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);
144 // If we never commited the mailbox, we need to release it here.
145 if (mailbox.IsValid()) {
146 holder_ref_ =
147 TextureMailboxHolder::Create(mailbox, release_callback.Pass());
148 } else {
149 holder_ref_.reset();
151 needs_set_mailbox_ = true;
152 // If we are within a commit, no need to do it again immediately after.
153 if (requires_commit)
154 SetNeedsCommit();
155 else
156 SetNeedsPushProperties();
158 // The active frame needs to be replaced and the mailbox returned before the
159 // commit is called complete.
160 SetNextCommitWaitsForActivation();
163 void TextureLayer::SetTextureMailbox(
164 const TextureMailbox& mailbox,
165 scoped_ptr<SingleReleaseCallback> release_callback) {
166 SetTextureMailboxInternal(
167 mailbox,
168 release_callback.Pass(),
169 true /* requires_commit */);
172 void TextureLayer::WillModifyTexture() {
173 if (!uses_mailbox_ && layer_tree_host() && (DrawsContent() ||
174 content_committed_)) {
175 layer_tree_host()->AcquireLayerTextures();
176 content_committed_ = false;
180 void TextureLayer::SetNeedsDisplayRect(const gfx::RectF& dirty_rect) {
181 Layer::SetNeedsDisplayRect(dirty_rect);
183 if (rate_limit_context_ && client_ && layer_tree_host() && DrawsContent())
184 layer_tree_host()->StartRateLimiter();
187 void TextureLayer::SetLayerTreeHost(LayerTreeHost* host) {
188 if (layer_tree_host() == host) {
189 Layer::SetLayerTreeHost(host);
190 return;
193 if (layer_tree_host()) {
194 if (texture_id_) {
195 layer_tree_host()->AcquireLayerTextures();
196 // The texture id needs to be removed from the active tree before the
197 // commit is called complete.
198 SetNextCommitWaitsForActivation();
200 if (rate_limit_context_ && client_)
201 layer_tree_host()->StopRateLimiter();
203 // If we're removed from the tree, the TextureLayerImpl will be destroyed, and
204 // we will need to set the mailbox again on a new TextureLayerImpl the next
205 // time we push.
206 if (!host && uses_mailbox_ && holder_ref_) {
207 needs_set_mailbox_ = true;
208 // The active frame needs to be replaced and the mailbox returned before the
209 // commit is called complete.
210 SetNextCommitWaitsForActivation();
212 Layer::SetLayerTreeHost(host);
215 bool TextureLayer::DrawsContent() const {
216 return (client_ || texture_id_ || holder_ref_) && Layer::DrawsContent();
219 bool TextureLayer::Update(ResourceUpdateQueue* queue,
220 const OcclusionTracker* occlusion) {
221 bool updated = Layer::Update(queue, occlusion);
222 if (client_) {
223 if (uses_mailbox_) {
224 TextureMailbox mailbox;
225 scoped_ptr<SingleReleaseCallback> release_callback;
226 if (client_->PrepareTextureMailbox(
227 &mailbox,
228 &release_callback,
229 layer_tree_host()->UsingSharedMemoryResources())) {
230 // Already within a commit, no need to do another one immediately.
231 SetTextureMailboxInternal(
232 mailbox,
233 release_callback.Pass(),
234 false /* requires_commit */);
235 updated = true;
237 } else {
238 texture_id_ = client_->PrepareTexture();
239 updated = true;
240 SetNeedsPushProperties();
241 // The texture id needs to be removed from the active tree before the
242 // commit is called complete.
243 SetNextCommitWaitsForActivation();
247 // SetTextureMailbox could be called externally and the same mailbox used for
248 // different textures. Such callers notify this layer that the texture has
249 // changed by calling SetNeedsDisplay, so check for that here.
250 return updated || !update_rect_.IsEmpty();
253 void TextureLayer::PushPropertiesTo(LayerImpl* layer) {
254 Layer::PushPropertiesTo(layer);
256 TextureLayerImpl* texture_layer = static_cast<TextureLayerImpl*>(layer);
257 texture_layer->SetFlipped(flipped_);
258 texture_layer->SetUVTopLeft(uv_top_left_);
259 texture_layer->SetUVBottomRight(uv_bottom_right_);
260 texture_layer->SetVertexOpacity(vertex_opacity_);
261 texture_layer->SetPremultipliedAlpha(premultiplied_alpha_);
262 texture_layer->SetBlendBackgroundColor(blend_background_color_);
263 if (uses_mailbox_ && needs_set_mailbox_) {
264 TextureMailbox texture_mailbox;
265 scoped_ptr<SingleReleaseCallback> release_callback;
266 if (holder_ref_) {
267 TextureMailboxHolder* holder = holder_ref_->holder();
268 texture_mailbox = holder->mailbox();
269 release_callback = holder->GetCallbackForImplThread();
271 texture_layer->SetTextureMailbox(texture_mailbox, release_callback.Pass());
272 needs_set_mailbox_ = false;
273 } else {
274 texture_layer->SetTextureId(texture_id_);
275 content_committed_ = DrawsContent();
279 Region TextureLayer::VisibleContentOpaqueRegion() const {
280 if (contents_opaque())
281 return visible_content_rect();
283 if (blend_background_color_ && (SkColorGetA(background_color()) == 0xFF))
284 return visible_content_rect();
286 return Region();
289 TextureLayer::TextureMailboxHolder::MainThreadReference::MainThreadReference(
290 TextureMailboxHolder* holder)
291 : holder_(holder) {
292 holder_->InternalAddRef();
295 TextureLayer::TextureMailboxHolder::MainThreadReference::
296 ~MainThreadReference() {
297 holder_->InternalRelease();
300 TextureLayer::TextureMailboxHolder::TextureMailboxHolder(
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) {}
310 TextureLayer::TextureMailboxHolder::~TextureMailboxHolder() {
311 DCHECK_EQ(0u, internal_references_);
314 scoped_ptr<TextureLayer::TextureMailboxHolder::MainThreadReference>
315 TextureLayer::TextureMailboxHolder::Create(
316 const TextureMailbox& mailbox,
317 scoped_ptr<SingleReleaseCallback> release_callback) {
318 return scoped_ptr<MainThreadReference>(new MainThreadReference(
319 new TextureMailboxHolder(mailbox, release_callback.Pass())));
322 void TextureLayer::TextureMailboxHolder::Return(uint32 sync_point,
323 bool is_lost) {
324 base::AutoLock lock(arguments_lock_);
325 sync_point_ = sync_point;
326 is_lost_ = is_lost;
329 scoped_ptr<SingleReleaseCallback>
330 TextureLayer::TextureMailboxHolder::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(&TextureMailboxHolder::ReturnAndReleaseOnImplThread, this));
339 void TextureLayer::TextureMailboxHolder::InternalAddRef() {
340 ++internal_references_;
343 void TextureLayer::TextureMailboxHolder::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();
352 void TextureLayer::TextureMailboxHolder::ReturnAndReleaseOnImplThread(
353 uint32 sync_point,
354 bool is_lost) {
355 Return(sync_point, is_lost);
356 message_loop_->PostTask(
357 FROM_HERE, base::Bind(&TextureMailboxHolder::InternalRelease, this));
360 } // namespace cc