Index: cc/layers/texture_layer.cc |
diff --git a/cc/layers/texture_layer.cc b/cc/layers/texture_layer.cc |
index d09963139101e955de76cb914513e31d51777b6f..0b19fdcc5e64d1f729ddd3ba17a396644e0f672a 100644 |
--- a/cc/layers/texture_layer.cc |
+++ b/cc/layers/texture_layer.cc |
@@ -4,6 +4,9 @@ |
#include "cc/layers/texture_layer.h" |
+#include "base/bind.h" |
+#include "base/location.h" |
+#include "base/message_loop/message_loop_proxy.h" |
#include "cc/base/thread.h" |
#include "cc/layers/texture_layer_client.h" |
#include "cc/layers/texture_layer_impl.h" |
@@ -12,28 +15,6 @@ |
namespace cc { |
-namespace { |
- |
-void RunCallback( |
- const TextureMailbox::ReleaseCallback& callback, |
- unsigned sync_point, |
- bool lost_resource) { |
- callback.Run(sync_point, lost_resource); |
-} |
- |
-void PostCallbackToThread( |
- Thread* thread, |
- const TextureMailbox::ReleaseCallback& callback, |
- unsigned sync_point, |
- bool lost_resource) { |
- if (!callback.is_null()) { |
- thread->PostTask(base::Bind(&RunCallback, callback, |
- sync_point, lost_resource)); |
- } |
-} |
- |
-} // namespace |
- |
scoped_refptr<TextureLayer> TextureLayer::Create(TextureLayerClient* client) { |
return scoped_refptr<TextureLayer>(new TextureLayer(client, false)); |
} |
@@ -55,7 +36,7 @@ TextureLayer::TextureLayer(TextureLayerClient* client, bool uses_mailbox) |
context_lost_(false), |
content_committed_(false), |
texture_id_(0), |
- own_mailbox_(false) { |
+ needs_set_mailbox_(false) { |
vertex_opacity_[0] = 1.0f; |
vertex_opacity_[1] = 1.0f; |
vertex_opacity_[2] = 1.0f; |
@@ -69,8 +50,6 @@ TextureLayer::~TextureLayer() { |
if (rate_limit_context_ && client_) |
layer_tree_host()->StopRateLimiter(client_->Context3d()); |
} |
- if (own_mailbox_) |
- texture_mailbox_.RunReleaseCallback(texture_mailbox_.sync_point(), false); |
} |
void TextureLayer::ClearClient() { |
@@ -147,13 +126,14 @@ void TextureLayer::SetTextureId(unsigned id) { |
void TextureLayer::SetTextureMailbox(const TextureMailbox& mailbox) { |
DCHECK(uses_mailbox_); |
- if (own_mailbox_) |
- DCHECK(!mailbox.IsValid() || !mailbox.Equals(texture_mailbox_)); |
- // If we never commited the mailbox, we need to release it here |
- if (own_mailbox_) |
- texture_mailbox_.RunReleaseCallback(texture_mailbox_.sync_point(), false); |
- texture_mailbox_ = mailbox; |
- own_mailbox_ = true; |
+ DCHECK(!mailbox.IsValid() || !holder_ref_ || |
+ !mailbox.Equals(holder_ref_->holder()->mailbox())); |
+ // If we never commited the mailbox, we need to release it here. |
+ if (mailbox.IsValid()) |
+ holder_ref_ = MailboxHolder::Create(mailbox); |
+ else |
+ holder_ref_.reset(); |
+ needs_set_mailbox_ = true; |
SetNeedsCommit(); |
} |
@@ -174,11 +154,16 @@ void TextureLayer::SetNeedsDisplayRect(const gfx::RectF& dirty_rect) { |
void TextureLayer::SetLayerTreeHost(LayerTreeHost* host) { |
if (texture_id_ && layer_tree_host() && host != layer_tree_host()) |
layer_tree_host()->AcquireLayerTextures(); |
+ // If we're removed from the tree, the TextureLayerImpl will be destroyed, and |
+ // we will need to set the mailbox again on a new TextureLayerImpl the next |
+ // time we push. |
+ if (!host && uses_mailbox_ && holder_ref_.get()) |
danakj
2013/06/18 02:20:20
nit: don't need .get() for scoped_ptr
piman
2013/06/18 02:53:01
Done.
|
+ needs_set_mailbox_ = true; |
Layer::SetLayerTreeHost(host); |
} |
bool TextureLayer::DrawsContent() const { |
- return (client_ || texture_id_ || texture_mailbox_.IsValid()) && |
+ return (client_ || texture_id_ || holder_ref_.get()) && |
danakj
2013/06/18 02:20:20
nit: don't need .get() for scoped_ptr
piman
2013/06/18 02:53:01
Done.
|
!context_lost_ && Layer::DrawsContent(); |
} |
@@ -213,13 +198,16 @@ void TextureLayer::PushPropertiesTo(LayerImpl* layer) { |
texture_layer->set_uv_bottom_right(uv_bottom_right_); |
texture_layer->set_vertex_opacity(vertex_opacity_); |
texture_layer->set_premultiplied_alpha(premultiplied_alpha_); |
- if (uses_mailbox_ && own_mailbox_) { |
- Thread* main_thread = layer_tree_host()->proxy()->MainThread(); |
- TextureMailbox::ReleaseCallback callback = base::Bind( |
- &PostCallbackToThread, main_thread, texture_mailbox_.callback()); |
- texture_layer->SetTextureMailbox( |
- texture_mailbox_.CopyWithNewCallback(callback)); |
- own_mailbox_ = false; |
+ if (uses_mailbox_ && needs_set_mailbox_) { |
+ TextureMailbox texture_mailbox; |
+ if (holder_ref_) { |
+ MailboxHolder* holder = holder_ref_->holder(); |
+ TextureMailbox::ReleaseCallback callback = |
+ holder->GetCallbackForImplThread(); |
+ texture_mailbox = holder->mailbox().CopyWithNewCallback(callback); |
+ } |
+ texture_layer->SetTextureMailbox(texture_mailbox); |
+ needs_set_mailbox_ = false; |
} else { |
texture_layer->set_texture_id(texture_id_); |
} |
@@ -237,4 +225,71 @@ bool TextureLayer::CanClipSelf() const { |
return true; |
} |
+TextureLayer::MailboxHolder::MainThreadReference::MainThreadReference( |
+ MailboxHolder* holder) |
+ : holder_(holder) { |
+} |
+ |
+TextureLayer::MailboxHolder::MainThreadReference::~MainThreadReference() { |
+ holder_->InternalRelease(); |
+} |
+ |
+TextureLayer::MailboxHolder::MailboxHolder(const TextureMailbox& mailbox) |
+ : message_loop_(base::MessageLoopProxy::current()), |
+ internal_references_(1), |
danakj
2013/06/18 02:20:20
nit: start with 0 here, and have MainThreadRef con
piman
2013/06/18 02:53:01
Done.
|
+ mailbox_(mailbox), |
+ sync_point_(mailbox.sync_point()), |
+ is_lost_(false) { |
+} |
+ |
+TextureLayer::MailboxHolder::~MailboxHolder() { |
+ DCHECK_EQ(0u, internal_references_); |
+} |
+ |
+scoped_ptr<TextureLayer::MailboxHolder::MainThreadReference> |
+TextureLayer::MailboxHolder::Create(const TextureMailbox& mailbox) { |
+ return scoped_ptr<MainThreadReference>(new MainThreadReference( |
+ new MailboxHolder(mailbox))); |
+} |
+ |
+void TextureLayer::MailboxHolder::Return(unsigned sync_point, bool is_lost) { |
+ sync_point_ = sync_point; |
+ is_lost_ = is_lost; |
+} |
+ |
+TextureMailbox::ReleaseCallback |
+TextureLayer::MailboxHolder::GetCallbackForImplThread() { |
+ // We can't call GetCallbackForImplThread if we released the main thread |
+ // reference. |
+ DCHECK(internal_references_); |
danakj
2013/06/18 02:20:20
nit: DCHECK_GT or DCHECK_NE 0?
piman
2013/06/18 02:53:01
Done.
|
+ InternalAddRef(); |
+ return base::Bind(&MailboxHolder::ReturnAndReleaseOnImplThread, this); |
+} |
+ |
+void TextureLayer::MailboxHolder::InternalAddRef() { |
+ ++internal_references_; |
+} |
+ |
+void TextureLayer::MailboxHolder::InternalRelease() { |
+ DCHECK(message_loop_->BelongsToCurrentThread()); |
+ if (!--internal_references_) { |
+ mailbox_.RunReleaseCallback(sync_point_, is_lost_); |
+ mailbox_ = TextureMailbox(); |
+ } |
+} |
+ |
+void TextureLayer::MailboxHolder::ReturnAndReleaseOnMainThread( |
+ unsigned sync_point, bool is_lost) { |
+ DCHECK(message_loop_->BelongsToCurrentThread()); |
+ Return(sync_point, is_lost); |
+ InternalRelease(); |
+} |
+ |
+void TextureLayer::MailboxHolder::ReturnAndReleaseOnImplThread( |
+ unsigned sync_point, bool is_lost) { |
+ message_loop_->PostTask(FROM_HERE, base::Bind( |
+ &MailboxHolder::ReturnAndReleaseOnMainThread, |
+ this, sync_point, is_lost)); |
+} |
+ |
} // namespace cc |