commit f058a705aed4e359d6136c6fd6b07e8f565238ac
parent 3f08434492003e9e056d21407693653a0025dc9c
Author: Sotaro Ikeda <sotaro.ikeda.g@gmail.com>
Date: Mon, 15 Dec 2025 07:36:53 +0000
Bug 2005103 - Use overlay with video rendering with rounded rects if possible r=gfx-reviewers,gw
Power usage of overlay could be more efficient than underlay.
Differential Revision: https://phabricator.services.mozilla.com/D275922
Diffstat:
3 files changed, 120 insertions(+), 4 deletions(-)
diff --git a/gfx/wr/webrender/src/composite.rs b/gfx/wr/webrender/src/composite.rs
@@ -214,6 +214,7 @@ pub struct ExternalSurfaceDescriptor {
pub local_clip_rect: PictureRect,
pub clip_rect: DeviceRect,
pub transform_index: CompositorTransformIndex,
+ pub compositor_clip_index: Option<CompositorClipIndex>,
pub image_rendering: ImageRendering,
pub z_id: ZBufferId,
pub dependency: ExternalSurfaceDependency,
@@ -1106,6 +1107,13 @@ impl CompositeState {
// For each compositor surface that was promoted, build the
// information required for the compositor to draw it
for compositor_surface in &sub_slice.compositor_surfaces {
+ let compositor_clip_index = if compositor_surface.descriptor.compositor_clip_index.is_some() {
+ assert!(tile_cache.compositor_clip.is_none());
+ compositor_surface.descriptor.compositor_clip_index
+ } else {
+ tile_cache.compositor_clip
+ };
+
self.push_compositor_surface(
&compositor_surface.descriptor,
compositor_surface.is_opaque,
@@ -1113,7 +1121,7 @@ impl CompositeState {
resource_cache,
gpu_buffer,
deferred_resolves,
- tile_cache.compositor_clip,
+ compositor_clip_index,
);
}
}
diff --git a/gfx/wr/webrender/src/tile_cache/mod.rs b/gfx/wr/webrender/src/tile_cache/mod.rs
@@ -1842,6 +1842,9 @@ impl TileCacheInstance {
surface_kind: CompositorSurfaceKind,
pic_coverage_rect: PictureRect,
frame_context: &FrameVisibilityContext,
+ data_stores: &DataStores,
+ clip_store: &ClipStore,
+ composite_state: &CompositeState,
force: bool,
) -> Result<CompositorSurfaceKind, SurfacePromotionFailure> {
use SurfacePromotionFailure::*;
@@ -1859,7 +1862,33 @@ impl TileCacheInstance {
// If a complex clip is being applied to this primitive, it can't be
// promoted directly to a compositor surface.
if prim_clip_chain.needs_mask {
- return Err(OverlayNeedsMask);
+ let mut is_supported_rounded_rect = false;
+ if let CompositorKind::Layer { .. } = composite_state.compositor_kind {
+ if prim_clip_chain.clips_range.count == 1 && self.compositor_clip.is_none() {
+ let clip_instance = clip_store.get_instance_from_range(&prim_clip_chain.clips_range, 0);
+ let clip_node = &data_stores.clip[clip_instance.handle];
+
+ if let ClipItemKind::RoundedRectangle { ref radius, mode: ClipMode::Clip, rect, .. } = clip_node.item.kind {
+ let max_corner_width = radius.top_left.width
+ .max(radius.bottom_left.width)
+ .max(radius.top_right.width)
+ .max(radius.bottom_right.width);
+ let max_corner_height = radius.top_left.height
+ .max(radius.bottom_left.height)
+ .max(radius.top_right.height)
+ .max(radius.bottom_right.height);
+
+ if max_corner_width <= 0.5 * rect.size().width &&
+ max_corner_height <= 0.5 * rect.size().height {
+ is_supported_rounded_rect = true;
+ }
+ }
+ }
+ }
+
+ if !is_supported_rounded_rect {
+ return Err(OverlayNeedsMask);
+ }
}
}
CompositorSurfaceKind::Underlay => {
@@ -1943,9 +1972,12 @@ impl TileCacheInstance {
prim_info: &mut PrimitiveDependencyInfo,
flags: PrimitiveFlags,
local_prim_rect: LayoutRect,
+ prim_clip_chain: &ClipChainInstance,
prim_spatial_node_index: SpatialNodeIndex,
pic_coverage_rect: PictureRect,
frame_context: &FrameVisibilityContext,
+ data_stores: &DataStores,
+ clip_store: &ClipStore,
image_dependencies: &[ImageDependency;3],
api_keys: &[ImageKey; 3],
resource_cache: &mut ResourceCache,
@@ -1975,9 +2007,12 @@ impl TileCacheInstance {
prim_info,
flags,
local_prim_rect,
+ prim_clip_chain,
prim_spatial_node_index,
pic_coverage_rect,
frame_context,
+ data_stores,
+ clip_store,
ExternalSurfaceDependency::Yuv {
image_dependencies: *image_dependencies,
color_space,
@@ -1999,9 +2034,12 @@ impl TileCacheInstance {
prim_info: &mut PrimitiveDependencyInfo,
flags: PrimitiveFlags,
local_prim_rect: LayoutRect,
+ prim_clip_chain: &ClipChainInstance,
prim_spatial_node_index: SpatialNodeIndex,
pic_coverage_rect: PictureRect,
frame_context: &FrameVisibilityContext,
+ data_stores: &DataStores,
+ clip_store: &ClipStore,
image_dependency: ImageDependency,
api_key: ImageKey,
resource_cache: &mut ResourceCache,
@@ -2033,9 +2071,12 @@ impl TileCacheInstance {
prim_info,
flags,
local_prim_rect,
+ prim_clip_chain,
prim_spatial_node_index,
pic_coverage_rect,
frame_context,
+ data_stores,
+ clip_store,
ExternalSurfaceDependency::Rgb {
image_dependency,
},
@@ -2056,9 +2097,12 @@ impl TileCacheInstance {
prim_info: &mut PrimitiveDependencyInfo,
flags: PrimitiveFlags,
local_prim_rect: LayoutRect,
+ prim_clip_chain: &ClipChainInstance,
prim_spatial_node_index: SpatialNodeIndex,
pic_coverage_rect: PictureRect,
frame_context: &FrameVisibilityContext,
+ data_stores: &DataStores,
+ clip_store: &ClipStore,
dependency: ExternalSurfaceDependency,
api_keys: &[ImageKey; 3],
resource_cache: &mut ResourceCache,
@@ -2157,6 +2201,57 @@ impl TileCacheInstance {
let clip_rect = (world_clip_rect * frame_context.global_device_pixel_scale).round();
+
+ let mut compositor_clip_index = None;
+
+ if surface_kind == CompositorSurfaceKind::Overlay &&
+ prim_clip_chain.needs_mask {
+ assert!(prim_clip_chain.clips_range.count == 1);
+ assert!(self.compositor_clip.is_none());
+
+ let clip_instance = clip_store.get_instance_from_range(&prim_clip_chain.clips_range, 0);
+ let clip_node = &data_stores.clip[clip_instance.handle];
+ if let ClipItemKind::RoundedRectangle { radius, mode: ClipMode::Clip, rect, .. } = clip_node.item.kind {
+ // Map the clip in to device space. We know from the shared
+ // clip creation logic it's in root coord system, so only a
+ // 2d axis-aligned transform can apply. For example, in the
+ // case of a pinch-zoom effect.
+ let map = ClipSpaceConversion::new(
+ frame_context.root_spatial_node_index,
+ clip_node.item.spatial_node_index,
+ frame_context.root_spatial_node_index,
+ frame_context.spatial_tree,
+ );
+
+ let (rect, radius) = match map {
+ ClipSpaceConversion::Local => {
+ (rect.cast_unit(), radius)
+ }
+ ClipSpaceConversion::ScaleOffset(scale_offset) => {
+ (
+ scale_offset.map_rect(&rect),
+ BorderRadius {
+ top_left: scale_offset.map_size(&radius.top_left),
+ top_right: scale_offset.map_size(&radius.top_right),
+ bottom_left: scale_offset.map_size(&radius.bottom_left),
+ bottom_right: scale_offset.map_size(&radius.bottom_right),
+ },
+ )
+ }
+ ClipSpaceConversion::Transform(..) => {
+ unreachable!();
+ }
+ };
+
+ compositor_clip_index = Some(composite_state.register_clip(
+ rect,
+ radius,
+ ));
+ } else {
+ unreachable!();
+ }
+ }
+
if surface_size.width >= MAX_COMPOSITOR_SURFACES_SIZE ||
surface_size.height >= MAX_COMPOSITOR_SURFACES_SIZE {
return Err(SizeTooLarge);
@@ -2265,6 +2360,7 @@ impl TileCacheInstance {
image_rendering,
clip_rect,
transform_index: compositor_transform_index,
+ compositor_clip_index: compositor_clip_index,
z_id: ZBufferId::invalid(),
native_surface_id,
update_params,
@@ -2593,6 +2689,9 @@ impl TileCacheInstance {
CompositorSurfaceKind::Overlay,
pic_coverage_rect,
frame_context,
+ data_stores,
+ clip_store,
+ composite_state,
false);
}
@@ -2608,9 +2707,12 @@ impl TileCacheInstance {
&mut prim_info,
image_key.common.flags,
local_prim_rect,
+ prim_clip_chain,
prim_spatial_node_index,
pic_coverage_rect,
frame_context,
+ data_stores,
+ clip_store,
ImageDependency {
key: image_data.key,
generation: resource_cache.get_image_generation(image_data.key),
@@ -2682,6 +2784,9 @@ impl TileCacheInstance {
kind,
pic_coverage_rect,
frame_context,
+ data_stores,
+ clip_store,
+ composite_state,
force);
if promotion_result.is_ok() {
break;
@@ -2724,9 +2829,12 @@ impl TileCacheInstance {
&mut prim_info,
prim_data.common.flags,
local_prim_rect,
+ prim_clip_chain,
prim_spatial_node_index,
pic_coverage_rect,
frame_context,
+ data_stores,
+ clip_store,
&image_dependencies,
&prim_data.kind.yuv_key,
resource_cache,
@@ -3352,7 +3460,7 @@ impl SubSlice {
}
}
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug)]
enum SurfacePromotionFailure {
ImageWaitingOnYuvImage,
NotPremultipliedAlpha,
diff --git a/layout/reftests/border-radius/reftest.list b/layout/reftests/border-radius/reftest.list
@@ -50,7 +50,7 @@ skip-if(Android&&emulator) == clipping-5-canvas.html clipping-5-refc.html
fuzzy-if(winWidget,0-1,0-5) == clipping-5-image.html clipping-5-refi.html
fuzzy(0-1,0-77) == clipping-5-overflow-hidden.html clipping-5-ref.html
fuzzy(0-1,0-97) == clipping-5-refi.html clipping-5-ref.html
-skip-if(Android&&emulator) fuzzy(0-1,0-77) fuzzy-if(useDrawSnapshot,1-1,97-97) == clipping-5-refc.html clipping-5-ref.html # bug 732535
+skip-if(Android&&emulator) fuzzy(0-1,0-77) fuzzy-if(useDrawSnapshot,1-1,97-97) fuzzy-if(winWidget,0-255,0-113) == clipping-5-refc.html clipping-5-ref.html # bug 732535
fuzzy(0-21,0-76) fuzzy-if(winWidget,0-144,0-335) == clipping-6.html clipping-6-ref.html # PaintedLayer and MaskLayer with transforms that aren't identical
fuzzy(0-28,0-97) == clipping-7.html clipping-7-ref.html # ColorLayer and MaskLayer with transforms that aren't identical. Reference image rendered without using layers (which causes fuzzy failures).
== clipping-and-zindex-1.html clipping-and-zindex-1-ref.html