Bug 1573886 - Fix backdrop-filter blur errors due to incorrect scaling r=kvark
authorConnor Brewster <cbrewster@mozilla.com>
Wed, 14 Aug 2019 20:13:06 +0000
changeset 488056 26094588b48e14bb39fb838196e8d489b1a4c3ee
parent 488055 ed066ea4b64cf7ec8253027ad11bf0f90d12c27b
child 488057 144fbfb409b72b5849ace2a1e3c199c259f7c1d3
child 488155 e777dd79ae26a8d420083de3a5b774aa4a6bdaca
push id36434
push usercbrindusan@mozilla.com
push dateThu, 15 Aug 2019 09:44:30 +0000
treeherdermozilla-central@144fbfb409b7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskvark
bugs1573886
milestone70.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1573886 - Fix backdrop-filter blur errors due to incorrect scaling r=kvark Differential Revision: https://phabricator.services.mozilla.com/D42013
gfx/wr/webrender/res/cs_blur.glsl
gfx/wr/webrender/src/picture.rs
gfx/wr/webrender/src/render_task.rs
--- a/gfx/wr/webrender/res/cs_blur.glsl
+++ b/gfx/wr/webrender/res/cs_blur.glsl
@@ -20,24 +20,26 @@ flat varying int vSupport;
 
 in int aBlurRenderTaskAddress;
 in int aBlurSourceTaskAddress;
 in int aBlurDirection;
 
 struct BlurTask {
     RenderTaskCommonData common_data;
     float blur_radius;
+    vec2 blur_region;
 };
 
 BlurTask fetch_blur_task(int address) {
     RenderTaskData task_data = fetch_render_task_data(address);
 
     BlurTask task = BlurTask(
         task_data.common_data,
-        task_data.user_data.x
+        task_data.user_data.x,
+        task_data.user_data.yz
     );
 
     return task;
 }
 
 void main(void) {
     BlurTask blur_task = fetch_blur_task(aBlurRenderTaskAddress);
     RenderTaskCommonData src_task = fetch_render_task_common_data(aBlurSourceTaskAddress);
@@ -67,17 +69,17 @@ void main(void) {
         case DIR_VERTICAL:
             vOffsetScale = vec2(0.0, 1.0 / texture_size.y);
             break;
         default:
             vOffsetScale = vec2(0.0);
     }
 
     vUvRect = vec4(src_rect.p0 + vec2(0.5),
-                   src_rect.p0 + src_rect.size - vec2(0.5));
+                   src_rect.p0 + blur_task.blur_region - vec2(0.5));
     vUvRect /= texture_size.xyxy;
 
     vec2 pos = target_rect.p0 + target_rect.size * aPosition.xy;
 
     vec2 uv0 = src_rect.p0 / texture_size;
     vec2 uv1 = (src_rect.p0 + src_rect.size) / texture_size;
     vUv.xy = mix(uv0, uv1, aPosition.xy);
 
