diff options
author | danakj@chromium.org <danakj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-13 20:54:53 +0000 |
---|---|---|
committer | danakj@chromium.org <danakj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-13 20:54:53 +0000 |
commit | f4e25f9a40366ba27f302fe51f30f1b7671287c6 (patch) | |
tree | 9343a1c937f58c42407f46e85f79ede067f8d966 | |
parent | 883255b1652d6aeb32d8b1c741ac2b477c03b6fb (diff) | |
download | chromium_src-f4e25f9a40366ba27f302fe51f30f1b7671287c6.zip chromium_src-f4e25f9a40366ba27f302fe51f30f1b7671287c6.tar.gz chromium_src-f4e25f9a40366ba27f302fe51f30f1b7671287c6.tar.bz2 |
cc: Early out in PushPropertiesTo tree walk for commit.
If a subtree is not dirty, don't walk it doing PushPropertiesTo for all
its layers.
We know a layer needs PushPropertiesTo called on it when it requests
SetNeedsCommit() for itself, as this implies it has some value to push
across to the impl tree. If this has been called, it has nothing to push.
There are exceptions to this rule for some layers:
1) tiled layer
- Occlusion can be affected by changes anywhere in the tree, and this
changes what the layer chooses to push.
2) scrollbar layer crbug.com/259095
- Resources for the impl thread are chosen by the main thread, and this
must be done every commit in order to deal with situations like lost
context.
3) picture layer crbug.com/259402
- SyncFromActiveTree needs to be done every commit. This could potentially
be resolved.
4) delegated renderer layer crbug.com/259090
- Resources returned from the parent compositor must be returned to the
main thread currently, and this is done during push properties.
5) any layer with an animation crbug.com/259088
- Animations that complete on the impl thread are cleaned up on the main
thread by the next push properties on the animating layer. This could
be avoided by doing this cleanup in another place during commit.
Tested by:
LayerTreeHostTestLayersPushProperties
LayerTreeHostTestPushPropertiesAddingToTreeRequiresPush
LayerTreeHostTestPushPropertiesRemovingChildStopsRecursion
LayerTreeHostTestPushPropertiesRemovingChildStopsRecursionWithPersistence
LayerTreeHostTestPushPropertiesSetPropertiesWhileOutsideTree
LayerTreeHostTestPushPropertiesSetPropertyInParentThenChild
LayerTreeHostTestPropertyChangesDuringUpdateArePushed
This adds a new perftest:
LayerTreeHostPerfTestLeafInvalidates.TenTenSingleThread
The test is basically the original TenTenSingleThread test, but it
toggles a property on a leaf node in the layer tree (the first node
in a pre-order walk) every commit to cause some push properties
to still happen.
Perf test results are as follows.
BEFORE:
LayerTreeHostPerfTestJsonReader.TenTenSingleThread
*RESULT 10_10_layer_tree: frames: 5725, 0.35 ms/frame
LayerTreeHostPerfTestJsonReader.TenTenSingleThread_FullDamageEachFrame
*RESULT 10_10_layer_tree: frames: 4505, 0.44 ms/frame
crollingLayerTreePerfTest.LongScrollablePage
*RESULT long_scrollable_page: frames: 22045, 0.09 ms/frame
ImplSidePaintingPerfTest.HeavyPage
*RESULT heavy_layer_tree: frames: 405, 5.00 ms/frame
*RESULT heavy_layer_tree: commits: 406, 0.58 ms/commit
PageScaleImplSidePaintingPerfTest.HeavyPage
*RESULT heavy_layer_tree: frames: 405, 5.00 ms/frame
*RESULT heavy_layer_tree: commits: 406, 0.74 ms/commit
LayerTreeHostPerfTestLeafInvalidates.TenTenSingleThread
*RESULT 10_10_layer_tree: frames: 4095, 0.49 ms/frame
AFTER:
LayerTreeHostPerfTestJsonReader.TenTenSingleThread
*RESULT 10_10_layer_tree: frames: 6635, 0.30 ms/frame
LayerTreeHostPerfTestJsonReader.TenTenSingleThread_FullDamageEachFrame
*RESULT 10_10_layer_tree: frames: 5035, 0.40 ms/frame
ScrollingLayerTreePerfTest.LongScrollablePage
*RESULT long_scrollable_page: frames: 22225, 0.09 ms/frame
ImplSidePaintingPerfTest.HeavyPage
*RESULT heavy_layer_tree: frames: 405, 5.00 ms/frame
*RESULT heavy_layer_tree: commits: 406, 0.57 ms/commit
PageScaleImplSidePaintingPerfTest.HeavyPage
*RESULT heavy_layer_tree: frames: 405, 5.00 ms/frame
*RESULT heavy_layer_tree: commits: 406, 0.75 ms/commit
LayerTreeHostPerfTestLeafInvalidates.TenTenSingleThread
*RESULT 10_10_layer_tree: frames: 4505, 0.44 ms/frame
This is a perf change only, there should be no change in behaviour.
BUG=177756
Review URL: https://chromiumcodereview.appspot.com/12340033
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@211576 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | cc/layers/delegated_renderer_layer.cc | 5 | ||||
-rw-r--r-- | cc/layers/layer.cc | 59 | ||||
-rw-r--r-- | cc/layers/layer.h | 21 | ||||
-rw-r--r-- | cc/layers/layer_impl.h | 4 | ||||
-rw-r--r-- | cc/layers/picture_layer.cc | 6 | ||||
-rw-r--r-- | cc/layers/scrollbar_layer.cc | 3 | ||||
-rw-r--r-- | cc/layers/scrollbar_layer_unittest.cc | 98 | ||||
-rw-r--r-- | cc/layers/tiled_layer.cc | 5 | ||||
-rw-r--r-- | cc/layers/tiled_layer_unittest.cc | 13 | ||||
-rw-r--r-- | cc/test/fake_content_layer.cc | 8 | ||||
-rw-r--r-- | cc/test/fake_content_layer.h | 6 | ||||
-rw-r--r-- | cc/test/fake_layer_tree_host.h | 67 | ||||
-rw-r--r-- | cc/test/fake_picture_layer.cc | 9 | ||||
-rw-r--r-- | cc/test/fake_picture_layer.h | 6 | ||||
-rw-r--r-- | cc/test/fake_scrollbar_layer.cc | 12 | ||||
-rw-r--r-- | cc/test/fake_scrollbar_layer.h | 10 | ||||
-rw-r--r-- | cc/test/tiled_layer_test_common.cc | 20 | ||||
-rw-r--r-- | cc/test/tiled_layer_test_common.h | 2 | ||||
-rw-r--r-- | cc/trees/layer_tree_host_perftest.cc | 33 | ||||
-rw-r--r-- | cc/trees/layer_tree_host_unittest.cc | 712 | ||||
-rw-r--r-- | cc/trees/tree_synchronizer.cc | 73 | ||||
-rw-r--r-- | cc/trees/tree_synchronizer.h | 12 | ||||
-rw-r--r-- | cc/trees/tree_synchronizer_unittest.cc | 86 |
23 files changed, 1151 insertions, 119 deletions
diff --git a/cc/layers/delegated_renderer_layer.cc b/cc/layers/delegated_renderer_layer.cc index 216d00d..cbff44e 100644 --- a/cc/layers/delegated_renderer_layer.cc +++ b/cc/layers/delegated_renderer_layer.cc @@ -60,6 +60,11 @@ void DelegatedRendererLayer::PushPropertiesTo(LayerImpl* impl) { if (client_) client_->DidCommitFrameData(); + + // TODO(danakj): TakeUnusedResourcesForChildCompositor requires a push + // properties to happen in order to push up newly unused resources returned + // from the parent compositor. crbug.com/259090 + needs_push_properties_ = true; } void DelegatedRendererLayer::SetDisplaySize(gfx::Size size) { diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc index ed979a9..52d9f9e 100644 --- a/cc/layers/layer.cc +++ b/cc/layers/layer.cc @@ -30,6 +30,8 @@ scoped_refptr<Layer> Layer::Create() { Layer::Layer() : needs_display_(false), + needs_push_properties_(false), + num_dependents_need_push_properties_(false), stacking_order_changed_(false), layer_id_(s_next_layer_id++), ignore_set_needs_commit_(false), @@ -92,6 +94,10 @@ void Layer::SetLayerTreeHost(LayerTreeHost* host) { layer_tree_host_ = host; + // When changing hosts, the layer needs to commit its properties to the impl + // side for the new host. + SetNeedsPushProperties(); + for (size_t i = 0; i < children_.size(); ++i) children_[i]->SetLayerTreeHost(host); @@ -116,15 +122,22 @@ void Layer::SetLayerTreeHost(LayerTreeHost* host) { } void Layer::SetNeedsCommit() { + if (!layer_tree_host_) + return; + + SetNeedsPushProperties(); + if (ignore_set_needs_commit_) return; - if (layer_tree_host_) - layer_tree_host_->SetNeedsCommit(); + + layer_tree_host_->SetNeedsCommit(); } void Layer::SetNeedsFullTreeSync() { - if (layer_tree_host_) - layer_tree_host_->SetNeedsFullTreeSync(); + if (!layer_tree_host_) + return; + + layer_tree_host_->SetNeedsFullTreeSync(); } bool Layer::IsPropertyChangeAllowed() const { @@ -137,6 +150,31 @@ bool Layer::IsPropertyChangeAllowed() const { return !layer_tree_host_->in_paint_layer_contents(); } +void Layer::SetNeedsPushProperties() { + if (needs_push_properties_) + return; + if (!parent_should_know_need_push_properties() && parent_) + parent_->AddDependentNeedsPushProperties(); + needs_push_properties_ = true; +} + +void Layer::AddDependentNeedsPushProperties() { + DCHECK_GE(num_dependents_need_push_properties_, 0); + + if (!parent_should_know_need_push_properties() && parent_) + parent_->AddDependentNeedsPushProperties(); + + num_dependents_need_push_properties_++; +} + +void Layer::RemoveDependentNeedsPushProperties() { + num_dependents_need_push_properties_--; + DCHECK_GE(num_dependents_need_push_properties_, 0); + + if (!parent_should_know_need_push_properties() && parent_) + parent_->RemoveDependentNeedsPushProperties(); +} + gfx::Rect Layer::LayerRectToContentRect(const gfx::RectF& layer_rect) const { gfx::RectF content_rect = gfx::ScaleRect(layer_rect, contents_scale_x(), contents_scale_y()); @@ -170,6 +208,14 @@ bool Layer::BlocksPendingCommitRecursive() const { void Layer::SetParent(Layer* layer) { DCHECK(!layer || !layer->HasAncestor(this)); + + if (parent_should_know_need_push_properties()) { + if (parent_) + parent_->RemoveDependentNeedsPushProperties(); + if (layer) + layer->AddDependentNeedsPushProperties(); + } + parent_ = layer; SetLayerTreeHost(parent_ ? parent_->layer_tree_host() : NULL); @@ -767,6 +813,11 @@ void Layer::PushPropertiesTo(LayerImpl* layer) { // Reset any state that should be cleared for the next update. stacking_order_changed_ = false; update_rect_ = gfx::RectF(); + + // Animating layers require further push properties to clean up the animation. + // crbug.com/259088 + needs_push_properties_ = layer_animation_controller_->has_any_animation(); + num_dependents_need_push_properties_ = 0; } scoped_ptr<LayerImpl> Layer::CreateLayerImpl(LayerTreeImpl* tree_impl) { diff --git a/cc/layers/layer.h b/cc/layers/layer.h index 879834d..077eb2c 100644 --- a/cc/layers/layer.h +++ b/cc/layers/layer.h @@ -381,6 +381,11 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, virtual bool SupportsLCDText() const; + bool needs_push_properties() const { return needs_push_properties_; } + bool descendant_needs_push_properties() const { + return num_dependents_need_push_properties_ > 0; + } + protected: friend class LayerImpl; friend class TreeSynchronizer; @@ -392,11 +397,27 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, void SetNeedsFullTreeSync(); bool IsPropertyChangeAllowed() const; + void SetNeedsPushProperties(); + void AddDependentNeedsPushProperties(); + void RemoveDependentNeedsPushProperties(); + bool parent_should_know_need_push_properties() const { + return needs_push_properties() || descendant_needs_push_properties(); + } + void reset_raster_scale_to_unknown() { raster_scale_ = 0.f; } // This flag is set when layer need repainting/updating. bool needs_display_; + // This flag is set when the layer needs to push properties to the impl + // side. + bool needs_push_properties_; + + // The number of direct children or dependent layers that need to be recursed + // to in order for them or a descendent of them to push properties to the impl + // side. + int num_dependents_need_push_properties_; + // Tracks whether this layer may have changed stacking order with its // siblings. bool stacking_order_changed_; diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h index 611bb7c..ff7e956 100644 --- a/cc/layers/layer_impl.h +++ b/cc/layers/layer_impl.h @@ -437,6 +437,10 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver { scoped_ptr<base::Value> AsValue() const; virtual size_t GPUMemoryUsageInBytes() const; + // TODO(danakj): Be true only if needed. crbug.com/259511 + bool needs_push_properties() const { return true; } + bool descendant_needs_push_properties() const { return true; } + protected: LayerImpl(LayerTreeImpl* layer_impl, int id); diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc index f5b83bd..1a155f6 100644 --- a/cc/layers/picture_layer.cc +++ b/cc/layers/picture_layer.cc @@ -48,6 +48,12 @@ void PictureLayer::PushPropertiesTo(LayerImpl* base_layer) { layer_impl->invalidation_.Swap(&pile_invalidation_); layer_impl->pile_ = PicturePileImpl::CreateFromOther(pile_.get()); layer_impl->SyncFromActiveLayer(); + + // PictureLayer must push properties every frame. + // TODO(danakj): If we can avoid requiring to do CreateTilingSetIfNeeded() and + // SyncFromActiveLayer() on every commit then this could go away, maybe + // conditionally. crbug.com/259402 + needs_push_properties_ = true; } void PictureLayer::SetLayerTreeHost(LayerTreeHost* host) { diff --git a/cc/layers/scrollbar_layer.cc b/cc/layers/scrollbar_layer.cc index a63b04b..927ae7b 100644 --- a/cc/layers/scrollbar_layer.cc +++ b/cc/layers/scrollbar_layer.cc @@ -139,6 +139,9 @@ void ScrollbarLayer::PushPropertiesTo(LayerImpl* layer) { scrollbar_layer->set_thumb_resource_id(0); scrollbar_layer->set_is_overlay_scrollbar(scrollbar_->IsOverlay()); + + // ScrollbarLayer must push properties every frame. crbug.com/259095 + needs_push_properties_ = true; } ScrollbarLayer* ScrollbarLayer::ToScrollbarLayer() { diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc index f8b009b..c71731d8 100644 --- a/cc/layers/scrollbar_layer_unittest.cc +++ b/cc/layers/scrollbar_layer_unittest.cc @@ -12,6 +12,7 @@ #include "cc/resources/priority_calculator.h" #include "cc/resources/resource_update_queue.h" #include "cc/test/fake_impl_proxy.h" +#include "cc/test/fake_layer_tree_host.h" #include "cc/test/fake_layer_tree_host_client.h" #include "cc/test/fake_layer_tree_host_impl.h" #include "cc/test/fake_scrollbar.h" @@ -28,8 +29,8 @@ namespace cc { namespace { -scoped_ptr<LayerImpl> LayerImplForScrollAreaAndScrollbar( - FakeLayerTreeHostImpl* host_impl, +LayerImpl* LayerImplForScrollAreaAndScrollbar( + FakeLayerTreeHost* host, scoped_ptr<Scrollbar> scrollbar, bool reverse_order) { scoped_refptr<Layer> layer_tree_root = Layer::Create(); @@ -39,53 +40,43 @@ scoped_ptr<LayerImpl> LayerImplForScrollAreaAndScrollbar( child1->id()); layer_tree_root->AddChild(child1); layer_tree_root->InsertChild(child2, reverse_order ? 0 : 1); - scoped_ptr<LayerImpl> layer_impl = - TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(), - scoped_ptr<LayerImpl>(), - host_impl->active_tree()); - TreeSynchronizer::PushProperties(layer_tree_root.get(), layer_impl.get()); - return layer_impl.Pass(); + host->SetRootLayer(layer_tree_root); + return host->CommitAndCreateLayerImplTree(); } TEST(ScrollbarLayerTest, ResolveScrollLayerPointer) { - FakeImplProxy proxy; - FakeLayerTreeHostImpl host_impl(&proxy); + scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(); + scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar); + LayerImpl* layer_impl_tree_root = + LayerImplForScrollAreaAndScrollbar(host.get(), scrollbar.Pass(), false); - { - scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar); - scoped_ptr<LayerImpl> layer_impl_tree_root = - LayerImplForScrollAreaAndScrollbar( - &host_impl, scrollbar.Pass(), false); + LayerImpl* cc_child1 = layer_impl_tree_root->children()[0]; + ScrollbarLayerImpl* cc_child2 = static_cast<ScrollbarLayerImpl*>( + layer_impl_tree_root->children()[1]); - LayerImpl* cc_child1 = layer_impl_tree_root->children()[0]; - ScrollbarLayerImpl* cc_child2 = static_cast<ScrollbarLayerImpl*>( - layer_impl_tree_root->children()[1]); + EXPECT_EQ(cc_child1->horizontal_scrollbar_layer(), cc_child2); +} - EXPECT_EQ(cc_child1->horizontal_scrollbar_layer(), cc_child2); - } - { - // another traverse order - scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar); - scoped_ptr<LayerImpl> layer_impl_tree_root = - LayerImplForScrollAreaAndScrollbar( - &host_impl, scrollbar.Pass(), true); +TEST(ScrollbarLayerTest, ResolveScrollLayerPointer_ReverseOrder) { + scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(); + scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar); + LayerImpl* layer_impl_tree_root = + LayerImplForScrollAreaAndScrollbar(host.get(), scrollbar.Pass(), true); - ScrollbarLayerImpl* cc_child1 = static_cast<ScrollbarLayerImpl*>( - layer_impl_tree_root->children()[0]); - LayerImpl* cc_child2 = layer_impl_tree_root->children()[1]; + ScrollbarLayerImpl* cc_child1 = static_cast<ScrollbarLayerImpl*>( + layer_impl_tree_root->children()[0]); + LayerImpl* cc_child2 = layer_impl_tree_root->children()[1]; - EXPECT_EQ(cc_child2->horizontal_scrollbar_layer(), cc_child1); - } + EXPECT_EQ(cc_child2->horizontal_scrollbar_layer(), cc_child1); } TEST(ScrollbarLayerTest, ShouldScrollNonOverlayOnMainThread) { - FakeImplProxy proxy; - FakeLayerTreeHostImpl host_impl(&proxy); + scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(); // Create and attach a non-overlay scrollbar. scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar); - scoped_ptr<LayerImpl> layer_impl_tree_root = - LayerImplForScrollAreaAndScrollbar(&host_impl, scrollbar.Pass(), false); + LayerImpl* layer_impl_tree_root = + LayerImplForScrollAreaAndScrollbar(host.get(), scrollbar.Pass(), false); ScrollbarLayerImpl* scrollbar_layer_impl = static_cast<ScrollbarLayerImpl*>(layer_impl_tree_root->children()[1]); @@ -100,7 +91,7 @@ TEST(ScrollbarLayerTest, ShouldScrollNonOverlayOnMainThread) { scrollbar.reset(new FakeScrollbar(false, false, true)); layer_impl_tree_root = - LayerImplForScrollAreaAndScrollbar(&host_impl, scrollbar.Pass(), false); + LayerImplForScrollAreaAndScrollbar(host.get(), scrollbar.Pass(), false); scrollbar_layer_impl = static_cast<ScrollbarLayerImpl*>(layer_impl_tree_root->children()[1]); @@ -112,8 +103,7 @@ TEST(ScrollbarLayerTest, ShouldScrollNonOverlayOnMainThread) { } TEST(ScrollbarLayerTest, ScrollOffsetSynchronization) { - FakeImplProxy proxy; - FakeLayerTreeHostImpl host_impl(&proxy); + scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(); scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar); scoped_refptr<Layer> layer_tree_root = Layer::Create(); @@ -131,12 +121,9 @@ TEST(ScrollbarLayerTest, ScrollOffsetSynchronization) { content_layer->SetBounds(gfx::Size(100, 200)); content_layer->SavePaintProperties(); - scoped_ptr<LayerImpl> layer_impl_tree_root = - TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(), - scoped_ptr<LayerImpl>(), - host_impl.active_tree()); - TreeSynchronizer::PushProperties(layer_tree_root.get(), - layer_impl_tree_root.get()); + host->SetRootLayer(layer_tree_root); + + LayerImpl* layer_impl_tree_root = host->CommitAndCreateLayerImplTree(); ScrollbarLayerImpl* cc_scrollbar_layer = static_cast<ScrollbarLayerImpl*>(layer_impl_tree_root->children()[1]); @@ -153,12 +140,7 @@ TEST(ScrollbarLayerTest, ScrollOffsetSynchronization) { ScrollbarAnimationController* scrollbar_controller = layer_impl_tree_root->scrollbar_animation_controller(); - layer_impl_tree_root = - TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(), - layer_impl_tree_root.Pass(), - host_impl.active_tree()); - TreeSynchronizer::PushProperties(layer_tree_root.get(), - layer_impl_tree_root.get()); + layer_impl_tree_root = host->CommitAndCreateLayerImplTree(); EXPECT_EQ(scrollbar_controller, layer_impl_tree_root->scrollbar_animation_controller()); @@ -175,12 +157,12 @@ TEST(ScrollbarLayerTest, SolidColorDrawQuads) { LayerTreeSettings layer_tree_settings; layer_tree_settings.solid_color_scrollbars = true; layer_tree_settings.solid_color_scrollbar_thickness_dip = 3; - FakeImplProxy proxy; - FakeLayerTreeHostImpl host_impl(layer_tree_settings, &proxy); + scoped_ptr<FakeLayerTreeHost> host = + FakeLayerTreeHost::Create(layer_tree_settings); scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true)); - scoped_ptr<LayerImpl> layer_impl_tree_root = - LayerImplForScrollAreaAndScrollbar(&host_impl, scrollbar.Pass(), false); + LayerImpl* layer_impl_tree_root = + LayerImplForScrollAreaAndScrollbar(host.get(), scrollbar.Pass(), false); ScrollbarLayerImpl* scrollbar_layer_impl = static_cast<ScrollbarLayerImpl*>(layer_impl_tree_root->children()[1]); scrollbar_layer_impl->set_thumb_thickness(3); @@ -236,12 +218,12 @@ TEST(ScrollbarLayerTest, LayerDrivenSolidColorDrawQuads) { LayerTreeSettings layer_tree_settings; layer_tree_settings.solid_color_scrollbars = true; layer_tree_settings.solid_color_scrollbar_thickness_dip = 3; - FakeImplProxy proxy; - FakeLayerTreeHostImpl host_impl(layer_tree_settings, &proxy); + scoped_ptr<FakeLayerTreeHost> host = + FakeLayerTreeHost::Create(layer_tree_settings); scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true)); - scoped_ptr<LayerImpl> layer_impl_tree_root = - LayerImplForScrollAreaAndScrollbar(&host_impl, scrollbar.Pass(), false); + LayerImpl* layer_impl_tree_root = + LayerImplForScrollAreaAndScrollbar(host.get(), scrollbar.Pass(), false); ScrollbarLayerImpl* scrollbar_layer_impl = static_cast<ScrollbarLayerImpl*>(layer_impl_tree_root->children()[1]); diff --git a/cc/layers/tiled_layer.cc b/cc/layers/tiled_layer.cc index 8a7e661..2aa36a0 100644 --- a/cc/layers/tiled_layer.cc +++ b/cc/layers/tiled_layer.cc @@ -228,6 +228,11 @@ void TiledLayer::PushPropertiesTo(LayerImpl* layer) { iter != invalid_tiles.end(); ++iter) tiler_->TakeTile((*iter)->i(), (*iter)->j()); + + // TiledLayer must push properties every frame, since viewport state and + // occlusion from anywhere in the tree can change what the layer decides to + // push to the impl tree. + needs_push_properties_ = true; } bool TiledLayer::BlocksPendingCommit() const { return true; } diff --git a/cc/layers/tiled_layer_unittest.cc b/cc/layers/tiled_layer_unittest.cc index 3eab50c..601c59d 100644 --- a/cc/layers/tiled_layer_unittest.cc +++ b/cc/layers/tiled_layer_unittest.cc @@ -110,6 +110,7 @@ class TiledLayerTest : public testing::Test { DebugScopedSetImplThreadAndMainThreadBlocked impl_thread_and_main_thread_blocked(proxy_); layer->PushPropertiesTo(layer_impl); + layer->ResetNumDependentsNeedPushProperties(); } void LayerUpdate(FakeTiledLayer* layer, TestOcclusionTracker* occluded) { @@ -1646,9 +1647,9 @@ TEST_F(TiledLayerTest, DontAllocateContentsWhenTargetSurfaceCantBeAllocated) { new FakeTiledLayerImpl(host_impl_->active_tree(), child->id())); scoped_ptr<FakeTiledLayerImpl> child2_impl = make_scoped_ptr( new FakeTiledLayerImpl(host_impl_->active_tree(), child2->id())); - LayerPushPropertiesTo(root.get(), root_impl.get()); - LayerPushPropertiesTo(child.get(), child_impl.get()); LayerPushPropertiesTo(child2.get(), child2_impl.get()); + LayerPushPropertiesTo(child.get(), child_impl.get()); + LayerPushPropertiesTo(root.get(), root_impl.get()); for (unsigned i = 0; i < 3; ++i) { for (unsigned j = 0; j < 2; ++j) @@ -1685,9 +1686,9 @@ TEST_F(TiledLayerTest, DontAllocateContentsWhenTargetSurfaceCantBeAllocated) { new FakeTiledLayerImpl(host_impl_->active_tree(), child->id())); scoped_ptr<FakeTiledLayerImpl> child2_impl = make_scoped_ptr( new FakeTiledLayerImpl(host_impl_->active_tree(), child2->id())); - LayerPushPropertiesTo(root.get(), root_impl.get()); - LayerPushPropertiesTo(child.get(), child_impl.get()); LayerPushPropertiesTo(child2.get(), child2_impl.get()); + LayerPushPropertiesTo(child.get(), child_impl.get()); + LayerPushPropertiesTo(root.get(), root_impl.get()); for (unsigned i = 0; i < 3; ++i) { for (unsigned j = 0; j < 2; ++j) @@ -1723,9 +1724,9 @@ TEST_F(TiledLayerTest, DontAllocateContentsWhenTargetSurfaceCantBeAllocated) { new FakeTiledLayerImpl(host_impl_->active_tree(), child->id())); scoped_ptr<FakeTiledLayerImpl> child2_impl = make_scoped_ptr( new FakeTiledLayerImpl(host_impl_->active_tree(), child2->id())); - LayerPushPropertiesTo(root.get(), root_impl.get()); - LayerPushPropertiesTo(child.get(), child_impl.get()); LayerPushPropertiesTo(child2.get(), child2_impl.get()); + LayerPushPropertiesTo(child.get(), child_impl.get()); + LayerPushPropertiesTo(root.get(), root_impl.get()); for (unsigned i = 0; i < 3; ++i) { for (unsigned j = 0; j < 2; ++j) diff --git a/cc/test/fake_content_layer.cc b/cc/test/fake_content_layer.cc index 5d452ea..5dcc512 100644 --- a/cc/test/fake_content_layer.cc +++ b/cc/test/fake_content_layer.cc @@ -11,7 +11,8 @@ namespace cc { FakeContentLayer::FakeContentLayer(ContentLayerClient* client) : ContentLayer(client), - update_count_(0) { + update_count_(0), + push_properties_count_(0) { SetAnchorPoint(gfx::PointF(0.f, 0.f)); SetBounds(gfx::Size(1, 1)); SetIsDrawable(true); @@ -31,6 +32,11 @@ bool FakeContentLayer::Update(ResourceUpdateQueue* queue, return updated; } +void FakeContentLayer::PushPropertiesTo(LayerImpl* layer) { + ContentLayer::PushPropertiesTo(layer); + push_properties_count_++; +} + bool FakeContentLayer::HaveBackingAt(int i, int j) { const PrioritizedResource* resource = ResourceAtForTesting(i, j); return resource && resource->have_backing_texture(); diff --git a/cc/test/fake_content_layer.h b/cc/test/fake_content_layer.h index a824787..6b7a37d 100644 --- a/cc/test/fake_content_layer.h +++ b/cc/test/fake_content_layer.h @@ -22,10 +22,15 @@ class FakeContentLayer : public ContentLayer { size_t update_count() const { return update_count_; } void reset_update_count() { update_count_ = 0; } + size_t push_properties_count() const { return push_properties_count_; } + void reset_push_properties_count() { push_properties_count_ = 0; } + virtual bool Update( ResourceUpdateQueue* queue, const OcclusionTracker* occlusion) OVERRIDE; + virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE; + bool HaveBackingAt(int i, int j); private: @@ -33,6 +38,7 @@ class FakeContentLayer : public ContentLayer { virtual ~FakeContentLayer(); size_t update_count_; + size_t push_properties_count_; }; } // namespace cc diff --git a/cc/test/fake_layer_tree_host.h b/cc/test/fake_layer_tree_host.h new file mode 100644 index 0000000..3c9ff2c --- /dev/null +++ b/cc/test/fake_layer_tree_host.h @@ -0,0 +1,67 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CC_TEST_FAKE_LAYER_TREE_HOST_H_ +#define CC_TEST_FAKE_LAYER_TREE_HOST_H_ + +#include "cc/test/fake_impl_proxy.h" +#include "cc/test/fake_layer_tree_host_client.h" +#include "cc/test/fake_layer_tree_host_impl.h" +#include "cc/trees/layer_tree_host.h" +#include "cc/trees/layer_tree_impl.h" +#include "cc/trees/tree_synchronizer.h" + +namespace cc { + +class FakeLayerTreeHost : protected LayerTreeHost { + public: + static scoped_ptr<FakeLayerTreeHost> Create() { + static FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D); + static LayerTreeSettings settings; + return make_scoped_ptr(new FakeLayerTreeHost(&client, settings)); + } + + static scoped_ptr<FakeLayerTreeHost> Create( + const LayerTreeSettings& settings) { + static FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D); + return make_scoped_ptr(new FakeLayerTreeHost(&client, settings)); + } + + virtual ~FakeLayerTreeHost() {} + + virtual void SetNeedsCommit() OVERRIDE {} + virtual void SetNeedsFullTreeSync() OVERRIDE {} + + using LayerTreeHost::SetRootLayer; + + LayerImpl* CommitAndCreateLayerImplTree() { + scoped_ptr<LayerImpl> old_root_layer_impl = + active_tree()->DetachLayerTree(); + + scoped_ptr<LayerImpl> layer_impl = + TreeSynchronizer::SynchronizeTrees( + root_layer(), + old_root_layer_impl.Pass(), + active_tree()); + TreeSynchronizer::PushProperties(root_layer(), layer_impl.get()); + + active_tree()->SetRootLayer(layer_impl.Pass()); + return active_tree()->root_layer(); + } + + LayerTreeImpl* active_tree() { return host_impl_.active_tree(); } + + private: + FakeLayerTreeHost(LayerTreeHostClient* client, + const LayerTreeSettings& settings) + : LayerTreeHost(client, settings), + host_impl_(settings, &proxy_) {} + + FakeImplProxy proxy_; + FakeLayerTreeHostImpl host_impl_; +}; + +} // namespace cc + +#endif // CC_TEST_FAKE_LAYER_TREE_HOST_H_ diff --git a/cc/test/fake_picture_layer.cc b/cc/test/fake_picture_layer.cc index 3690f7c..997197c 100644 --- a/cc/test/fake_picture_layer.cc +++ b/cc/test/fake_picture_layer.cc @@ -10,7 +10,8 @@ namespace cc { FakePictureLayer::FakePictureLayer(ContentLayerClient* client) : PictureLayer(client), - update_count_(0) { + update_count_(0), + push_properties_count_(0) { SetAnchorPoint(gfx::PointF(0.f, 0.f)); SetBounds(gfx::Size(1, 1)); SetIsDrawable(true); @@ -30,4 +31,10 @@ bool FakePictureLayer::Update(ResourceUpdateQueue* queue, return updated; } +void FakePictureLayer::PushPropertiesTo(LayerImpl* layer) { + PictureLayer::PushPropertiesTo(layer); + push_properties_count_++; +} + + } // namespace cc diff --git a/cc/test/fake_picture_layer.h b/cc/test/fake_picture_layer.h index 7608644..b5b81de 100644 --- a/cc/test/fake_picture_layer.h +++ b/cc/test/fake_picture_layer.h @@ -23,15 +23,21 @@ class FakePictureLayer : public PictureLayer { size_t update_count() const { return update_count_; } void reset_update_count() { update_count_ = 0; } + size_t push_properties_count() const { return push_properties_count_; } + void reset_push_properties_count() { push_properties_count_ = 0; } + virtual bool Update( ResourceUpdateQueue* queue, const OcclusionTracker* occlusion) OVERRIDE; + virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE; + private: explicit FakePictureLayer(ContentLayerClient* client); virtual ~FakePictureLayer(); size_t update_count_; + size_t push_properties_count_; }; } // namespace cc diff --git a/cc/test/fake_scrollbar_layer.cc b/cc/test/fake_scrollbar_layer.cc index b3b6f2f..64e08ad 100644 --- a/cc/test/fake_scrollbar_layer.cc +++ b/cc/test/fake_scrollbar_layer.cc @@ -4,6 +4,7 @@ #include "cc/test/fake_scrollbar_layer.h" +#include "base/auto_reset.h" #include "cc/resources/resource_update_queue.h" #include "cc/test/fake_scrollbar.h" @@ -17,6 +18,7 @@ FakeScrollbarLayer::FakeScrollbarLayer(bool paint_during_update, new FakeScrollbar(paint_during_update, has_thumb, false)).Pass(), scrolling_layer_id), update_count_(0), + push_properties_count_(0), last_update_full_upload_size_(0), last_update_partial_upload_size_(0) { SetAnchorPoint(gfx::PointF(0.f, 0.f)); @@ -37,4 +39,14 @@ bool FakeScrollbarLayer::Update(ResourceUpdateQueue* queue, return updated; } +void FakeScrollbarLayer::PushPropertiesTo(LayerImpl* layer) { + ScrollbarLayer::PushPropertiesTo(layer); + ++push_properties_count_; +} + +scoped_ptr<base::AutoReset<bool> > FakeScrollbarLayer::IgnoreSetNeedsCommit() { + return make_scoped_ptr( + new base::AutoReset<bool>(&ignore_set_needs_commit_, true)); +} + } // namespace cc diff --git a/cc/test/fake_scrollbar_layer.h b/cc/test/fake_scrollbar_layer.h index 2292210..43be832 100644 --- a/cc/test/fake_scrollbar_layer.h +++ b/cc/test/fake_scrollbar_layer.h @@ -8,6 +8,8 @@ #include "base/memory/scoped_ptr.h" #include "cc/layers/scrollbar_layer.h" +namespace base { template<typename T> class AutoReset; } + namespace cc { class FakeScrollbarLayer : public ScrollbarLayer { @@ -31,6 +33,13 @@ class FakeScrollbarLayer : public ScrollbarLayer { virtual bool Update(ResourceUpdateQueue* queue, const OcclusionTracker* occlusion) OVERRIDE; + virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE; + + scoped_ptr<base::AutoReset<bool> > IgnoreSetNeedsCommit(); + + size_t push_properties_count() const { return push_properties_count_; } + void reset_push_properties_count() { push_properties_count_ = 0; } + private: FakeScrollbarLayer(bool paint_during_update, bool has_thumb, @@ -38,6 +47,7 @@ class FakeScrollbarLayer : public ScrollbarLayer { virtual ~FakeScrollbarLayer(); int update_count_; + size_t push_properties_count_; size_t last_update_full_upload_size_; size_t last_update_partial_upload_size_; }; diff --git a/cc/test/tiled_layer_test_common.cc b/cc/test/tiled_layer_test_common.cc index acd21e3..92fc9b9 100644 --- a/cc/test/tiled_layer_test_common.cc +++ b/cc/test/tiled_layer_test_common.cc @@ -123,6 +123,26 @@ void FakeTiledLayer::UpdateContentsScale(float ideal_contents_scale) { &draw_properties().content_bounds); } +void FakeTiledLayer::ResetNumDependentsNeedPushProperties() { + size_t num = 0; + if (mask_layer()) { + if (mask_layer()->needs_push_properties() || + mask_layer()->descendant_needs_push_properties()) + ++num; + } + if (replica_layer()) { + if (replica_layer()->needs_push_properties() || + replica_layer()->descendant_needs_push_properties()) + ++num; + } + for (size_t i = 0; i < children().size(); ++i) { + if (children()[i]->needs_push_properties() || + children()[i]->descendant_needs_push_properties()) + ++num; + } + num_dependents_need_push_properties_ = num; +} + LayerUpdater* FakeTiledLayer::Updater() const { return fake_updater_.get(); } diff --git a/cc/test/tiled_layer_test_common.h b/cc/test/tiled_layer_test_common.h index 305fd90..c793c00 100644 --- a/cc/test/tiled_layer_test_common.h +++ b/cc/test/tiled_layer_test_common.h @@ -119,6 +119,8 @@ class FakeTiledLayer : public TiledLayer { // Simulate CalcDrawProperties. void UpdateContentsScale(float ideal_contents_scale); + void ResetNumDependentsNeedPushProperties(); + protected: virtual LayerUpdater* Updater() const OVERRIDE; virtual void CreateUpdaterIfNeeded() OVERRIDE {} diff --git a/cc/trees/layer_tree_host_perftest.cc b/cc/trees/layer_tree_host_perftest.cc index 1f76126..4103158 100644 --- a/cc/trees/layer_tree_host_perftest.cc +++ b/cc/trees/layer_tree_host_perftest.cc @@ -151,6 +151,39 @@ TEST_F(LayerTreeHostPerfTestJsonReader, RunTest(false, false, false); } +// Invalidates a leaf layer in the tree on the main thread after every commit. +class LayerTreeHostPerfTestLeafInvalidates + : public LayerTreeHostPerfTestJsonReader { + public: + virtual void BuildTree() OVERRIDE { + LayerTreeHostPerfTestJsonReader::BuildTree(); + + // Find a leaf layer. + for (layer_to_invalidate_ = layer_tree_host()->root_layer(); + layer_to_invalidate_->children().size(); + layer_to_invalidate_ = layer_to_invalidate_->children()[0]) {} + } + + virtual void DidCommitAndDrawFrame() OVERRIDE { + if (TestEnded()) + return; + + static bool flip = true; + layer_to_invalidate_->SetOpacity(flip ? 1.f : 0.5f); + flip = !flip; + } + + protected: + Layer* layer_to_invalidate_; +}; + +// Simulates a tab switcher scene with two stacks of 10 tabs each. Invalidate a +// property on a leaf layer in the tree every commit. +TEST_F(LayerTreeHostPerfTestLeafInvalidates, TenTenSingleThread) { + ReadTestFile("10_10_layer_tree"); + RunTest(false, false, false); +} + // Simulates main-thread scrolling on each frame. class ScrollingLayerTreePerfTest : public LayerTreeHostPerfTestJsonReader { public: diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc index c7310cb..d4ac4dc 100644 --- a/cc/trees/layer_tree_host_unittest.cc +++ b/cc/trees/layer_tree_host_unittest.cc @@ -6,6 +6,7 @@ #include <algorithm> +#include "base/auto_reset.h" #include "base/synchronization/lock.h" #include "cc/animation/timing_function.h" #include "cc/debug/frame_rate_counter.h" @@ -3179,5 +3180,716 @@ class LayerTreeHostTestDeferredInitialize : public LayerTreeHostTest { MULTI_THREAD_TEST_F(LayerTreeHostTestDeferredInitialize); +class PushPropertiesCountingLayer : public Layer { + public: + static scoped_refptr<PushPropertiesCountingLayer> Create() { + return new PushPropertiesCountingLayer(); + } + + virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE { + Layer::PushPropertiesTo(layer); + push_properties_count_++; + if (persist_needs_push_properties_) + needs_push_properties_ = true; + } + + size_t push_properties_count() const { return push_properties_count_; } + void reset_push_properties_count() { push_properties_count_ = 0; } + + void set_persist_needs_push_properties(bool persist) { + persist_needs_push_properties_ = persist; + } + + private: + PushPropertiesCountingLayer() + : push_properties_count_(0), + persist_needs_push_properties_(false) { + SetAnchorPoint(gfx::PointF()); + SetBounds(gfx::Size(1, 1)); + SetIsDrawable(true); + } + virtual ~PushPropertiesCountingLayer() {} + + size_t push_properties_count_; + bool persist_needs_push_properties_; +}; + +class LayerTreeHostTestLayersPushProperties : public LayerTreeHostTest { + protected: + virtual void BeginTest() OVERRIDE { + num_commits_ = 0; + expected_push_properties_root_ = 0; + expected_push_properties_child_ = 0; + expected_push_properties_grandchild_ = 0; + expected_push_properties_child2_ = 0; + expected_push_properties_other_root_ = 0; + expected_push_properties_leaf_layer_ = 0; + PostSetNeedsCommitToMainThread(); + } + + virtual void SetupTree() OVERRIDE { + root_ = PushPropertiesCountingLayer::Create(); + child_ = PushPropertiesCountingLayer::Create(); + child2_ = PushPropertiesCountingLayer::Create(); + grandchild_ = PushPropertiesCountingLayer::Create(); + + if (layer_tree_host()->settings().impl_side_painting) + leaf_picture_layer_ = FakePictureLayer::Create(&client_); + else + leaf_content_layer_ = FakeContentLayer::Create(&client_); + + root_->AddChild(child_); + root_->AddChild(child2_); + child_->AddChild(grandchild_); + if (leaf_picture_layer_) + child2_->AddChild(leaf_picture_layer_); + if (leaf_content_layer_) + child2_->AddChild(leaf_content_layer_); + + other_root_ = PushPropertiesCountingLayer::Create(); + + // Don't set the root layer here. + LayerTreeHostTest::SetupTree(); + } + + virtual void DidCommitAndDrawFrame() OVERRIDE { + ++num_commits_; + + EXPECT_EQ(expected_push_properties_root_, root_->push_properties_count()); + EXPECT_EQ(expected_push_properties_child_, child_->push_properties_count()); + EXPECT_EQ(expected_push_properties_grandchild_, + grandchild_->push_properties_count()); + EXPECT_EQ(expected_push_properties_child2_, + child2_->push_properties_count()); + EXPECT_EQ(expected_push_properties_other_root_, + other_root_->push_properties_count()); + if (leaf_content_layer_) { + EXPECT_EQ(expected_push_properties_leaf_layer_, + leaf_content_layer_->push_properties_count()); + } + if (leaf_picture_layer_) { + EXPECT_EQ(expected_push_properties_leaf_layer_, + leaf_picture_layer_->push_properties_count()); + } + + // The content/picture layer always needs to be pushed. + if (root_->layer_tree_host()) { + EXPECT_TRUE(root_->descendant_needs_push_properties()); + EXPECT_FALSE(root_->needs_push_properties()); + } + if (child2_->layer_tree_host()) { + EXPECT_TRUE(child2_->descendant_needs_push_properties()); + EXPECT_FALSE(child2_->needs_push_properties()); + } + if (leaf_content_layer_.get() && leaf_content_layer_->layer_tree_host()) { + EXPECT_FALSE(leaf_content_layer_->descendant_needs_push_properties()); + EXPECT_TRUE(leaf_content_layer_->needs_push_properties()); + } + if (leaf_picture_layer_.get() && leaf_picture_layer_->layer_tree_host()) { + EXPECT_FALSE(leaf_picture_layer_->descendant_needs_push_properties()); + EXPECT_TRUE(leaf_picture_layer_->needs_push_properties()); + } + + // child_ and grandchild_ don't persist their need to push properties. + if (child_->layer_tree_host()) { + EXPECT_FALSE(child_->descendant_needs_push_properties()); + EXPECT_FALSE(child_->needs_push_properties()); + } + if (grandchild_->layer_tree_host()) { + EXPECT_FALSE(grandchild_->descendant_needs_push_properties()); + EXPECT_FALSE(grandchild_->needs_push_properties()); + } + + if (other_root_->layer_tree_host()) { + EXPECT_FALSE(other_root_->descendant_needs_push_properties()); + EXPECT_FALSE(other_root_->needs_push_properties()); + } + + switch (num_commits_) { + case 1: + layer_tree_host()->SetRootLayer(root_); + // Layers added to the tree get committed. + ++expected_push_properties_root_; + ++expected_push_properties_child_; + ++expected_push_properties_grandchild_; + ++expected_push_properties_child2_; + break; + case 2: + layer_tree_host()->SetNeedsCommit(); + // No layers need commit. + break; + case 3: + layer_tree_host()->SetRootLayer(other_root_); + // Layers added to the tree get committed. + ++expected_push_properties_other_root_; + break; + case 4: + layer_tree_host()->SetRootLayer(root_); + // Layers added to the tree get committed. + ++expected_push_properties_root_; + ++expected_push_properties_child_; + ++expected_push_properties_grandchild_; + ++expected_push_properties_child2_; + break; + case 5: + layer_tree_host()->SetNeedsCommit(); + // No layers need commit. + break; + case 6: + child_->RemoveFromParent(); + // No layers need commit. + break; + case 7: + root_->AddChild(child_); + // Layers added to the tree get committed. + ++expected_push_properties_child_; + ++expected_push_properties_grandchild_; + break; + case 8: + grandchild_->RemoveFromParent(); + // No layers need commit. + break; + case 9: + child_->AddChild(grandchild_); + // Layers added to the tree get committed. + ++expected_push_properties_grandchild_; + break; + case 10: + layer_tree_host()->SetViewportSize(gfx::Size(20, 20)); + // No layers need commit. + break; + case 11: + layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.8f, 1.1f); + // No layers need commit. + break; + case 12: + child_->SetPosition(gfx::Point(1, 1)); + // The modified layer needs commit + ++expected_push_properties_child_; + break; + case 13: + child2_->SetPosition(gfx::Point(1, 1)); + // The modified layer needs commit + ++expected_push_properties_child2_; + break; + case 14: + child_->RemoveFromParent(); + root_->AddChild(child_); + // Layers added to the tree get committed. + ++expected_push_properties_child_; + ++expected_push_properties_grandchild_; + break; + case 15: + grandchild_->SetPosition(gfx::Point(1, 1)); + // The modified layer needs commit + ++expected_push_properties_grandchild_; + break; + case 16: + child_->SetNeedsDisplay(); + // The modified layer needs commit + ++expected_push_properties_child_; + break; + case 17: + EndTest(); + break; + } + + // Content/Picture layers require PushProperties every commit that they are + // in the tree. + if ((leaf_content_layer_.get() && leaf_content_layer_->layer_tree_host()) || + (leaf_picture_layer_.get() && leaf_picture_layer_->layer_tree_host())) + ++expected_push_properties_leaf_layer_; + } + + virtual void AfterTest() OVERRIDE {} + + int num_commits_; + FakeContentLayerClient client_; + scoped_refptr<PushPropertiesCountingLayer> root_; + scoped_refptr<PushPropertiesCountingLayer> child_; + scoped_refptr<PushPropertiesCountingLayer> child2_; + scoped_refptr<PushPropertiesCountingLayer> grandchild_; + scoped_refptr<PushPropertiesCountingLayer> other_root_; + scoped_refptr<FakeContentLayer> leaf_content_layer_; + scoped_refptr<FakePictureLayer> leaf_picture_layer_; + size_t expected_push_properties_root_; + size_t expected_push_properties_child_; + size_t expected_push_properties_child2_; + size_t expected_push_properties_grandchild_; + size_t expected_push_properties_other_root_; + size_t expected_push_properties_leaf_layer_; +}; + +MULTI_THREAD_TEST_F(LayerTreeHostTestLayersPushProperties); + +class LayerTreeHostTestPropertyChangesDuringUpdateArePushed + : public LayerTreeHostTest { + protected: + virtual void BeginTest() OVERRIDE { + PostSetNeedsCommitToMainThread(); + } + + virtual void SetupTree() OVERRIDE { + root_ = Layer::Create(); + root_->SetBounds(gfx::Size(1, 1)); + + bool paint_scrollbar = true; + bool has_thumb = false; + scrollbar_layer_ = + FakeScrollbarLayer::Create(paint_scrollbar, has_thumb, root_->id()); + + root_->AddChild(scrollbar_layer_); + + layer_tree_host()->SetRootLayer(root_); + LayerTreeHostTest::SetupTree(); + } + + virtual void DidCommitAndDrawFrame() OVERRIDE { + switch (layer_tree_host()->commit_number()) { + case 0: + break; + case 1: { + // During update, the ignore_set_needs_commit_ bit is set to true to + // avoid causing a second commit to be scheduled. If a property change + // is made during this, however, it needs to be pushed in the upcoming + // commit. + scoped_ptr<base::AutoReset<bool> > ignore = + scrollbar_layer_->IgnoreSetNeedsCommit(); + + scrollbar_layer_->SetBounds(gfx::Size(30, 30)); + + EXPECT_TRUE(scrollbar_layer_->needs_push_properties()); + EXPECT_TRUE(root_->descendant_needs_push_properties()); + layer_tree_host()->SetNeedsCommit(); + + scrollbar_layer_->reset_push_properties_count(); + EXPECT_EQ(0u, scrollbar_layer_->push_properties_count()); + break; + } + case 2: + EXPECT_EQ(1u, scrollbar_layer_->push_properties_count()); + EndTest(); + break; + } + } + + virtual void AfterTest() OVERRIDE {} + + scoped_refptr<Layer> root_; + scoped_refptr<FakeScrollbarLayer> scrollbar_layer_; +}; + +MULTI_THREAD_TEST_F(LayerTreeHostTestPropertyChangesDuringUpdateArePushed); + +class LayerTreeHostTestCasePushPropertiesThreeGrandChildren + : public LayerTreeHostTest { + protected: + virtual void BeginTest() OVERRIDE { + expected_push_properties_root_ = 0; + expected_push_properties_child_ = 0; + expected_push_properties_grandchild1_ = 0; + expected_push_properties_grandchild2_ = 0; + expected_push_properties_grandchild3_ = 0; + PostSetNeedsCommitToMainThread(); + } + + virtual void SetupTree() OVERRIDE { + root_ = PushPropertiesCountingLayer::Create(); + child_ = PushPropertiesCountingLayer::Create(); + grandchild1_ = PushPropertiesCountingLayer::Create(); + grandchild2_ = PushPropertiesCountingLayer::Create(); + grandchild3_ = PushPropertiesCountingLayer::Create(); + + root_->AddChild(child_); + child_->AddChild(grandchild1_); + child_->AddChild(grandchild2_); + child_->AddChild(grandchild3_); + + // Don't set the root layer here. + LayerTreeHostTest::SetupTree(); + } + + virtual void AfterTest() OVERRIDE {} + + FakeContentLayerClient client_; + scoped_refptr<PushPropertiesCountingLayer> root_; + scoped_refptr<PushPropertiesCountingLayer> child_; + scoped_refptr<PushPropertiesCountingLayer> grandchild1_; + scoped_refptr<PushPropertiesCountingLayer> grandchild2_; + scoped_refptr<PushPropertiesCountingLayer> grandchild3_; + size_t expected_push_properties_root_; + size_t expected_push_properties_child_; + size_t expected_push_properties_grandchild1_; + size_t expected_push_properties_grandchild2_; + size_t expected_push_properties_grandchild3_; +}; + +class LayerTreeHostTestPushPropertiesAddingToTreeRequiresPush + : public LayerTreeHostTestCasePushPropertiesThreeGrandChildren { + protected: + virtual void DidCommitAndDrawFrame() OVERRIDE { + int last_source_frame_number = layer_tree_host()->commit_number() - 1; + switch (last_source_frame_number) { + case 0: + EXPECT_FALSE(root_->needs_push_properties()); + EXPECT_FALSE(root_->descendant_needs_push_properties()); + EXPECT_FALSE(child_->needs_push_properties()); + EXPECT_FALSE(child_->descendant_needs_push_properties()); + EXPECT_FALSE(grandchild1_->needs_push_properties()); + EXPECT_FALSE(grandchild1_->descendant_needs_push_properties()); + EXPECT_FALSE(grandchild2_->needs_push_properties()); + EXPECT_FALSE(grandchild2_->descendant_needs_push_properties()); + EXPECT_FALSE(grandchild3_->needs_push_properties()); + EXPECT_FALSE(grandchild3_->descendant_needs_push_properties()); + + layer_tree_host()->SetRootLayer(root_); + + EXPECT_TRUE(root_->needs_push_properties()); + EXPECT_TRUE(root_->descendant_needs_push_properties()); + EXPECT_TRUE(child_->needs_push_properties()); + EXPECT_TRUE(child_->descendant_needs_push_properties()); + EXPECT_TRUE(grandchild1_->needs_push_properties()); + EXPECT_FALSE(grandchild1_->descendant_needs_push_properties()); + EXPECT_TRUE(grandchild2_->needs_push_properties()); + EXPECT_FALSE(grandchild2_->descendant_needs_push_properties()); + EXPECT_TRUE(grandchild3_->needs_push_properties()); + EXPECT_FALSE(grandchild3_->descendant_needs_push_properties()); + break; + case 1: + EndTest(); + break; + } + } +}; + +MULTI_THREAD_TEST_F(LayerTreeHostTestPushPropertiesAddingToTreeRequiresPush); + +class LayerTreeHostTestPushPropertiesRemovingChildStopsRecursion + : public LayerTreeHostTestCasePushPropertiesThreeGrandChildren { + protected: + virtual void DidCommitAndDrawFrame() OVERRIDE { + int last_source_frame_number = layer_tree_host()->commit_number() - 1; + switch (last_source_frame_number) { + case 0: + layer_tree_host()->SetRootLayer(root_); + break; + case 1: + EXPECT_FALSE(root_->needs_push_properties()); + EXPECT_FALSE(root_->descendant_needs_push_properties()); + EXPECT_FALSE(child_->needs_push_properties()); + EXPECT_FALSE(child_->descendant_needs_push_properties()); + EXPECT_FALSE(grandchild1_->needs_push_properties()); + EXPECT_FALSE(grandchild1_->descendant_needs_push_properties()); + EXPECT_FALSE(grandchild2_->needs_push_properties()); + EXPECT_FALSE(grandchild2_->descendant_needs_push_properties()); + EXPECT_FALSE(grandchild3_->needs_push_properties()); + EXPECT_FALSE(grandchild3_->descendant_needs_push_properties()); + + grandchild1_->RemoveFromParent(); + grandchild1_->SetPosition(gfx::Point(1, 1)); + + EXPECT_FALSE(root_->needs_push_properties()); + EXPECT_FALSE(root_->descendant_needs_push_properties()); + EXPECT_FALSE(child_->needs_push_properties()); + EXPECT_FALSE(child_->descendant_needs_push_properties()); + EXPECT_FALSE(grandchild2_->needs_push_properties()); + EXPECT_FALSE(grandchild2_->descendant_needs_push_properties()); + EXPECT_FALSE(grandchild3_->needs_push_properties()); + EXPECT_FALSE(grandchild3_->descendant_needs_push_properties()); + + child_->AddChild(grandchild1_); + + EXPECT_FALSE(root_->needs_push_properties()); + EXPECT_TRUE(root_->descendant_needs_push_properties()); + EXPECT_FALSE(child_->needs_push_properties()); + EXPECT_TRUE(child_->descendant_needs_push_properties()); + EXPECT_TRUE(grandchild1_->needs_push_properties()); + EXPECT_FALSE(grandchild1_->descendant_needs_push_properties()); + EXPECT_FALSE(grandchild2_->needs_push_properties()); + EXPECT_FALSE(grandchild2_->descendant_needs_push_properties()); + EXPECT_FALSE(grandchild3_->needs_push_properties()); + EXPECT_FALSE(grandchild3_->descendant_needs_push_properties()); + + grandchild2_->SetPosition(gfx::Point(1, 1)); + + EXPECT_FALSE(root_->needs_push_properties()); + EXPECT_TRUE(root_->descendant_needs_push_properties()); + EXPECT_FALSE(child_->needs_push_properties()); + EXPECT_TRUE(child_->descendant_needs_push_properties()); + EXPECT_TRUE(grandchild1_->needs_push_properties()); + EXPECT_FALSE(grandchild1_->descendant_needs_push_properties()); + EXPECT_TRUE(grandchild2_->needs_push_properties()); + EXPECT_FALSE(grandchild2_->descendant_needs_push_properties()); + EXPECT_FALSE(grandchild3_->needs_push_properties()); + EXPECT_FALSE(grandchild3_->descendant_needs_push_properties()); + + // grandchild2_ will still need a push properties. + grandchild1_->RemoveFromParent(); + + EXPECT_FALSE(root_->needs_push_properties()); + EXPECT_TRUE(root_->descendant_needs_push_properties()); + EXPECT_FALSE(child_->needs_push_properties()); + EXPECT_TRUE(child_->descendant_needs_push_properties()); + + // grandchild3_ does not need a push properties, so recursing should + // no longer be needed. + grandchild2_->RemoveFromParent(); + + EXPECT_FALSE(root_->needs_push_properties()); + EXPECT_FALSE(root_->descendant_needs_push_properties()); + EXPECT_FALSE(child_->needs_push_properties()); + EXPECT_FALSE(child_->descendant_needs_push_properties()); + EndTest(); + break; + } + } +}; + +MULTI_THREAD_TEST_F(LayerTreeHostTestPushPropertiesRemovingChildStopsRecursion); + +class LayerTreeHostTestPushPropertiesRemovingChildStopsRecursionWithPersistence + : public LayerTreeHostTestCasePushPropertiesThreeGrandChildren { + protected: + virtual void DidCommitAndDrawFrame() OVERRIDE { + int last_source_frame_number = layer_tree_host()->commit_number() - 1; + switch (last_source_frame_number) { + case 0: + layer_tree_host()->SetRootLayer(root_); + grandchild1_->set_persist_needs_push_properties(true); + grandchild2_->set_persist_needs_push_properties(true); + break; + case 1: + EXPECT_FALSE(root_->needs_push_properties()); + EXPECT_TRUE(root_->descendant_needs_push_properties()); + EXPECT_FALSE(child_->needs_push_properties()); + EXPECT_TRUE(child_->descendant_needs_push_properties()); + EXPECT_TRUE(grandchild1_->needs_push_properties()); + EXPECT_FALSE(grandchild1_->descendant_needs_push_properties()); + EXPECT_TRUE(grandchild2_->needs_push_properties()); + EXPECT_FALSE(grandchild2_->descendant_needs_push_properties()); + EXPECT_FALSE(grandchild3_->needs_push_properties()); + EXPECT_FALSE(grandchild3_->descendant_needs_push_properties()); + + // grandchild2_ will still need a push properties. + grandchild1_->RemoveFromParent(); + + EXPECT_FALSE(root_->needs_push_properties()); + EXPECT_TRUE(root_->descendant_needs_push_properties()); + EXPECT_FALSE(child_->needs_push_properties()); + EXPECT_TRUE(child_->descendant_needs_push_properties()); + + // grandchild3_ does not need a push properties, so recursing should + // no longer be needed. + grandchild2_->RemoveFromParent(); + + EXPECT_FALSE(root_->needs_push_properties()); + EXPECT_FALSE(root_->descendant_needs_push_properties()); + EXPECT_FALSE(child_->needs_push_properties()); + EXPECT_FALSE(child_->descendant_needs_push_properties()); + EndTest(); + break; + } + } +}; + +MULTI_THREAD_TEST_F( + LayerTreeHostTestPushPropertiesRemovingChildStopsRecursionWithPersistence); + +class LayerTreeHostTestPushPropertiesSetPropertiesWhileOutsideTree + : public LayerTreeHostTestCasePushPropertiesThreeGrandChildren { + protected: + virtual void DidCommitAndDrawFrame() OVERRIDE { + int last_source_frame_number = layer_tree_host()->commit_number() - 1; + switch (last_source_frame_number) { + case 0: + layer_tree_host()->SetRootLayer(root_); + break; + case 1: + EXPECT_FALSE(root_->needs_push_properties()); + EXPECT_FALSE(root_->descendant_needs_push_properties()); + EXPECT_FALSE(child_->needs_push_properties()); + EXPECT_FALSE(child_->descendant_needs_push_properties()); + EXPECT_FALSE(grandchild1_->needs_push_properties()); + EXPECT_FALSE(grandchild1_->descendant_needs_push_properties()); + EXPECT_FALSE(grandchild2_->needs_push_properties()); + EXPECT_FALSE(grandchild2_->descendant_needs_push_properties()); + EXPECT_FALSE(grandchild3_->needs_push_properties()); + EXPECT_FALSE(grandchild3_->descendant_needs_push_properties()); + + // Change grandchildren while their parent is not in the tree. + child_->RemoveFromParent(); + grandchild1_->SetPosition(gfx::Point(1, 1)); + grandchild2_->SetPosition(gfx::Point(1, 1)); + root_->AddChild(child_); + + EXPECT_FALSE(root_->needs_push_properties()); + EXPECT_TRUE(root_->descendant_needs_push_properties()); + EXPECT_TRUE(child_->needs_push_properties()); + EXPECT_TRUE(child_->descendant_needs_push_properties()); + EXPECT_TRUE(grandchild1_->needs_push_properties()); + EXPECT_FALSE(grandchild1_->descendant_needs_push_properties()); + EXPECT_TRUE(grandchild2_->needs_push_properties()); + EXPECT_FALSE(grandchild2_->descendant_needs_push_properties()); + EXPECT_TRUE(grandchild3_->needs_push_properties()); + EXPECT_FALSE(grandchild3_->descendant_needs_push_properties()); + + grandchild1_->RemoveFromParent(); + + EXPECT_FALSE(root_->needs_push_properties()); + EXPECT_TRUE(root_->descendant_needs_push_properties()); + EXPECT_TRUE(child_->needs_push_properties()); + EXPECT_TRUE(child_->descendant_needs_push_properties()); + + grandchild2_->RemoveFromParent(); + + EXPECT_FALSE(root_->needs_push_properties()); + EXPECT_TRUE(root_->descendant_needs_push_properties()); + EXPECT_TRUE(child_->needs_push_properties()); + EXPECT_TRUE(child_->descendant_needs_push_properties()); + + grandchild3_->RemoveFromParent(); + + EXPECT_FALSE(root_->needs_push_properties()); + EXPECT_TRUE(root_->descendant_needs_push_properties()); + EXPECT_TRUE(child_->needs_push_properties()); + EXPECT_FALSE(child_->descendant_needs_push_properties()); + + EndTest(); + break; + } + } +}; + +MULTI_THREAD_TEST_F( + LayerTreeHostTestPushPropertiesSetPropertiesWhileOutsideTree); + +class LayerTreeHostTestPushPropertiesSetPropertyInParentThenChild + : public LayerTreeHostTestCasePushPropertiesThreeGrandChildren { + protected: + virtual void DidCommitAndDrawFrame() OVERRIDE { + int last_source_frame_number = layer_tree_host()->commit_number() - 1; + switch (last_source_frame_number) { + case 0: + layer_tree_host()->SetRootLayer(root_); + break; + case 1: + EXPECT_FALSE(root_->needs_push_properties()); + EXPECT_FALSE(root_->descendant_needs_push_properties()); + EXPECT_FALSE(child_->needs_push_properties()); + EXPECT_FALSE(child_->descendant_needs_push_properties()); + EXPECT_FALSE(grandchild1_->needs_push_properties()); + EXPECT_FALSE(grandchild1_->descendant_needs_push_properties()); + EXPECT_FALSE(grandchild2_->needs_push_properties()); + EXPECT_FALSE(grandchild2_->descendant_needs_push_properties()); + EXPECT_FALSE(grandchild3_->needs_push_properties()); + EXPECT_FALSE(grandchild3_->descendant_needs_push_properties()); + + child_->SetPosition(gfx::Point(1, 1)); + grandchild1_->SetPosition(gfx::Point(1, 1)); + grandchild2_->SetPosition(gfx::Point(1, 1)); + + EXPECT_FALSE(root_->needs_push_properties()); + EXPECT_TRUE(root_->descendant_needs_push_properties()); + EXPECT_TRUE(child_->needs_push_properties()); + EXPECT_TRUE(child_->descendant_needs_push_properties()); + EXPECT_TRUE(grandchild1_->needs_push_properties()); + EXPECT_FALSE(grandchild1_->descendant_needs_push_properties()); + EXPECT_TRUE(grandchild2_->needs_push_properties()); + EXPECT_FALSE(grandchild2_->descendant_needs_push_properties()); + EXPECT_FALSE(grandchild3_->needs_push_properties()); + EXPECT_FALSE(grandchild3_->descendant_needs_push_properties()); + + grandchild1_->RemoveFromParent(); + + EXPECT_FALSE(root_->needs_push_properties()); + EXPECT_TRUE(root_->descendant_needs_push_properties()); + EXPECT_TRUE(child_->needs_push_properties()); + EXPECT_TRUE(child_->descendant_needs_push_properties()); + + grandchild2_->RemoveFromParent(); + + EXPECT_FALSE(root_->needs_push_properties()); + EXPECT_TRUE(root_->descendant_needs_push_properties()); + EXPECT_TRUE(child_->needs_push_properties()); + EXPECT_FALSE(child_->descendant_needs_push_properties()); + + child_->RemoveFromParent(); + + EXPECT_FALSE(root_->needs_push_properties()); + EXPECT_FALSE(root_->descendant_needs_push_properties()); + + EndTest(); + break; + } + } +}; + +MULTI_THREAD_TEST_F( + LayerTreeHostTestPushPropertiesSetPropertyInParentThenChild); + +class LayerTreeHostTestPushPropertiesSetPropertyInChildThenParent + : public LayerTreeHostTestCasePushPropertiesThreeGrandChildren { + protected: + virtual void DidCommitAndDrawFrame() OVERRIDE { + int last_source_frame_number = layer_tree_host()->commit_number() - 1; + switch (last_source_frame_number) { + case 0: + layer_tree_host()->SetRootLayer(root_); + break; + case 1: + EXPECT_FALSE(root_->needs_push_properties()); + EXPECT_FALSE(root_->descendant_needs_push_properties()); + EXPECT_FALSE(child_->needs_push_properties()); + EXPECT_FALSE(child_->descendant_needs_push_properties()); + EXPECT_FALSE(grandchild1_->needs_push_properties()); + EXPECT_FALSE(grandchild1_->descendant_needs_push_properties()); + EXPECT_FALSE(grandchild2_->needs_push_properties()); + EXPECT_FALSE(grandchild2_->descendant_needs_push_properties()); + EXPECT_FALSE(grandchild3_->needs_push_properties()); + EXPECT_FALSE(grandchild3_->descendant_needs_push_properties()); + + grandchild1_->SetPosition(gfx::Point(1, 1)); + grandchild2_->SetPosition(gfx::Point(1, 1)); + child_->SetPosition(gfx::Point(1, 1)); + + EXPECT_FALSE(root_->needs_push_properties()); + EXPECT_TRUE(root_->descendant_needs_push_properties()); + EXPECT_TRUE(child_->needs_push_properties()); + EXPECT_TRUE(child_->descendant_needs_push_properties()); + EXPECT_TRUE(grandchild1_->needs_push_properties()); + EXPECT_FALSE(grandchild1_->descendant_needs_push_properties()); + EXPECT_TRUE(grandchild2_->needs_push_properties()); + EXPECT_FALSE(grandchild2_->descendant_needs_push_properties()); + EXPECT_FALSE(grandchild3_->needs_push_properties()); + EXPECT_FALSE(grandchild3_->descendant_needs_push_properties()); + + grandchild1_->RemoveFromParent(); + + EXPECT_FALSE(root_->needs_push_properties()); + EXPECT_TRUE(root_->descendant_needs_push_properties()); + EXPECT_TRUE(child_->needs_push_properties()); + EXPECT_TRUE(child_->descendant_needs_push_properties()); + + grandchild2_->RemoveFromParent(); + + EXPECT_FALSE(root_->needs_push_properties()); + EXPECT_TRUE(root_->descendant_needs_push_properties()); + EXPECT_TRUE(child_->needs_push_properties()); + EXPECT_FALSE(child_->descendant_needs_push_properties()); + + child_->RemoveFromParent(); + + EXPECT_FALSE(root_->needs_push_properties()); + EXPECT_FALSE(root_->descendant_needs_push_properties()); + + EndTest(); + break; + } + } +}; + +MULTI_THREAD_TEST_F( + LayerTreeHostTestPushPropertiesSetPropertyInChildThenParent); + } // namespace } // namespace cc diff --git a/cc/trees/tree_synchronizer.cc b/cc/trees/tree_synchronizer.cc index 9c4461d..f307257 100644 --- a/cc/trees/tree_synchronizer.cc +++ b/cc/trees/tree_synchronizer.cc @@ -183,33 +183,80 @@ void UpdateScrollbarLayerPointersRecursive(const RawPtrLayerImplMap* new_layers, new_layers, layer); } +// static +void TreeSynchronizer::SetNumDependentsNeedPushProperties( + Layer* layer, size_t num) { + layer->num_dependents_need_push_properties_ = num; +} + +// static +void TreeSynchronizer::SetNumDependentsNeedPushProperties( + LayerImpl* layer, size_t num) { +} + +// static template <typename LayerType> -void PushPropertiesInternal(LayerType* layer, LayerImpl* layer_impl) { +void TreeSynchronizer::PushPropertiesInternal( + LayerType* layer, + LayerImpl* layer_impl, + size_t* num_dependents_need_push_properties_for_parent) { if (!layer) { DCHECK(!layer_impl); return; } DCHECK_EQ(layer->id(), layer_impl->id()); - layer->PushPropertiesTo(layer_impl); - PushPropertiesInternal(layer->mask_layer(), layer_impl->mask_layer()); - PushPropertiesInternal(layer->replica_layer(), layer_impl->replica_layer()); - - const OwnedLayerImplList& impl_children = layer_impl->children(); - DCHECK_EQ(layer->children().size(), impl_children.size()); - - for (size_t i = 0; i < layer->children().size(); ++i) { - PushPropertiesInternal(layer->child_at(i), impl_children[i]); + bool push_layer = layer->needs_push_properties(); + bool recurse_on_children_and_dependents = + layer->descendant_needs_push_properties(); + + if (push_layer) + layer->PushPropertiesTo(layer_impl); + + size_t num_dependents_need_push_properties = 0; + if (recurse_on_children_and_dependents) { + PushPropertiesInternal(layer->mask_layer(), + layer_impl->mask_layer(), + &num_dependents_need_push_properties); + PushPropertiesInternal(layer->replica_layer(), + layer_impl->replica_layer(), + &num_dependents_need_push_properties); + + const OwnedLayerImplList& impl_children = layer_impl->children(); + DCHECK_EQ(layer->children().size(), impl_children.size()); + + for (size_t i = 0; i < layer->children().size(); ++i) { + PushPropertiesInternal(layer->child_at(i), + impl_children[i], + &num_dependents_need_push_properties); + } + + // When PushPropertiesTo completes for a layer, it may still keep + // its needs_push_properties() state if the layer must push itself + // every PushProperties tree walk. Here we keep track of those layers, and + // ensure that their ancestors know about them for the next PushProperties + // tree walk. + SetNumDependentsNeedPushProperties( + layer, num_dependents_need_push_properties); } + + bool add_self_to_parent = num_dependents_need_push_properties > 0 || + layer->needs_push_properties(); + *num_dependents_need_push_properties_for_parent += add_self_to_parent ? 1 : 0; } -void TreeSynchronizer::PushProperties(Layer* layer, LayerImpl* layer_impl) { - PushPropertiesInternal(layer, layer_impl); +void TreeSynchronizer::PushProperties(Layer* layer, + LayerImpl* layer_impl) { + size_t num_dependents_need_push_properties = 0; + PushPropertiesInternal( + layer, layer_impl, &num_dependents_need_push_properties); } void TreeSynchronizer::PushProperties(LayerImpl* layer, LayerImpl* layer_impl) { - PushPropertiesInternal(layer, layer_impl); + size_t num_dependents_need_push_properties = 0; + PushPropertiesInternal( + layer, layer_impl, &num_dependents_need_push_properties); } } // namespace cc diff --git a/cc/trees/tree_synchronizer.h b/cc/trees/tree_synchronizer.h index cfd77c6..40fa69d 100644 --- a/cc/trees/tree_synchronizer.h +++ b/cc/trees/tree_synchronizer.h @@ -32,12 +32,22 @@ class CC_EXPORT TreeSynchronizer { // Pushes properties from a Layer or LayerImpl tree to a structurally // equivalent LayerImpl tree. - static void PushProperties(Layer* layer_root, LayerImpl* layer_impl_root); + static void PushProperties(Layer* layer_root, + LayerImpl* layer_impl_root); static void PushProperties(LayerImpl* layer_root, LayerImpl* layer_impl_root); private: TreeSynchronizer(); // Not instantiable. + static void SetNumDependentsNeedPushProperties(Layer* layer, size_t num); + static void SetNumDependentsNeedPushProperties(LayerImpl* layer, size_t num); + + template <typename LayerType> + static void PushPropertiesInternal( + LayerType* layer, + LayerImpl* layer_impl, + size_t* num_dependents_need_push_properties_for_parent); + DISALLOW_COPY_AND_ASSIGN(TreeSynchronizer); }; diff --git a/cc/trees/tree_synchronizer_unittest.cc b/cc/trees/tree_synchronizer_unittest.cc index d70e4ef..f1b6d32 100644 --- a/cc/trees/tree_synchronizer_unittest.cc +++ b/cc/trees/tree_synchronizer_unittest.cc @@ -12,7 +12,7 @@ #include "cc/layers/layer_impl.h" #include "cc/test/animation_test_common.h" #include "cc/test/fake_impl_proxy.h" -#include "cc/test/fake_layer_tree_host_impl.h" +#include "cc/test/fake_layer_tree_host.h" #include "cc/trees/proxy.h" #include "cc/trees/single_thread_proxy.h" #include "testing/gtest/include/gtest/gtest.h" @@ -132,11 +132,10 @@ void ExpectTreesAreIdentical(Layer* layer, class TreeSynchronizerTest : public testing::Test { public: - TreeSynchronizerTest() : host_impl_(&proxy_) {} + TreeSynchronizerTest() : host_(FakeLayerTreeHost::Create()) {} protected: - FakeImplProxy proxy_; - FakeLayerTreeHostImpl host_impl_; + scoped_ptr<FakeLayerTreeHost> host_; }; // Attempts to synchronizes a null tree. This should not crash, and should @@ -145,7 +144,7 @@ TEST_F(TreeSynchronizerTest, SyncNullTree) { scoped_ptr<LayerImpl> layer_impl_tree_root = TreeSynchronizer::SynchronizeTrees(static_cast<Layer*>(NULL), scoped_ptr<LayerImpl>(), - host_impl_.active_tree()); + host_->active_tree()); EXPECT_TRUE(!layer_impl_tree_root.get()); } @@ -157,14 +156,16 @@ TEST_F(TreeSynchronizerTest, SyncSimpleTreeFromEmpty) { layer_tree_root->AddChild(Layer::Create()); layer_tree_root->AddChild(Layer::Create()); + host_->SetRootLayer(layer_tree_root); + scoped_ptr<LayerImpl> layer_impl_tree_root = TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(), scoped_ptr<LayerImpl>(), - host_impl_.active_tree()); + host_->active_tree()); ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root.get(), - host_impl_.active_tree()); + host_->active_tree()); } // Constructs a very simple tree and synchronizes it attempting to reuse some @@ -177,13 +178,15 @@ TEST_F(TreeSynchronizerTest, SyncSimpleTreeReusingLayers) { layer_tree_root->AddChild(MockLayer::Create(&layer_impl_destruction_list)); layer_tree_root->AddChild(MockLayer::Create(&layer_impl_destruction_list)); + host_->SetRootLayer(layer_tree_root); + scoped_ptr<LayerImpl> layer_impl_tree_root = TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(), scoped_ptr<LayerImpl>(), - host_impl_.active_tree()); + host_->active_tree()); ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root.get(), - host_impl_.active_tree()); + host_->active_tree()); // We have to push properties to pick up the destruction list pointer. TreeSynchronizer::PushProperties(layer_tree_root.get(), @@ -201,10 +204,10 @@ TEST_F(TreeSynchronizerTest, SyncSimpleTreeReusingLayers) { layer_impl_tree_root = TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(), layer_impl_tree_root.Pass(), - host_impl_.active_tree()); + host_->active_tree()); ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root.get(), - host_impl_.active_tree()); + host_->active_tree()); ASSERT_EQ(1u, layer_impl_destruction_list.size()); EXPECT_EQ(second_layer_impl_id, layer_impl_destruction_list[0]); @@ -222,13 +225,16 @@ TEST_F(TreeSynchronizerTest, SyncSimpleTreeAndTrackStackingOrderChange) { scoped_refptr<Layer> child2 = MockLayer::Create(&layer_impl_destruction_list); layer_tree_root->AddChild(MockLayer::Create(&layer_impl_destruction_list)); layer_tree_root->AddChild(child2); + + host_->SetRootLayer(layer_tree_root); + scoped_ptr<LayerImpl> layer_impl_tree_root = TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(), scoped_ptr<LayerImpl>(), - host_impl_.active_tree()); + host_->active_tree()); ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root.get(), - host_impl_.active_tree()); + host_->active_tree()); // We have to push properties to pick up the destruction list pointer. TreeSynchronizer::PushProperties(layer_tree_root.get(), @@ -242,10 +248,10 @@ TEST_F(TreeSynchronizerTest, SyncSimpleTreeAndTrackStackingOrderChange) { layer_impl_tree_root = TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(), layer_impl_tree_root.Pass(), - host_impl_.active_tree()); + host_->active_tree()); ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root.get(), - host_impl_.active_tree()); + host_->active_tree()); TreeSynchronizer::PushProperties(layer_tree_root.get(), layer_impl_tree_root.get()); @@ -261,6 +267,8 @@ TEST_F(TreeSynchronizerTest, SyncSimpleTreeAndProperties) { layer_tree_root->AddChild(Layer::Create()); layer_tree_root->AddChild(Layer::Create()); + host_->SetRootLayer(layer_tree_root); + // Pick some random properties to set. The values are not important, we're // just testing that at least some properties are making it through. gfx::PointF root_position = gfx::PointF(2.3f, 7.4f); @@ -276,10 +284,10 @@ TEST_F(TreeSynchronizerTest, SyncSimpleTreeAndProperties) { scoped_ptr<LayerImpl> layer_impl_tree_root = TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(), scoped_ptr<LayerImpl>(), - host_impl_.active_tree()); + host_->active_tree()); ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root.get(), - host_impl_.active_tree()); + host_->active_tree()); TreeSynchronizer::PushProperties(layer_tree_root.get(), layer_impl_tree_root.get()); @@ -322,13 +330,15 @@ TEST_F(TreeSynchronizerTest, ReuseLayerImplsAfterStructuralChange) { layer_b->AddChild(MockLayer::Create(&layer_impl_destruction_list)); scoped_refptr<Layer> layer_d = layer_b->children()[1].get(); + host_->SetRootLayer(layer_tree_root); + scoped_ptr<LayerImpl> layer_impl_tree_root = TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(), scoped_ptr<LayerImpl>(), - host_impl_.active_tree()); + host_->active_tree()); ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root.get(), - host_impl_.active_tree()); + host_->active_tree()); // We have to push properties to pick up the destruction list pointer. TreeSynchronizer::PushProperties(layer_tree_root.get(), @@ -353,10 +363,10 @@ TEST_F(TreeSynchronizerTest, ReuseLayerImplsAfterStructuralChange) { layer_impl_tree_root = TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(), layer_impl_tree_root.Pass(), - host_impl_.active_tree()); + host_->active_tree()); ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root.get(), - host_impl_.active_tree()); + host_->active_tree()); EXPECT_EQ(0u, layer_impl_destruction_list.size()); } @@ -373,6 +383,8 @@ TEST_F(TreeSynchronizerTest, SyncSimpleTreeThenDestroy) { old_layer_tree_root->AddChild( MockLayer::Create(&layer_impl_destruction_list)); + host_->SetRootLayer(old_layer_tree_root); + int old_tree_root_layer_id = old_layer_tree_root->id(); int old_tree_first_child_layer_id = old_layer_tree_root->children()[0]->id(); int old_tree_second_child_layer_id = old_layer_tree_root->children()[1]->id(); @@ -380,10 +392,10 @@ TEST_F(TreeSynchronizerTest, SyncSimpleTreeThenDestroy) { scoped_ptr<LayerImpl> layer_impl_tree_root = TreeSynchronizer::SynchronizeTrees(old_layer_tree_root.get(), scoped_ptr<LayerImpl>(), - host_impl_.active_tree()); + host_->active_tree()); ExpectTreesAreIdentical(old_layer_tree_root.get(), layer_impl_tree_root.get(), - host_impl_.active_tree()); + host_->active_tree()); // We have to push properties to pick up the destruction list pointer. TreeSynchronizer::PushProperties(old_layer_tree_root.get(), @@ -395,13 +407,14 @@ TEST_F(TreeSynchronizerTest, SyncSimpleTreeThenDestroy) { // Synchronize again. After the sync all LayerImpls from the old tree should // be deleted. scoped_refptr<Layer> new_layer_tree_root = Layer::Create(); + host_->SetRootLayer(new_layer_tree_root); layer_impl_tree_root = TreeSynchronizer::SynchronizeTrees(new_layer_tree_root.get(), layer_impl_tree_root.Pass(), - host_impl_.active_tree()); + host_->active_tree()); ExpectTreesAreIdentical(new_layer_tree_root.get(), layer_impl_tree_root.get(), - host_impl_.active_tree()); + host_->active_tree()); ASSERT_EQ(3u, layer_impl_destruction_list.size()); @@ -441,44 +454,46 @@ TEST_F(TreeSynchronizerTest, SyncMaskReplicaAndReplicaMaskLayers) { layer_tree_root->children()[2]-> SetReplicaLayer(replica_layer_with_mask.get()); + host_->SetRootLayer(layer_tree_root); + scoped_ptr<LayerImpl> layer_impl_tree_root = TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(), scoped_ptr<LayerImpl>(), - host_impl_.active_tree()); + host_->active_tree()); ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root.get(), - host_impl_.active_tree()); + host_->active_tree()); // Remove the mask layer. layer_tree_root->children()[0]->SetMaskLayer(NULL); layer_impl_tree_root = TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(), layer_impl_tree_root.Pass(), - host_impl_.active_tree()); + host_->active_tree()); ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root.get(), - host_impl_.active_tree()); + host_->active_tree()); // Remove the replica layer. layer_tree_root->children()[1]->SetReplicaLayer(NULL); layer_impl_tree_root = TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(), layer_impl_tree_root.Pass(), - host_impl_.active_tree()); + host_->active_tree()); ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root.get(), - host_impl_.active_tree()); + host_->active_tree()); // Remove the replica mask. replica_layer_with_mask->SetMaskLayer(NULL); layer_impl_tree_root = TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(), layer_impl_tree_root.Pass(), - host_impl_.active_tree()); + host_->active_tree()); ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root.get(), - host_impl_.active_tree()); + host_->active_tree()); } TEST_F(TreeSynchronizerTest, SynchronizeAnimations) { @@ -493,6 +508,7 @@ TEST_F(TreeSynchronizerTest, SynchronizeAnimations) { &stats_instrumentation); scoped_refptr<Layer> layer_tree_root = Layer::Create(); + host_->SetRootLayer(layer_tree_root); layer_tree_root->SetLayerAnimationControllerForTest( FakeLayerAnimationController::Create()); @@ -503,13 +519,13 @@ TEST_F(TreeSynchronizerTest, SynchronizeAnimations) { scoped_ptr<LayerImpl> layer_impl_tree_root = TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(), scoped_ptr<LayerImpl>(), - host_impl_.active_tree()); + host_->active_tree()); TreeSynchronizer::PushProperties(layer_tree_root.get(), layer_impl_tree_root.get()); layer_impl_tree_root = TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(), layer_impl_tree_root.Pass(), - host_impl_.active_tree()); + host_->active_tree()); EXPECT_TRUE(static_cast<FakeLayerAnimationController*>( layer_tree_root->layer_animation_controller())->SynchronizedAnimations()); |