Bug 1892398 - Supply local space coords to compositing quads when drawing patterns. r=gw

The quad primitive info takes a scale+offset transform which is applied to the coordinate space of the pattern. This allows the quad coorinates to be optionally specified in device space while the pattern remains in layout space.

Differential Revision: https://phabricator.services.mozilla.com/D209694
This commit is contained in:
Nicolas Silva 2024-05-14 08:26:31 +00:00
parent e0ba5eff98
commit 0ce772b727
6 changed files with 63 additions and 43 deletions

View file

@ -92,13 +92,14 @@ struct PrimitiveInfo {
struct QuadPrimitive {
RectWithEndpoint bounds;
RectWithEndpoint clip;
vec4 pattern_scale_offset;
vec4 color;
};
QuadSegment fetch_segment(int base, int index) {
QuadSegment seg;
vec4 texels[2] = fetch_from_gpu_buffer_2f(base + 3 + index * 2);
vec4 texels[2] = fetch_from_gpu_buffer_2f(base + 4 + index * 2);
seg.rect = RectWithEndpoint(texels[0].xy, texels[0].zw);
seg.uv_rect = RectWithEndpoint(texels[1].xy, texels[1].zw);
@ -109,11 +110,12 @@ QuadSegment fetch_segment(int base, int index) {
QuadPrimitive fetch_primitive(int index) {
QuadPrimitive prim;
vec4 texels[3] = fetch_from_gpu_buffer_3f(index);
vec4 texels[4] = fetch_from_gpu_buffer_4f(index);
prim.bounds = RectWithEndpoint(texels[0].xy, texels[0].zw);
prim.clip = RectWithEndpoint(texels[1].xy, texels[1].zw);
prim.color = texels[2];
prim.pattern_scale_offset = texels[2];
prim.color = texels[3];
return prim;
}
@ -215,9 +217,18 @@ float edge_aa_offset(int edge, int flags) {
return ((flags & edge) != 0) ? AA_PIXEL_RADIUS : 0.0;
}
#ifdef WR_VERTEX_SHADER
void pattern_vertex(PrimitiveInfo prim);
#endif
vec2 scale_offset_map_point(vec4 scale_offset, vec2 p) {
return p * scale_offset.xy + scale_offset.zw;
}
RectWithEndpoint scale_offset_map_rect(vec4 scale_offset, RectWithEndpoint r) {
return RectWithEndpoint(
scale_offset_map_point(scale_offset, r.p0),
scale_offset_map_point(scale_offset, r.p1)
);
}
PrimitiveInfo quad_primive_info(void) {
QuadInstance qi = decode_instance();
@ -326,10 +337,13 @@ PrimitiveInfo quad_primive_info(void) {
v_color = prim.color;
vec4 pattern_tx = prim.pattern_scale_offset;
seg.rect = scale_offset_map_rect(pattern_tx, seg.rect);
return PrimitiveInfo(
vi.local_pos,
prim.bounds,
prim.clip,
scale_offset_map_point(pattern_tx, vi.local_pos),
scale_offset_map_rect(pattern_tx, prim.bounds),
scale_offset_map_rect(pattern_tx, prim.clip),
seg,
qi.edge_flags,
qi.quad_flags,

View file

@ -67,17 +67,4 @@ impl Pattern {
is_opaque: false,
}
}
pub fn supports_segmented_rendering(&self) -> bool {
match self.kind {
PatternKind::ColorOrTexture | PatternKind::Mask => {
true
}
PatternKind::RadialGradient | PatternKind::ConicGradient => {
// TODO: We need to fix up the layout coords mismatch in pattern
// and quad rendering to allow these to be segmented.
false
}
}
}
}

View file

@ -35,7 +35,7 @@ use crate::render_task_cache::RenderTaskCacheKeyKind;
use crate::render_task_cache::{RenderTaskCacheKey, to_cache_size, RenderTaskParent};
use crate::render_task::{RenderTaskKind, RenderTask, SubPass, MaskSubPass, EmptyTask};
use crate::segment::SegmentBuilder;
use crate::util::{clamp_to_scale_factor, pack_as_float};
use crate::util::{clamp_to_scale_factor, pack_as_float, ScaleOffset};
use crate::visibility::{compute_conservative_visible_rect, PrimitiveVisibility, VisibilityState};
@ -994,6 +994,7 @@ fn prepare_interned_prim_for_render(
prim_instance.vis.clip_chain.local_clip_rect,
PremultipliedColorF::WHITE,
&[],
ScaleOffset::identity(),
);
// Handle masks on the source. This is the common case, and occurs for:

View file

@ -19,8 +19,8 @@ use crate::render_task_graph::{RenderTaskGraph, RenderTaskId};
use crate::renderer::{BlendMode, GpuBufferAddress, GpuBufferBuilder, GpuBufferBuilderF};
use crate::segment::EdgeAaSegmentMask;
use crate::space::SpaceMapper;
use crate::spatial_tree::{SpatialNodeIndex, SpatialTree};
use crate::util::MaxRect;
use crate::spatial_tree::{CoordinateSpaceMapping, SpatialNodeIndex, SpatialTree};
use crate::util::{MaxRect, ScaleOffset};
const MIN_AA_SEGMENTS_SIZE: f32 = 4.0;
const MIN_QUAD_SPLIT_SIZE: f32 = 256.0;
@ -88,7 +88,6 @@ pub fn push_quad(
frame_state.clip_store,
interned_clips,
prim_is_2d_scale_translation,
pattern,
frame_context.spatial_tree,
);
@ -133,6 +132,7 @@ pub fn push_quad(
clip_chain.local_clip_rect,
pattern.base_color,
&[],
ScaleOffset::identity(),
);
if let QuadRenderStrategy::Direct = strategy {
@ -270,6 +270,15 @@ pub fn push_quad(
let clip_coverage_rect = surface
.map_to_device_rect(&clip_chain.pic_coverage_rect, frame_context.spatial_tree);
let local_to_device = match map_prim_to_surface {
CoordinateSpaceMapping::Local => ScaleOffset::identity(),
CoordinateSpaceMapping::ScaleOffset(scale_offset) => scale_offset.inverse(),
CoordinateSpaceMapping::Transform(..) => panic!("bug: nine-patch segments should be axis-aligned only"),
}.scale(device_pixel_scale.0);
let device_prim_rect: DeviceRect = local_to_device.map_rect(&local_rect);
let local_corner_0 = LayoutRect::new(
clip_rect.min,
clip_rect.min + radius,
@ -379,18 +388,12 @@ pub fn push_quad(
}
if !scratch.quad_direct_segments.is_empty() {
let clip_rect = clip_coverage_rect.cast_unit();
// TODO(1892398): This is not correct. Patterns rely on the origin of the primitive
// rect to work in coordinates relative to the primitive. Passing a rectangle
// which is affected by clips causes patterns to shift as the clip changes the
// primitive origin.
let rect = clip_rect;
add_pattern_prim(
pattern,
local_to_device.inverse(),
prim_instance_index,
rect,
clip_rect,
device_prim_rect.cast_unit(),
clip_coverage_rect.cast_unit(),
pattern.is_opaque,
frame_state,
targets,
@ -420,7 +423,6 @@ fn get_prim_render_strategy(
clip_store: &ClipStore,
interned_clips: &DataStore<ClipIntern>,
can_use_nine_patch: bool,
pattern: &Pattern,
spatial_tree: &SpatialTree,
) -> QuadRenderStrategy {
if !clip_chain.needs_mask {
@ -440,10 +442,6 @@ fn get_prim_render_strategy(
return QuadRenderStrategy::Indirect;
}
if !pattern.supports_segmented_rendering() {
return QuadRenderStrategy::Indirect;
}
if can_use_nine_patch && clip_chain.clips_range.count == 1 {
let clip_instance = clip_store.get_instance_from_range(&clip_chain.clips_range, 0);
let clip_node = &interned_clips[clip_instance.handle];
@ -541,9 +539,8 @@ fn add_render_task_with_mask(
fn add_pattern_prim(
pattern: &Pattern,
pattern_transform: ScaleOffset,
prim_instance_index: PrimitiveInstanceIndex,
// TODO(1892398): At the moment we pass the rect and clip rect either in layout or device
// coordinates, which causes some issues.
rect: LayoutRect,
clip_rect: LayoutRect,
is_opaque: bool,
@ -557,6 +554,7 @@ fn add_pattern_prim(
clip_rect,
pattern.base_color,
segments,
pattern_transform,
);
frame_state.set_segments(segments, targets);
@ -598,6 +596,7 @@ fn add_composite_prim(
rect,
PremultipliedColorF::WHITE,
segments,
ScaleOffset::identity(),
);
frame_state.set_segments(segments, targets);
@ -630,11 +629,13 @@ pub fn write_prim_blocks(
clip_rect: LayoutRect,
color: PremultipliedColorF,
segments: &[QuadSegment],
scale_offset: ScaleOffset,
) -> GpuBufferAddress {
let mut writer = builder.write_blocks(3 + segments.len() * 2);
let mut writer = builder.write_blocks(4 + segments.len() * 2);
writer.push_one(prim_rect);
writer.push_one(clip_rect);
writer.push_one(scale_offset);
writer.push_one(color);
for segment in segments {

View file

@ -32,6 +32,7 @@ use crate::render_task::{RenderTask, ScalingTask, SvgFilterInfo, MaskSubPass, SV
use crate::render_task_graph::{RenderTaskGraph, RenderTaskId};
use crate::resource_cache::ResourceCache;
use crate::spatial_tree::{SpatialNodeIndex};
use crate::util::ScaleOffset;
const STYLE_SOLID: i32 = ((BorderStyle::Solid as i32) << 8) | ((BorderStyle::Solid as i32) << 16);
@ -1243,7 +1244,8 @@ fn build_mask_tasks(
&[QuadSegment {
rect: tile.tile_rect,
task_id: tile.task_id,
}]
}],
ScaleOffset::identity(),
);
let texture = render_tasks
@ -1308,6 +1310,7 @@ fn build_mask_tasks(
task_world_rect.cast_unit(),
PremultipliedColorF::WHITE,
&[],
ScaleOffset::identity(),
);
(ClipSpace::Raster, clip_transform_id, main_prim_address, prim_transform_id, true)

View file

@ -12,6 +12,7 @@
*/
use crate::renderer::MAX_VERTEX_TEXTURE_WIDTH;
use crate::util::ScaleOffset;
use api::units::{DeviceIntRect, DeviceIntSize, LayoutRect, PictureRect, DeviceRect};
use api::{PremultipliedColorF, ImageFormat};
use crate::device::Texel;
@ -105,6 +106,19 @@ impl Into<GpuBufferBlockF> for LayoutRect {
}
}
impl Into<GpuBufferBlockF> for ScaleOffset {
fn into(self) -> GpuBufferBlockF {
GpuBufferBlockF {
data: [
self.scale.x,
self.scale.y,
self.offset.x,
self.offset.y,
],
}
}
}
impl Into<GpuBufferBlockF> for PictureRect {
fn into(self) -> GpuBufferBlockF {
GpuBufferBlockF {