--- a/gfx/wr/webrender/src/picture.rs
+++ b/gfx/wr/webrender/src/picture.rs
@@ -2558,17 +2558,17 @@ impl PicturePrimitive {
                 let dep_info = match raster_config.composite_mode {
                     PictureCompositeMode::Filter(Filter::Blur(blur_radius)) => {
                         let blur_std_deviation = blur_radius * device_pixel_scale.0;
                         let scale_factors = scale_factors(&transform);
                         let blur_std_deviation = DeviceSize::new(
                             blur_std_deviation * scale_factors.0,
                             blur_std_deviation * scale_factors.1
                         );
-                        let device_rect = if self.options.inflate_if_required {
+                        let mut device_rect = if self.options.inflate_if_required {
                             let inflation_factor = frame_state.surfaces[raster_config.surface_index.0].inflation_factor;
                             let inflation_factor = (inflation_factor * device_pixel_scale.0).ceil();
 
                             // The clipped field is the part of the picture that is visible
                             // on screen. The unclipped field is the screen-space rect of
                             // the complete picture, if no screen / clip-chain was applied
                             // (this includes the extra space for blur region). To ensure
                             // that we draw a large enough part of the picture to get correct
@@ -2577,36 +2577,36 @@ impl PicturePrimitive {
                             // allocation size.
                             // We cast clipped to f32 instead of casting unclipped to i32
                             // because unclipped can overflow an i32.
                             let device_rect = clipped.to_f32()
                                 .inflate(inflation_factor, inflation_factor)
                                 .intersection(&unclipped)
                                 .unwrap();
 
-                            let mut device_rect = match device_rect.try_cast::<i32>() {
+                            match device_rect.try_cast::<i32>() {
                                 Some(rect) => rect,
                                 None => {
                                     return None
                                 }
-                            };
-
-                            // Adjust the size to avoid introducing sampling errors during the down-scaling passes.
-                            // what would be even better is to rasterize the picture at the down-scaled size
-                            // directly.
-                            device_rect.size = RenderTask::adjusted_blur_source_size(
-                                device_rect.size,
-                                blur_std_deviation,
-                            );
-
-                            device_rect
+                            }
                         } else {
                             clipped
                         };
 
+                        let original_size = device_rect.size;
+
+                        // Adjust the size to avoid introducing sampling errors during the down-scaling passes.
+                        // what would be even better is to rasterize the picture at the down-scaled size
+                        // directly.
+                        device_rect.size = RenderTask::adjusted_blur_source_size(
+                            device_rect.size,
+                            blur_std_deviation,
+                        );
+
                         let uv_rect_kind = calculate_uv_rect_kind(
                             &pic_rect,
                             &transform,
                             &device_rect,
                             device_pixel_scale,
                             true,
                         );
 
@@ -2625,16 +2625,17 @@ impl PicturePrimitive {
 
                         let blur_render_task_id = RenderTask::new_blur(
                             blur_std_deviation,
                             picture_task_id,
                             frame_state.render_tasks,
                             RenderTargetKind::Color,
                             ClearMode::Transparent,
                             None,
+                            original_size,
                         );
 
                         Some((blur_render_task_id, picture_task_id))
                     }
                     PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => {
                         let mut max_std_deviation = 0.0;
                         for shadow in shadows {
                             // TODO(nical) presumably we should compute the clipped rect for each shadow
@@ -2696,16 +2697,17 @@ impl PicturePrimitive {
                             let std_dev = f32::round(shadow.blur_radius * device_pixel_scale.0);
                             blur_render_task_id = RenderTask::new_blur(
                                 DeviceSize::new(std_dev, std_dev),
                                 picture_task_id,
                                 frame_state.render_tasks,
                                 RenderTargetKind::Color,
                                 ClearMode::Transparent,
                                 Some(&mut blur_tasks),
+                                device_rect.size,
                             );
                         }
 
                         // TODO(nical) the second one should to be the blur's task id but we have several blurs now
                         Some((blur_render_task_id, picture_task_id))
                     }
                     PictureCompositeMode::MixBlend(..) if !frame_context.fb_config.gpu_supports_advanced_blend => {
                         let uv_rect_kind = calculate_uv_rect_kind(
--- a/gfx/wr/webrender/src/render_task.rs
+++ b/gfx/wr/webrender/src/render_task.rs
@@ -554,16 +554,17 @@ pub struct PictureTask {
 
 #[derive(Debug)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct BlurTask {
     pub blur_std_deviation: f32,
     pub target_kind: RenderTargetKind,
     pub uv_rect_handle: GpuCacheHandle,
+    pub blur_region: DeviceIntSize,
     uv_rect_kind: UvRectKind,
 }
 
 impl BlurTask {
     #[cfg(feature = "debugger")]
     fn print_with<T: PrintTreePrinter>(&self, pt: &mut T) {
         pt.add_item(format!("std deviation: {}", self.blur_std_deviation));
         pt.add_item(format!("target: {:?}", self.target_kind));
@@ -970,16 +971,17 @@ impl RenderTask {
                             // Blur it
                             RenderTask::new_blur(
                                 DeviceSize::new(blur_radius_dp, blur_radius_dp),
                                 mask_task_id,
                                 render_tasks,
                                 RenderTargetKind::Alpha,
                                 ClearMode::Zero,
                                 None,
+                                cache_size,
                             )
                         }
                     ));
                 }
                 ClipItem::Rectangle(_, ClipMode::Clip) => {
                     if !clip_instance.flags.contains(ClipNodeFlags::SAME_COORD_SYSTEM) {
                         // This is conservative - it's only the case that we actually need
                         // a clear here if we end up adding this mask via add_tiled_clip_mask,
@@ -1081,16 +1083,17 @@ impl RenderTask {
     //
     pub fn new_blur(
         blur_std_deviation: DeviceSize,
         src_task_id: RenderTaskId,
         render_tasks: &mut RenderTaskGraph,
         target_kind: RenderTargetKind,
         clear_mode: ClearMode,
         mut blur_cache: Option<&mut BlurTaskCache>,
+        blur_region: DeviceIntSize,
     ) -> RenderTaskId {
         // Adjust large std deviation value.
         let mut adjusted_blur_std_deviation = blur_std_deviation;
         let (blur_target_size, uv_rect_kind) = {
             let src_task = &render_tasks[src_task_id];
             (src_task.get_dynamic_size(), src_task.uv_rect_kind())
         };
         let mut adjusted_blur_target_size = blur_target_size;
@@ -1132,38 +1135,42 @@ impl RenderTask {
 
         let blur_key = BlurTaskKey::downscale_and_blur(n_downscales, adjusted_blur_std_deviation);
 
         let cached_task = match blur_cache {
             Some(ref mut cache) => cache.get(&blur_key).cloned(),
             None => None,
         };
 
+        let blur_region = blur_region / (scale_factor as i32);
+
         let blur_task_id = cached_task.unwrap_or_else(|| {
             let blur_task_v = RenderTask::with_dynamic_location(
                 adjusted_blur_target_size,
                 vec![downscaling_src_task_id],
                 RenderTaskKind::VerticalBlur(BlurTask {
                     blur_std_deviation: adjusted_blur_std_deviation.height,
                     target_kind,
                     uv_rect_handle: GpuCacheHandle::new(),
+                    blur_region,
                     uv_rect_kind,
                 }),
                 clear_mode,
             );
 
             let blur_task_v_id = render_tasks.add(blur_task_v);
 
             let blur_task_h = RenderTask::with_dynamic_location(
                 adjusted_blur_target_size,
                 vec![blur_task_v_id],
                 RenderTaskKind::HorizontalBlur(BlurTask {
                     blur_std_deviation: adjusted_blur_std_deviation.width,
                     target_kind,
                     uv_rect_handle: GpuCacheHandle::new(),
+                    blur_region,
                     uv_rect_kind,
                 }),
                 clear_mode,
             );
 
             render_tasks.add(blur_task_h)
         });
 
@@ -1358,16 +1365,17 @@ impl RenderTask {
 
                     RenderTask::new_blur(
                         DeviceSize::new(blur_std_deviation, blur_std_deviation),
                         render_tasks.add(svg_task),
                         render_tasks,
                         RenderTargetKind::Color,
                         ClearMode::Transparent,
                         None,
+                        content_size,
                     )
                 }
                 FilterPrimitiveKind::Opacity(ref opacity) => {
                     let input_task_id = get_task_input(
                         &opacity.input,
                         filter_primitives,
                         render_tasks,
                         cur_index,
@@ -1427,16 +1435,17 @@ impl RenderTask {
 
                     let blur_task_id = RenderTask::new_blur(
                         DeviceSize::new(blur_std_deviation, blur_std_deviation),
                         offset_task_id,
                         render_tasks,
                         RenderTargetKind::Color,
                         ClearMode::Transparent,
                         None,
+                        content_size,
                     );
 
                     let task = RenderTask::new_svg_filter_primitive(
                         vec![input_task_id, blur_task_id],
                         content_size,
                         uv_rect_kind,
                         SvgFilterInfo::DropShadow(drop_shadow.shadow.color),
                     );
@@ -1580,18 +1589,18 @@ impl RenderTask {
                     0.0,
                     0.0,
                 ]
             }
             RenderTaskKind::VerticalBlur(ref task) |
             RenderTaskKind::HorizontalBlur(ref task) => {
                 [
                     task.blur_std_deviation,
-                    0.0,
-                    0.0,
+                    task.blur_region.width as f32,
+                    task.blur_region.height as f32,
                 ]
             }
             RenderTaskKind::Readback(..) |
             RenderTaskKind::Scaling(..) |
             RenderTaskKind::Border(..) |
             RenderTaskKind::LineDecoration(..) |
             RenderTaskKind::Gradient(..) |
             RenderTaskKind::Blit(..) => {