diff --git a/gfx/wr/webrender/src/prepare.rs b/gfx/wr/webrender/src/prepare.rs index 867c052445a7..713fa86e7010 100644 --- a/gfx/wr/webrender/src/prepare.rs +++ b/gfx/wr/webrender/src/prepare.rs @@ -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; } diff --git a/gfx/wr/webrender/src/render_target.rs b/gfx/wr/webrender/src/render_target.rs index 871fc1f46846..a440b149fde3 100644 --- a/gfx/wr/webrender/src/render_target.rs +++ b/gfx/wr/webrender/src/render_target.rs @@ -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>, } +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( - 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)>, render_tasks: &RenderTaskGraph, diff --git a/gfx/wr/webrender/src/render_task.rs b/gfx/wr/webrender/src/render_task.rs index efd62fcfc772..530d107ea967 100644 --- a/gfx/wr/webrender/src/render_task.rs +++ b/gfx/wr/webrender/src/render_task.rs @@ -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, diff --git a/gfx/wr/webrender/src/renderer/mod.rs b/gfx/wr/webrender/src/renderer/mod.rs index 9a1d5625ac7a..37231c8e1907 100644 --- a/gfx/wr/webrender/src/renderer/mod.rs +++ b/gfx/wr/webrender/src/renderer/mod.rs @@ -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)); diff --git a/gfx/wr/wrench/reftests/aa/indirect-rotate.png b/gfx/wr/wrench/reftests/aa/indirect-rotate.png new file mode 100644 index 000000000000..2110c35e154f Binary files /dev/null and b/gfx/wr/wrench/reftests/aa/indirect-rotate.png differ diff --git a/gfx/wr/wrench/reftests/aa/indirect-rotate.yaml b/gfx/wr/wrench/reftests/aa/indirect-rotate.yaml new file mode 100644 index 000000000000..1478c613aa43 --- /dev/null +++ b/gfx/wr/wrench/reftests/aa/indirect-rotate.yaml @@ -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 diff --git a/gfx/wr/wrench/reftests/aa/reftest.list b/gfx/wr/wrench/reftests/aa/reftest.list index 49d151cb3479..156556f6c507 100644 --- a/gfx/wr/wrench/reftests/aa/reftest.list +++ b/gfx/wr/wrench/reftests/aa/reftest.list @@ -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 diff --git a/gfx/wr/wrench/reftests/clip/clip-45-degree-rotation-ref.png b/gfx/wr/wrench/reftests/clip/clip-45-degree-rotation-ref.png index ec54c78aa034..81116d0f8e5e 100644 Binary files a/gfx/wr/wrench/reftests/clip/clip-45-degree-rotation-ref.png and b/gfx/wr/wrench/reftests/clip/clip-45-degree-rotation-ref.png differ