Bug 1955501 - Change logic for finding compositing / shared clip roots to support rounded-rects r=gfx-reviewers,lsalzman

(This is not actually used yet until a follow up patch, the
existing behavior should remain)

Differential Revision: https://phabricator.services.mozilla.com/D242464
This commit is contained in:
Glenn Watson
2025-04-02 20:32:26 +00:00
parent adc5d103ea
commit 9331bc3ef8
4 changed files with 103 additions and 82 deletions

View File

@@ -641,6 +641,7 @@ impl<'a> SceneBuilder<'a> {
&builder.spatial_tree,
&builder.prim_instances,
&mut builder.clip_tree_builder,
&builder.interners,
);
// Add all the tile cache pictures as roots of the picture graph

View File

@@ -4,7 +4,7 @@
use api::{ColorF, DebugFlags, PrimitiveFlags, QualitySettings, RasterSpace, ClipId};
use api::units::*;
use crate::clip::{ClipNodeKind, ClipLeafId, ClipNodeId, ClipTreeBuilder};
use crate::clip::{ClipItemKeyKind, ClipNodeId, ClipTreeBuilder};
use crate::frame_builder::FrameBuilderConfig;
use crate::internal_types::FastHashMap;
use crate::picture::{PrimitiveList, PictureCompositeMode, PicturePrimitive, SliceId};
@@ -34,7 +34,6 @@ const MAX_CACHE_SLICES: usize = 12;
struct SliceDescriptor {
prim_list: PrimitiveList,
scroll_root: SpatialNodeIndex,
shared_clip_node_id: ClipNodeId,
}
enum SliceKind {
@@ -203,8 +202,6 @@ impl TileCacheBuilder {
&mut self,
prim_list: PrimitiveList,
spatial_tree: &SceneSpatialTree,
prim_instances: &[PrimitiveInstance],
clip_tree_builder: &ClipTreeBuilder,
) -> Option<SliceDescriptor> {
if prim_list.is_empty() {
return None;
@@ -264,33 +261,8 @@ impl TileCacheBuilder {
.map(|(spatial_node_index, _)| *spatial_node_index)
.unwrap_or(self.root_spatial_node_index);
// Work out which clips are shared by all prim instances and can thus be applied
// at the tile cache level. In future, we aim to remove this limitation by knowing
// during initial scene build which are the relevant compositor clips, but for now
// this is unlikely to be a significant cost.
let mut shared_clip_node_id = None;
for cluster in &prim_list.clusters {
for prim_instance in &prim_instances[cluster.prim_range()] {
let leaf = clip_tree_builder.get_leaf(prim_instance.clip_leaf_id);
// TODO(gw): Need to cache last clip-node id here?
shared_clip_node_id = match shared_clip_node_id {
Some(current) => {
Some(clip_tree_builder.find_lowest_common_ancestor(current, leaf.node_id))
}
None => {
Some(leaf.node_id)
}
}
}
}
let shared_clip_node_id = shared_clip_node_id.expect("bug: no shared clip root");
Some(SliceDescriptor {
scroll_root,
shared_clip_node_id,
prim_list,
})
}
@@ -399,18 +371,9 @@ impl TileCacheBuilder {
}
if want_new_tile_cache {
let shared_clip_node_id = find_shared_clip_root(
scroll_root,
prim_instance.clip_leaf_id,
spatial_tree,
clip_tree_builder,
interners,
);
secondary_slices.push(SliceDescriptor {
prim_list: PrimitiveList::empty(),
scroll_root,
shared_clip_node_id,
});
}
@@ -438,6 +401,7 @@ impl TileCacheBuilder {
spatial_tree: &SceneSpatialTree,
prim_instances: &[PrimitiveInstance],
clip_tree_builder: &mut ClipTreeBuilder,
interners: &Interners,
) -> (TileCacheConfig, Vec<PictureIndex>) {
let mut result = TileCacheConfig::new(self.primary_slices.len());
let mut tile_cache_pictures = Vec::new();
@@ -459,8 +423,6 @@ impl TileCacheBuilder {
if let Some(descriptor) = self.build_tile_cache(
prim_list,
spatial_tree,
prim_instances,
clip_tree_builder,
) {
create_tile_cache(
self.debug_flags,
@@ -470,12 +432,14 @@ impl TileCacheBuilder {
primary_slice.iframe_clip,
descriptor.prim_list,
primary_slice.background_color,
descriptor.shared_clip_node_id,
prim_store,
prim_instances,
config,
&mut result.tile_caches,
&mut tile_cache_pictures,
clip_tree_builder,
interners,
spatial_tree,
);
}
}
@@ -489,12 +453,14 @@ impl TileCacheBuilder {
primary_slice.iframe_clip,
descriptor.prim_list,
primary_slice.background_color,
descriptor.shared_clip_node_id,
prim_store,
prim_instances,
config,
&mut result.tile_caches,
&mut tile_cache_pictures,
clip_tree_builder,
interners,
spatial_tree,
);
}
}
@@ -522,43 +488,6 @@ fn find_scroll_root(
scroll_root
}
fn find_shared_clip_root(
scroll_root: SpatialNodeIndex,
clip_leaf_id: ClipLeafId,
spatial_tree: &SceneSpatialTree,
clip_tree_builder: &ClipTreeBuilder,
interners: &Interners,
) -> ClipNodeId {
let leaf = clip_tree_builder.get_leaf(clip_leaf_id);
let mut current_node_id = leaf.node_id;
while current_node_id != ClipNodeId::NONE {
let node = clip_tree_builder.get_node(current_node_id);
let clip_node_data = &interners.clip[node.handle];
if let ClipNodeKind::Rectangle = clip_node_data.key.kind.node_kind() {
let is_ancestor = spatial_tree.is_ancestor(
clip_node_data.key.spatial_node_index,
scroll_root,
);
let has_complex_clips = clip_tree_builder.clip_node_has_complex_clips(
current_node_id,
interners,
);
if is_ancestor && !has_complex_clips {
break;
}
}
current_node_id = node.parent;
}
current_node_id
}
/// Given a PrimitiveList and scroll root, construct a tile cache primitive instance
/// that wraps the primitive list.
fn create_tile_cache(
@@ -569,12 +498,14 @@ fn create_tile_cache(
iframe_clip: Option<ClipId>,
prim_list: PrimitiveList,
background_color: Option<ColorF>,
shared_clip_node_id: ClipNodeId,
prim_store: &mut PrimitiveStore,
prim_instances: &[PrimitiveInstance],
frame_builder_config: &FrameBuilderConfig,
tile_caches: &mut FastHashMap<SliceId, TileCacheParams>,
tile_cache_pictures: &mut Vec<PictureIndex>,
clip_tree_builder: &mut ClipTreeBuilder,
interners: &Interners,
spatial_tree: &SceneSpatialTree,
) {
// Accumulate any clip instances from the iframe_clip into the shared clips
// that will be applied by this tile cache during compositing.
@@ -584,6 +515,95 @@ fn create_tile_cache(
additional_clips.push(clip_id);
}
// Find the best shared clip node that we can apply while compositing tiles,
// rather than applying to each item individually.
// Step 1: Walk the primitive list, and find the LCA of the clip-tree that
// matches all primitives. This gives us our "best-case" shared
// clip node that moves as many clips as possible to compositing.
let mut shared_clip_node_id = None;
for cluster in &prim_list.clusters {
for prim_instance in &prim_instances[cluster.prim_range()] {
let leaf = clip_tree_builder.get_leaf(prim_instance.clip_leaf_id);
// TODO(gw): Need to cache last clip-node id here?
shared_clip_node_id = match shared_clip_node_id {
Some(current) => {
Some(clip_tree_builder.find_lowest_common_ancestor(current, leaf.node_id))
}
None => {
Some(leaf.node_id)
}
}
}
}
// Step 2: Now we need to walk up the shared clip node hierarchy, and remove clips
// that we can't handle during compositing, such as:
// (a) Non axis-aligned clips
// (b) Box-shadow or image-mask clips
// (c) Rounded rect clips.
//
// A follow up patch to this series will relax the condition on (c) to
// allow tile caches to apply a single rounded-rect clip during compositing.
let mut shared_clip_node_id = shared_clip_node_id.unwrap_or(ClipNodeId::NONE);
let mut current_node_id = shared_clip_node_id;
let mut rounded_rect_count = 0;
// Walk up the hierarchy to the root of the clip-tree
while current_node_id != ClipNodeId::NONE {
let node = clip_tree_builder.get_node(current_node_id);
let clip_node_data = &interners.clip[node.handle];
// Check if this clip is in the root coord system (i.e. is axis-aligned with tile-cache)
let is_rcs = spatial_tree.is_root_coord_system(clip_node_data.key.spatial_node_index);
let node_valid = if is_rcs {
match clip_node_data.key.kind {
ClipItemKeyKind::BoxShadow(..) | ClipItemKeyKind::ImageMask(..) => {
// Has a box-shadow / image-mask, we can't handle this as a shared clip
false
}
ClipItemKeyKind::RoundedRectangle(..) => {
rounded_rect_count += 1;
// TODO(gw): This initial patch retains existing behavior by not
// allowing a rounded-rect clip to be part of the shared
// clip. Follow up patch in this series will relax this.
false
}
ClipItemKeyKind::Rectangle(..) => {
// We can apply multiple (via combining) axis-aligned rectangle
// clips to the shared compositing clip.
true
}
}
} else {
// Has a complex transform, we can't handle this as a shared clip
false
};
if node_valid {
// This node was found to be one we can apply during compositing.
if rounded_rect_count > 1 {
// However, we plan to only support one rounded-rect clip. If
// we have found > 1 rounded rect, drop children from the shared
// clip, and continue looking up the chain.
shared_clip_node_id = current_node_id;
rounded_rect_count = 1;
}
} else {
// Node was invalid, due to transform / clip type. Drop this clip
// and reset the rounded rect count to 0, since we drop children
// from here too.
shared_clip_node_id = node.parent;
rounded_rect_count = 0;
}
current_node_id = node.parent;
}
let shared_clip_leaf_id = Some(clip_tree_builder.build_for_tile_cache(
shared_clip_node_id,
&additional_clips,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -6,9 +6,9 @@ pref(ui.key.menuAccessKey,18) == chrome://reftest/content/xul/accesskey.xhtml ch
fuzzy-if(gtkWidget,0-1,0-11) fuzzy-if(winWidget,0-1,0-1) == chrome://reftest/content/xul/tree-row-outline-1.xhtml chrome://reftest/content/xul/tree-row-outline-1-ref.xhtml # win8: bug 1254832
skip-if(!cocoaWidget) == chrome://reftest/content/xul/mac-tab-toolbar.xhtml chrome://reftest/content/xul/mac-tab-toolbar-ref.xhtml
!= chrome://reftest/content/xul/tree-row-outline-1.xhtml chrome://reftest/content/xul/tree-row-outline-1-notref.xhtml
== chrome://reftest/content/xul/text-crop.xhtml chrome://reftest/content/xul/text-crop-ref.xhtml
fuzzy(0-92,0-2920) == chrome://reftest/content/xul/text-crop.xhtml chrome://reftest/content/xul/text-crop-ref.xhtml
== chrome://reftest/content/xul/text-crop-002.xhtml chrome://reftest/content/xul/text-crop-002-ref.xhtml
== chrome://reftest/content/xul/text-small-caps-1.xhtml chrome://reftest/content/xul/text-small-caps-1-ref.xhtml
fuzzy(0-92,0-980) == chrome://reftest/content/xul/text-small-caps-1.xhtml chrome://reftest/content/xul/text-small-caps-1-ref.xhtml
fuzzy(0-1,0-2500) == chrome://reftest/content/xul/inactive-fixed-bg-bug1205630.xhtml inactive-fixed-bg-bug1205630-ref.html
fuzzy(0-1,0-2500) == chrome://reftest/content/xul/inactive-fixed-bg-bug1272525.xhtml inactive-fixed-bg-bug1272525-ref.html