diff options
author | jaydasika <jaydasika@chromium.org> | 2016-01-27 09:05:07 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-01-27 17:06:16 +0000 |
commit | 8665451221d678b75feeebbea51fd780148aa2cc (patch) | |
tree | d8bb9febcf7a2dd13d4a8075a54c1c9168947c4d /cc | |
parent | 477b16c4b0051e183d22d3705faeebcb2cc0cc42 (diff) | |
download | chromium_src-8665451221d678b75feeebbea51fd780148aa2cc.zip chromium_src-8665451221d678b75feeebbea51fd780148aa2cc.tar.gz chromium_src-8665451221d678b75feeebbea51fd780148aa2cc.tar.bz2 |
cc :: Reland compute if layer is drawn from property trees
This CL :
* deletes is_hidden
* computes if a layer is drawn using the effect tree
BUG=575413
CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel
patch from issue 1588093004 at patchset 250001 (http://crrev.com/1588093004#ps250001)
Review URL: https://codereview.chromium.org/1633203002
Cr-Commit-Position: refs/heads/master@{#371807}
Diffstat (limited to 'cc')
-rw-r--r-- | cc/layers/layer.cc | 8 | ||||
-rw-r--r-- | cc/layers/layer.h | 8 | ||||
-rw-r--r-- | cc/layers/layer_impl.cc | 23 | ||||
-rw-r--r-- | cc/layers/layer_impl.h | 10 | ||||
-rw-r--r-- | cc/proto/property_tree.proto | 10 | ||||
-rw-r--r-- | cc/trees/draw_property_utils.cc | 23 | ||||
-rw-r--r-- | cc/trees/layer_tree_host_common.cc | 60 | ||||
-rw-r--r-- | cc/trees/layer_tree_host_common_unittest.cc | 114 | ||||
-rw-r--r-- | cc/trees/occlusion_tracker.cc | 2 | ||||
-rw-r--r-- | cc/trees/property_tree.cc | 58 | ||||
-rw-r--r-- | cc/trees/property_tree.h | 7 | ||||
-rw-r--r-- | cc/trees/property_tree_builder.cc | 26 |
12 files changed, 238 insertions, 111 deletions
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc index 10a75d8..b3dca99 100644 --- a/cc/layers/layer.cc +++ b/cc/layers/layer.cc @@ -100,8 +100,7 @@ Layer::Layer(const LayerSettings& settings) replica_layer_(nullptr), client_(nullptr), num_unclipped_descendants_(0), - frame_timing_requests_dirty_(false), - is_hidden_from_property_trees_(false) { + frame_timing_requests_dirty_(false) { if (!settings.use_compositor_animation_timelines) { layer_animation_controller_ = LayerAnimationController::Create(layer_id_); layer_animation_controller_->AddValueObserver(this); @@ -539,6 +538,10 @@ void Layer::SetOpacity(float opacity) { SetNeedsCommit(); } +float Layer::EffectiveOpacity() const { + return hide_layer_and_subtree_ ? 0.f : opacity_; +} + bool Layer::OpacityIsAnimating() const { DCHECK(layer_tree_host_); return layer_animation_controller_ @@ -1241,7 +1244,6 @@ void Layer::PushPropertiesTo(LayerImpl* layer) { layer->set_user_scrollable_vertical(user_scrollable_vertical_); layer->SetElementId(element_id_); layer->SetMutableProperties(mutable_properties_); - layer->set_is_hidden_from_property_trees(is_hidden_from_property_trees_); LayerImpl* scroll_parent = nullptr; if (scroll_parent_) { diff --git a/cc/layers/layer.h b/cc/layers/layer.h index e009169..1ddb5e8 100644 --- a/cc/layers/layer.h +++ b/cc/layers/layer.h @@ -141,6 +141,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, void SetOpacity(float opacity); float opacity() const { return opacity_; } + float EffectiveOpacity() const; bool OpacityIsAnimating() const; bool HasPotentiallyRunningOpacityAnimation() const; virtual bool OpacityCanAnimateOnImplThread() const; @@ -560,12 +561,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, bool layer_or_descendant_is_drawn(); void set_sorted_for_recursion(bool sorted_for_recursion); bool sorted_for_recursion(); - void set_is_hidden_from_property_trees(bool is_hidden) { - if (is_hidden == is_hidden_from_property_trees_) - return; - is_hidden_from_property_trees_ = is_hidden; - SetNeedsPushProperties(); - } // LayerAnimationValueProvider implementation. gfx::ScrollOffset ScrollOffsetForAnimation() const override; @@ -792,7 +787,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, std::vector<FrameTimingRequest> frame_timing_requests_; bool frame_timing_requests_dirty_; - bool is_hidden_from_property_trees_; DISALLOW_COPY_AND_ASSIGN(Layer); }; diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc index 57b62f8..f585bde 100644 --- a/cc/layers/layer_impl.cc +++ b/cc/layers/layer_impl.cc @@ -100,8 +100,7 @@ LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, visited_(false), layer_or_descendant_is_drawn_(false), layer_or_descendant_has_input_handler_(false), - sorted_for_recursion_(false), - is_hidden_from_property_trees_(false) { + sorted_for_recursion_(false) { DCHECK_GT(layer_id_, 0); DCHECK(layer_tree_impl_); layer_tree_impl_->RegisterLayer(this); @@ -659,7 +658,6 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) { layer->SetClipTreeIndex(clip_tree_index_); layer->SetEffectTreeIndex(effect_tree_index_); layer->set_offset_to_transform_parent(offset_to_transform_parent_); - layer->set_is_hidden_from_property_trees(is_hidden_from_property_trees_); LayerImpl* scroll_parent = nullptr; if (scroll_parent_) { @@ -962,7 +960,7 @@ void LayerImpl::UpdatePropertyTreeOpacity() { // started, but might have finished since then on the compositor thread. if (node->owner_id != id()) return; - node->data.opacity = opacity_; + node->data.opacity = EffectiveOpacity(); effect_tree.set_needs_update(true); } } @@ -991,7 +989,10 @@ void LayerImpl::OnFilterAnimated(const FilterOperations& filters) { void LayerImpl::OnOpacityAnimated(float opacity) { SetOpacity(opacity); - UpdatePropertyTreeOpacity(); + // When hide_layer_and_subtree is true, the effective opacity is zero and we + // need not update the opacity on property trees. + if (!hide_layer_and_subtree_) + UpdatePropertyTreeOpacity(); } void LayerImpl::OnTransformAnimated(const gfx::Transform& transform) { @@ -1248,6 +1249,10 @@ void LayerImpl::SetOpacity(float opacity) { NoteLayerPropertyChangedForSubtree(); } +float LayerImpl::EffectiveOpacity() const { + return hide_layer_and_subtree_ ? 0.f : opacity_; +} + bool LayerImpl::OpacityIsAnimating() const { LayerAnimationController::ObserverType observer_type = IsActive() ? LayerAnimationController::ObserverType::ACTIVE @@ -1923,11 +1928,13 @@ gfx::Rect LayerImpl::GetScaledEnclosingRectInTargetSpace(float scale) const { gfx::Rect(scaled_bounds)); } -bool LayerImpl::LayerIsHidden() const { +bool LayerImpl::IsHidden() const { if (layer_tree_impl()->settings().use_property_trees) { - return is_hidden_from_property_trees_; + EffectTree& effect_tree = layer_tree_impl_->property_trees()->effect_tree; + EffectNode* node = effect_tree.Node(effect_tree_index_); + return node->data.screen_space_opacity == 0.f; } else { - return hide_layer_and_subtree_ || (parent() && parent()->LayerIsHidden()); + return EffectiveOpacity() == 0.f || (parent() && parent()->IsHidden()); } } diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h index 12ee4c0..e3d0c87 100644 --- a/cc/layers/layer_impl.h +++ b/cc/layers/layer_impl.h @@ -321,6 +321,7 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, void SetOpacity(float opacity); float opacity() const { return opacity_; } + float EffectiveOpacity() const; bool OpacityIsAnimating() const; bool HasPotentiallyRunningOpacityAnimation() const; bool OpacityIsAnimatingOnImplOnly() const; @@ -685,13 +686,7 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, void UpdatePropertyTreeForScrollingAndAnimationIfNeeded(); - void set_is_hidden_from_property_trees(bool is_hidden) { - if (is_hidden == is_hidden_from_property_trees_) - return; - is_hidden_from_property_trees_ = is_hidden; - SetNeedsPushProperties(); - } - bool LayerIsHidden() const; + bool IsHidden() const; float GetIdealContentsScale() const; @@ -895,7 +890,6 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, // If true, the layer or one of its descendants has a wheel or touch handler. bool layer_or_descendant_has_input_handler_; bool sorted_for_recursion_; - bool is_hidden_from_property_trees_; DISALLOW_COPY_AND_ASSIGN(LayerImpl); }; diff --git a/cc/proto/property_tree.proto b/cc/proto/property_tree.proto index 50cfb45..d35f264 100644 --- a/cc/proto/property_tree.proto +++ b/cc/proto/property_tree.proto @@ -81,9 +81,13 @@ message EffectNodeData { optional float opacity = 1; optional float screen_space_opacity = 2; optional bool has_render_surface = 3; - optional int64 num_copy_requests_in_subtree = 4; - optional int64 transform_id = 5; - optional int64 clip_id = 6; + optional bool has_copy_request = 4; + optional bool has_background_filters = 5; + optional bool is_drawn = 6; + optional bool screen_space_opacity_is_animating = 7; + optional int64 num_copy_requests_in_subtree = 8; + optional int64 transform_id = 9; + optional int64 clip_id = 10; } message ScrollNodeData { diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc index fa52236..6899816 100644 --- a/cc/trees/draw_property_utils.cc +++ b/cc/trees/draw_property_utils.cc @@ -344,7 +344,7 @@ static inline bool SubtreeShouldBeSkipped(LayerImpl* layer, // The opacity of a layer always applies to its children (either implicitly // via a render surface or explicitly if the parent preserves 3D), so the // entire subtree can be skipped if this layer is fully transparent. - return !layer->opacity(); + return !layer->EffectiveOpacity(); } static inline bool SubtreeShouldBeSkipped(Layer* layer, @@ -380,7 +380,8 @@ static inline bool SubtreeShouldBeSkipped(Layer* layer, // In particular, it should not cause the subtree to be skipped. // Similarly, for layers that might animate opacity using an impl-only // animation, their subtree should also not be skipped. - return !layer->opacity() && !layer->HasPotentiallyRunningOpacityAnimation() && + return !layer->EffectiveOpacity() && + !layer->HasPotentiallyRunningOpacityAnimation() && !layer->OpacityCanAnimateOnImplThread(); } @@ -430,18 +431,19 @@ static bool LayerShouldBeSkipped(LayerType* layer, template <typename LayerType> void FindLayersThatNeedUpdates( LayerType* layer, - const TransformTree& tree, - bool subtree_is_visible_from_ancestor, + const TransformTree& transform_tree, + const EffectTree& effect_tree, typename LayerType::LayerListType* update_layer_list, std::vector<LayerType*>* visible_layer_list) { + DCHECK_GE(layer->effect_tree_index(), 0); bool layer_is_drawn = - layer->HasCopyRequest() || - (subtree_is_visible_from_ancestor && !layer->hide_layer_and_subtree()); + effect_tree.Node(layer->effect_tree_index())->data.is_drawn; - if (layer->parent() && SubtreeShouldBeSkipped(layer, layer_is_drawn, tree)) + if (layer->parent() && + SubtreeShouldBeSkipped(layer, layer_is_drawn, transform_tree)) return; - if (!LayerShouldBeSkipped(layer, layer_is_drawn, tree)) { + if (!LayerShouldBeSkipped(layer, layer_is_drawn, transform_tree)) { visible_layer_list->push_back(layer); update_layer_list->push_back(layer); } @@ -457,7 +459,7 @@ void FindLayersThatNeedUpdates( } for (size_t i = 0; i < layer->children().size(); ++i) { - FindLayersThatNeedUpdates(layer->child_at(i), tree, layer_is_drawn, + FindLayersThatNeedUpdates(layer->child_at(i), transform_tree, effect_tree, update_layer_list, visible_layer_list); } } @@ -679,9 +681,8 @@ static void ComputeVisibleRectsUsingPropertyTreesInternal( can_render_to_separate_surface); ComputeEffects(&property_trees->effect_tree); - const bool subtree_is_visible_from_ancestor = true; FindLayersThatNeedUpdates(root_layer, property_trees->transform_tree, - subtree_is_visible_from_ancestor, update_layer_list, + property_trees->effect_tree, update_layer_list, visible_layer_list); CalculateVisibleRects<LayerType>( *visible_layer_list, property_trees->clip_tree, diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc index 76c91a0..1414918 100644 --- a/cc/trees/layer_tree_host_common.cc +++ b/cc/trees/layer_tree_host_common.cc @@ -668,7 +668,7 @@ static inline bool SubtreeShouldBeSkipped(LayerImpl* layer, // The opacity of a layer always applies to its children (either implicitly // via a render surface or explicitly if the parent preserves 3D), so the // entire subtree can be skipped if this layer is fully transparent. - return !layer->opacity(); + return !layer->EffectiveOpacity(); } static inline void SavePaintPropertiesLayer(LayerImpl* layer) {} @@ -1515,7 +1515,7 @@ static void CalculateDrawPropertiesInternal( // the right results. const bool layer_is_visible = data_from_ancestor.subtree_is_visible_from_ancestor && - !layer->hide_layer_and_subtree(); + layer->EffectiveOpacity() != 0; const bool layer_is_drawn = layer_is_visible || layer->HasCopyRequest(); // The root layer cannot skip CalcDrawProperties. @@ -2327,11 +2327,21 @@ enum PropertyTreeOption { }; void CalculateRenderTargetInternal(LayerImpl* layer, + PropertyTrees* property_trees, bool subtree_visible_from_ancestor, - bool can_render_to_separate_surface) { - const bool layer_is_visible = - subtree_visible_from_ancestor && !layer->hide_layer_and_subtree(); - const bool layer_is_drawn = layer_is_visible || layer->HasCopyRequest(); + bool can_render_to_separate_surface, + bool use_property_trees) { + bool layer_is_drawn; + if (use_property_trees) { + DCHECK_GE(layer->effect_tree_index(), 0); + layer_is_drawn = + property_trees->effect_tree.Node(layer->effect_tree_index()) + ->data.is_drawn; + } else { + layer_is_drawn = + (subtree_visible_from_ancestor && layer->EffectiveOpacity() != 0) || + layer->HasCopyRequest(); + } // The root layer cannot be skipped. if (!IsRootLayer(layer) && SubtreeShouldBeSkipped(layer, layer_is_drawn)) { @@ -2364,7 +2374,8 @@ void CalculateRenderTargetInternal(LayerImpl* layer, for (size_t i = 0; i < layer->children().size(); ++i) { CalculateRenderTargetInternal( LayerTreeHostCommon::get_layer_as_raw_ptr(layer->children(), i), - layer_is_drawn, can_render_to_separate_surface); + property_trees, layer_is_drawn, can_render_to_separate_surface, + use_property_trees); } } @@ -2395,14 +2406,17 @@ void CalculateRenderSurfaceLayerListInternal( // |can_render_to_separate_surface| and |current_render_surface_layer_list_id| // are settings that should stay the same during recursion. - - // Layers that are marked as hidden will hide themselves and their subtree. - // Exception: Layers with copy requests, whether hidden or not, must be drawn - // anyway. In this case, we will inform their subtree they are visible to get - // the right results. - const bool layer_is_visible = - subtree_visible_from_ancestor && !layer->hide_layer_and_subtree(); - const bool layer_is_drawn = layer_is_visible || layer->HasCopyRequest(); + bool layer_is_drawn = false; + if (use_property_trees) { + DCHECK_GE(layer->effect_tree_index(), 0); + layer_is_drawn = + property_trees->effect_tree.Node(layer->effect_tree_index()) + ->data.is_drawn; + } else { + layer_is_drawn = + (subtree_visible_from_ancestor && layer->EffectiveOpacity() != 0) || + layer->HasCopyRequest(); + } // The root layer cannot be skipped. if (!IsRootLayer(layer) && SubtreeShouldBeSkipped(layer, layer_is_drawn)) { @@ -2451,10 +2465,14 @@ void CalculateRenderSurfaceLayerListInternal( // target. layer->render_surface()->set_contributes_to_drawn_surface(false); } else { - // Even if the |layer_is_drawn|, it only contributes to a drawn surface - // when the |layer_is_visible|. + bool contributes_to_drawn_surface = + use_property_trees + ? property_trees->effect_tree.ContributesToDrawnSurface( + layer->effect_tree_index()) + : subtree_visible_from_ancestor && + layer->EffectiveOpacity() != 0.f; layer->render_surface()->set_contributes_to_drawn_surface( - layer_is_visible); + contributes_to_drawn_surface); } // Ignore occlusion from outside the surface when surface contents need to @@ -2619,8 +2637,10 @@ void CalculateRenderSurfaceLayerListInternal( void CalculateRenderTarget( LayerTreeHostCommon::CalcDrawPropsImplInputs* inputs) { - CalculateRenderTargetInternal(inputs->root_layer, true, - inputs->can_render_to_separate_surface); + CalculateRenderTargetInternal( + inputs->root_layer, inputs->property_trees, true, + inputs->can_render_to_separate_surface, + inputs->verify_property_trees || inputs->use_property_trees); } void CalculateRenderSurfaceLayerList( diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc index f4e5b60..3a426ec 100644 --- a/cc/trees/layer_tree_host_common_unittest.cc +++ b/cc/trees/layer_tree_host_common_unittest.cc @@ -150,7 +150,10 @@ TEST_F(LayerTreeHostCommonTest, TransformsForNoOpLayer) { grand_child->screen_space_transform()); } -TEST_F(LayerTreeHostCommonTest, DoNotSkipLayersWithHandlers) { +TEST_F(LayerTreeHostCommonTest, + ScreenSpaceTransformOfSkippedLayersWithHandlers) { + // Even for layers that are skipped, we need to compute the correct screen + // space transform because it is used during hit testing. LayerImpl* parent = root_layer(); LayerImpl* child = AddChild<LayerImpl>(parent); LayerImpl* grand_child = AddChild<LayerImpl>(child); @@ -163,9 +166,7 @@ TEST_F(LayerTreeHostCommonTest, DoNotSkipLayersWithHandlers) { SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), gfx::PointF(10, 10), gfx::Size(100, 100), true, false); - // This would have previously caused us to skip our subtree, but this would be - // wrong; we need up-to-date draw properties to do hit testing on the layers - // with handlers. + // This will cause the subtree to be skipped. child->SetOpacity(0.f); SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), gfx::PointF(10, 10), gfx::Size(100, 100), true, @@ -178,10 +179,8 @@ TEST_F(LayerTreeHostCommonTest, DoNotSkipLayersWithHandlers) { EXPECT_FALSE(grand_child->has_render_surface()); // Check that we've computed draw properties for the subtree rooted at // |child|. - EXPECT_TRUE(child->draw_properties().target_space_transform.IsIdentity()); - EXPECT_FALSE(child->render_surface()->draw_transform().IsIdentity()); - EXPECT_FALSE( - grand_child->draw_properties().target_space_transform.IsIdentity()); + EXPECT_FALSE(child->render_surface()->screen_space_transform().IsIdentity()); + EXPECT_FALSE(grand_child->ScreenSpaceTransform().IsIdentity()); } TEST_F(LayerTreeHostCommonTest, EffectTreeTransformIdTest) { @@ -1341,6 +1340,8 @@ TEST_F(LayerTreeHostCommonTest, gfx::PointF(), gfx::Size(10, 10), true, false, false); render_surface1->SetOpacity(0.f); + render_surface1->SetDrawsContent(true); + child->SetDrawsContent(true); FilterOperations filters; filters.Append(FilterOperation::CreateBlurFilter(1.5f)); render_surface1->SetBackgroundFilters(filters); @@ -5184,6 +5185,23 @@ TEST_F(LayerTreeHostCommonTest, OpacityAnimatingOnPendingTree) { // layer should be included even though it is transparent. ASSERT_EQ(1u, render_surface_layer_list.size()); ASSERT_EQ(2u, root->render_surface()->layer_list().size()); + + // If the root itself is hidden, the child should not be drawn even if it has + // an animating opacity. + root->SetOpacity(0.f); + root->layer_tree_impl()->property_trees()->needs_rebuild = true; + LayerImplList render_surface_layer_list2; + root->layer_tree_impl()->IncrementRenderSurfaceListIdForTesting(); + LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs2( + root.get(), root->bounds(), &render_surface_layer_list2, + root->layer_tree_impl()->current_render_surface_list_id()); + inputs2.can_adjust_raster_scales = true; + LayerTreeHostCommon::CalculateDrawProperties(&inputs2); + + LayerImpl* child_ptr = root->layer_tree_impl()->LayerById(2); + EffectTree tree = root->layer_tree_impl()->property_trees()->effect_tree; + EffectNode* node = tree.Node(child_ptr->effect_tree_index()); + EXPECT_FALSE(node->data.is_drawn); } class LayerTreeSettingsForLCDTextTest : public LayerTreeSettings { @@ -5582,8 +5600,16 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHiddenWithCopyRequest) { copy_child->SetDrawsContent(true); LayerImpl* copy_child_layer = copy_child.get(); - scoped_ptr<LayerImpl> copy_grand_parent_sibling_before = + scoped_ptr<LayerImpl> copy_grand_child = LayerImpl::Create(host_impl.pending_tree(), 6); + SetLayerPropertiesForTesting(copy_grand_child.get(), identity_matrix, + gfx::Point3F(), gfx::PointF(), gfx::Size(20, 20), + true, false, false); + copy_child->SetDrawsContent(true); + LayerImpl* copy_grand_child_layer = copy_grand_child.get(); + + scoped_ptr<LayerImpl> copy_grand_parent_sibling_before = + LayerImpl::Create(host_impl.pending_tree(), 7); SetLayerPropertiesForTesting(copy_grand_parent_sibling_before.get(), identity_matrix, gfx::Point3F(), gfx::PointF(), gfx::Size(40, 40), true, false, false); @@ -5592,7 +5618,7 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHiddenWithCopyRequest) { copy_grand_parent_sibling_before.get(); scoped_ptr<LayerImpl> copy_grand_parent_sibling_after = - LayerImpl::Create(host_impl.pending_tree(), 7); + LayerImpl::Create(host_impl.pending_tree(), 8); SetLayerPropertiesForTesting(copy_grand_parent_sibling_after.get(), identity_matrix, gfx::Point3F(), gfx::PointF(), gfx::Size(40, 40), true, false, false); @@ -5600,6 +5626,7 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHiddenWithCopyRequest) { LayerImpl* copy_grand_parent_sibling_after_layer = copy_grand_parent_sibling_after.get(); + copy_child->AddChild(std::move(copy_grand_child)); copy_request->AddChild(std::move(copy_child)); copy_parent->AddChild(std::move(copy_request)); copy_grand_parent->AddChild(std::move(copy_parent)); @@ -5608,10 +5635,12 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHiddenWithCopyRequest) { root->AddChild(std::move(copy_grand_parent_sibling_after)); // Hide the copy_grand_parent and its subtree. But make a copy request in that - // hidden subtree on copy_layer. + // hidden subtree on copy_layer. Also hide the copy grand child and its + // subtree. copy_grand_parent_layer->SetHideLayerAndSubtree(true); copy_grand_parent_sibling_before_layer->SetHideLayerAndSubtree(true); copy_grand_parent_sibling_after_layer->SetHideLayerAndSubtree(true); + copy_grand_child_layer->SetHideLayerAndSubtree(true); std::vector<scoped_ptr<CopyOutputRequest>> copy_requests; copy_requests.push_back( @@ -5632,27 +5661,27 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHiddenWithCopyRequest) { EXPECT_GT(copy_parent_layer->num_copy_requests_in_target_subtree(), 0); EXPECT_GT(copy_layer->num_copy_requests_in_target_subtree(), 0); - // We should have three render surfaces, one for the root, one for the parent + // We should have four render surfaces, one for the root, one for the grand + // parent since it has opacity and two drawing descendants, one for the parent // since it owns a surface, and one for the copy_layer. - ASSERT_EQ(3u, render_surface_layer_list.size()); + ASSERT_EQ(4u, render_surface_layer_list.size()); EXPECT_EQ(root->id(), render_surface_layer_list.at(0)->id()); - EXPECT_EQ(copy_parent_layer->id(), render_surface_layer_list.at(1)->id()); - EXPECT_EQ(copy_layer->id(), render_surface_layer_list.at(2)->id()); + EXPECT_EQ(copy_grand_parent_layer->id(), + render_surface_layer_list.at(1)->id()); + EXPECT_EQ(copy_parent_layer->id(), render_surface_layer_list.at(2)->id()); + EXPECT_EQ(copy_layer->id(), render_surface_layer_list.at(3)->id()); - // The root render surface should have 2 contributing layers. The - // copy_grand_parent is hidden along with its siblings, but the copy_parent - // will appear since something in its subtree needs to be drawn for a copy - // request. + // The root render surface should have 2 contributing layers. ASSERT_EQ(2u, root->render_surface()->layer_list().size()); EXPECT_EQ(root->id(), root->render_surface()->layer_list().at(0)->id()); - EXPECT_EQ(copy_parent_layer->id(), + EXPECT_EQ(copy_grand_parent_layer->id(), root->render_surface()->layer_list().at(1)->id()); // Nothing actually draws into the copy parent, so only the copy_layer will // appear in its list, since it needs to be drawn for the copy request. ASSERT_EQ(1u, copy_parent_layer->render_surface()->layer_list().size()); EXPECT_EQ(copy_layer->id(), - copy_parent_layer->render_surface()->layer_list().at(0)->id()); + copy_layer->render_surface()->layer_list().at(0)->id()); // The copy_layer's render surface should have two contributing layers. ASSERT_EQ(2u, copy_layer->render_surface()->layer_list().size()); @@ -5660,6 +5689,26 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHiddenWithCopyRequest) { copy_layer->render_surface()->layer_list().at(0)->id()); EXPECT_EQ(copy_child_layer->id(), copy_layer->render_surface()->layer_list().at(1)->id()); + + // copy_grand_parent, copy_parent shouldn't be drawn because they are hidden, + // but the copy_layer and copy_child should be drawn for the copy request. + // copy grand child should not be drawn as its hidden even in the copy + // request. + EffectTree tree = root->layer_tree_impl()->property_trees()->effect_tree; + EffectNode* node = tree.Node(copy_grand_parent_layer->effect_tree_index()); + EXPECT_FALSE(node->data.is_drawn); + node = tree.Node(copy_parent_layer->effect_tree_index()); + EXPECT_FALSE(node->data.is_drawn); + node = tree.Node(copy_layer->effect_tree_index()); + EXPECT_TRUE(node->data.is_drawn); + node = tree.Node(copy_child_layer->effect_tree_index()); + EXPECT_TRUE(node->data.is_drawn); + node = tree.Node(copy_grand_child_layer->effect_tree_index()); + EXPECT_FALSE(node->data.is_drawn); + + // Though copy_layer is drawn, it shouldn't contribute to drawn surface as its + // actually hidden. + EXPECT_FALSE(copy_layer->render_surface()->contributes_to_drawn_surface()); } TEST_F(LayerTreeHostCommonTest, ClippedOutCopyRequest) { @@ -8840,11 +8889,11 @@ TEST_F(LayerTreeHostCommonTest, SkippingSubtreeMain) { // Now, even though child has zero opacity, we will configure |grandchild| and // |greatgrandchild| in several ways that should force the subtree to be // processed anyhow. - greatgrandchild->RequestCopyOfOutput( + grandchild->RequestCopyOfOutput( CopyOutputRequest::CreateBitmapRequest(base::Bind(&CopyOutputCallback))); ExecuteCalculateDrawPropertiesWithPropertyTrees(root.get()); EXPECT_EQ(gfx::Rect(10, 10), grandchild->visible_rect_from_property_trees()); - grandchild->set_visible_rect_from_property_trees(gfx::Rect()); + greatgrandchild->set_visible_rect_from_property_trees(gfx::Rect()); // Add an opacity animation with a start delay. animation_id = 1; @@ -8892,15 +8941,10 @@ TEST_F(LayerTreeHostCommonTest, SkippingSubtreeImpl) { SetLayerPropertiesForTesting(grandchild.get(), identity, gfx::Point3F(), gfx::PointF(), gfx::Size(10, 10), true, false, false); - SetLayerPropertiesForTesting(greatgrandchild.get(), identity, gfx::Point3F(), - gfx::PointF(), gfx::Size(10, 10), true, false, - true); LayerImpl* child_ptr = child.get(); LayerImpl* grandchild_ptr = grandchild.get(); - LayerImpl* greatgrandchild_ptr = greatgrandchild.get(); - grandchild->AddChild(std::move(greatgrandchild)); child->AddChild(std::move(grandchild)); root->AddChild(std::move(child)); @@ -8940,7 +8984,7 @@ TEST_F(LayerTreeHostCommonTest, SkippingSubtreeImpl) { std::vector<scoped_ptr<CopyOutputRequest>> requests; requests.push_back(CopyOutputRequest::CreateEmptyRequest()); - greatgrandchild_ptr->PassCopyRequests(&requests); + grandchild_ptr->PassCopyRequests(&requests); root.get()->layer_tree_impl()->property_trees()->needs_rebuild = true; ExecuteCalculateDrawPropertiesWithPropertyTrees(root.get()); EXPECT_EQ(gfx::Rect(10, 10), @@ -9532,7 +9576,9 @@ TEST_F(LayerTreeHostCommonTest, LayerWithInputHandlerAndZeroOpacity) { SetLayerPropertiesForTesting(render_surface, identity_matrix, gfx::Point3F(), gfx::PointF(), gfx::Size(30, 30), true, false, true); - SetLayerPropertiesForTesting(test_layer, identity_matrix, gfx::Point3F(), + gfx::Transform translation; + translation.Translate(10, 10); + SetLayerPropertiesForTesting(test_layer, translation, gfx::Point3F(), gfx::PointF(), gfx::Size(20, 20), true, false, false); @@ -9542,9 +9588,7 @@ TEST_F(LayerTreeHostCommonTest, LayerWithInputHandlerAndZeroOpacity) { test_layer->SetHaveWheelEventHandlers(true); ExecuteCalculateDrawProperties(root); - EXPECT_EQ(gfx::Rect(20, 20), test_layer->drawable_content_rect()); - EXPECT_EQ(gfx::RectF(20, 20), - render_surface->render_surface()->DrawableContentRect()); + EXPECT_EQ(translation, test_layer->ScreenSpaceTransform()); } TEST_F(LayerTreeHostCommonTest, ClipChildVisibleRect) { @@ -9627,12 +9671,12 @@ TEST_F(LayerTreeHostCommonTest, SubtreeIsHiddenTest) { hidden->SetHideLayerAndSubtree(true); ExecuteCalculateDrawProperties(root); - EXPECT_TRUE(test->LayerIsHidden()); + EXPECT_TRUE(test->IsHidden()); hidden->SetHideLayerAndSubtree(false); root->layer_tree_impl()->property_trees()->needs_rebuild = true; ExecuteCalculateDrawProperties(root); - EXPECT_FALSE(test->LayerIsHidden()); + EXPECT_FALSE(test->IsHidden()); } TEST_F(LayerTreeHostCommonTest, TwoUnclippedRenderSurfaces) { diff --git a/cc/trees/occlusion_tracker.cc b/cc/trees/occlusion_tracker.cc index 250ac4d..4bcb762 100644 --- a/cc/trees/occlusion_tracker.cc +++ b/cc/trees/occlusion_tracker.cc @@ -174,7 +174,7 @@ void OcclusionTracker::FinishedRenderTarget(const LayerImpl* finished_target) { // Readbacks always happen on render targets so we only need to check // for readbacks here. bool target_is_only_for_copy_request = - finished_target->HasCopyRequest() && finished_target->LayerIsHidden(); + finished_target->HasCopyRequest() && finished_target->IsHidden(); // If the occlusion within the surface can not be applied to things outside of // the surface's subtree, then clear the occlusion here so it won't be used. diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc index 64209e9..aae88ae 100644 --- a/cc/trees/property_tree.cc +++ b/cc/trees/property_tree.cc @@ -415,6 +415,10 @@ EffectNodeData::EffectNodeData() : opacity(1.f), screen_space_opacity(1.f), has_render_surface(false), + has_copy_request(false), + has_background_filters(false), + is_drawn(true), + screen_space_opacity_is_animating(false), num_copy_requests_in_subtree(0), transform_id(0), clip_id(0) {} @@ -423,6 +427,11 @@ bool EffectNodeData::operator==(const EffectNodeData& other) const { return opacity == other.opacity && screen_space_opacity == other.screen_space_opacity && has_render_surface == other.has_render_surface && + has_copy_request == other.has_copy_request && + has_background_filters == other.has_background_filters && + is_drawn == other.is_drawn && + screen_space_opacity_is_animating == + other.screen_space_opacity_is_animating && num_copy_requests_in_subtree == other.num_copy_requests_in_subtree && transform_id == other.transform_id && clip_id == other.clip_id; } @@ -433,6 +442,11 @@ void EffectNodeData::ToProtobuf(proto::TreeNode* proto) const { data->set_opacity(opacity); data->set_screen_space_opacity(screen_space_opacity); data->set_has_render_surface(has_render_surface); + data->set_has_copy_request(has_copy_request); + data->set_has_background_filters(has_background_filters); + data->set_is_drawn(is_drawn); + data->set_screen_space_opacity_is_animating( + screen_space_opacity_is_animating); data->set_num_copy_requests_in_subtree(num_copy_requests_in_subtree); data->set_transform_id(transform_id); data->set_clip_id(clip_id); @@ -445,6 +459,10 @@ void EffectNodeData::FromProtobuf(const proto::TreeNode& proto) { opacity = data.opacity(); screen_space_opacity = data.screen_space_opacity(); has_render_surface = data.has_render_surface(); + has_copy_request = data.has_copy_request(); + has_background_filters = data.has_background_filters(); + is_drawn = data.is_drawn(); + screen_space_opacity_is_animating = data.screen_space_opacity_is_animating(); num_copy_requests_in_subtree = data.num_copy_requests_in_subtree(); transform_id = data.transform_id(); clip_id = data.clip_id(); @@ -1075,16 +1093,54 @@ void EffectTree::UpdateOpacities(EffectNode* node, EffectNode* parent_node) { node->data.screen_space_opacity *= parent_node->data.screen_space_opacity; } +void EffectTree::UpdateIsDrawn(EffectNode* node, EffectNode* parent_node) { + // Nodes that have screen space opacity 0 are hidden. So they are not drawn. + // Exceptions: + // 1) Nodes that contribute to copy requests, whether hidden or not, must be + // drawn. + // 2) Nodes that have a background filter. + // 3) Nodes with animating screen space opacity are drawn if their parent is + // drawn irrespective of their opacity. + if (node->data.has_copy_request || node->data.has_background_filters) + node->data.is_drawn = true; + else if (node->data.screen_space_opacity_is_animating) + node->data.is_drawn = parent_node ? parent_node->data.is_drawn : true; + else if (node->data.opacity == 0.f) + node->data.is_drawn = false; + else if (parent_node) + node->data.is_drawn = parent_node->data.is_drawn; + else + node->data.is_drawn = true; +} + void EffectTree::UpdateEffects(int id) { EffectNode* node = Node(id); EffectNode* parent_node = parent(node); UpdateOpacities(node, parent_node); + UpdateIsDrawn(node, parent_node); } void EffectTree::ClearCopyRequests() { - for (auto& node : nodes()) + for (auto& node : nodes()) { node.data.num_copy_requests_in_subtree = 0; + node.data.has_copy_request = false; + } + set_needs_update(true); +} + +bool EffectTree::ContributesToDrawnSurface(int id) { + // All drawn nodes contribute to drawn surface. + // Exception : Nodes that are hidden and are drawn only for the sake of + // copy requests. + EffectNode* node = Node(id); + EffectNode* parent_node = parent(node); + bool contributes_to_drawn_surface = + node->data.is_drawn && + (node->data.opacity != 0.f || node->data.has_background_filters); + if (parent_node && !parent_node->data.is_drawn) + contributes_to_drawn_surface = false; + return contributes_to_drawn_surface; } void TransformTree::UpdateNodeAndAncestorsHaveIntegerTranslations( diff --git a/cc/trees/property_tree.h b/cc/trees/property_tree.h index db0396d..dc479a9 100644 --- a/cc/trees/property_tree.h +++ b/cc/trees/property_tree.h @@ -244,6 +244,10 @@ struct CC_EXPORT EffectNodeData { float screen_space_opacity; bool has_render_surface; + bool has_copy_request; + bool has_background_filters; + bool is_drawn; + bool screen_space_opacity_is_animating; int num_copy_requests_in_subtree; int transform_id; int clip_id; @@ -499,11 +503,14 @@ class CC_EXPORT EffectTree final : public PropertyTree<EffectNode> { void ClearCopyRequests(); + bool ContributesToDrawnSurface(int id); + void ToProtobuf(proto::PropertyTree* proto) const; void FromProtobuf(const proto::PropertyTree& proto); private: void UpdateOpacities(EffectNode* node, EffectNode* parent_node); + void UpdateIsDrawn(EffectNode* node, EffectNode* parent_node); }; class CC_EXPORT ScrollTree final : public PropertyTree<ScrollNode> { diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc index a27bd3c..8af9eb8 100644 --- a/cc/trees/property_tree_builder.cc +++ b/cc/trees/property_tree_builder.cc @@ -520,7 +520,7 @@ bool ShouldCreateRenderSurface(LayerType* layer, num_descendants_that_draw_content > 0 && (layer->DrawsContent() || num_descendants_that_draw_content > 1); - if (layer->opacity() != 1.f && layer->should_flatten_transform() && + if (layer->EffectiveOpacity() != 1.f && layer->should_flatten_transform() && at_least_two_layers_in_subtree_draw_content) { TRACE_EVENT_INSTANT0( "cc", "PropertyTreeBuilder::ShouldCreateRenderSurface opacity", @@ -557,7 +557,7 @@ bool AddEffectNodeIfNeeded( LayerType* layer, DataForRecursion<LayerType>* data_for_children) { const bool is_root = !layer->parent(); - const bool has_transparency = layer->opacity() != 1.f; + const bool has_transparency = layer->EffectiveOpacity() != 1.f; const bool has_animated_opacity = IsAnimatingOpacity(layer); const bool should_create_render_surface = ShouldCreateRenderSurface( layer, data_from_ancestor.compound_transform_since_render_target, @@ -580,9 +580,10 @@ bool AddEffectNodeIfNeeded( EffectNode node; node.owner_id = layer->id(); - node.data.opacity = layer->opacity(); - node.data.screen_space_opacity = layer->opacity(); + node.data.opacity = layer->EffectiveOpacity(); node.data.has_render_surface = should_create_render_surface; + node.data.has_copy_request = layer->HasCopyRequest(); + node.data.has_background_filters = !layer->background_filters().IsEmpty(); if (!is_root) { // The effect node's transform id is used only when we create a render @@ -597,9 +598,9 @@ bool AddEffectNodeIfNeeded( } node.data.clip_id = data_from_ancestor.clip_tree_parent; - node.data.screen_space_opacity *= - data_from_ancestor.effect_tree->Node(parent_id) - ->data.screen_space_opacity; + EffectNode* parent = data_from_ancestor.effect_tree->Node(parent_id); + node.data.screen_space_opacity_is_animating = + parent->data.screen_space_opacity_is_animating || has_animated_opacity; } else { // Root render surface acts the unbounded and untransformed to draw content // into. Transform node created from root layer (includes device scale @@ -607,6 +608,7 @@ bool AddEffectNodeIfNeeded( // to root render surface's content, but not root render surface itself. node.data.transform_id = kRootPropertyTreeNodeId; node.data.clip_id = kRootPropertyTreeNodeId; + node.data.screen_space_opacity_is_animating = has_animated_opacity; } data_for_children->effect_tree_parent = data_for_children->effect_tree->Insert(node, parent_id); @@ -646,10 +648,6 @@ void BuildPropertyTreesInternal( AddClipNodeIfNeeded(data_from_parent, layer, created_render_surface, created_transform_node, &data_for_children); - data_for_children.is_hidden = - layer->hide_layer_and_subtree() || data_from_parent.is_hidden; - layer->set_is_hidden_from_property_trees(data_for_children.is_hidden); - for (size_t i = 0; i < layer->children().size(); ++i) { if (!layer->child_at(i)->scroll_parent()) { DataForRecursionFromChild<LayerType> data_from_child; @@ -768,11 +766,11 @@ void BuildPropertyTreesTopLevelInternal( property_trees->needs_rebuild = false; // The transform tree is kept up-to-date as it is built, but the - // combined_clips stored in the clip tree aren't computed during tree - // building. + // combined_clips stored in the clip tree and the screen_space_opacity and + // is_drawn in the effect tree aren't computed during tree building. property_trees->transform_tree.set_needs_update(false); property_trees->clip_tree.set_needs_update(true); - property_trees->effect_tree.set_needs_update(false); + property_trees->effect_tree.set_needs_update(true); } void PropertyTreeBuilder::BuildPropertyTrees( |