commit 1e163710b0012b1b79466b875f482c772ee9dfe9
parent 96837ab7824d38825845fa93dfaac2d6cae3d078
Author: Sotaro Ikeda <sotaro.ikeda.g@gmail.com>
Date: Mon, 15 Dec 2025 02:39:25 +0000
Bug 2003698 - Drop overlapped rounded corner in composite_simple() r=gfx-reviewers,gw
Differential Revision: https://phabricator.services.mozilla.com/D274869
Diffstat:
2 files changed, 65 insertions(+), 3 deletions(-)
diff --git a/gfx/wr/webrender/src/composite.rs b/gfx/wr/webrender/src/composite.rs
@@ -15,11 +15,12 @@ use crate::tile_cache::{TileCacheInstance, TileSurface};
use crate::tile_cache::TileId;
use crate::prim_store::DeferredResolve;
use crate::resource_cache::{ImageRequest, ResourceCache};
+use crate::segment::EdgeAaSegmentMask;
use crate::util::{extract_inner_rect_safe, Preallocator, ScaleOffset};
use crate::tile_cache::PictureCacheDebugInfo;
use crate::device::Device;
use crate::space::SpaceMapper;
-use std::{ops, u64, os::raw::c_void};
+use std::{ops, u64, os::raw::c_void, hash};
use std::num::NonZeroUsize;
/*
@@ -621,6 +622,27 @@ pub struct CompositorClip {
pub radius: BorderRadius,
}
+#[derive(PartialEq, Debug)]
+pub struct CompositeRoundedCorner {
+ pub rect: LayoutRect,
+ pub radius: LayoutSize,
+ pub edge_flags: EdgeAaSegmentMask,
+}
+
+impl Eq for CompositeRoundedCorner {}
+
+impl hash::Hash for CompositeRoundedCorner {
+ fn hash<H: hash::Hasher>(&self, state: &mut H) {
+ self.rect.min.x.to_bits().hash(state);
+ self.rect.min.y.to_bits().hash(state);
+ self.rect.max.x.to_bits().hash(state);
+ self.rect.max.y.to_bits().hash(state);
+ self.radius.width.to_bits().hash(state);
+ self.radius.height.to_bits().hash(state);
+ self.edge_flags.bits().hash(state);
+ }
+}
+
/// The list of tiles to be drawn this frame
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
diff --git a/gfx/wr/webrender/src/renderer/mod.rs b/gfx/wr/webrender/src/renderer/mod.rs
@@ -57,10 +57,10 @@ use crate::capture::{CaptureConfig, ExternalCaptureImage, PlainExternalImage};
use crate::composite::{CompositeState, CompositeTileSurface, CompositorInputLayer, CompositorSurfaceTransform, ResolvedExternalSurface};
use crate::composite::{CompositorKind, Compositor, NativeTileId, CompositeFeatures, CompositeSurfaceFormat, ResolvedExternalSurfaceColorData};
use crate::composite::{CompositorConfig, NativeSurfaceOperationDetails, NativeSurfaceId, NativeSurfaceOperation, ClipRadius};
-use crate::composite::TileKind;
+use crate::composite::{CompositeRoundedCorner, TileKind};
#[cfg(feature = "debugger")]
use api::debugger::{CompositorDebugInfo, DebuggerTextureContent};
-use crate::segment::SegmentBuilder;
+use crate::segment::{EdgeAaSegmentMask, SegmentBuilder};
use crate::{debug_colors, CompositorInputConfig, CompositorSurfaceUsage};
use crate::device::{DepthFunction, Device, DrawTarget, ExternalTexture, GpuFrameId, UploadPBOPool};
use crate::device::{ReadTarget, ShaderError, Texture, TextureFilter, TextureFlags, TextureSlot, Texel};
@@ -108,6 +108,7 @@ use std::sync::Arc;
use std::{
cell::RefCell,
+ collections::HashSet,
collections::VecDeque,
f32,
ffi::c_void,
@@ -4082,6 +4083,8 @@ impl Renderer {
// Check tiles handling with partial_present_mode
+ let mut opaque_rounded_corners: HashSet<CompositeRoundedCorner> = HashSet::new();
+
// NOTE: Tiles here are being iterated in front-to-back order by
// z-id, due to the sort in composite_state.end_frame()
for (idx, tile) in composite_state.tiles.iter().enumerate() {
@@ -4142,6 +4145,43 @@ impl Renderer {
segment_builder.build(|segment| {
let key = OcclusionItemKey { tile_index: idx, needs_mask: segment.has_mask };
+ let radius = if segment.edge_flags ==
+ EdgeAaSegmentMask::TOP | EdgeAaSegmentMask::LEFT &&
+ !clip.radius.top_left.is_empty() {
+ Some(clip.radius.top_left)
+ } else if segment.edge_flags ==
+ EdgeAaSegmentMask::TOP | EdgeAaSegmentMask::RIGHT &&
+ !clip.radius.top_right.is_empty() {
+ Some(clip.radius.top_right)
+ } else if segment.edge_flags ==
+ EdgeAaSegmentMask::BOTTOM | EdgeAaSegmentMask::LEFT &&
+ !clip.radius.bottom_left.is_empty() {
+ Some(clip.radius.bottom_left)
+ } else if segment.edge_flags ==
+ EdgeAaSegmentMask::BOTTOM | EdgeAaSegmentMask::RIGHT &&
+ !clip.radius.bottom_right.is_empty() {
+ Some(clip.radius.bottom_right)
+ } else {
+ None
+ };
+
+ if let Some(radius) = radius {
+ let rounded_corner = CompositeRoundedCorner {
+ rect: segment.rect.cast_unit(),
+ radius: radius,
+ edge_flags: segment.edge_flags,
+ };
+
+ // Drop overdraw rounded rect
+ if opaque_rounded_corners.contains(&rounded_corner) {
+ return;
+ }
+
+ if is_opaque {
+ opaque_rounded_corners.insert(rounded_corner);
+ }
+ }
+
layer.occlusion.add(
&segment.rect.cast_unit(),
is_opaque && !segment.has_mask,