From 87867505d6d12d92241fcd67bf5cec7bb91be8b4 Mon Sep 17 00:00:00 2001 From: chenyang Date: Wed, 31 Jul 2024 12:29:32 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DCVE-2023-7013?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: chenyang --- cc/base/features.cc | 4 ++ cc/base/features.h | 5 ++ cc/layers/render_surface_impl.h | 34 ++++++++++- cc/trees/draw_property_utils.cc | 99 ++++++++++++++++++++++++++++----- 4 files changed, 126 insertions(+), 16 deletions(-) diff --git a/cc/base/features.cc b/cc/base/features.cc index 4a60589f2f..93116ae45d 100644 --- a/cc/base/features.cc +++ b/cc/base/features.cc @@ -70,6 +70,10 @@ BASE_FEATURE(kHudDisplayForPerformanceMetrics, "HudDisplayForPerformanceMetrics", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kRenderSurfaceCommonAncestorClip, + "RenderSurfaceCommonAncestorClip", + base::FEATURE_ENABLED_BY_DEFAULT); + BASE_FEATURE(kJankInjectionAblationFeature, "JankInjectionAblation", base::FEATURE_DISABLED_BY_DEFAULT); diff --git a/cc/base/features.h b/cc/base/features.h index 45f4ea1cf9..c9d522d735 100644 --- a/cc/base/features.h +++ b/cc/base/features.h @@ -50,6 +50,11 @@ CC_BASE_EXPORT BASE_DECLARE_FEATURE(kSchedulerSmoothnessForAnimatedScrolls); // display. CC_BASE_EXPORT BASE_DECLARE_FEATURE(kHudDisplayForPerformanceMetrics); +// Whether RenderSurface::common_ancestor_clip_id() is used to clip to the +// common ancestor clip when any contributing layer escapes the clip of the +// render surface's owning effect. +CC_BASE_EXPORT BASE_DECLARE_FEATURE(kRenderSurfaceCommonAncestorClip); + // When enabled, some jank is injected to the animation/scrolling pipeline. CC_BASE_EXPORT BASE_DECLARE_FEATURE(kJankInjectionAblationFeature); diff --git a/cc/layers/render_surface_impl.h b/cc/layers/render_surface_impl.h index 3c61bb86ad..ae1de2aeff 100644 --- a/cc/layers/render_surface_impl.h +++ b/cc/layers/render_surface_impl.h @@ -126,12 +126,35 @@ class CC_EXPORT RenderSurfaceImpl { contributes_to_drawn_surface_ = contributes_to_drawn_surface; } + // Called when any contributing layer's escapes OwningEffectNode's clip node, + // or to clear the current `common_ancestor_clip_id_` before a full update. + // After this is called for all clip-escaping layers, + // `common_ancestor_clip_id_` is the lowest common ancestor of OwningEffect's + // clip node and all contributing layers' clips. It will be used as the + // render surface's clip. For now this is behind the + // RenderSurfaceCommonAncestorClip feature. + void set_common_ancestor_clip_id(int id) { + DCHECK_NE(id, ClipTreeIndex()); + DCHECK(id < ClipTreeIndex() || id == kInvalidPropertyNodeId); + common_ancestor_clip_id_ = id; + } + int common_ancestor_clip_id() const { + return common_ancestor_clip_id_ == kInvalidPropertyNodeId + ? ClipTreeIndex() + : common_ancestor_clip_id_; + } + + // TODO(wangxianzhu): Remove this when removing the + // RenderSurfaceCommonAncestorClip feature. void set_has_contributing_layer_that_escapes_clip( bool contributing_layer_escapes_clip) { has_contributing_layer_that_escapes_clip_ = contributing_layer_escapes_clip; } bool has_contributing_layer_that_escapes_clip() const { - return has_contributing_layer_that_escapes_clip_; + return common_ancestor_clip_id_ != kInvalidPropertyNodeId || + // TODO(wangxianzhu): Remove this when removing the + // RenderSurfaceCommonAncestorClip feature. + has_contributing_layer_that_escapes_clip_; } void set_is_render_surface_list_member(bool is_render_surface_list_member) { @@ -289,8 +312,17 @@ class CC_EXPORT RenderSurfaceImpl { // Is used to calculate the content rect from property trees. gfx::Rect accumulated_content_rect_; int num_contributors_; + + // If this is not kInvalidPropertyNodeId, it means that some contributing + // layer escaping the effect's clip node, and this is the the lowest common + // ancestor of the effect's clip node and the clip nodes of all contributing + // layers. Otherwise `ClipTreeIndex()` is already the common ancestor clip. + int common_ancestor_clip_id_ = kInvalidPropertyNodeId; // Is used to decide if the surface is clipped. + // TODO(wangxianzhu): Remove this when removing the + // RenderSurfaceCommonAncestorClip feature. bool has_contributing_layer_that_escapes_clip_ : 1; + bool surface_property_changed_ : 1; bool ancestor_property_changed_ : 1; diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc index f8a808a51f..c80e655f95 100644 --- a/cc/trees/draw_property_utils.cc +++ b/cc/trees/draw_property_utils.cc @@ -365,6 +365,8 @@ int LowestCommonAncestor(int clip_id_1, void SetHasContributingLayerThatEscapesClip(int lca_clip_id, int target_effect_id, EffectTree* effect_tree) { + DCHECK(!base::FeatureList::IsEnabled( + features::kRenderSurfaceCommonAncestorClip)); const EffectNode* effect_node = effect_tree->Node(target_effect_id); // Find all ancestor targets starting from effect_node who are clipped by // a descendant of lowest ancestor clip and set their @@ -378,6 +380,44 @@ void SetHasContributingLayerThatEscapesClip(int lca_clip_id, } } +void UpdateRenderSurfaceCommonAncestorClip(LayerImpl* layer, + const ClipTree* clip_tree, + EffectTree* effect_tree) { + DCHECK( + base::FeatureList::IsEnabled(features::kRenderSurfaceCommonAncestorClip)); + RenderSurfaceImpl* render_surface = layer->render_target(); + CHECK(render_surface); + int clip_id = layer->clip_tree_index(); + // Find each ancestor targets whose clip is escaped by the layer's clip, and + // set its common_ancestor_clip_id to be the lowest common ancestor of both + // clips. + while (clip_id < render_surface->common_ancestor_clip_id()) { + clip_id = LowestCommonAncestor( + clip_id, render_surface->common_ancestor_clip_id(), clip_tree); + render_surface->set_common_ancestor_clip_id(clip_id); + RenderSurfaceImpl* parent_render_surface = render_surface->render_target(); + if (parent_render_surface == render_surface) { + break; + } + render_surface = parent_render_surface; + } +} + +void ClearRenderSurfaceCommonAncestorClip(LayerImpl* layer) { + DCHECK( + base::FeatureList::IsEnabled(features::kRenderSurfaceCommonAncestorClip)); + RenderSurfaceImpl* render_surface = layer->render_target(); + CHECK(render_surface); + while (render_surface->has_contributing_layer_that_escapes_clip()) { + render_surface->set_common_ancestor_clip_id(kInvalidPropertyNodeId); + RenderSurfaceImpl* parent_render_surface = render_surface->render_target(); + if (parent_render_surface == render_surface) { + break; + } + render_surface = parent_render_surface; + } +} + template int TransformTreeIndexForBackfaceVisibility(LayerType* layer, const TransformTree& tree) { @@ -541,11 +581,26 @@ gfx::Rect LayerDrawableContentRect( void SetSurfaceIsClipped(const ClipTree& clip_tree, RenderSurfaceImpl* render_surface) { - bool is_clipped; + bool is_clipped = false; if (render_surface->EffectTreeIndex() == kContentsRootPropertyNodeId) { // Root render surface is always clipped. is_clipped = true; + } else if (base::FeatureList::IsEnabled( + features::kRenderSurfaceCommonAncestorClip)) { + int parent_target_clip_id = + render_surface->render_target()->common_ancestor_clip_id(); + for (const ClipNode* clip_node = + clip_tree.Node(render_surface->common_ancestor_clip_id()); + clip_node && clip_node->id != parent_target_clip_id; + clip_node = clip_tree.parent(clip_node)) { + if (clip_node->AppliesLocalClip()) { + is_clipped = true; + break; + } + } } else if (render_surface->has_contributing_layer_that_escapes_clip()) { + CHECK_EQ(render_surface->common_ancestor_clip_id(), + render_surface->ClipTreeIndex()); // We cannot clip a surface that has a contribuitng layer which escapes the // clip. is_clipped = false; @@ -623,9 +678,12 @@ void SetSurfaceClipRect(const ClipNode* parent_clip_node, render_surface->SetClipRect( ToEnclosingClipRect(clip_tree.Node(effect_node->clip_id)->clip)); } else { - ConditionalClip accumulated_clip_rect = - ComputeAccumulatedClip(property_trees, include_expanding_clips, - effect_node->clip_id, target_node->id); + DCHECK(base::FeatureList::IsEnabled( + features::kRenderSurfaceCommonAncestorClip) || + render_surface->common_ancestor_clip_id() == effect_node->clip_id); + ConditionalClip accumulated_clip_rect = ComputeAccumulatedClip( + property_trees, include_expanding_clips, + render_surface->common_ancestor_clip_id(), target_node->id); render_surface->SetClipRect( ToEnclosingClipRect(accumulated_clip_rect.clip_rect)); } @@ -1219,7 +1277,10 @@ void UpdateElasticOverscroll( void ComputeDrawPropertiesOfVisibleLayers(const LayerImplList* layer_list, PropertyTrees* property_trees) { - // Compute transforms + const bool common_ancestor_clip_enabled = + base::FeatureList::IsEnabled(features::kRenderSurfaceCommonAncestorClip); + + // Compute transforms and clear common ancestor clips of render surfaces. for (LayerImpl* layer : *layer_list) { const TransformNode* transform_node = property_trees->transform_tree().Node(layer->transform_tree_index()); @@ -1235,22 +1296,30 @@ void ComputeDrawPropertiesOfVisibleLayers(const LayerImplList* layer_list, layer->draw_properties().mask_filter_info = mask_filter_info_pair.first; layer->draw_properties().is_fast_rounded_corner = mask_filter_info_pair.second; + + if (common_ancestor_clip_enabled) { + ClearRenderSurfaceCommonAncestorClip(layer); + } } - // Compute effects and determine if render surfaces have contributing layers - // that escape clip. + // Compute effects and common ancestor clips of render surfaces. for (LayerImpl* layer : *layer_list) { layer->draw_properties().opacity = LayerDrawOpacity(layer, property_trees->effect_tree()); - - RenderSurfaceImpl* render_target = layer->render_target(); - int lca_clip_id = LowestCommonAncestor(layer->clip_tree_index(), - render_target->ClipTreeIndex(), - &property_trees->clip_tree()); - if (lca_clip_id != render_target->ClipTreeIndex()) { - SetHasContributingLayerThatEscapesClip( - lca_clip_id, render_target->EffectTreeIndex(), + if (common_ancestor_clip_enabled) { + UpdateRenderSurfaceCommonAncestorClip( + layer, &property_trees->clip_tree(), &property_trees->effect_tree_mutable()); + } else { + RenderSurfaceImpl* render_target = layer->render_target(); + int lca_clip_id = LowestCommonAncestor(layer->clip_tree_index(), + render_target->ClipTreeIndex(), + &property_trees->clip_tree()); + if (lca_clip_id != render_target->ClipTreeIndex()) { + SetHasContributingLayerThatEscapesClip( + lca_clip_id, render_target->EffectTreeIndex(), + &property_trees->effect_tree_mutable()); + } } } -- Gitee