diff --git a/gfx/wr/webrender/src/display_list_flattener.rs b/gfx/wr/webrender/src/display_list_flattener.rs index 5e34dc4c40fe..46cf0c536f54 100644 --- a/gfx/wr/webrender/src/display_list_flattener.rs +++ b/gfx/wr/webrender/src/display_list_flattener.rs @@ -1319,22 +1319,26 @@ impl<'a> DisplayListFlattener<'a> { // (b) It's useful for the initial version of picture caching in gecko, by enabling // is to just look for interesting scroll roots on the root stacking context, // without having to consider cuts at stacking context boundaries. - if let Some(parent_sc) = self.sc_stack.last_mut() { - if stacking_context.is_redundant( - parent_sc, - self.clip_scroll_tree, - ) { - // If the parent context primitives list is empty, it's faster - // to assign the storage of the popped context instead of paying - // the copying cost for extend. - if parent_sc.primitives.is_empty() { - parent_sc.primitives = stacking_context.primitives; - } else { - parent_sc.primitives.extend(stacking_context.primitives); + let parent_is_empty = match self.sc_stack.last_mut() { + Some(parent_sc) => { + if stacking_context.is_redundant( + parent_sc, + self.clip_scroll_tree, + ) { + // If the parent context primitives list is empty, it's faster + // to assign the storage of the popped context instead of paying + // the copying cost for extend. + if parent_sc.primitives.is_empty() { + parent_sc.primitives = stacking_context.primitives; + } else { + parent_sc.primitives.extend(stacking_context.primitives); + } + return; } - return; - } - } + parent_sc.primitives.is_empty() + }, + None => true, + }; if stacking_context.create_tile_cache { self.setup_picture_caching( @@ -1499,8 +1503,19 @@ impl<'a> DisplayListFlattener<'a> { self.prim_store.optimize_picture_if_possible(current_pic_index); } - // Same for mix-blend-mode. - if let Some(mix_blend_mode) = stacking_context.composite_ops.mix_blend_mode { + // 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: + // Cs = (1 - ab) x Cs + ab x Blend(Cb, Cs) + // where + // Cs = Source color + // ab = Backdrop alpha + // Cb = Backdrop color + // + // If we're the first primitive within a stacking context, then we can guarantee that the + // backdrop alpha will be 0, and then the blend equation collapses to just + // Cs = Cs, and the blend mode isn't taken into account at all. + if let (Some(mix_blend_mode), false) = (stacking_context.composite_ops.mix_blend_mode, parent_is_empty) { let composite_mode = Some(PictureCompositeMode::MixBlend(mix_blend_mode)); let blend_pic_index = PictureIndex(self.prim_store.pictures @@ -1544,6 +1559,7 @@ impl<'a> DisplayListFlattener<'a> { let has_mix_blend_on_secondary_framebuffer = stacking_context.composite_ops.mix_blend_mode.is_some() && + !parent_is_empty && self.sc_stack.len() > 2; // The primitive instance for the remainder of flat children of this SC @@ -2629,7 +2645,14 @@ impl FlattenedStackingContext { } // If there are filters / mix-blend-mode - if !self.composite_ops.is_empty() { + if !self.composite_ops.filters.is_empty() { + return false; + } + + // We can skip mix-blend modes if they are the first primitive in a stacking context, + // see pop_stacking_context for a full explanation. + if !self.composite_ops.mix_blend_mode.is_none() && + !parent.primitives.is_empty() { return false; } diff --git a/gfx/wr/wrench/reftests/blend/multiply-3.yaml b/gfx/wr/wrench/reftests/blend/multiply-3.yaml new file mode 100644 index 000000000000..057c22d57adf --- /dev/null +++ b/gfx/wr/wrench/reftests/blend/multiply-3.yaml @@ -0,0 +1,17 @@ +--- +root: + items: + - type: rect + bounds: [0, 0, 100, 100] + color: [0, 255, 0] + - type: stacking-context + bounds: [0, 0, 100, 100] + mix-blend-mode: multiply + items: + - type: stacking-context + bounds: [0, 0, 100, 100] + mix-blend-mode: multiply + items: + - type: rect + bounds: [0, 0, 100, 100] + color: [255, 128, 0] diff --git a/gfx/wr/wrench/reftests/blend/reftest.list b/gfx/wr/wrench/reftests/blend/reftest.list index d76c3954f086..995142def23f 100644 --- a/gfx/wr/wrench/reftests/blend/reftest.list +++ b/gfx/wr/wrench/reftests/blend/reftest.list @@ -1,5 +1,6 @@ == multiply.yaml multiply-ref.yaml == multiply-2.yaml multiply-2-ref.yaml +== color_targets(2) alpha_targets(0) multiply-3.yaml multiply-2-ref.yaml == difference.yaml difference-ref.yaml fuzzy(1,10000) == difference-transparent.yaml difference-transparent-ref.yaml == darken.yaml darken-ref.yaml diff --git a/layout/reftests/css-blending/reftest.list b/layout/reftests/css-blending/reftest.list index e408f735f3c9..fa4c2e73546e 100644 --- a/layout/reftests/css-blending/reftest.list +++ b/layout/reftests/css-blending/reftest.list @@ -6,12 +6,12 @@ fuzzy-if(webrender,1-3,1313-7888) == blend-gradient-background-color.html blend- fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-10000) fuzzy-if(skiaContent,0-1,0-30000) == background-blending-alpha.html background-blending-alpha-ref.html fuzzy-if(webrender,1-3,1313-7888) == background-blending-gradient-color.html background-blending-gradient-color-ref.html -fuzzy-if(azureSkiaGL,0-3,0-7597) fuzzy-if(cocoaWidget,0-3,0-7597) fuzzy-if(d2d,0-1,0-3800) fuzzy-if(d3d11,0-1,0-4200) fuzzy-if(skiaContent,0-2,0-9450) fuzzy-if(webrender,1-5,3938-23663) == background-blending-gradient-gradient.html background-blending-gradient-gradient-ref.html -fuzzy-if(azureSkiaGL,0-2,0-7174) fuzzy-if(webrender,1-1,1288-7887) == background-blending-gradient-image.html background-blending-gradient-color-ref.html +fuzzy-if(azureSkiaGL,0-3,0-7597) fuzzy-if(cocoaWidget,0-3,0-7597) fuzzy-if(d2d,0-1,0-3800) fuzzy-if(d3d11,0-1,0-4200) fuzzy-if(skiaContent,0-2,0-9450) fuzzy-if(webrender,1-5,3938-23925) == background-blending-gradient-gradient.html background-blending-gradient-gradient-ref.html +fuzzy-if(azureSkiaGL,0-2,0-7174) fuzzy-if(webrender,1-3,1288-7888) == background-blending-gradient-image.html background-blending-gradient-color-ref.html fuzzy-if(azureSkia||d2d||gtkWidget,0-1,0-10000) == background-blending-image-color-jpg.html background-blending-image-color-ref.html == background-blending-image-color-png.html background-blending-image-color-ref.html == background-blending-image-color-svg.html background-blending-image-color-ref.html -fuzzy-if(azureSkiaGL,0-2,0-7174) fuzzy-if(webrender,1-3,1313-7888) == background-blending-image-gradient.html background-blending-gradient-color-ref.html +fuzzy-if(azureSkiaGL,0-2,0-7174) fuzzy-if(webrender,1-3,1288-7888) == background-blending-image-gradient.html background-blending-gradient-color-ref.html == background-blending-image-image.html background-blending-image-color-ref.html == background-blending-isolation.html background-blending-isolation-ref.html == background-blending-list-repeat.html background-blending-list-repeat-ref.html @@ -87,7 +87,7 @@ fuzzy(0-1,0-6800) == clipped-opacity-containing-unclipped-mixblendmode.html clip == background-blending-background-attachement-fixed.html background-blending-background-attachement-fixed-ref.html == background-blending-background-attachement-fixed-scroll.html background-blending-background-attachement-fixed-scroll-ref.html -fuzzy-if(webrender,0-1,0-49710) == background-blend-mode-body-image.html background-blend-mode-body-image-ref.html +fuzzy-if(webrender,0-1,0-49719) == background-blend-mode-body-image.html background-blend-mode-body-image-ref.html fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-16408) fuzzy-if(Android,0-4,0-768) fuzzy-if(gtkWidget,0-1,0-132) fuzzy-if(skiaContent,0-1,0-800) fuzzy-if(d2d,0-1,0-33208) fuzzy-if(webrender,0-1,0-78472) == background-blend-mode-body-transparent-image.html background-blend-mode-body-transparent-image-ref.html == background-blending-moz-element.html background-blending-moz-element-ref.html