Bug 1837902 - Support disparate coordinate systems with new WR clip mask code path r=gfx-reviewers,lsalzman

Differential Revision: https://phabricator.services.mozilla.com/D180632
This commit is contained in:
Glenn Watson 2023-07-11 21:05:30 +00:00
Родитель 4e5c385892
Коммит 4e84680754
8 изменённых файлов: 286 добавлений и 159 удалений

Просмотреть файл

@ -33,7 +33,8 @@ use crate::render_task_cache::{RenderTaskCacheKey, to_cache_size, RenderTaskPare
use crate::render_task::{RenderTaskKind, RenderTask};
use crate::renderer::{GpuBufferBuilder, GpuBufferAddress};
use crate::segment::{EdgeAaSegmentMask, SegmentBuilder};
use crate::util::{clamp_to_scale_factor, pack_as_float};
use crate::space::SpaceMapper;
use crate::util::{clamp_to_scale_factor, pack_as_float, MaxRect};
use crate::visibility::{compute_conservative_visible_rect, PrimitiveVisibility, VisibilityState};
@ -107,7 +108,6 @@ pub fn prepare_primitives(
fn can_use_clip_chain_for_quad_path(
clip_chain: &ClipChainInstance,
prim_spatial_node_index: SpatialNodeIndex,
clip_store: &ClipStore,
data_stores: &DataStores,
) -> bool {
@ -119,11 +119,6 @@ fn can_use_clip_chain_for_quad_path(
let clip_instance = clip_store.get_instance_from_range(&clip_chain.clips_range, i);
let clip_node = &data_stores.clip[clip_instance.handle];
// Temporary hack only for landing next stage...
if prim_spatial_node_index != clip_node.item.spatial_node_index {
return false;
}
match clip_node.item.kind {
ClipItemKind::Rectangle { mode: ClipMode::ClipOut, .. } |
ClipItemKind::RoundedRectangle { mode: ClipMode::ClipOut, .. } => {
@ -158,10 +153,12 @@ pub enum QuadRenderStrategy {
}
fn get_prim_render_strategy(
prim_spatial_node_index: SpatialNodeIndex,
clip_chain: &ClipChainInstance,
clip_store: &ClipStore,
data_stores: &DataStores,
can_use_nine_patch: bool,
spatial_tree: &SpatialTree,
) -> QuadRenderStrategy {
if clip_chain.needs_mask {
fn tile_count_for_size(size: f32) -> u16 {
@ -192,10 +189,26 @@ fn get_prim_render_strategy(
if max_corner_width <= 0.5 * rect.size().width &&
max_corner_height <= 0.5 * rect.size().height {
return QuadRenderStrategy::NinePatch {
radius: LayoutVector2D::new(max_corner_width, max_corner_height),
clip_rect: rect,
};
let clip_prim_coords_match = spatial_tree.is_matching_coord_system(
prim_spatial_node_index,
clip_node.item.spatial_node_index,
);
if clip_prim_coords_match {
let map_clip_to_prim = SpaceMapper::new_with_target(
prim_spatial_node_index,
clip_node.item.spatial_node_index,
LayoutRect::max_rect(),
spatial_tree,
);
if let Some(rect) = map_clip_to_prim.map(&rect) {
return QuadRenderStrategy::NinePatch {
radius: LayoutVector2D::new(max_corner_width, max_corner_height),
clip_rect: rect,
};
}
}
}
}
}
@ -296,7 +309,6 @@ fn prepare_prim_for_render(
PrimitiveInstanceKind::Rectangle { ref mut use_legacy_path, .. } => {
*use_legacy_path = !can_use_clip_chain_for_quad_path(
&prim_instance.vis.clip_chain,
cluster.spatial_node_index,
frame_state.clip_store,
data_stores,
);
@ -685,10 +697,12 @@ fn prepare_interned_prim_for_render(
let prim_is_2d_axis_aligned = map_prim_to_surface.is_2d_axis_aligned();
let strategy = get_prim_render_strategy(
prim_spatial_node_index,
&prim_instance.vis.clip_chain,
frame_state.clip_store,
data_stores,
prim_is_2d_scale_translation,
frame_context.spatial_tree,
);
let prim_data = &data_stores.prim[*data_handle];
@ -780,6 +794,7 @@ fn prepare_interned_prim_for_render(
true,
prim_instance,
prim_spatial_node_index,
pic_context.raster_spatial_node_index,
main_prim_address,
transform_id,
aa_flags,
@ -863,6 +878,7 @@ fn prepare_interned_prim_for_render(
create_task,
prim_instance,
prim_spatial_node_index,
pic_context.raster_spatial_node_index,
main_prim_address,
transform_id,
aa_flags,
@ -977,6 +993,7 @@ fn prepare_interned_prim_for_render(
create_task,
prim_instance,
prim_spatial_node_index,
pic_context.raster_spatial_node_index,
main_prim_address,
transform_id,
aa_flags,
@ -1963,7 +1980,7 @@ fn adjust_mask_scale_for_max_size(device_rect: DeviceRect, device_pixel_scale: D
}
}
fn write_prim_blocks(
pub fn write_prim_blocks(
builder: &mut GpuBufferBuilder,
prim_rect: LayoutRect,
clip_rect: LayoutRect,
@ -1999,6 +2016,7 @@ fn add_segment(
create_task: bool,
prim_instance: &PrimitiveInstance,
prim_spatial_node_index: SpatialNodeIndex,
raster_spatial_node_index: SpatialNodeIndex,
main_prim_address: GpuBufferAddress,
transform_id: TransformPaletteId,
aa_flags: EdgeAaSegmentMask,
@ -2020,6 +2038,7 @@ fn add_segment(
task_size,
RenderTaskKind::new_prim(
prim_spatial_node_index,
raster_spatial_node_index,
device_pixel_scale,
content_origin,
main_prim_address,
@ -2069,7 +2088,7 @@ fn add_composite_prim(
targets,
);
let mut composite_quad_flags = QuadFlags::IGNORE_DEVICE_PIXEL_SCALE;
let mut composite_quad_flags = QuadFlags::IGNORE_DEVICE_PIXEL_SCALE | QuadFlags::APPLY_DEVICE_CLIP;
if quad_flags.contains(QuadFlags::IS_OPAQUE) {
composite_quad_flags |= QuadFlags::IS_OPAQUE;
}

Просмотреть файл

@ -3,13 +3,14 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::units::*;
use api::{ColorF, ClipMode, ImageFormat, LineOrientation, BorderStyle};
use api::{units::*, PremultipliedColorF, ClipMode};
use api::{ColorF, ImageFormat, LineOrientation, BorderStyle};
use crate::batch::{AlphaBatchBuilder, AlphaBatchContainer, BatchTextures, add_quad_to_batch};
use crate::batch::{ClipBatcher, BatchBuilder, INVALID_SEGMENT_INDEX};
use crate::command_buffer::{CommandBufferList};
use crate::segment::EdgeAaSegmentMask;
use crate::spatial_tree::SpatialTree;
use crate::clip::{ClipStore, ClipNodeRange, ClipItemKind};
use crate::clip::{ClipStore, ClipItemKind};
use crate::frame_builder::{FrameGlobalResources};
use crate::gpu_cache::{GpuCache, GpuCacheAddress};
use crate::gpu_types::{BorderInstance, SvgFilterInstance, BlurDirection, BlurInstance, PrimitiveHeaders, ScalingInstance};
@ -17,14 +18,15 @@ use crate::gpu_types::{TransformPalette, ZBufferIdGenerator, TransformPaletteId,
use crate::gpu_types::{ZBufferId};
use crate::internal_types::{FastHashMap, TextureSource, CacheTextureId};
use crate::picture::{SliceId, SurfaceInfo, ResolvedSurfaceTexture, TileCacheInstance};
use crate::prepare::write_prim_blocks;
use crate::prim_store::{PrimitiveInstance, PrimitiveStore, PrimitiveScratchBuffer};
use crate::prim_store::gradient::{
FastLinearGradientInstance, LinearGradientInstance, RadialGradientInstance,
ConicGradientInstance,
};
use crate::renderer::{GpuBufferAddress, GpuBufferBuilder};
use crate::renderer::{GpuBufferBuilder};
use crate::render_backend::DataStores;
use crate::render_task::{RenderTaskKind, RenderTaskAddress};
use crate::render_task::{RenderTaskKind, RenderTaskAddress, PrimTask};
use crate::render_task::{RenderTask, ScalingTask, SvgFilterInfo};
use crate::render_task_graph::{RenderTaskGraph, RenderTaskId};
use crate::resource_cache::ResourceCache;
@ -239,6 +241,205 @@ pub struct ColorRenderTarget {
pub mask_instances_slow_with_scissor: FastHashMap<DeviceIntRect, Vec<MaskInstance>>,
}
impl ColorRenderTarget {
fn build_mask_tasks(
&mut self,
info: &PrimTask,
render_task_address: RenderTaskAddress,
target_rect: DeviceIntRect,
clip_store: &ClipStore,
data_stores: &DataStores,
spatial_tree: &SpatialTree,
gpu_buffer_builder: &mut GpuBufferBuilder,
transforms: &mut TransformPalette,
render_tasks: &RenderTaskGraph,
) {
for i in 0 .. info.clip_node_range.count {
let clip_instance = clip_store.get_instance_from_range(&info.clip_node_range, i);
let clip_node = &data_stores.clip[clip_instance.handle];
let is_same_coord_system = spatial_tree.is_matching_coord_system(
clip_node.item.spatial_node_index,
info.raster_spatial_node_index,
);
match clip_node.item.kind {
ClipItemKind::RoundedRectangle { rect, radius, mode } => {
let clip_transform_id = transforms.get_id(
info.prim_spatial_node_index,
clip_node.item.spatial_node_index,
spatial_tree,
);
let (fast_path, clip_address) = if radius.is_uniform().is_some() {
let mut writer = gpu_buffer_builder.write_blocks(3);
writer.push_one(rect);
writer.push_one([radius.top_left.width, 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();
(true, clip_address)
} else {
let mut writer = gpu_buffer_builder.write_blocks(4);
writer.push_one(rect);
writer.push_one([
radius.top_left.width,
radius.top_left.height,
radius.top_right.width,
radius.top_right.height,
]);
writer.push_one([
radius.bottom_left.width,
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]);
let clip_address = writer.finish();
(false, clip_address)
};
add_quad_to_batch(
render_task_address,
info.transform_id,
info.prim_address,
info.quad_flags,
info.edge_flags,
INVALID_SEGMENT_INDEX as u8,
RenderTaskId::INVALID,
ZBufferId(0),
render_tasks,
|_, prim| {
let instance = MaskInstance {
prim,
clip_transform_id,
clip_address: clip_address.as_int(),
info: [0; 2],
};
if info.needs_scissor_rect {
if fast_path {
self.mask_instances_fast_with_scissor
.entry(target_rect)
.or_insert(Vec::new())
.push(instance);
} else {
self.mask_instances_slow_with_scissor
.entry(target_rect)
.or_insert(Vec::new())
.push(instance);
}
} else {
if fast_path {
self.mask_instances_fast.push(instance);
} else {
self.mask_instances_slow.push(instance);
}
}
}
);
}
ClipItemKind::Rectangle { rect, mode, .. } => {
let mut writer = gpu_buffer_builder.write_blocks(3);
writer.push_one(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();
let draw_clip_prim = is_same_coord_system && mode == ClipMode::Clip;
if draw_clip_prim {
let clip_transform_id = transforms.get_id(
clip_node.item.spatial_node_index,
info.raster_spatial_node_index,
spatial_tree,
);
let clip_prim_address = write_prim_blocks(
gpu_buffer_builder,
rect,
rect,
PremultipliedColorF::WHITE,
&[],
);
add_quad_to_batch(
render_task_address,
clip_transform_id,
clip_prim_address,
info.quad_flags,
EdgeAaSegmentMask::empty(),
INVALID_SEGMENT_INDEX as u8,
RenderTaskId::INVALID,
ZBufferId(0),
render_tasks,
|_, prim| {
let instance = MaskInstance {
prim,
clip_transform_id: TransformPaletteId::IDENTITY,
clip_address: clip_address.as_int(),
info: [0; 2],
};
if info.needs_scissor_rect {
self.mask_instances_fast_with_scissor
.entry(target_rect)
.or_insert(Vec::new())
.push(instance);
} else {
self.mask_instances_fast.push(instance);
}
}
);
} else {
let clip_transform_id = transforms.get_id(
info.prim_spatial_node_index,
clip_node.item.spatial_node_index,
spatial_tree,
);
add_quad_to_batch(
render_task_address,
info.transform_id,
info.prim_address,
info.quad_flags,
info.edge_flags,
INVALID_SEGMENT_INDEX as u8,
RenderTaskId::INVALID,
ZBufferId(0),
render_tasks,
|_, prim| {
let instance = MaskInstance {
prim,
clip_transform_id,
clip_address: clip_address.as_int(),
info: [0; 2],
};
if info.needs_scissor_rect {
self.mask_instances_fast_with_scissor
.entry(target_rect)
.or_insert(Vec::new())
.push(instance);
} else {
self.mask_instances_fast.push(instance);
}
}
);
}
}
ClipItemKind::BoxShadow { .. } => {
panic!("bug: box-shadow clips not expected on non-legacy rect/quads");
}
ClipItemKind::Image { .. } => {
panic!("bug: image-masks not expected on rect/quads");
}
};
}
}
}
impl RenderTarget for ColorRenderTarget {
fn new(
texture_id: CacheTextureId,
@ -399,60 +600,16 @@ impl RenderTarget for ColorRenderTarget {
}
);
let mask_instances_fast = &mut self.mask_instances_fast;
let mask_instances_slow = &mut self.mask_instances_slow;
let mask_instances_fast_with_scissor = &mut self.mask_instances_fast_with_scissor;
let mask_instances_slow_with_scissor = &mut self.mask_instances_slow_with_scissor;
build_mask_tasks(
info.clip_node_range,
info.prim_spatial_node_index,
self.build_mask_tasks(
info,
render_task_address,
target_rect,
ctx.clip_store,
ctx.data_stores,
ctx.spatial_tree,
gpu_buffer_builder,
transforms,
|fast_path, clip_address, clip_transform_id| {
add_quad_to_batch(
render_task_address,
info.transform_id,
info.prim_address,
info.quad_flags,
info.edge_flags,
INVALID_SEGMENT_INDEX as u8,
RenderTaskId::INVALID,
ZBufferId(0),
render_tasks,
|_, prim| {
let instance = MaskInstance {
prim,
clip_transform_id,
clip_address: clip_address.as_int(),
info: [0; 2],
};
if info.needs_scissor_rect {
if fast_path {
mask_instances_fast_with_scissor
.entry(target_rect)
.or_insert(Vec::new())
.push(instance);
} else {
mask_instances_slow_with_scissor
.entry(target_rect)
.or_insert(Vec::new())
.push(instance);
}
} else {
if fast_path {
mask_instances_fast.push(instance);
} else {
mask_instances_slow.push(instance);
}
}
}
);
}
render_tasks,
);
}
RenderTaskKind::VerticalBlur(..) => {
@ -875,86 +1032,6 @@ fn add_scaling_instances(
});
}
fn build_mask_tasks<F>(
clips_range: ClipNodeRange,
prim_spatial_node_index: SpatialNodeIndex,
clip_store: &ClipStore,
data_stores: &DataStores,
spatial_tree: &SpatialTree,
gpu_buffer_builder: &mut GpuBufferBuilder,
transforms: &mut TransformPalette,
mut f: F,
) where F: FnMut(bool, GpuBufferAddress, TransformPaletteId) {
for i in 0 .. clips_range.count {
let clip_instance = clip_store.get_instance_from_range(&clips_range, i);
let clip_node = &data_stores.clip[clip_instance.handle];
// TODO(gw): We know that the prim <-> clip mapping is 2d in this initial patch
// set, due to the checks in `can_use_clip_chain_for_quad_path`. The
// next set of patches needs to account for perspective here in how
// we draw the mask.
let clip_transform_id = transforms.get_id(
prim_spatial_node_index,
clip_node.item.spatial_node_index,
spatial_tree,
);
match clip_node.item.kind {
ClipItemKind::RoundedRectangle { rect, radius, mode } => {
let (fast_path, clip_address) = if radius.is_uniform().is_some() {
let mut writer = gpu_buffer_builder.write_blocks(3);
writer.push_one(rect);
writer.push_one([radius.top_left.width, 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();
(true, clip_address)
} else {
let mut writer = gpu_buffer_builder.write_blocks(4);
writer.push_one(rect);
writer.push_one([
radius.top_left.width,
radius.top_left.height,
radius.top_right.width,
radius.top_right.height,
]);
writer.push_one([
radius.bottom_left.width,
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]);
let clip_address = writer.finish();
(false, clip_address)
};
f(fast_path, clip_address, clip_transform_id);
}
ClipItemKind::Rectangle { rect, mode: ClipMode::ClipOut, .. } => {
let mut writer = gpu_buffer_builder.write_blocks(3);
writer.push_one(rect);
writer.push_one([0.0, 0.0, 0.0, 0.0]);
writer.push_one([ClipMode::ClipOut as i32 as f32, 0.0, 0.0, 0.0]);
let clip_address = writer.finish();
f(true, clip_address, clip_transform_id);
}
ClipItemKind::Rectangle { mode: ClipMode::Clip, .. } => {
// Handled by local clip rect in vertex shader
}
ClipItemKind::BoxShadow { .. } => {
panic!("bug: box-shadow clips not expected on non-legacy rect/quads");
}
ClipItemKind::Image { .. } => {
panic!("bug: image-masks not expected on rect/quads");
}
}
}
}
fn add_svg_filter_instances(
instances: &mut Vec<(BatchTextures, Vec<SvgFilterInstance>)>,
render_tasks: &RenderTaskGraph,

Просмотреть файл

@ -180,6 +180,7 @@ pub struct PrimTask {
pub content_origin: DevicePoint,
pub prim_address: GpuBufferAddress,
pub prim_spatial_node_index: SpatialNodeIndex,
pub raster_spatial_node_index: SpatialNodeIndex,
pub transform_id: TransformPaletteId,
pub edge_flags: EdgeAaSegmentMask,
pub quad_flags: QuadFlags,
@ -505,6 +506,7 @@ impl RenderTaskKind {
pub fn new_prim(
prim_spatial_node_index: SpatialNodeIndex,
raster_spatial_node_index: SpatialNodeIndex,
device_pixel_scale: DevicePixelScale,
content_origin: DevicePoint,
prim_address: GpuBufferAddress,
@ -516,6 +518,7 @@ impl RenderTaskKind {
) -> Self {
RenderTaskKind::Prim(PrimTask {
prim_spatial_node_index,
raster_spatial_node_index,
device_pixel_scale,
content_origin,
prim_address,

Просмотреть файл

@ -2186,21 +2186,22 @@ impl Renderer {
return;
}
self.device.disable_depth_write();
{
let _timer = self.gpu_profiler.start_timer(GPU_TAG_INDIRECT_PRIM);
self.device.disable_depth_write();
self.set_blend(false, FramebufferKind::Other);
self.shaders.borrow_mut().ps_quad_textured.bind(
&mut self.device,
projection,
None,
&mut self.renderer_errors,
&mut self.profile,
);
if !prim_instances.is_empty() {
self.set_blend(false, FramebufferKind::Other);
self.shaders.borrow_mut().ps_quad_textured.bind(
&mut self.device,
projection,
None,
&mut self.renderer_errors,
&mut self.profile,
);
self.draw_instanced_batch(
prim_instances,
VertexArrayKind::Primitive,
@ -2210,8 +2211,18 @@ impl Renderer {
}
if !prim_instances_with_scissor.is_empty() {
self.set_blend(true, FramebufferKind::Other);
self.device.set_blend_mode_premultiplied_alpha();
self.device.enable_scissor();
self.shaders.borrow_mut().ps_quad_textured.bind(
&mut self.device,
projection,
None,
&mut self.renderer_errors,
&mut self.profile,
);
for (scissor_rect, prim_instances) in prim_instances_with_scissor {
self.device.set_scissor_rect(draw_target.to_framebuffer_rect(*scissor_rect));

Двоичные данные
gfx/wr/wrench/reftests/aa/indirect-rotate.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.4 KiB

Просмотреть файл

@ -0,0 +1,16 @@
# Verify that we select correct blend mode for indirect rotated primitives with an
# axis-aligned clip. This allows SWGL to correctly apply the native AA.
---
root:
items:
- type: clip
bounds: 110 100 180 200
id: 3
- bounds: 100 100 200 100
type: stacking-context
transform: rotate-y(10) rotate-x(30)
clip-chain: [3]
items:
- type: rect
bounds: 0 0 200 100
color: blue

Просмотреть файл

@ -2,3 +2,4 @@ skip_on(android) fuzzy(1,1) fuzzy-if(platform(swgl),4,27) == rounded-rects.yaml
== aa-dist-bug.yaml aa-dist-bug-ref.yaml
fuzzy-if(env(android,device),6,792) == fractional-radii.yaml fractional-radii-ref.yaml
platform(linux) == fractional-nine-patch.yaml fractional-nine-patch.png
platform(linux) == indirect-rotate.yaml indirect-rotate.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 13 KiB

После

Ширина:  |  Высота:  |  Размер: 13 KiB