gh-6302: Remove corner shape for browser stack rendering (gh-15318)

This commit is contained in:
mr. m
2026-09-09 19:35:46 +02:00
committed by GitHub
parent da995e8653
commit 2e9aecd41b
15 changed files with 2648 additions and 2129 deletions

View File

@@ -20,6 +20,9 @@
- name: zen.theme.acrylic-elements
value: "@IS_TWILIGHT@"
- name: zen.theme.squircle-browser-view
value: "@IS_TWILIGHT@"
- name: zen.theme.disable-lightweight
value: true

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,558 @@
diff --git a/gfx/wr/webrender/res/ps_quad_mask.glsl b/gfx/wr/webrender/res/ps_quad_mask.glsl
--- a/gfx/wr/webrender/res/ps_quad_mask.glsl
+++ b/gfx/wr/webrender/res/ps_quad_mask.glsl
@@ -19,12 +19,14 @@
// We pack 4 vec3 clip planes into 3 vec4 to save a varying slot.
flat varying highp vec4 vClipPlane_A;
flat varying highp vec4 vClipPlane_B;
flat varying highp vec4 vClipPlane_C;
+#ifdef WR_FEATURE_SUPERELLIPSE
flat varying highp vec4 vClipShape;
flat varying highp vec4 vClipClampedInset;
+#endif
#endif
flat varying highp vec2 vClipMode;
#ifdef WR_VERTEX_SHADER
@@ -40,12 +42,14 @@
vec4 radii;
#else
vec4 radii_top;
vec4 radii_bottom;
+#ifdef WR_FEATURE_SUPERELLIPSE
vec4 shape;
vec4 inset;
+#endif
#endif
float mode;
int space;
};
@@ -58,22 +62,29 @@
vec4 texels[3] = fetch_from_gpu_buffer_3f(index);
clip.rect = RectWithEndpoint(texels[0].xy, texels[0].zw);
clip.radii = texels[1];
clip.mode = texels[2].x;
#else
+#ifdef WR_FEATURE_SUPERELLIPSE
vec4 texels[6] = fetch_from_gpu_buffer_6f(index);
+#else
+ vec4 texels[4] = fetch_from_gpu_buffer_4f(index);
+#endif
clip.rect = RectWithEndpoint(texels[0].xy, texels[0].zw);
clip.radii_top = texels[1];
clip.radii_bottom = texels[2];
clip.mode = texels[3].x;
+#ifdef WR_FEATURE_SUPERELLIPSE
clip.shape = texels[4];
clip.inset = texels[5];
+#endif
#endif
return clip;
}
+#ifdef WR_FEATURE_SUPERELLIPSE
vec4 precalc_corner(vec2 center, vec2 radii, vec2 inset, vec2 clip_sign, float k) {
if (k == 1.0) {
// round/ellipse corner, precalc the ellipse parameters
return vec4(center, inverse_radii_squared(radii));
} else {
@@ -85,10 +96,11 @@
radii = offset_radii.zw;
}
return vec4(center, inverse_radii(radii));
}
}
+#endif
void pattern_vertex(PrimitiveInfo prim_info) {
Clip clip = fetch_clip(aClipData.y);
Transform clip_transform = fetch_transform(aClipData.x);
@@ -121,10 +133,11 @@
vec2 r_tl = clip.radii_top.xy;
vec2 r_tr = clip.radii_top.zw;
vec2 r_br = clip.radii_bottom.zw;
vec2 r_bl = clip.radii_bottom.xy;
+#ifdef WR_FEATURE_SUPERELLIPSE
vClipCenter_Radius_TL = precalc_corner(clip.rect.p0 + r_tl,
r_tl,
clip.inset.wx,
vec2(-1.0, -1.0),
clip.shape.x);
@@ -146,10 +159,25 @@
clip.rect.p1.y - r_bl.y),
r_bl,
clip.inset.wz,
vec2(-1.0, 1.0),
clip.shape.w);
+#else
+ vClipCenter_Radius_TL = vec4(clip.rect.p0 + r_tl,
+ inverse_radii_squared(r_tl));
+
+ vClipCenter_Radius_TR = vec4(clip.rect.p1.x - r_tr.x,
+ clip.rect.p0.y + r_tr.y,
+ inverse_radii_squared(r_tr));
+
+ vClipCenter_Radius_BR = vec4(clip.rect.p1 - r_br,
+ inverse_radii_squared(r_br));
+
+ vClipCenter_Radius_BL = vec4(clip.rect.p0.x + r_bl.x,
+ clip.rect.p1.y - r_bl.y,
+ inverse_radii_squared(r_bl));
+#endif
// We need to know the half-spaces of the corners separate from the center
// and radius. We compute a point that falls on the diagonal (which is just
// an inner vertex pushed out along one axis, but not on both) to get the
// plane offset of the half-space. We also compute the direction vector of
@@ -170,13 +198,15 @@
vClipPlane_A = vec4(tl.x, tl.y, tl.z, tr.x);
vClipPlane_B = vec4(tr.y, tr.z, br.x, br.y);
vClipPlane_C = vec4(br.z, bl.x, bl.y, bl.z);
+#ifdef WR_FEATURE_SUPERELLIPSE
vClipShape = clip.shape;
vClipClampedInset = min(clip.inset, 0.0);
#endif
+#endif
}
#endif
#ifdef WR_FRAGMENT_SHADER
@@ -205,11 +235,13 @@
vec3 plane_tr = vec3(vClipPlane_A.w, vClipPlane_B.x, vClipPlane_B.y);
vec3 plane_br = vec3(vClipPlane_B.z, vClipPlane_B.w, vClipPlane_C.x);
vec3 plane_bl = vec3(vClipPlane_C.y, vClipPlane_C.z, vClipPlane_C.w);
float dist;
+#ifdef WR_FEATURE_SUPERELLIPSE
if (vClipShape == vec4(1.0)) {
+#endif
dist = distance_to_rounded_rect(
clip_local_pos,
plane_tl,
vClipCenter_Radius_TL,
plane_tr,
@@ -218,10 +250,11 @@
vClipCenter_Radius_BR,
plane_bl,
vClipCenter_Radius_BL,
vTransformBounds
);
+#ifdef WR_FEATURE_SUPERELLIPSE
} else {
dist = distance_to_shaped_rect(
clip_local_pos,
vClipCenter_Radius_TL,
vClipCenter_Radius_TR,
@@ -230,10 +263,11 @@
vTransformBounds,
vClipShape,
vClipClampedInset
);
}
+#endif
#endif
// Compute AA for the given dist and range.
float alpha = distance_aa(aa_range, dist);
@@ -340,13 +374,13 @@
#define AA_RECT(local_pos) \
sd_round_box(local_pos, v_clip_size, v_clip_radii)
#else
// The span fast path only handles elliptical corners. For superellipse
// shapes, bail out and let SWGL fall back to the fragment shader.
- if (vClipShape != vec4(1.0)) {
+ #ifdef WR_FEATURE_SUPERELLIPSE
return;
- }
+ #endif
// Unpack the corner half-spaces packed into vClipPlane_A/B/C.
vec3 plane_tl = vec3(vClipPlane_A.x, vClipPlane_A.y, vClipPlane_A.z);
vec3 plane_tr = vec3(vClipPlane_A.w, vClipPlane_B.x, vClipPlane_B.y);
vec3 plane_br = vec3(vClipPlane_B.z, vClipPlane_B.w, vClipPlane_C.x);
diff --git a/gfx/wr/webrender/src/batch.rs b/gfx/wr/webrender/src/batch.rs
--- a/gfx/wr/webrender/src/batch.rs
+++ b/gfx/wr/webrender/src/batch.rs
@@ -1224,25 +1224,29 @@
/// A list of clip instances to be drawn into a target.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct ClipMaskInstanceList {
pub mask_instances_fast: FrameVec<MaskInstance>,
+ pub mask_instances_superellipse: FrameVec<MaskInstance>,
pub mask_instances_slow: FrameVec<MaskInstance>,
pub mask_instances_fast_with_scissor: FastHashMap<DeviceIntRect, FrameVec<MaskInstance>>,
+ pub mask_instances_superellipse_with_scissor: FastHashMap<DeviceIntRect, FrameVec<MaskInstance>>,
pub mask_instances_slow_with_scissor: FastHashMap<DeviceIntRect, FrameVec<MaskInstance>>,
pub image_mask_instances: FastHashMap<TextureSource, FrameVec<PrimitiveInstanceData>>,
pub image_mask_instances_with_scissor: FastHashMap<(DeviceIntRect, TextureSource), FrameVec<PrimitiveInstanceData>>,
}
impl ClipMaskInstanceList {
pub fn new(memory: &FrameMemory) -> Self {
ClipMaskInstanceList {
mask_instances_fast: memory.new_vec(),
+ mask_instances_superellipse: memory.new_vec(),
mask_instances_slow: memory.new_vec(),
mask_instances_fast_with_scissor: FastHashMap::default(),
+ mask_instances_superellipse_with_scissor: FastHashMap::default(),
mask_instances_slow_with_scissor: FastHashMap::default(),
image_mask_instances: FastHashMap::default(),
image_mask_instances_with_scissor: FastHashMap::default(),
}
}
@@ -1250,20 +1254,24 @@
pub fn is_empty(&self) -> bool {
// Destructure self to make sure we don't forget to update this method if
// a new member is added.
let ClipMaskInstanceList {
mask_instances_fast,
+ mask_instances_superellipse,
mask_instances_slow,
mask_instances_fast_with_scissor,
+ mask_instances_superellipse_with_scissor,
mask_instances_slow_with_scissor,
image_mask_instances,
image_mask_instances_with_scissor,
} = self;
mask_instances_fast.is_empty()
+ && mask_instances_superellipse.is_empty()
&& mask_instances_slow.is_empty()
&& mask_instances_fast_with_scissor.is_empty()
+ && mask_instances_superellipse_with_scissor.is_empty()
&& mask_instances_slow_with_scissor.is_empty()
&& image_mask_instances.is_empty()
&& image_mask_instances_with_scissor.is_empty()
}
}
diff --git a/gfx/wr/webrender/src/quad.rs b/gfx/wr/webrender/src/quad.rs
--- a/gfx/wr/webrender/src/quad.rs
+++ b/gfx/wr/webrender/src/quad.rs
@@ -1807,11 +1807,11 @@
gpu_buffer: &mut GpuBufferBuilderF,
clip_rect: LayoutRect,
radius: &BorderRadius,
inset: LayoutSideOffsets,
mode: ClipMode,
-) -> (GpuBufferAddress, bool) {
+) -> (GpuBufferAddress, bool, bool) {
let radius = clamped_radius(radius, clip_rect.size());
if radius.can_use_fast_path_in(&clip_rect) {
let mut writer = gpu_buffer.write_blocks(3);
writer.push_one(clip_rect);
@@ -1821,13 +1821,15 @@
radius.bottom_left.width,
radius.top_left.width,
]);
writer.push_one([mode as i32 as f32, 0.0, 0.0, 0.0]);
- (writer.finish(), true)
+ (writer.finish(), true, false)
} else {
- let mut writer = gpu_buffer.write_blocks(6);
+ let superellipse = !radius.shapes_all_round();
+ let block_count = if superellipse { 6 } else { 4 };
+ let mut writer = gpu_buffer.write_blocks(block_count);
writer.push_one(clip_rect);
writer.push_one([
radius.top_left.width,
radius.top_left.height,
radius.top_right.width,
@@ -1838,19 +1840,21 @@
radius.bottom_left.height,
radius.bottom_right.width,
radius.bottom_right.height,
]);
writer.push_one([mode as i32 as f32, 0.0, 0.0, 0.0]);
- writer.push_one([
- radius.shape_top_left,
- radius.shape_top_right,
- radius.shape_bottom_right,
- radius.shape_bottom_left,
- ]);
- writer.push_one(inset);
+ if superellipse {
+ writer.push_one([
+ radius.shape_top_left,
+ radius.shape_top_right,
+ radius.shape_bottom_right,
+ radius.shape_bottom_left,
+ ]);
+ writer.push_one(inset);
+ }
- (writer.finish(), false)
+ (writer.finish(), false, superellipse)
}
}
pub fn prepare_clip_task(
clip_instance: &ClipNodeInstance,
@@ -1865,11 +1869,11 @@
gpu_buffer: &mut GpuBufferBuilderF,
transforms: &mut TransformPalette,
rg_builder: &mut RenderTaskGraphBuilder,
sub_tasks: &mut SubTaskRange,
) {
- let (clip_address, fast_path) = match clip_item.kind {
+ let (clip_address, fast_path, superellipse) = match clip_item.kind {
ClipItemKind::RoundedRectangle { radius, inset, mode } => {
write_rounded_rect_clip_blocks(
gpu_buffer,
clip_instance.clip_rect,
&radius,
@@ -1882,11 +1886,11 @@
writer.push_one(clip_instance.clip_rect);
writer.push_one([0.0, 0.0, 0.0, 0.0]);
writer.push_one([mode as i32 as f32, 0.0, 0.0, 0.0]);
let clip_address = writer.finish();
- (clip_address, true)
+ (clip_address, true, false)
}
ClipItemKind::Image { .. } => {
let transform_id = transforms.gpu.get_id_with_post_scale(
clip_instance.spatial_node_index,
raster_spatial_node_index,
@@ -2033,10 +2037,11 @@
clip_transform_id,
quad_flags,
clip_space,
needs_scissor_rect,
rounded_rect_fast_path: fast_path,
+ rounded_rect_superellipse: superellipse,
}),
);
}
fn create_quad_primitive(
diff --git a/gfx/wr/webrender/src/render_target.rs b/gfx/wr/webrender/src/render_target.rs
--- a/gfx/wr/webrender/src/render_target.rs
+++ b/gfx/wr/webrender/src/render_target.rs
@@ -441,11 +441,11 @@
// so the target must be initialized to one.
self.clears.push((target_rect, ColorF::WHITE));
let device_rect = DeviceRect::from_size(target_rect.size().to_f32());
- let (clip_address, fast_path) = quad::write_rounded_rect_clip_blocks(
+ let (clip_address, fast_path, superellipse) = quad::write_rounded_rect_clip_blocks(
&mut gpu_buffer_builder.f32,
region_task.clip_rect,
&region_task.radius,
region_task.inset,
region_task.mode,
@@ -495,10 +495,12 @@
unused: 0,
};
if fast_path {
self.clip_masks.mask_instances_fast.push(instance);
+ } else if superellipse {
+ self.clip_masks.mask_instances_superellipse.push(instance);
} else {
self.clip_masks.mask_instances_slow.push(instance);
}
},
);
@@ -925,19 +927,26 @@
if task.rounded_rect_fast_path {
results.mask_instances_fast_with_scissor
.entry(*target_rect)
.or_insert_with(|| memory.new_vec())
.push(instance);
+ } else if task.rounded_rect_superellipse {
+ results.mask_instances_superellipse_with_scissor
+ .entry(*target_rect)
+ .or_insert_with(|| memory.new_vec())
+ .push(instance);
} else {
results.mask_instances_slow_with_scissor
.entry(*target_rect)
.or_insert_with(|| memory.new_vec())
.push(instance);
}
} else {
if task.rounded_rect_fast_path {
results.mask_instances_fast.push(instance);
+ } else if task.rounded_rect_superellipse {
+ results.mask_instances_superellipse.push(instance);
} else {
results.mask_instances_slow.push(instance);
}
}
}
diff --git a/gfx/wr/webrender/src/render_task.rs b/gfx/wr/webrender/src/render_task.rs
--- a/gfx/wr/webrender/src/render_task.rs
+++ b/gfx/wr/webrender/src/render_task.rs
@@ -2240,10 +2240,11 @@
/// Transform from the quad primitive's space to the clip's local space.
pub clip_transform_id: GpuTransformId,
pub quad_flags: QuadFlags,
pub needs_scissor_rect: bool,
pub rounded_rect_fast_path: bool,
+ pub rounded_rect_superellipse: bool,
}
/// An clip applied to a render task using the multiply blend mode on top of
/// the content being clipped.
#[derive(Debug)]
diff --git a/gfx/wr/webrender/src/renderer/mod.rs b/gfx/wr/webrender/src/renderer/mod.rs
--- a/gfx/wr/webrender/src/renderer/mod.rs
+++ b/gfx/wr/webrender/src/renderer/mod.rs
@@ -2450,10 +2450,54 @@
}
self.device.disable_scissor();
}
+ if !masks.mask_instances_superellipse.is_empty() {
+ self.shaders.borrow_mut().ps_mask_superellipse().bind(
+ &mut self.device,
+ projection,
+ None,
+ &mut self.renderer_errors,
+ &mut self.profile,
+ &mut self.command_log,
+ );
+
+ self.draw_instanced_batch(
+ &masks.mask_instances_superellipse,
+ VertexArrayKind::Mask,
+ &BatchTextures::empty(),
+ stats,
+ );
+ }
+
+ if !masks.mask_instances_superellipse_with_scissor.is_empty() {
+ self.shaders.borrow_mut().ps_mask_superellipse().bind(
+ &mut self.device,
+ projection,
+ None,
+ &mut self.renderer_errors,
+ &mut self.profile,
+ &mut self.command_log,
+ );
+
+ self.device.enable_scissor();
+
+ for (scissor_rect, instances) in &masks.mask_instances_superellipse_with_scissor {
+ self.device.set_scissor_rect(draw_target.to_framebuffer_rect(*scissor_rect));
+
+ self.draw_instanced_batch(
+ instances,
+ VertexArrayKind::Mask,
+ &BatchTextures::empty(),
+ stats,
+ );
+ }
+
+ self.device.disable_scissor();
+ }
+
if !masks.image_mask_instances.is_empty() {
self.shaders.borrow_mut().ps_quad_textured().bind(
&mut self.device,
projection,
None,
diff --git a/gfx/wr/webrender/src/renderer/shade.rs b/gfx/wr/webrender/src/renderer/shade.rs
--- a/gfx/wr/webrender/src/renderer/shade.rs
+++ b/gfx/wr/webrender/src/renderer/shade.rs
@@ -65,10 +65,11 @@
];
const DITHERING_FEATURE: &str = "DITHERING";
const DUAL_SOURCE_FEATURE: &str = "DUAL_SOURCE_BLENDING";
const FAST_PATH_FEATURE: &str = "FAST_PATH";
+const SUPERELLIPSE_FEATURE: &str = "SUPERELLIPSE";
pub(crate) enum ShaderKind {
Primitive,
Cache(VertexArrayKind),
Text,
@@ -449,10 +450,11 @@
ps_quad_backdrop: ShaderHandle,
ps_quad_blend: ShaderHandle,
ps_quad_mix_blend: ShaderHandle,
ps_mask: ShaderHandle,
ps_mask_fast: ShaderHandle,
+ ps_mask_superellipse: ShaderHandle,
ps_clear: ShaderHandle,
ps_copy: ShaderHandle,
composite: CompositorShaders,
}
@@ -514,10 +516,17 @@
"ps_quad_mask",
&[FAST_PATH_FEATURE],
&shader_list,
)?;
+ let ps_mask_superellipse = loader.create_shader(
+ ShaderKind::Cache(VertexArrayKind::Mask),
+ "ps_quad_mask",
+ &[SUPERELLIPSE_FEATURE],
+ &shader_list,
+ )?;
+
let mut cs_scale = Vec::new();
let scale_shader_num = IMAGE_BUFFER_KINDS.len();
// PrimitiveShader is not clonable. Use push() to initialize the vec.
for _ in 0 .. scale_shader_num {
cs_scale.push(None);
@@ -786,10 +795,11 @@
ps_quad_backdrop,
ps_quad_blend,
ps_quad_mix_blend,
ps_mask,
ps_mask_fast,
+ ps_mask_superellipse,
ps_split_composite,
ps_clear,
ps_copy,
composite,
})
@@ -963,10 +973,11 @@
pub fn ps_quad_textured(&mut self) -> &mut LazilyCompiledShader {
self.loader.get(self.ps_quad_textured)
}
pub fn ps_mask(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_mask) }
pub fn ps_mask_fast(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_mask_fast) }
+ pub fn ps_mask_superellipse(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_mask_superellipse) }
pub fn ps_clear(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_clear) }
pub fn ps_copy(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.ps_copy) }
pub fn deinit(self, device: &mut Device) {
self.loader.deinit(device);
diff --git a/gfx/wr/webrender_build/src/shader_features.rs b/gfx/wr/webrender_build/src/shader_features.rs
--- a/gfx/wr/webrender_build/src/shader_features.rs
+++ b/gfx/wr/webrender_build/src/shader_features.rs
@@ -65,11 +65,11 @@
let mut shaders = ShaderFeatures::new();
// Cache shaders
shaders.insert("cs_blur", vec!["ALPHA_TARGET".to_string(), "COLOR_TARGET".to_string()]);
- shaders.insert("ps_quad_mask", vec![String::new(), "FAST_PATH".to_string()]);
+ shaders.insert("ps_quad_mask", vec![String::new(), "FAST_PATH".to_string(), "SUPERELLIPSE".to_string()]);
for name in &[
"cs_line_decoration",
"cs_border_segment",
"cs_border_solid",

View File

@@ -0,0 +1,307 @@
diff --git a/gfx/wr/webrender/res/ps_quad_box_shadow.glsl b/gfx/wr/webrender/res/ps_quad_box_shadow.glsl
--- a/gfx/wr/webrender/res/ps_quad_box_shadow.glsl
+++ b/gfx/wr/webrender/res/ps_quad_box_shadow.glsl
@@ -49,22 +49,26 @@
flat varying highp vec4 vElemCenter_Radius_TL;
flat varying highp vec4 vElemCenter_Radius_TR;
flat varying highp vec4 vElemCenter_Radius_BR;
flat varying highp vec4 vElemCenter_Radius_BL;
+#ifdef WR_FEATURE_SUPERELLIPSE
flat varying highp vec4 vElemShape;
+#endif
#ifdef WR_VERTEX_SHADER
void pattern_vertex(PrimitiveInfo info) {
vec4 data0 = fetch_from_gpu_buffer_1f(info.pattern_input.x);
vec4 data1 = fetch_from_gpu_buffer_1f(info.pattern_input.x + 1);
vec4 data2 = fetch_from_gpu_buffer_1f(info.pattern_input.x + 2);
vec4 data3 = fetch_from_gpu_buffer_1f(info.pattern_input.x + 3);
vec4 data4 = fetch_from_gpu_buffer_1f(info.pattern_input.x + 4);
vec4 data5 = fetch_from_gpu_buffer_1f(info.pattern_input.x + 5);
+#ifdef WR_FEATURE_SUPERELLIPSE
vec4 data6 = fetch_from_gpu_buffer_1f(info.pattern_input.x + 6);
+#endif
vec2 alloc_size = data0.xy;
vec2 dest_rect_size = data0.zw;
vec2 dest_rect_off = data1.xy;
v_uv_scale_inset = vec4(vec2(1.0) / alloc_size, data1.z, 0.0);
@@ -84,11 +88,11 @@
// Map nine-patch UV=1.0 to the true content edge (uv_p0 + content_device_size)
// rather than the rounded atlas entry edge (info.segment.uv_rect.p1). The atlas
// allocation is rounded up from content_device_size, so this edge always lies
// inside the entry; using it keeps the mapping stable to sub-texel precision as
// the blur animates (bug 2002194).
- vec2 content_device_size = data6.xy;
+ vec2 content_device_size = data5.xy;
vec2 texture_size = vec2(TEX_SIZE(sColor0));
vec2 uv_p0 = info.segment.uv_rect.p0;
vec2 uv_p1 = uv_p0 + content_device_size;
v_uv_rect = vec4(uv_p0, uv_p1) / texture_size.xyxy;
v_uv_bounds = vec4(
@@ -110,11 +114,13 @@
vElemCenter_Radius_TL = vec4(elem_p0 + r_tl, r_tl);
vElemCenter_Radius_TR = vec4(elem_p1.x - r_tr.x, elem_p0.y + r_tr.y, r_tr);
vElemCenter_Radius_BR = vec4(elem_p1 - r_br, r_br);
vElemCenter_Radius_BL = vec4(elem_p0.x + r_bl.x, elem_p1.y - r_bl.y, r_bl);
- vElemShape = data5;
+#ifdef WR_FEATURE_SUPERELLIPSE
+ vElemShape = data6;
+#endif
}
#endif
#ifdef WR_FRAGMENT_SHADER
@@ -170,22 +176,24 @@
vec3 elem_plane_bl = vec3(n_bl, dot(n_bl, vec2(c_bl.x, c_bl.y + r_bl.y)));
// Reconstruct the element rect bounds from the TL and BR corner data.
vec4 elem_bounds = vec4(c_tl - r_tl, c_br + r_br);
- vec4 elem_shape = vElemShape;
-
float elem_dist;
+#ifdef WR_FEATURE_SUPERELLIPSE
+ vec4 elem_shape = vElemShape;
if (elem_shape == vec4(1.0)) {
+#endif
elem_dist = distance_to_rounded_rect(
local_pos,
elem_plane_tl, vec4(c_tl, inverse_radii_squared(r_tl)),
elem_plane_tr, vec4(c_tr, inverse_radii_squared(r_tr)),
elem_plane_br, vec4(c_br, inverse_radii_squared(r_br)),
elem_plane_bl, vec4(c_bl, inverse_radii_squared(r_bl)),
elem_bounds
);
+#ifdef WR_FEATURE_SUPERELLIPSE
} else {
elem_dist = distance_to_shaped_rect(
local_pos,
vec4(c_tl, elem_shape.x == 1.0 ? inverse_radii_squared(r_tl) : inverse_radii(r_tl)),
vec4(c_tr, elem_shape.y == 1.0 ? inverse_radii_squared(r_tr) : inverse_radii(r_tr)),
@@ -194,10 +202,11 @@
elem_bounds,
elem_shape,
vec4(0.0)
);
}
+#endif
// Outset (inset=0): dist < 0 = inside element → should be clipped out → use -elem_dist.
// Inset (inset=1): dist < 0 = inside element → should be kept → use elem_dist.
float element_clip = distance_aa(aa_range, mix(-elem_dist, elem_dist, inset));
diff --git a/gfx/wr/webrender/src/pattern/box_shadow.rs b/gfx/wr/webrender/src/pattern/box_shadow.rs
--- a/gfx/wr/webrender/src/pattern/box_shadow.rs
+++ b/gfx/wr/webrender/src/pattern/box_shadow.rs
@@ -41,11 +41,14 @@
_sub_rect: Option<DeviceRect>,
_offset: LayoutVector2D,
_ctx: &PatternBuilderContext,
state: &mut PatternBuilderState,
) -> Pattern {
- let mut writer = state.frame_gpu_data.f32.write_blocks(7);
+ let superellipse = !self.element_radius.shapes_all_round();
+
+ let block_count = if superellipse { 7 } else { 6 };
+ let mut writer = state.frame_gpu_data.f32.write_blocks(block_count);
writer.push_one([
self.shadow_rect_alloc_size.width,
self.shadow_rect_alloc_size.height,
self.dest_rect_size.width,
self.dest_rect_size.height,
@@ -72,26 +75,28 @@
self.element_radius.bottom_right.width,
self.element_radius.bottom_right.height,
self.element_radius.bottom_left.width,
self.element_radius.bottom_left.height,
]);
- writer.push_one([
- self.element_radius.shape_top_left,
- self.element_radius.shape_top_right,
- self.element_radius.shape_bottom_right,
- self.element_radius.shape_bottom_left,
- ]);
writer.push_one([
self.content_device_size.width,
self.content_device_size.height,
0.0,
0.0,
]);
+ if superellipse {
+ writer.push_one([
+ self.element_radius.shape_top_left,
+ self.element_radius.shape_top_right,
+ self.element_radius.shape_bottom_right,
+ self.element_radius.shape_bottom_left,
+ ]);
+ }
let addr = writer.finish();
Pattern {
- kind: PatternKind::BoxShadow,
+ kind: if superellipse { PatternKind::BoxShadowSuperellipse } else { PatternKind::BoxShadow },
shader_input: PatternShaderInput(addr.as_int(), 0),
texture_input: PatternTextureInput::new(self.render_task),
base_color: self.color,
is_opaque: false,
blend_mode: BlendMode::PremultipliedAlpha,
diff --git a/gfx/wr/webrender/src/pattern/mod.rs b/gfx/wr/webrender/src/pattern/mod.rs
--- a/gfx/wr/webrender/src/pattern/mod.rs
+++ b/gfx/wr/webrender/src/pattern/mod.rs
@@ -29,36 +29,37 @@
Gradient = 1,
Repeat = 2,
Mask = 3,
BoxShadow = 4,
+ BoxShadowSuperellipse = 5,
// Variants of ColorOrTexture that use a non-default sampler type
// (samplerExternalOES / __samplerExternal2DY2YEXT / sampler2DRect). The
// quad shader is compiled in matching per-kind variants; see
// ps_quad_textured.glsl.
- TextureExternal = 5,
- TextureExternalBT709 = 6,
- TextureRect = 7,
+ TextureExternal = 6,
+ TextureExternalBT709 = 7,
+ TextureRect = 8,
// Samples up to three planes (sColor0/1/2) and converts from YUV to RGB.
// Like ColorOrTexture, the YUV pattern comes in sampler-type-specific
// variants so that the planes are sampled with the matching sColor
// declaration; see ps_quad_yuv.glsl. `Yuv` is the default (TEXTURE_2D).
- Yuv = 8,
- YuvTextureExternal = 9,
- YuvTextureExternalBT709 = 10,
- YuvTextureRect = 11,
+ Yuv = 9,
+ YuvTextureExternal = 10,
+ YuvTextureExternalBT709 = 11,
+ YuvTextureRect = 12,
// Samples a captured backdrop texture using a (bilerp) 4-corner uv quad.
- Backdrop = 12,
+ Backdrop = 13,
// Applies a filter to a sampled source texture; see ps_quad_blend.glsl.
- Blend = 13,
+ Blend = 14,
// Composites a picture over its backdrop with a software mix-blend-mode;
// samples two textures (backdrop + source). See ps_quad_mix_blend.glsl.
- MixBlend = 14,
+ MixBlend = 15,
// When adding patterns, don't forget to update the NUM_PATTERNS constant.
}
-pub const NUM_PATTERNS: u32 = 15;
+pub const NUM_PATTERNS: u32 = 16;
impl PatternKind {
pub fn from_u32(val: u32) -> Self {
assert!(val < NUM_PATTERNS);
unsafe { std::mem::transmute(val) }
diff --git a/gfx/wr/webrender/src/renderer/mod.rs b/gfx/wr/webrender/src/renderer/mod.rs
--- a/gfx/wr/webrender/src/renderer/mod.rs
+++ b/gfx/wr/webrender/src/renderer/mod.rs
@@ -251,10 +251,11 @@
BatchKind::Quad(PatternKind::TextureExternalBT709) => GPU_TAG_PRIMITIVE,
BatchKind::Quad(PatternKind::TextureRect) => GPU_TAG_PRIMITIVE,
BatchKind::Quad(PatternKind::Gradient) => GPU_TAG_GRADIENT,
BatchKind::Quad(PatternKind::Repeat) => GPU_TAG_REPEAT,
BatchKind::Quad(PatternKind::BoxShadow) => GPU_TAG_PRIMITIVE,
+ BatchKind::Quad(PatternKind::BoxShadowSuperellipse) => GPU_TAG_PRIMITIVE,
BatchKind::Quad(PatternKind::Yuv) => GPU_TAG_BRUSH_YUV_IMAGE,
BatchKind::Quad(PatternKind::YuvTextureExternal) => GPU_TAG_BRUSH_YUV_IMAGE,
BatchKind::Quad(PatternKind::YuvTextureExternalBT709) => GPU_TAG_BRUSH_YUV_IMAGE,
BatchKind::Quad(PatternKind::YuvTextureRect) => GPU_TAG_BRUSH_YUV_IMAGE,
BatchKind::Quad(PatternKind::Backdrop) => GPU_TAG_PRIMITIVE,
diff --git a/gfx/wr/webrender/src/renderer/shade.rs b/gfx/wr/webrender/src/renderer/shade.rs
--- a/gfx/wr/webrender/src/renderer/shade.rs
+++ b/gfx/wr/webrender/src/renderer/shade.rs
@@ -438,10 +438,11 @@
ps_quad_textured_external_bt709: Option<ShaderHandle>,
ps_quad_textured_rect: Option<ShaderHandle>,
ps_quad_repeat: ShaderHandle,
ps_quad_gradient: ShaderHandle,
ps_quad_box_shadow: ShaderHandle,
+ ps_quad_box_shadow_superellipse: ShaderHandle,
// ps_quad_yuv, like ps_quad_textured, comes in sampler-type-specific
// variants so the YUV planes are sampled with the matching sColor
// declaration. The variant is selected via PatternKind.
ps_quad_yuv: ShaderHandle,
ps_quad_yuv_external: Option<ShaderHandle>,
@@ -651,10 +652,17 @@
"ps_quad_box_shadow",
&[],
&shader_list,
)?;
+ let ps_quad_box_shadow_superellipse = loader.create_shader(
+ ShaderKind::Primitive,
+ "ps_quad_box_shadow",
+ &[SUPERELLIPSE_FEATURE],
+ &shader_list,
+ )?;
+
let ps_quad_yuv = loader.create_shader(
ShaderKind::Primitive,
"ps_quad_yuv",
&["TEXTURE_2D"],
&shader_list,
@@ -786,10 +794,11 @@
ps_quad_textured_external_bt709,
ps_quad_textured_rect,
ps_quad_repeat,
ps_quad_gradient,
ps_quad_box_shadow,
+ ps_quad_box_shadow_superellipse,
ps_quad_yuv,
ps_quad_yuv_external,
ps_quad_yuv_external_bt709,
ps_quad_yuv_rect,
ps_quad_backdrop,
@@ -867,10 +876,11 @@
PatternKind::TextureRect => self.ps_quad_textured_rect
.expect("bug: ps_quad_textured TEXTURE_RECT variant not loaded"),
PatternKind::Gradient => self.ps_quad_gradient,
PatternKind::Repeat => self.ps_quad_repeat,
PatternKind::BoxShadow => self.ps_quad_box_shadow,
+ PatternKind::BoxShadowSuperellipse => self.ps_quad_box_shadow_superellipse,
PatternKind::Yuv => self.ps_quad_yuv,
PatternKind::YuvTextureExternal => self.ps_quad_yuv_external
.expect("bug: ps_quad_yuv TEXTURE_EXTERNAL variant not loaded"),
PatternKind::YuvTextureExternalBT709 => self.ps_quad_yuv_external_bt709
.expect("bug: ps_quad_yuv TEXTURE_EXTERNAL_BT709 variant not loaded"),
@@ -923,10 +933,13 @@
self.ps_quad_repeat
}
BatchKind::Quad(PatternKind::BoxShadow) => {
self.ps_quad_box_shadow
}
+ BatchKind::Quad(PatternKind::BoxShadowSuperellipse) => {
+ self.ps_quad_box_shadow_superellipse
+ }
BatchKind::Quad(PatternKind::Yuv) => {
self.ps_quad_yuv
}
BatchKind::Quad(PatternKind::YuvTextureExternal) => {
self.ps_quad_yuv_external
diff --git a/gfx/wr/webrender_build/src/shader_features.rs b/gfx/wr/webrender_build/src/shader_features.rs
--- a/gfx/wr/webrender_build/src/shader_features.rs
+++ b/gfx/wr/webrender_build/src/shader_features.rs
@@ -166,11 +166,11 @@
}
shaders.insert("ps_quad_textured", ps_quad_textured_features);
shaders.insert("ps_quad_repeat", vec![base_prim_features.finish()]);
- shaders.insert("ps_quad_box_shadow", vec![base_prim_features.finish()]);
+ shaders.insert("ps_quad_box_shadow", vec![base_prim_features.finish(), "SUPERELLIPSE".to_string()]);
// Like ps_quad_textured, ps_quad_yuv needs per-texture-kind variants so that
// the YUV planes are sampled with the correct sampler type.
let mut ps_quad_yuv_features: Vec<String> = vec!["TEXTURE_2D".to_string()];
if flags.contains(ShaderFeatureFlags::GL) {

View File

@@ -0,0 +1,560 @@
diff --git a/gfx/wr/webrender/res/border_shared.glsl b/gfx/wr/webrender/res/border_shared.glsl
--- a/gfx/wr/webrender/res/border_shared.glsl
+++ b/gfx/wr/webrender/res/border_shared.glsl
@@ -27,25 +27,33 @@
vec4 rect;
vec4 color0;
vec4 color1;
vec2 widths;
vec2 radii;
+#ifdef WR_FEATURE_SUPERELLIPSE
float shape;
vec2 shape_offset;
vec2 inset;
+#endif
};
BorderInstanceGpuData fetch_gpu_data(int index) {
BorderInstanceGpuData data;
+#ifdef WR_FEATURE_SUPERELLIPSE
vec4 texels[6] = fetch_from_gpu_buffer_6f(index);
+#else
+ vec4 texels[4] = fetch_from_gpu_buffer_4f(index);
+#endif
data.rect = texels[0];
data.color0 = texels[1];
data.color1 = texels[2];
data.widths = texels[3].xy;
data.radii = texels[3].zw;
+#ifdef WR_FEATURE_SUPERELLIPSE
data.shape = texels[4].x;
data.shape_offset = texels[4].yz;
data.inset = texels[5].xy;
+#endif
return data;
}
diff --git a/gfx/wr/webrender/res/cs_border_segment.glsl b/gfx/wr/webrender/res/cs_border_segment.glsl
--- a/gfx/wr/webrender/res/cs_border_segment.glsl
+++ b/gfx/wr/webrender/res/cs_border_segment.glsl
@@ -30,11 +30,13 @@
flat varying highp vec4 vClipCenter_Sign;
// An outer and inner elliptical radii for border
// corner clipping.
flat varying highp vec4 vClipRadii;
+#ifdef WR_FEATURE_SUPERELLIPSE
flat varying highp vec4 vClipOffsets;
+#endif
// Reference point for determine edge clip lines.
flat varying highp vec4 vEdgeReference;
// Stores widths/2 and widths/3 to save doing this in FS.
@@ -192,26 +194,34 @@
vColor00 = color0[0];
vColor01 = color0[1];
vec4[2] color1 = get_colors_for_side(data.color1, style1);
vColor10 = color1[0];
vColor11 = color1[1];
+#ifdef WR_FEATURE_SUPERELLIPSE
vClipCenter_Sign = vec4(outer + clip_sign * (data.radii + data.shape_offset), clip_sign);
+#else
+ vClipCenter_Sign = vec4(outer + clip_sign * data.radii, clip_sign);
+#endif
vClipRadii = vec4(data.radii, max(data.radii - data.widths, 0.0));
+#ifdef WR_FEATURE_SUPERELLIPSE
vClipOffsets = vec4(0.0);
+#endif
vColorLine = vec4(outer, data.widths.y * -clip_sign.y, data.widths.x * clip_sign.x);
vEdgeReference = vec4(edge_reference, edge_reference + data.widths);
vClipParams1 = aClipParams1;
vClipParams2 = aClipParams2;
+#ifdef WR_FEATURE_SUPERELLIPSE
if (data.shape != 1.0)
{
vec2 reference_radii = (data.radii == vec2(0.0)) ? vec2(0.0) : data.radii + data.inset;
vec4 contour1 = compute_contoured_superellipse(reference_radii, data.shape, data.inset);
vec4 contour2 = compute_contoured_superellipse(reference_radii, data.shape, data.inset + data.widths);
vClipOffsets = vec4(contour1.xy, contour2.xy);
vClipRadii = vec4(contour1.zw, contour2.zw);
}
+#endif
// For the case of dot and dash clips, optimize the number of pixels that
// are hit to just include the dot itself.
if (clip_mode == CLIP_DOT) {
float radius = aClipParams1.z;
@@ -258,19 +268,22 @@
// also 0.67 of the radii. Use these to form a
// SDF subtraction which will clip out the inside
// third of the rounded edge.
float d_radii_a;
float d_radii_b;
+#ifdef WR_FEATURE_SUPERELLIPSE
if (data.shape == 1.0) {
+#endif
d_radii_a = distance_to_ellipse(
clip_relative_pos,
clip_radii.xy - vPartialWidths.xy
);
d_radii_b = distance_to_ellipse(
clip_relative_pos,
clip_radii.xy - 2.0 * vPartialWidths.xy
);
+#ifdef WR_FEATURE_SUPERELLIPSE
} else {
d_radii_a = distance_to_superellipse(
clip_relative_pos - mix(vClipOffsets.xy, vClipOffsets.zw, 1.0 / 3.0),
mix(clip_radii.xy, clip_radii.zw, 1.0 / 3.0),
data.shape
@@ -286,24 +299,28 @@
d_radii_a = max(d_radii_a, -min(included_region_a.x, included_region_a.y));
vec2 included_region_b = data.radii - 2.0 * vPartialWidths.xy - clip_relative_pos;
d_radii_b = max(d_radii_b, -min(included_region_b.x, included_region_b.y));
}
+#endif
float d = min(-d_radii_a, d_radii_b);
color0 *= distance_aa(aa_range, d);
break;
}
case BORDER_STYLE_GROOVE:
case BORDER_STYLE_RIDGE: {
float d;
+#ifdef WR_FEATURE_SUPERELLIPSE
if (data.shape == 1.0) {
+#endif
d = distance_to_ellipse(
clip_relative_pos,
clip_radii.xy - vPartialWidths.zw
);
+#ifdef WR_FEATURE_SUPERELLIPSE
} else {
d = distance_to_superellipse(
clip_relative_pos - mix(vClipOffsets.xy, vClipOffsets.zw, 0.5),
mix(clip_radii.xy, clip_radii.zw, 0.5),
data.shape
@@ -311,10 +328,11 @@
// Clamp to the middle of the adjacent borders
vec2 included_region = data.radii - vPartialWidths.zw - clip_relative_pos;
d = max(d, -min(included_region.x, included_region.y));
}
+#endif
float alpha = distance_aa(aa_range, d);
float swizzled_factor;
switch (segment) {
case SEGMENT_TOP_LEFT: swizzled_factor = 0.0; break;
case SEGMENT_TOP_RIGHT: swizzled_factor = mix_factor; break;
@@ -435,22 +453,26 @@
if (in_clip_region) {
float d_radii_a;
float d_radii_b;
+#ifdef WR_FEATURE_SUPERELLIPSE
if (data.shape == 1.0) {
+#endif
d_radii_a = distance_to_ellipse(clip_relative_pos, vClipRadii.xy);
d_radii_b = distance_to_ellipse(clip_relative_pos, vClipRadii.zw);
+#ifdef WR_FEATURE_SUPERELLIPSE
} else {
clip_relative_pos = abs(clip_relative_pos) - data.shape_offset;
d_radii_a = distance_to_superellipse(clip_relative_pos - vClipOffsets.xy, vClipRadii.xy, data.shape);
d_radii_b = distance_to_superellipse(clip_relative_pos - vClipOffsets.zw, vClipRadii.zw, data.shape);
// exclude the straight border part from the subtracted region
vec2 included_region = data.radii - data.widths - clip_relative_pos;
d_radii_b = max(d_radii_b, -min(included_region.x, included_region.y));
}
+#endif
float d_radii = max(d_radii_a, -d_radii_b);
d = max(d, d_radii);
color0 = evaluate_color_for_style_in_corner(
diff --git a/gfx/wr/webrender/res/cs_border_solid.glsl b/gfx/wr/webrender/res/cs_border_solid.glsl
--- a/gfx/wr/webrender/res/cs_border_solid.glsl
+++ b/gfx/wr/webrender/res/cs_border_solid.glsl
@@ -31,11 +31,13 @@
flat varying highp vec4 vClipCenter_Sign;
// An outer and inner elliptical radii for border
// corner clipping.
flat varying highp vec4 vClipRadii;
+#ifdef WR_FEATURE_SUPERELLIPSE
flat varying highp vec4 vClipOffsets;
+#endif
// Position, scale, and radii of horizontally and vertically adjacent corner clips.
flat varying highp vec4 vHorizontalClipCenter_Sign;
flat varying highp vec2 vHorizontalClipRadii;
flat varying highp vec4 vVerticalClipCenter_Sign;
@@ -74,11 +76,11 @@
void main(void) {
BorderInstanceGpuData data = fetch_gpu_data(aGpuDataAddress);
vGpuDataAddress.x = aGpuDataAddress;
int segment = aFlags & 0xff;
- bool do_aa = ((aFlags >> 24) & 0xf0) != 0;
+ bool do_aa = ((aFlags >> 28) & 0x1) != 0;
vec2 outer_scale = get_outer_corner_scale(segment);
vec2 size = data.rect.zw - data.rect.xy;
vec2 outer = outer_scale * size;
vec2 clip_sign = 1.0 - 2.0 * outer_scale;
@@ -100,23 +102,31 @@
vMixColors.x = mix_colors;
vPos = size * aPosition.xy;
vColor0 = data.color0;
vColor1 = data.color1;
+#ifdef WR_FEATURE_SUPERELLIPSE
vClipCenter_Sign = vec4(outer + clip_sign * (data.radii + data.shape_offset), clip_sign);
+#else
+ vClipCenter_Sign = vec4(outer + clip_sign * data.radii, clip_sign);
+#endif
vClipRadii = vec4(data.radii, max(data.radii - data.widths, 0.0));
+#ifdef WR_FEATURE_SUPERELLIPSE
vClipOffsets = vec4(0.0);
+#endif
vColorLine = vec4(outer, data.widths.y * -clip_sign.y, data.widths.x * clip_sign.x);
+#ifdef WR_FEATURE_SUPERELLIPSE
if (data.shape != 1.0)
{
vec2 reference_radii = (data.radii == vec2(0.0)) ? vec2(0.0) : data.radii + data.inset;
vec4 contour1 = compute_contoured_superellipse(reference_radii, data.shape, data.inset);
vec4 contour2 = compute_contoured_superellipse(reference_radii, data.shape, data.inset + data.widths);
vClipOffsets = vec4(contour1.xy, contour2.xy);
vClipRadii = vec4(contour1.zw, contour2.zw);
}
+#endif
vec2 horizontal_clip_sign = vec2(-clip_sign.x, clip_sign.y);
vHorizontalClipCenter_Sign = vec4(aClipParams1.xy +
horizontal_clip_sign * aClipParams1.zw,
horizontal_clip_sign);
@@ -156,22 +166,26 @@
float d = -1.0;
if (in_clip_region) {
float d_radii_a;
float d_radii_b;
+#ifdef WR_FEATURE_SUPERELLIPSE
if (data.shape == 1.0) {
+#endif
d_radii_a = distance_to_ellipse(clip_relative_pos, vClipRadii.xy);
d_radii_b = distance_to_ellipse(clip_relative_pos, vClipRadii.zw);
+#ifdef WR_FEATURE_SUPERELLIPSE
} else {
clip_relative_pos = abs(clip_relative_pos) - data.shape_offset;
d_radii_a = distance_to_superellipse(clip_relative_pos - vClipOffsets.xy, vClipRadii.xy, data.shape);
d_radii_b = distance_to_superellipse(clip_relative_pos - vClipOffsets.zw, vClipRadii.zw, data.shape);
// exclude the straight border part from the subtracted region
vec2 included_region = data.radii - data.widths - clip_relative_pos;
d_radii_b = max(d_radii_b, -min(included_region.x, included_region.y));
}
+#endif
d = max(d_radii_a, -d_radii_b);
}
// And again for horizontally-adjacent corner
diff --git a/gfx/wr/webrender/src/border.rs b/gfx/wr/webrender/src/border.rs
--- a/gfx/wr/webrender/src/border.rs
+++ b/gfx/wr/webrender/src/border.rs
@@ -855,14 +855,17 @@
h_adjacent_corner_radius: DeviceSize,
v_adjacent_corner_outer: DevicePoint,
v_adjacent_corner_radius: DeviceSize,
gpu_buffer_builder: &mut GpuBufferBuilderF,
) {
+ let superellipse = shape != 1.0;
+
let base_flags = (segment as i32) |
((style0 as i32) << 8) |
((style1 as i32) << 16) |
- ((do_aa as i32) << 28);
+ ((do_aa as i32) << 28) |
+ ((superellipse as i32) << 29);
let instance_gpu_data = BorderInstanceGpuData {
local_rect: task_rect,
color0: color0.premultiplied(),
color1: color1.premultiplied(),
@@ -875,11 +878,11 @@
let base_instance = BorderInstance {
task_origin: DevicePoint::zero(),
flags: base_flags,
clip_params: [0.0; 8],
- gpu_data_address: instance_gpu_data.write(gpu_buffer_builder)
+ gpu_data_address: instance_gpu_data.write(superellipse, gpu_buffer_builder)
};
match segment {
BorderSegment::TopLeft |
BorderSegment::TopRight |
diff --git a/gfx/wr/webrender/src/gpu_types.rs b/gfx/wr/webrender/src/gpu_types.rs
--- a/gfx/wr/webrender/src/gpu_types.rs
+++ b/gfx/wr/webrender/src/gpu_types.rs
@@ -192,18 +192,21 @@
pub shape_offset: DeviceSize,
pub inset: DeviceSize,
}
impl BorderInstanceGpuData {
- pub fn write(&self, gpu_buffer_builder: &mut GpuBufferBuilderF) -> GpuBufferAddress {
- let mut writer = gpu_buffer_builder.write_blocks(6);
+ pub fn write(&self, superellipse: bool, gpu_buffer_builder: &mut GpuBufferBuilderF) -> GpuBufferAddress {
+ let block_count = if superellipse { 6 } else { 4 };
+ let mut writer = gpu_buffer_builder.write_blocks(block_count);
writer.push_one(self.local_rect);
writer.push_one(self.color0);
writer.push_one(self.color1);
writer.push_one([self.widths.width, self.widths.height, self.radius.width, self.radius.height]);
- writer.push_one([self.shape, self.shape_offset.width, self.shape_offset.height, 0.0]);
- writer.push_one([self.inset.width, self.inset.height, 0.0, 0.0]);
+ if superellipse {
+ writer.push_one([self.shape, self.shape_offset.width, self.shape_offset.height, 0.0]);
+ writer.push_one([self.inset.width, self.inset.height, 0.0, 0.0]);
+ }
writer.finish()
}
}
diff --git a/gfx/wr/webrender/src/render_target.rs b/gfx/wr/webrender/src/render_target.rs
--- a/gfx/wr/webrender/src/render_target.rs
+++ b/gfx/wr/webrender/src/render_target.rs
@@ -33,10 +33,11 @@
use crate::spatial_tree::SpatialNodeIndex;
const STYLE_SOLID: i32 = ((BorderStyle::Solid as i32) << 8) | ((BorderStyle::Solid as i32) << 16);
const STYLE_MASK: i32 = 0x00FF_FF00;
+const SUPERELLIPSE_MASK: i32 = 1 << 29;
/// A tag used to identify the output format of a `RenderTarget`.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
@@ -163,10 +164,12 @@
pub clip_masks: ClipMaskInstanceList,
pub border_segments_complex: FrameVec<BorderInstance>,
pub border_segments_solid: FrameVec<BorderInstance>,
+ pub border_segments_complex_superellipse: FrameVec<BorderInstance>,
+ pub border_segments_solid_superellipse: FrameVec<BorderInstance>,
pub line_decorations: FrameVec<LineDecorationJob>,
// Clearing render targets has a fair amount of special cases.
// The general rules are:
// - Depth (for at least the used potion of the target) is always cleared if it
@@ -223,10 +226,12 @@
prim_instances: std::array::from_fn(|_| FastHashMap::default()),
prim_instances_with_scissor: FastHashMap::default(),
clip_masks: ClipMaskInstanceList::new(memory),
border_segments_complex: memory.new_vec(),
border_segments_solid: memory.new_vec(),
+ border_segments_complex_superellipse: memory.new_vec(),
+ border_segments_solid_superellipse: memory.new_vec(),
clears: memory.new_vec(),
line_decorations: memory.new_vec(),
}
}
@@ -547,14 +552,23 @@
let instances = task_info.instances.clone();
for mut instance in instances {
// TODO(gw): It may be better to store the task origin in
// the render task data instead of per instance.
instance.task_origin = task_origin;
+ let superellipse = (instance.flags & SUPERELLIPSE_MASK) != 0;
if instance.flags & STYLE_MASK == STYLE_SOLID {
- self.border_segments_solid.push(instance);
+ if superellipse {
+ self.border_segments_solid_superellipse.push(instance);
+ } else {
+ self.border_segments_solid.push(instance);
+ }
} else {
- self.border_segments_complex.push(instance);
+ if superellipse {
+ self.border_segments_complex_superellipse.push(instance);
+ } else {
+ self.border_segments_complex.push(instance);
+ }
}
}
}
RenderTaskKind::Image(..) |
RenderTaskKind::Cached(..) |
diff --git a/gfx/wr/webrender/src/renderer/mod.rs b/gfx/wr/webrender/src/renderer/mod.rs
--- a/gfx/wr/webrender/src/renderer/mod.rs
+++ b/gfx/wr/webrender/src/renderer/mod.rs
@@ -3394,11 +3394,13 @@
draw_target,
);
// Draw any borders for this target.
if !target.border_segments_solid.is_empty() ||
- !target.border_segments_complex.is_empty()
+ !target.border_segments_complex.is_empty() ||
+ !target.border_segments_solid_superellipse.is_empty() ||
+ !target.border_segments_complex_superellipse.is_empty()
{
let _timer = self.gpu_profiler.start_timer(GPU_TAG_CACHE_BORDER);
self.set_blend(true, FramebufferKind::Other);
self.set_blend_mode_premultiplied_alpha(FramebufferKind::Other);
@@ -3437,10 +3439,46 @@
&BatchTextures::empty(),
stats,
);
}
+ if !target.border_segments_solid_superellipse.is_empty() {
+ self.shaders.borrow_mut().cs_border_solid_superellipse().bind(
+ &mut self.device,
+ &projection,
+ None,
+ &mut self.renderer_errors,
+ &mut self.profile,
+ &mut self.command_log,
+ );
+
+ self.draw_instanced_batch(
+ &target.border_segments_solid_superellipse,
+ VertexArrayKind::Border,
+ &BatchTextures::empty(),
+ stats,
+ );
+ }
+
+ if !target.border_segments_complex_superellipse.is_empty() {
+ self.shaders.borrow_mut().cs_border_segment_superellipse().bind(
+ &mut self.device,
+ &projection,
+ None,
+ &mut self.renderer_errors,
+ &mut self.profile,
+ &mut self.command_log,
+ );
+
+ self.draw_instanced_batch(
+ &target.border_segments_complex_superellipse,
+ VertexArrayKind::Border,
+ &BatchTextures::empty(),
+ stats,
+ );
+ }
+
self.set_blend(false, FramebufferKind::Other);
}
// Draw any line decorations for this target.
if !target.line_decorations.is_empty() {
diff --git a/gfx/wr/webrender/src/renderer/shade.rs b/gfx/wr/webrender/src/renderer/shade.rs
--- a/gfx/wr/webrender/src/renderer/shade.rs
+++ b/gfx/wr/webrender/src/renderer/shade.rs
@@ -413,10 +413,12 @@
// draw intermediate results to cache targets. The results
// of these shaders are then used by the primitive shaders.
cs_blur_rgba8: ShaderHandle,
cs_border_segment: ShaderHandle,
cs_border_solid: ShaderHandle,
+ cs_border_segment_superellipse: ShaderHandle,
+ cs_border_solid_superellipse: ShaderHandle,
cs_scale: Vec<Option<ShaderHandle>>,
cs_line_decoration: ShaderHandle,
cs_svg_filter_node: ShaderHandle,
// The are "primitive shaders". These shaders draw and blend
@@ -774,19 +776,35 @@
"cs_border_solid",
&[],
&shader_list,
)?;
+ let cs_border_segment_superellipse = loader.create_shader(
+ ShaderKind::Cache(VertexArrayKind::Border),
+ "cs_border_segment",
+ &[SUPERELLIPSE_FEATURE],
+ &shader_list,
+ )?;
+
+ let cs_border_solid_superellipse = loader.create_shader(
+ ShaderKind::Cache(VertexArrayKind::Border),
+ "cs_border_solid",
+ &[SUPERELLIPSE_FEATURE],
+ &shader_list,
+ )?;
+
let composite = CompositorShaders::new(device, gl_type, &mut loader)?;
Ok(Shaders {
loader,
cs_blur_rgba8,
cs_border_segment,
- cs_line_decoration,
cs_border_solid,
+ cs_border_segment_superellipse,
+ cs_border_solid_superellipse,
+ cs_line_decoration,
cs_scale,
cs_svg_filter_node,
ps_text_run,
ps_text_run_dual_source,
ps_quad_textured,
@@ -979,10 +997,12 @@
}
pub fn cs_blur_rgba8(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_blur_rgba8) }
pub fn cs_border_segment(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_border_segment) }
pub fn cs_border_solid(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_border_solid) }
+ pub fn cs_border_segment_superellipse(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_border_segment_superellipse) }
+ pub fn cs_border_solid_superellipse(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_border_solid_superellipse) }
pub fn cs_line_decoration(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_line_decoration) }
pub fn cs_svg_filter_node(&mut self) -> &mut LazilyCompiledShader { self.loader.get(self.cs_svg_filter_node) }
pub fn ps_quad_textured(&mut self) -> &mut LazilyCompiledShader {
self.loader.get(self.ps_quad_textured)
}
diff --git a/gfx/wr/webrender_build/src/shader_features.rs b/gfx/wr/webrender_build/src/shader_features.rs
--- a/gfx/wr/webrender_build/src/shader_features.rs
+++ b/gfx/wr/webrender_build/src/shader_features.rs
@@ -69,17 +69,22 @@
shaders.insert("ps_quad_mask", vec![String::new(), "FAST_PATH".to_string(), "SUPERELLIPSE".to_string()]);
for name in &[
"cs_line_decoration",
- "cs_border_segment",
- "cs_border_solid",
"cs_svg_filter_node",
] {
shaders.insert(name, vec![String::new()]);
}
+ for name in &[
+ "cs_border_segment",
+ "cs_border_solid",
+ ] {
+ shaders.insert(name, vec![String::new(), "SUPERELLIPSE".to_string()]);
+ }
+
let mut base_prim_features = FeatureList::new();
let mut texture_types = vec!["TEXTURE_2D"];
if flags.contains(ShaderFeatureFlags::GL) {
texture_types.push("TEXTURE_RECT");

View File

@@ -0,0 +1,15 @@
diff --git a/devtools/client/responsive/test/browser/browser.toml b/devtools/client/responsive/test/browser/browser.toml
--- a/devtools/client/responsive/test/browser/browser.toml
+++ b/devtools/client/responsive/test/browser/browser.toml
@@ -275,7 +275,10 @@
skip-if = [
"os == 'win' && os_version == '11.26100' && arch == 'x86_64' && asan", # Bug 2016837
]
["browser_window_sizing.js"]
+skip-if = [
+ "os == 'win' && opt && standalone", # Bug 2063169
+]
["browser_zoom.js"]

View File

@@ -0,0 +1,34 @@
diff --git a/layout/painting/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -4606,12 +4606,12 @@
wr::LayoutRect deviceClipRect = wr::ToLayoutRect(clipRect);
nscoord spread = shadow.spread.ToAppUnits();
float spreadRadius = float(spread) / float(appUnitsPerDevPixel);
- wr::BorderRadius borderRadius{};
- wr::BorderRadius shadowRadius{};
+ wr::BorderRadius borderRadius = wr::EmptyBorderRadius();
+ wr::BorderRadius shadowRadius = wr::EmptyBorderRadius();
if (hasBorderRadius) {
borderRadius = wr::ToBorderRadius(borderRadii);
if (spreadRadius) {
auto shadowRadii = borderRadii;
shadowRadii.AdjustOutwards(
@@ -4727,12 +4727,12 @@
float(shadow.base.blur.ToAppUnits()) / float(appUnitsPerDevPixel);
nscoord spread = shadow.spread.ToAppUnits();
float spreadRadius = spread / float(appUnitsPerDevPixel);
- wr::BorderRadius borderRadius{};
- wr::BorderRadius shadowRadius{};
+ wr::BorderRadius borderRadius = wr::EmptyBorderRadius();
+ wr::BorderRadius shadowRadius = wr::EmptyBorderRadius();
if (hasBorderRadius) {
borderRadius = wr::ToBorderRadius(innerRadii);
if (spreadRadius) {
RectCornerRadii shadowRadii = innerRadii;
shadowRadii.AdjustInwards(

View File

@@ -0,0 +1,53 @@
diff --git a/gfx/wr/webrender/res/ps_quad_mask.glsl b/gfx/wr/webrender/res/ps_quad_mask.glsl
--- a/gfx/wr/webrender/res/ps_quad_mask.glsl
+++ b/gfx/wr/webrender/res/ps_quad_mask.glsl
@@ -318,12 +318,30 @@
#endif
vec4 clip_dist =
mix(clip_rect, clip_rect.zwxy, lessThan(local_step, vec2(0.0)).xyxy)
- local_pos0.xyxy;
+
+ // Half-width, in local units, of the band around an edge over which
+ // distance_aa() produces partial coverage.
+ float aa_band = 0.5 * recip(aa_range);
+ // An axis the span does not step along has the same distance to its two
+ // edges for every pixel of the span, so the inside/outside test below
+ // cannot resolve an edge that runs parallel to the span and coverage ends
+ // up quantized to whole spans. Grow the rect by the AA band so that a span
+ // landing inside the band counts as inside, which leaves the corner
+ // selection below unchanged, and remember that the span is only partially
+ // covered so the opaque run can be dropped further down.
+ // `inset` is the distance from the span to the nearer of an axis' two
+ // edges, positive when the span is between them.
+ vec2 inset = min(-clip_dist.xy, clip_dist.zw);
+ bvec2 flat_axis = equal(local_step, vec2(0.0));
+ bvec2 partial = lessThan(inset, vec2(aa_band));
+ bool aa_span = (flat_axis.x && partial.x) || (flat_axis.y && partial.y);
+
clip_dist =
- mix(1.0e6 * step(0.0, clip_dist),
+ mix(1.0e6 * step(0.0, clip_dist - vec4(aa_band, aa_band, -aa_band, -aa_band)),
clip_dist * recip(local_step).xyxy,
notEqual(local_step, vec2(0.0)).xyxy);
float opaque_start = max(clip_dist.x, clip_dist.y);
float opaque_end = min(clip_dist.z, clip_dist.w);
@@ -404,10 +422,16 @@
aa_margin = max(aa_margin - max(aa_start - aa_end, 0.0), 0.0);
aa_start -= aa_margin;
aa_end += aa_margin;
+ if (aa_span) {
+ // No pixel of the span is fully covered, so collapse the opaque run and
+ // let the anti-aliased runs on either side of it cover the whole span.
+ opaque_end = min(opaque_end, opaque_start);
+ }
+
ivec4 steps = ivec4(clamp(
swgl_SpanLength -
swgl_StepSize *
vec4(floor(aa_start), ceil(opaque_start), floor(opaque_end), ceil(aa_end)),
0.0, swgl_SpanLength));

File diff suppressed because it is too large Load Diff

View File

@@ -53,7 +53,14 @@
},
{
"type": "local",
"path": "firefox/css_corner_shape_rendering.patch"
// Sorts before bug_2063169/ on purpose: D319869 builds on the border
// shader hunks in here, and surfer applies patches in path order.
"path": "firefox/bug_2047627_corner_shape_borders.patch"
},
{
"type": "phabricator",
"ids": ["D319577", "D319796", "D319869", "D320211", "D320568", "D321282"],
"name": "Bug 2063169"
},
{
"type": "local",

View File

@@ -11,6 +11,11 @@
:root:not([zen-no-padding="true"]) &:not(.zen-glance-overlay) {
border-radius: var(--zen-native-inner-radius);
box-shadow: var(--zen-big-shadow);
@media not (-moz-pref("zen.theme.squircle-browser-view")) {
/* stylelint-disable-next-line property-no-unknown */
corner-shape: round;
border-radius: calc(var(--zen-native-inner-radius) / var(--zen-squircle-value));
}
}
& browser[type="content"] {

View File

@@ -105,6 +105,11 @@
.browserSidebarContainer.zen-glance-background,
.browserSidebarContainer.zen-glance-overlay .browserContainer:not([fade-out="true"]) {
border-radius: var(--zen-native-inner-radius);
@media not (-moz-pref("zen.theme.squircle-browser-view")) {
/* stylelint-disable-next-line property-no-unknown */
corner-shape: round;
border-radius: calc(var(--zen-native-inner-radius) / var(--zen-squircle-value));
}
}
.browserSidebarContainer.zen-glance-overlay {
@@ -144,6 +149,11 @@
border-radius: var(--zen-native-inner-radius);
overflow: hidden;
box-shadow: var(--zen-big-shadow);
@media not (-moz-pref("zen.theme.squircle-browser-view")) {
/* stylelint-disable-next-line property-no-unknown */
corner-shape: round;
border-radius: calc(var(--zen-native-inner-radius) / var(--zen-squircle-value));
}
}
& browser {

View File

@@ -110,7 +110,7 @@ class nsZenWorkspaceIcons extends MozXULElement {
button.setAttribute("zen-workspace-id", workspace.uuid);
button.setAttribute("context", "zenWorkspaceMoreActions");
const icon = document.createXULElement("label");
icon.setAttribute("class", "zen-workspace-icon");
icon.setAttribute("class", "zen-workspace-icon no-squircles");
const isSvgIcon = workspace.icon && workspace.icon.endsWith(".svg");
if (gZenWorkspaces.workspaceHasIcon(workspace)) {
if (isSvgIcon) {

View File

@@ -30,9 +30,9 @@
& toolbarbutton {
margin: 0;
max-width: 28px;
max-width: 30px;
border-radius: var(--toolbarbutton-border-radius);
height: 28px;
height: 30px;
display: flex;
justify-content: center;
padding: 0 !important;
@@ -58,8 +58,8 @@
}
&[no-icon='true'] {
width: 6px;
height: 6px;
width: 8px;
height: 8px;
background: light-dark(rgba(0, 0, 0, 0.4), rgba(255, 255, 255, 0.4));
border-radius: 50%;
}

View File

@@ -1059,7 +1059,6 @@
#tabs-newtab-button {
display: none;
font-weight: 500;
-moz-user-focus: ignore !important;
}
@@ -1342,7 +1341,7 @@
}
}
#tabs-newtab-button:not([in-urlbar="true"]) label,
#tabs-newtab-button:not([in-urlbar="true"]),
.zen-current-workspace-indicator-name {
color: color-mix(in srgb, currentColor 70%, transparent);
}