summaryrefslogtreecommitdiffstats
path: root/cc
diff options
context:
space:
mode:
authordanakj@chromium.org <danakj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-30 06:29:27 +0000
committerdanakj@chromium.org <danakj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-30 06:29:27 +0000
commit74b43cce8bf2f7d13fc1576d96088d2ac584e69d (patch)
tree0d86665c1f56e21696e862189e500d4fb2cc828c /cc
parentaaa60babeabcbb8d4b3ba0e587a85398b5fbd099 (diff)
downloadchromium_src-74b43cce8bf2f7d13fc1576d96088d2ac584e69d.zip
chromium_src-74b43cce8bf2f7d13fc1576d96088d2ac584e69d.tar.gz
chromium_src-74b43cce8bf2f7d13fc1576d96088d2ac584e69d.tar.bz2
cc: Block commit on activate by setting a flag on LayerTreeHost.
Currently the ThreadProxy recursively asks all layers in the tree if they should block the commit. This is problematic as when you remove a layer from a the tree, it may want to block the commit to get back resources from its active-tree impl-layer. Instead, have layers call SetNextCommitWaitsForActivation() when they want the next commit to block on activate. This way we only block commits that matter, not every commit when there's a texture layer present. And we can allow a layer to block the commit when it is leaving the tree. Tests: TextureLayerNoMailboxIsActivatedDuringCommit TextureLayerMailboxIsActivatedDuringCommit DelegatedFrameIsActivatedDuringCommit R=enne, piman BUG=277953 Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=220418 Review URL: https://chromiumcodereview.appspot.com/23530003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@220515 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cc')
-rw-r--r--cc/layers/delegated_renderer_layer.cc28
-rw-r--r--cc/layers/delegated_renderer_layer.h3
-rw-r--r--cc/layers/layer.cc37
-rw-r--r--cc/layers/layer.h15
-rw-r--r--cc/layers/texture_layer.cc28
-rw-r--r--cc/layers/texture_layer.h2
-rw-r--r--cc/layers/texture_layer_unittest.cc241
-rw-r--r--cc/layers/tiled_layer.cc6
-rw-r--r--cc/layers/tiled_layer.h1
-rw-r--r--cc/test/fake_proxy.h1
-rw-r--r--cc/trees/layer_tree_host.cc10
-rw-r--r--cc/trees/layer_tree_host.h4
-rw-r--r--cc/trees/layer_tree_host_unittest_delegated.cc105
-rw-r--r--cc/trees/proxy.h1
-rw-r--r--cc/trees/single_thread_proxy.cc4
-rw-r--r--cc/trees/single_thread_proxy.h1
-rw-r--r--cc/trees/thread_proxy.cc15
-rw-r--r--cc/trees/thread_proxy.h5
18 files changed, 442 insertions, 65 deletions
diff --git a/cc/layers/delegated_renderer_layer.cc b/cc/layers/delegated_renderer_layer.cc
index 0ffa54a..1e1a8a0 100644
--- a/cc/layers/delegated_renderer_layer.cc
+++ b/cc/layers/delegated_renderer_layer.cc
@@ -29,6 +29,23 @@ scoped_ptr<LayerImpl> DelegatedRendererLayer::CreateLayerImpl(
tree_impl, layer_id_).PassAs<LayerImpl>();
}
+void DelegatedRendererLayer::SetLayerTreeHost(LayerTreeHost* host) {
+ if (layer_tree_host() == host) {
+ Layer::SetLayerTreeHost(host);
+ return;
+ }
+
+ if (!host) {
+ // The active frame needs to be removed from the active tree and resources
+ // returned before the commit is called complete.
+ // TODO(danakj): Don't need to do this if the last frame commited was empty
+ // or we never commited a frame with resources.
+ SetNextCommitWaitsForActivation();
+ }
+
+ Layer::SetLayerTreeHost(host);
+}
+
bool DelegatedRendererLayer::DrawsContent() const {
return Layer::DrawsContent() && !frame_size_.IsEmpty();
}
@@ -83,6 +100,9 @@ void DelegatedRendererLayer::SetFrameData(
frame_size_ = gfx::Size();
}
SetNeedsCommit();
+ // The active frame needs to be replaced and resources returned before the
+ // commit is called complete.
+ SetNextCommitWaitsForActivation();
}
void DelegatedRendererLayer::TakeUnusedResourcesForChildCompositor(
@@ -93,12 +113,4 @@ void DelegatedRendererLayer::TakeUnusedResourcesForChildCompositor(
array->swap(unused_resources_for_child_compositor_);
}
-bool DelegatedRendererLayer::BlocksPendingCommit() const {
- // The active frame needs to be replaced and resources returned before the
- // commit is called complete. This is true even whenever there may be
- // resources to return, regardless of if the layer will draw in its new
- // state.
- return true;
-}
-
} // namespace cc
diff --git a/cc/layers/delegated_renderer_layer.h b/cc/layers/delegated_renderer_layer.h
index f16217b..afee475f 100644
--- a/cc/layers/delegated_renderer_layer.h
+++ b/cc/layers/delegated_renderer_layer.h
@@ -21,6 +21,7 @@ class CC_EXPORT DelegatedRendererLayer : public Layer {
virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
OVERRIDE;
+ virtual void SetLayerTreeHost(LayerTreeHost* host) OVERRIDE;
virtual void PushPropertiesTo(LayerImpl* impl) OVERRIDE;
virtual bool DrawsContent() const OVERRIDE;
@@ -36,8 +37,6 @@ class CC_EXPORT DelegatedRendererLayer : public Layer {
// compositor to the given array, so they can be given back to the child.
void TakeUnusedResourcesForChildCompositor(ReturnedResourceArray* array);
- virtual bool BlocksPendingCommit() const OVERRIDE;
-
protected:
explicit DelegatedRendererLayer(DelegatedRendererLayerClient* client);
virtual ~DelegatedRendererLayer();
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index 8cb61d9..e7cf755 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -152,14 +152,11 @@ void Layer::SetNeedsFullTreeSync() {
layer_tree_host_->SetNeedsFullTreeSync();
}
-bool Layer::IsPropertyChangeAllowed() const {
+void Layer::SetNextCommitWaitsForActivation() {
if (!layer_tree_host_)
- return true;
-
- if (!layer_tree_host_->settings().strict_layer_property_change_checking)
- return true;
+ return;
- return !layer_tree_host_->in_paint_layer_contents();
+ layer_tree_host_->SetNextCommitWaitsForActivation();
}
void Layer::SetNeedsPushProperties() {
@@ -187,6 +184,16 @@ void Layer::RemoveDependentNeedsPushProperties() {
parent_->RemoveDependentNeedsPushProperties();
}
+bool Layer::IsPropertyChangeAllowed() const {
+ if (!layer_tree_host_)
+ return true;
+
+ if (!layer_tree_host_->settings().strict_layer_property_change_checking)
+ return true;
+
+ return !layer_tree_host_->in_paint_layer_contents();
+}
+
gfx::Rect Layer::LayerRectToContentRect(const gfx::RectF& layer_rect) const {
gfx::RectF content_rect =
gfx::ScaleRect(layer_rect, contents_scale_x(), contents_scale_y());
@@ -196,10 +203,6 @@ gfx::Rect Layer::LayerRectToContentRect(const gfx::RectF& layer_rect) const {
return gfx::ToEnclosingRect(content_rect);
}
-bool Layer::BlocksPendingCommit() const {
- return false;
-}
-
skia::RefPtr<SkPicture> Layer::GetPicture() const {
return skia::RefPtr<SkPicture>();
}
@@ -208,20 +211,6 @@ bool Layer::CanClipSelf() const {
return false;
}
-bool Layer::BlocksPendingCommitRecursive() const {
- if (BlocksPendingCommit())
- return true;
- if (mask_layer() && mask_layer()->BlocksPendingCommitRecursive())
- return true;
- if (replica_layer() && replica_layer()->BlocksPendingCommitRecursive())
- return true;
- for (size_t i = 0; i < children_.size(); ++i) {
- if (children_[i]->BlocksPendingCommitRecursive())
- return true;
- }
- return false;
-}
-
void Layer::SetParent(Layer* layer) {
DCHECK(!layer || !layer->HasAncestor(this));
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index 2f4d581..7a8f9d1 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -397,13 +397,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
gfx::Rect LayerRectToContentRect(const gfx::RectF& layer_rect) const;
- // In impl-side painting, this returns true if this layer type is not
- // compatible with the main thread running freely, such as a double-buffered
- // canvas that doesn't want to be triple-buffered across all three trees.
- virtual bool BlocksPendingCommit() const;
- // Returns true if anything in this tree blocksPendingCommit.
- bool BlocksPendingCommitRecursive() const;
-
virtual skia::RefPtr<SkPicture> GetPicture() const;
virtual bool CanClipSelf() const;
@@ -455,7 +448,11 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
// Called when there's been a change in layer structure. Implies both
// SetNeedsUpdate and SetNeedsCommit, but not SetNeedsPushProperties.
void SetNeedsFullTreeSync();
- bool IsPropertyChangeAllowed() const;
+
+ // Called when the next commit should wait until the pending tree is activated
+ // before finishing the commit and unblocking the main thread. Used to ensure
+ // unused resources on the impl thread are returned before commit completes.
+ void SetNextCommitWaitsForActivation();
void SetNeedsPushProperties();
void AddDependentNeedsPushProperties();
@@ -464,6 +461,8 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
return needs_push_properties() || descendant_needs_push_properties();
}
+ bool IsPropertyChangeAllowed() const;
+
// If this layer has a scroll parent, it removes |this| from its list of
// scroll children.
void RemoveFromScrollTree();
diff --git a/cc/layers/texture_layer.cc b/cc/layers/texture_layer.cc
index 4d6df14..d0ab7d9 100644
--- a/cc/layers/texture_layer.cc
+++ b/cc/layers/texture_layer.cc
@@ -125,6 +125,9 @@ void TextureLayer::SetTextureId(unsigned id) {
layer_tree_host()->AcquireLayerTextures();
texture_id_ = id;
SetNeedsCommit();
+ // The texture id needs to be removed from the active tree before the
+ // commit is called complete.
+ SetNextCommitWaitsForActivation();
}
void TextureLayer::SetTextureMailbox(const TextureMailbox& mailbox) {
@@ -138,6 +141,9 @@ void TextureLayer::SetTextureMailbox(const TextureMailbox& mailbox) {
holder_ref_.reset();
needs_set_mailbox_ = true;
SetNeedsCommit();
+ // The active frame needs to be replaced and the mailbox returned before the
+ // commit is called complete.
+ SetNextCommitWaitsForActivation();
}
void TextureLayer::WillModifyTexture() {
@@ -161,16 +167,24 @@ void TextureLayer::SetLayerTreeHost(LayerTreeHost* host) {
}
if (layer_tree_host()) {
- if (texture_id_)
+ if (texture_id_) {
layer_tree_host()->AcquireLayerTextures();
+ // The texture id needs to be removed from the active tree before the
+ // commit is called complete.
+ SetNextCommitWaitsForActivation();
+ }
if (rate_limit_context_ && client_)
layer_tree_host()->StopRateLimiter(client_->Context3d());
}
// 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_)
+ if (!host && uses_mailbox_ && holder_ref_) {
needs_set_mailbox_ = true;
+ // The active frame needs to be replaced and the mailbox returned before the
+ // commit is called complete.
+ SetNextCommitWaitsForActivation();
+ }
Layer::SetLayerTreeHost(host);
}
@@ -196,6 +210,9 @@ bool TextureLayer::Update(ResourceUpdateQueue* queue,
client_->Context3d()->getGraphicsResetStatusARB() != GL_NO_ERROR)
texture_id_ = 0;
updated = true;
+ // The texture id needs to be removed from the active tree before the
+ // commit is called complete.
+ SetNextCommitWaitsForActivation();
}
}
@@ -241,13 +258,6 @@ Region TextureLayer::VisibleContentOpaqueRegion() const {
return Region();
}
-bool TextureLayer::BlocksPendingCommit() const {
- // Double-buffered texture layers need to be blocked until they can be made
- // triple-buffered. Single-buffered layers already prevent draws, so
- // can block too for simplicity.
- return DrawsContent();
-}
-
bool TextureLayer::CanClipSelf() const {
return true;
}
diff --git a/cc/layers/texture_layer.h b/cc/layers/texture_layer.h
index f8c1c6a..cb34cf5 100644
--- a/cc/layers/texture_layer.h
+++ b/cc/layers/texture_layer.h
@@ -120,6 +120,7 @@ class CC_EXPORT TextureLayer : public Layer {
void SetRateLimitContext(bool rate_limit);
// Code path for plugins which supply their own texture ID.
+ // DEPRECATED. DO NOT USE.
void SetTextureId(unsigned texture_id);
// Code path for plugins which supply their own mailbox.
@@ -136,7 +137,6 @@ class CC_EXPORT TextureLayer : public Layer {
const OcclusionTracker* occlusion) OVERRIDE;
virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
virtual Region VisibleContentOpaqueRegion() const OVERRIDE;
- virtual bool BlocksPendingCommit() const OVERRIDE;
virtual bool CanClipSelf() const OVERRIDE;
diff --git a/cc/layers/texture_layer_unittest.cc b/cc/layers/texture_layer_unittest.cc
index 729f4a1..a3c568f 100644
--- a/cc/layers/texture_layer_unittest.cc
+++ b/cc/layers/texture_layer_unittest.cc
@@ -8,6 +8,8 @@
#include "base/callback.h"
#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
#include "cc/debug/test_web_graphics_context_3d.h"
#include "cc/layers/texture_layer_client.h"
#include "cc/layers/texture_layer_impl.h"
@@ -861,6 +863,245 @@ class TextureLayerImplWithMailboxThreadedCallback : public LayerTreeTest {
SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
TextureLayerImplWithMailboxThreadedCallback);
+
+class TextureLayerNoMailboxIsActivatedDuringCommit : public LayerTreeTest,
+ public TextureLayerClient {
+ protected:
+ TextureLayerNoMailboxIsActivatedDuringCommit()
+ : wait_thread_("WAIT"),
+ wait_event_(false, false) {
+ wait_thread_.Start();
+ }
+
+ virtual void BeginTest() OVERRIDE {
+ activate_count_ = 0;
+
+ gfx::Size bounds(100, 100);
+ root_ = Layer::Create();
+ root_->SetAnchorPoint(gfx::PointF());
+ root_->SetBounds(bounds);
+
+ layer_ = TextureLayer::Create(this);
+ layer_->SetIsDrawable(true);
+ layer_->SetAnchorPoint(gfx::PointF());
+ layer_->SetBounds(bounds);
+
+ root_->AddChild(layer_);
+ layer_tree_host()->SetRootLayer(root_);
+ layer_tree_host()->SetViewportSize(bounds);
+
+ PostSetNeedsCommitToMainThread();
+ }
+
+ // TextureLayerClient implementation.
+ virtual unsigned PrepareTexture() OVERRIDE {
+ return OffscreenContextProviderForMainThread()
+ ->Context3d()->createTexture();
+ }
+ virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE {
+ return OffscreenContextProviderForMainThread()->Context3d();
+ }
+ virtual bool PrepareTextureMailbox(TextureMailbox* mailbox,
+ bool use_shared_memory) OVERRIDE {
+ return false;
+ }
+
+ virtual void WillActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ // Slow down activation so the main thread DidCommit() will run if
+ // not blocked.
+ wait_thread_.message_loop()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&base::WaitableEvent::Signal,
+ base::Unretained(&wait_event_)),
+ base::TimeDelta::FromMilliseconds(10));
+ wait_event_.Wait();
+
+ base::AutoLock lock(activate_lock_);
+ ++activate_count_;
+ }
+
+ virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ // The main thread is awake now, and will run DidCommit() immediately.
+ // Run DidActivate() afterwards by posting it now.
+ proxy()->MainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerNoMailboxIsActivatedDuringCommit::DidActivate,
+ base::Unretained(this)));
+ }
+
+ void DidActivate() {
+ base::AutoLock lock(activate_lock_);
+ switch (activate_count_) {
+ case 1:
+ // The first texture has been activated. Invalidate the layer so it
+ // grabs a new texture id from the client.
+ layer_->SetNeedsDisplay();
+ // So this commit number should complete after the second activate.
+ EXPECT_EQ(1, layer_tree_host()->source_frame_number());
+ break;
+ case 2:
+ // The second mailbox has been activated. Remove the layer from
+ // the tree to cause another commit/activation. The commit should
+ // finish *after* the layer is removed from the active tree.
+ layer_->RemoveFromParent();
+ // So this commit number should complete after the third activate.
+ EXPECT_EQ(2, layer_tree_host()->source_frame_number());
+ break;
+ case 3:
+ EndTest();
+ break;
+ }
+ }
+
+ virtual void DidCommit() OVERRIDE {
+ switch (layer_tree_host()->source_frame_number()) {
+ case 2: {
+ // The activate for the 2nd texture should have happened before now.
+ base::AutoLock lock(activate_lock_);
+ EXPECT_EQ(2, activate_count_);
+ break;
+ }
+ case 3: {
+ // The activate to remove the layer should have happened before now.
+ base::AutoLock lock(activate_lock_);
+ EXPECT_EQ(3, activate_count_);
+ break;
+ }
+ }
+ }
+
+
+ virtual void AfterTest() OVERRIDE {}
+
+ base::Thread wait_thread_;
+ base::WaitableEvent wait_event_;
+ base::Lock activate_lock_;
+ int activate_count_;
+ int activate_commit_;
+ scoped_refptr<Layer> root_;
+ scoped_refptr<TextureLayer> layer_;
+};
+
+SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
+ TextureLayerNoMailboxIsActivatedDuringCommit);
+
+class TextureLayerMailboxIsActivatedDuringCommit : public LayerTreeTest {
+ protected:
+ TextureLayerMailboxIsActivatedDuringCommit()
+ : wait_thread_("WAIT"),
+ wait_event_(false, false) {
+ wait_thread_.Start();
+ }
+
+ static void ReleaseCallback(unsigned sync_point, bool lost_resource) {}
+
+ void SetMailbox(char mailbox_char) {
+ TextureMailbox mailbox(
+ std::string(64, mailbox_char),
+ base::Bind(
+ &TextureLayerMailboxIsActivatedDuringCommit::ReleaseCallback));
+ layer_->SetTextureMailbox(mailbox);
+ }
+
+ virtual void BeginTest() OVERRIDE {
+ activate_count_ = 0;
+
+ gfx::Size bounds(100, 100);
+ root_ = Layer::Create();
+ root_->SetAnchorPoint(gfx::PointF());
+ root_->SetBounds(bounds);
+
+ layer_ = TextureLayer::CreateForMailbox(NULL);
+ layer_->SetIsDrawable(true);
+ layer_->SetAnchorPoint(gfx::PointF());
+ layer_->SetBounds(bounds);
+
+ root_->AddChild(layer_);
+ layer_tree_host()->SetRootLayer(root_);
+ layer_tree_host()->SetViewportSize(bounds);
+ SetMailbox('1');
+
+ PostSetNeedsCommitToMainThread();
+ }
+
+ virtual void WillActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ // Slow down activation so the main thread DidCommit() will run if
+ // not blocked.
+ wait_thread_.message_loop()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&base::WaitableEvent::Signal,
+ base::Unretained(&wait_event_)),
+ base::TimeDelta::FromMilliseconds(10));
+ wait_event_.Wait();
+
+ base::AutoLock lock(activate_lock_);
+ ++activate_count_;
+ }
+
+ virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ // The main thread is awake now, and will run DidCommit() immediately.
+ // Run DidActivate() afterwards by posting it now.
+ proxy()->MainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&TextureLayerMailboxIsActivatedDuringCommit::DidActivate,
+ base::Unretained(this)));
+ }
+
+ void DidActivate() {
+ base::AutoLock lock(activate_lock_);
+ switch (activate_count_) {
+ case 1:
+ // The first mailbox has been activated. Set a new mailbox, and
+ // expect the next commit to finish *after* it is activated.
+ SetMailbox('2');
+ // So this commit number should complete after the second activate.
+ EXPECT_EQ(1, layer_tree_host()->source_frame_number());
+ break;
+ case 2:
+ // The second mailbox has been activated. Remove the layer from
+ // the tree to cause another commit/activation. The commit should
+ // finish *after* the layer is removed from the active tree.
+ layer_->RemoveFromParent();
+ // So this commit number should complete after the third activate.
+ EXPECT_EQ(2, layer_tree_host()->source_frame_number());
+ break;
+ case 3:
+ EndTest();
+ break;
+ }
+ }
+
+ virtual void DidCommit() OVERRIDE {
+ switch (layer_tree_host()->source_frame_number()) {
+ case 2: {
+ // The activate for the 2nd mailbox should have happened before now.
+ base::AutoLock lock(activate_lock_);
+ EXPECT_EQ(2, activate_count_);
+ break;
+ }
+ case 3: {
+ // The activate to remove the layer should have happened before now.
+ base::AutoLock lock(activate_lock_);
+ EXPECT_EQ(3, activate_count_);
+ break;
+ }
+ }
+ }
+
+
+ virtual void AfterTest() OVERRIDE {}
+
+ base::Thread wait_thread_;
+ base::WaitableEvent wait_event_;
+ base::Lock activate_lock_;
+ int activate_count_;
+ scoped_refptr<Layer> root_;
+ scoped_refptr<TextureLayer> layer_;
+};
+
+SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
+ TextureLayerMailboxIsActivatedDuringCommit);
+
class TextureLayerImplWithMailboxTest : public TextureLayerTest {
protected:
TextureLayerImplWithMailboxTest()
diff --git a/cc/layers/tiled_layer.cc b/cc/layers/tiled_layer.cc
index 556b8231..2d812e8 100644
--- a/cc/layers/tiled_layer.cc
+++ b/cc/layers/tiled_layer.cc
@@ -235,8 +235,6 @@ void TiledLayer::PushPropertiesTo(LayerImpl* layer) {
needs_push_properties_ = true;
}
-bool TiledLayer::BlocksPendingCommit() const { return true; }
-
PrioritizedResourceManager* TiledLayer::ResourceManager() {
if (!layer_tree_host())
return NULL;
@@ -731,6 +729,10 @@ bool TiledLayer::Update(ResourceUpdateQueue* queue,
const OcclusionTracker* occlusion) {
DCHECK(!skips_draw_ && !failed_update_); // Did ResetUpdateState get skipped?
+ // Tiled layer always causes commits to wait for activation, as it does
+ // not support pending trees.
+ SetNextCommitWaitsForActivation();
+
bool updated = false;
{
diff --git a/cc/layers/tiled_layer.h b/cc/layers/tiled_layer.h
index 56e91f8..51afed2 100644
--- a/cc/layers/tiled_layer.h
+++ b/cc/layers/tiled_layer.h
@@ -26,7 +26,6 @@ class CC_EXPORT TiledLayer : public ContentsScalingLayer {
// Layer implementation.
virtual void SetIsMask(bool is_mask) OVERRIDE;
virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
- virtual bool BlocksPendingCommit() const OVERRIDE;
virtual bool DrawsContent() const OVERRIDE;
virtual void ReduceMemoryUsage() OVERRIDE;
virtual void SetNeedsDisplayRect(const gfx::RectF& dirty_rect) OVERRIDE;
diff --git a/cc/test/fake_proxy.h b/cc/test/fake_proxy.h
index b3bca69..3127cb4 100644
--- a/cc/test/fake_proxy.h
+++ b/cc/test/fake_proxy.h
@@ -32,6 +32,7 @@ class FakeProxy : public Proxy {
virtual void SetNeedsUpdateLayers() OVERRIDE {}
virtual void SetNeedsCommit() OVERRIDE {}
virtual void SetNeedsRedraw(gfx::Rect damage_rect) OVERRIDE {}
+ virtual void SetNextCommitWaitsForActivation() OVERRIDE {}
virtual void NotifyInputThrottledUntilCommit() OVERRIDE {}
virtual void SetDeferCommits(bool defer_commits) OVERRIDE {}
virtual void MainThreadHasStoppedFlinging() OVERRIDE {}
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index f18e3b8..27659e0 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -518,6 +518,10 @@ bool LayerTreeHost::CommitRequested() const {
return proxy_->CommitRequested();
}
+void LayerTreeHost::SetNextCommitWaitsForActivation() {
+ proxy_->SetNextCommitWaitsForActivation();
+}
+
void LayerTreeHost::SetAnimationEvents(scoped_ptr<AnimationEventsVector> events,
base::Time wall_clock_time) {
DCHECK(proxy_->IsMainThread());
@@ -1089,12 +1093,6 @@ void LayerTreeHost::UpdateTopControlsState(TopControlsState constraints,
animate));
}
-bool LayerTreeHost::BlocksPendingCommit() const {
- if (!root_layer_.get())
- return false;
- return root_layer_->BlocksPendingCommitRecursive();
-}
-
scoped_ptr<base::Value> LayerTreeHost::AsValue() const {
scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue());
state->Set("proxy", proxy_->AsValue().release());
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index 619c18e..be0ab06 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -191,6 +191,8 @@ class CC_EXPORT LayerTreeHost : NON_EXPORTED_BASE(public RateLimiterClient) {
void SetNeedsRedrawRect(gfx::Rect damage_rect);
bool CommitRequested() const;
+ void SetNextCommitWaitsForActivation();
+
void SetAnimationEvents(scoped_ptr<AnimationEventsVector> events,
base::Time wall_clock_time);
@@ -266,8 +268,6 @@ class CC_EXPORT LayerTreeHost : NON_EXPORTED_BASE(public RateLimiterClient) {
return animation_registrar_.get();
}
- bool BlocksPendingCommit() const;
-
// Obtains a thorough dump of the LayerTreeHost as a value.
scoped_ptr<base::Value> AsValue() const;
diff --git a/cc/trees/layer_tree_host_unittest_delegated.cc b/cc/trees/layer_tree_host_unittest_delegated.cc
index 721613a..3fd040bc 100644
--- a/cc/trees/layer_tree_host_unittest_delegated.cc
+++ b/cc/trees/layer_tree_host_unittest_delegated.cc
@@ -7,6 +7,9 @@
#include <algorithm>
#include "base/bind.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
#include "cc/layers/delegated_renderer_layer.h"
#include "cc/layers/delegated_renderer_layer_client.h"
#include "cc/layers/delegated_renderer_layer_impl.h"
@@ -1582,5 +1585,107 @@ class LayerTreeHostDelegatedTestCommitWithoutTake
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDelegatedTestCommitWithoutTake);
+class DelegatedFrameIsActivatedDuringCommit
+ : public LayerTreeHostDelegatedTestCaseSingleDelegatedLayer {
+ protected:
+ DelegatedFrameIsActivatedDuringCommit()
+ : wait_thread_("WAIT"),
+ wait_event_(false, false) {
+ wait_thread_.Start();
+ }
+
+ virtual void BeginTest() OVERRIDE {
+ activate_count_ = 0;
+
+ scoped_ptr<DelegatedFrameData> frame =
+ CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1));
+ AddTextureQuad(frame.get(), 999);
+ AddTransferableResource(frame.get(), 999);
+ delegated_->SetFrameData(frame.Pass());
+
+ PostSetNeedsCommitToMainThread();
+ }
+
+ virtual void WillActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ // Slow down activation so the main thread DidCommit() will run if
+ // not blocked.
+ wait_thread_.message_loop()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&base::WaitableEvent::Signal,
+ base::Unretained(&wait_event_)),
+ base::TimeDelta::FromMilliseconds(10));
+ wait_event_.Wait();
+
+ base::AutoLock lock(activate_lock_);
+ ++activate_count_;
+ }
+
+ virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ // The main thread is awake now, and will run DidCommit() immediately.
+ // Run DidActivate() afterwards by posting it now.
+ proxy()->MainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&DelegatedFrameIsActivatedDuringCommit::DidActivate,
+ base::Unretained(this)));
+ }
+
+ void DidActivate() {
+ base::AutoLock lock(activate_lock_);
+ switch (activate_count_) {
+ case 1: {
+ // The first frame has been activated. Set a new frame, and
+ // expect the next commit to finish *after* it is activated.
+ scoped_ptr<DelegatedFrameData> frame =
+ CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1));
+ AddTextureQuad(frame.get(), 555);
+ AddTransferableResource(frame.get(), 555);
+ delegated_->SetFrameData(frame.Pass());
+ // So this commit number should complete after the second activate.
+ EXPECT_EQ(1, layer_tree_host()->source_frame_number());
+ break;
+ }
+ case 2:
+ // The second frame has been activated. Remove the layer from
+ // the tree to cause another commit/activation. The commit should
+ // finish *after* the layer is removed from the active tree.
+ delegated_->RemoveFromParent();
+ // So this commit number should complete after the third activate.
+ EXPECT_EQ(2, layer_tree_host()->source_frame_number());
+ break;
+ case 3:
+ EndTest();
+ break;
+ }
+ }
+
+ virtual void DidCommit() OVERRIDE {
+ switch (layer_tree_host()->source_frame_number()) {
+ case 2: {
+ // The activate for the 2nd frame should have happened before now.
+ base::AutoLock lock(activate_lock_);
+ EXPECT_EQ(2, activate_count_);
+ break;
+ }
+ case 3: {
+ // The activate to remove the layer should have happened before now.
+ base::AutoLock lock(activate_lock_);
+ EXPECT_EQ(3, activate_count_);
+ break;
+ }
+ }
+ }
+
+
+ virtual void AfterTest() OVERRIDE {}
+
+ base::Thread wait_thread_;
+ base::WaitableEvent wait_event_;
+ base::Lock activate_lock_;
+ int activate_count_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+ DelegatedFrameIsActivatedDuringCommit);
+
} // namespace
} // namespace cc
diff --git a/cc/trees/proxy.h b/cc/trees/proxy.h
index 9845b0f..84844c8 100644
--- a/cc/trees/proxy.h
+++ b/cc/trees/proxy.h
@@ -69,6 +69,7 @@ class CC_EXPORT Proxy {
virtual void SetNeedsUpdateLayers() = 0;
virtual void SetNeedsCommit() = 0;
virtual void SetNeedsRedraw(gfx::Rect damage_rect) = 0;
+ virtual void SetNextCommitWaitsForActivation() = 0;
virtual void NotifyInputThrottledUntilCommit() = 0;
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index 516fa69..7390a32 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -244,6 +244,10 @@ void SingleThreadProxy::SetNeedsRedraw(gfx::Rect damage_rect) {
SetNeedsRedrawRectOnImplThread(damage_rect);
}
+void SingleThreadProxy::SetNextCommitWaitsForActivation() {
+ // There is no activation here other than commit. So do nothing.
+}
+
void SingleThreadProxy::SetDeferCommits(bool defer_commits) {
// Thread-only feature.
NOTREACHED();
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h
index 8ad0c2f..ee92173 100644
--- a/cc/trees/single_thread_proxy.h
+++ b/cc/trees/single_thread_proxy.h
@@ -35,6 +35,7 @@ class SingleThreadProxy : public Proxy, LayerTreeHostImplClient {
virtual void SetNeedsUpdateLayers() OVERRIDE;
virtual void SetNeedsCommit() OVERRIDE;
virtual void SetNeedsRedraw(gfx::Rect damage_rect) OVERRIDE;
+ virtual void SetNextCommitWaitsForActivation() OVERRIDE;
virtual void NotifyInputThrottledUntilCommit() OVERRIDE {}
virtual void SetDeferCommits(bool defer_commits) OVERRIDE;
virtual bool CommitRequested() const OVERRIDE;
diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc
index dc73f3b..dda25ec 100644
--- a/cc/trees/thread_proxy.cc
+++ b/cc/trees/thread_proxy.cc
@@ -76,6 +76,8 @@ ThreadProxy::ThreadProxy(
textures_acquired_(true),
in_composite_and_readback_(false),
manage_tiles_pending_(false),
+ commit_waits_for_activation_(false),
+ inside_commit_(false),
weak_factory_on_impl_thread_(this),
weak_factory_(this),
begin_frame_sent_to_main_thread_completion_event_on_impl_thread_(NULL),
@@ -506,6 +508,12 @@ void ThreadProxy::SetNeedsRedraw(gfx::Rect damage_rect) {
damage_rect));
}
+void ThreadProxy::SetNextCommitWaitsForActivation() {
+ DCHECK(IsMainThread());
+ DCHECK(!inside_commit_);
+ commit_waits_for_activation_ = true;
+}
+
void ThreadProxy::SetDeferCommits(bool defer_commits) {
DCHECK(IsMainThread());
DCHECK_NE(defer_commits_, defer_commits);
@@ -933,10 +941,12 @@ void ThreadProxy::ScheduledActionCommit() {
current_resource_update_controller_on_impl_thread_->Finalize();
current_resource_update_controller_on_impl_thread_.reset();
+ inside_commit_ = true;
layer_tree_host_impl_->BeginCommit();
layer_tree_host_->BeginCommitOnImplThread(layer_tree_host_impl_.get());
layer_tree_host_->FinishCommitOnImplThread(layer_tree_host_impl_.get());
layer_tree_host_impl_->CommitComplete();
+ inside_commit_ = false;
SetInputThrottledUntilCommitOnImplThread(false);
@@ -945,8 +955,7 @@ void ThreadProxy::ScheduledActionCommit() {
next_frame_is_newly_committed_frame_on_impl_thread_ = true;
if (layer_tree_host_->settings().impl_side_painting &&
- layer_tree_host_->BlocksPendingCommit() &&
- layer_tree_host_impl_->pending_tree()) {
+ commit_waits_for_activation_) {
// For some layer types in impl-side painting, the commit is held until
// the pending tree is activated. It's also possible that the
// pending tree has already activated if there was no work to be done.
@@ -959,6 +968,8 @@ void ThreadProxy::ScheduledActionCommit() {
commit_completion_event_on_impl_thread_ = NULL;
}
+ commit_waits_for_activation_ = false;
+
commit_complete_time_ = base::TimeTicks::HighResNow();
begin_frame_to_commit_duration_history_.InsertSample(
commit_complete_time_ - begin_frame_sent_to_main_thread_time_);
diff --git a/cc/trees/thread_proxy.h b/cc/trees/thread_proxy.h
index d159eb5..8122bf4 100644
--- a/cc/trees/thread_proxy.h
+++ b/cc/trees/thread_proxy.h
@@ -52,6 +52,7 @@ class ThreadProxy : public Proxy,
virtual void SetNeedsUpdateLayers() OVERRIDE;
virtual void SetNeedsCommit() OVERRIDE;
virtual void SetNeedsRedraw(gfx::Rect damage_rect) OVERRIDE;
+ virtual void SetNextCommitWaitsForActivation() OVERRIDE;
virtual void NotifyInputThrottledUntilCommit() OVERRIDE;
virtual void SetDeferCommits(bool defer_commits) OVERRIDE;
virtual bool CommitRequested() const OVERRIDE;
@@ -204,6 +205,10 @@ class ThreadProxy : public Proxy,
// anything else.
scoped_ptr<OutputSurface> first_output_surface_;
+ // Accessed on the main thread, or when main thread is blocked.
+ bool commit_waits_for_activation_;
+ bool inside_commit_;
+
base::WeakPtrFactory<ThreadProxy> weak_factory_on_impl_thread_;
base::WeakPtr<ThreadProxy> main_thread_weak_ptr_;