diff --git a/gfx/wr/webrender/src/batch.rs b/gfx/wr/webrender/src/batch.rs index 0e7a52802a8a..5d6ab620caaa 100644 --- a/gfx/wr/webrender/src/batch.rs +++ b/gfx/wr/webrender/src/batch.rs @@ -1640,6 +1640,38 @@ impl BatchBuilder { ctx, ); } + PictureCompositeMode::SvgFilter(..) => { + let kind = BatchKind::Brush( + BrushBatchKind::Image(ImageBufferKind::Texture2DArray) + ); + let (uv_rect_address, textures) = render_tasks.resolve_surface( + surface_task.expect("bug: surface must be allocated by now"), + gpu_cache, + ); + let key = BatchKey::new( + kind, + non_segmented_blend_mode, + textures, + ); + let prim_header_index = prim_headers.push(&prim_header, z_id, [ + ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16), + RasterizationSpace::Screen as i32, + get_shader_opacity(1.0), + 0, + ]); + + self.add_brush_instance_to_batches( + key, + bounding_rect, + z_id, + INVALID_SEGMENT_INDEX, + EdgeAaSegmentMask::empty(), + clip_task_address, + brush_flags, + prim_header_index, + uv_rect_address.as_int(), + ); + } } } None => { diff --git a/gfx/wr/webrender/src/display_list_flattener.rs b/gfx/wr/webrender/src/display_list_flattener.rs index d93bb13e4c91..ae6b41424eaf 100644 --- a/gfx/wr/webrender/src/display_list_flattener.rs +++ b/gfx/wr/webrender/src/display_list_flattener.rs @@ -1981,6 +1981,48 @@ impl<'a> DisplayListFlattener<'a> { self.prim_store.optimize_picture_if_possible(current_pic_index); } + if !stacking_context.composite_ops.filter_primitives.is_empty() { + let composite_mode = PictureCompositeMode::SvgFilter(stacking_context.composite_ops.filter_primitives.clone()); + + let filter_pic_index = PictureIndex(self.prim_store.pictures + .alloc() + .init(PicturePrimitive::new_image( + Some(composite_mode.clone()), + Picture3DContext::Out, + stacking_context.pipeline_id, + None, + true, + stacking_context.is_backface_visible, + stacking_context.requested_raster_space, + PrimitiveList::new( + vec![cur_instance.clone()], + &self.interners, + ), + stacking_context.spatial_node_index, + None, + PictureOptions::default(), + )) + ); + + current_pic_index = filter_pic_index; + cur_instance = create_prim_instance( + current_pic_index, + Some(composite_mode).into(), + stacking_context.is_backface_visible, + ClipChainId::NONE, + stacking_context.spatial_node_index, + &mut self.interners, + ); + + if cur_instance.is_chased() { + println!("\tis a composite picture for a stacking context with an SVG filter"); + } + + // Run the optimize pass on this picture, to see if we can + // collapse opacity and avoid drawing to an off-screen surface. + self.prim_store.optimize_picture_if_possible(current_pic_index); + } + // Same for mix-blend-mode, except we can skip if this primitive is the first in the parent // stacking context. // From https://drafts.fxtf.org/compositing-1/#generalformula, the formula for blending is: diff --git a/gfx/wr/webrender/src/picture.rs b/gfx/wr/webrender/src/picture.rs index 353c6cb15960..1489be31f2f4 100644 --- a/gfx/wr/webrender/src/picture.rs +++ b/gfx/wr/webrender/src/picture.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use api::{MixBlendMode, PipelineId, PremultipliedColorF}; -use api::{PropertyBinding, PropertyBindingId, FontRenderMode}; +use api::{PropertyBinding, PropertyBindingId, FilterPrimitive, FontRenderMode}; use api::{DebugFlags, RasterSpace, ImageKey, ColorF}; use api::units::*; use crate::box_shadow::{BLUR_SAMPLE_SCALE}; @@ -1573,6 +1573,8 @@ pub enum PictureCompositeMode { /// Used to cache a picture as a series of tiles. TileCache { }, + /// Apply an SVG filter + SvgFilter(Vec), } /// Enum value describing the place of a picture in a 3D context. @@ -1938,7 +1940,8 @@ impl PicturePrimitive { Some(RasterConfig { composite_mode: PictureCompositeMode::MixBlend(..), .. }) | Some(RasterConfig { composite_mode: PictureCompositeMode::Filter(..), .. }) | Some(RasterConfig { composite_mode: PictureCompositeMode::ComponentTransferFilter(..), .. }) | - Some(RasterConfig { composite_mode: PictureCompositeMode::TileCache { .. }, ..}) | + Some(RasterConfig { composite_mode: PictureCompositeMode::TileCache { .. }, .. }) | + Some(RasterConfig { composite_mode: PictureCompositeMode::SvgFilter(..), .. }) | None => { false } @@ -2442,6 +2445,30 @@ impl PicturePrimitive { Some((render_task_id, render_task_id)) } + PictureCompositeMode::SvgFilter(..) => { + let uv_rect_kind = calculate_uv_rect_kind( + &pic_rect, + &transform, + &clipped, + device_pixel_scale, + true, + ); + + let picture_task = RenderTask::new_picture( + RenderTaskLocation::Dynamic(None, clipped.size), + unclipped.size, + pic_index, + clipped.origin, + uv_rect_kind, + raster_spatial_node_index, + surface_spatial_node_index, + device_pixel_scale, + ); + + let render_task_id = frame_state.render_tasks.add(picture_task); + + (render_task_id, render_task_id) + } }; if let Some((root, port)) = dep_info { @@ -2990,7 +3017,8 @@ impl PicturePrimitive { filter_data.update(frame_state); } PictureCompositeMode::MixBlend(..) | - PictureCompositeMode::Blit(_) => {} + PictureCompositeMode::Blit(_) | + PictureCompositeMode::SvgFilter(_) => {} } true diff --git a/gfx/wr/webrender/src/prim_store/picture.rs b/gfx/wr/webrender/src/prim_store/picture.rs index ba05cc2dd83b..427c249de528 100644 --- a/gfx/wr/webrender/src/prim_store/picture.rs +++ b/gfx/wr/webrender/src/prim_store/picture.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use api::{ - ColorU, MixBlendMode, + ColorU, MixBlendMode, FilterPrimitive, PropertyBinding, PropertyBindingId, }; use api::units::{Au, LayoutSize, LayoutVector2D}; @@ -44,6 +44,7 @@ pub enum PictureCompositeKey { LinearToSrgb, ComponentTransfer(ItemUid), Flood(ColorU), + SvgFilter(Vec), // MixBlendMode Multiply, @@ -130,6 +131,9 @@ impl From> for PictureCompositeKey { Some(PictureCompositeMode::ComponentTransferFilter(handle)) => { PictureCompositeKey::ComponentTransfer(handle.uid()) } + Some(PictureCompositeMode::SvgFilter(filter_primitives)) => { + PictureCompositeKey::SvgFilter(filter_primitives) + } Some(PictureCompositeMode::Blit(_)) | Some(PictureCompositeMode::TileCache { .. }) | None => { diff --git a/gfx/wr/webrender_api/src/display_item.rs b/gfx/wr/webrender_api/src/display_item.rs index dd48635a77ad..72daa9b72b11 100644 --- a/gfx/wr/webrender_api/src/display_item.rs +++ b/gfx/wr/webrender_api/src/display_item.rs @@ -679,7 +679,7 @@ impl RasterSpace { } #[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub enum MixBlendMode { Normal = 0, Multiply = 1, @@ -701,7 +701,7 @@ pub enum MixBlendMode { /// An input to a SVG filter primitive. #[repr(C)] -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub enum FilterPrimitiveInput { /// The input is the original graphic that the filter is being applied to. Original, @@ -712,7 +712,7 @@ pub enum FilterPrimitiveInput { } #[repr(C)] -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub struct BlendPrimitive { pub input1: FilterPrimitiveInput, pub input2: FilterPrimitiveInput, @@ -721,7 +721,7 @@ pub struct BlendPrimitive { /// SVG Filter Primitive. #[repr(C)] -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub enum FilterPrimitive { Blend(BlendPrimitive), }