Bug 1523495 - Adjust shadow blur target sizes to avoid down-scaling artifacts. r=gw
authorNicolas Silva <nsilva@mozilla.com>
Wed, 06 Feb 2019 16:08:24 +0100
changeset 458695 4f7935bfb0eb
parent 458694 bf40d50fa8af
child 458696 782ec3fc98e0
push id35544
push userccoroiu@mozilla.com
push dateTue, 12 Feb 2019 16:29:08 +0000
treeherdermozilla-central@c849fb69e2e7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgw
bugs1523495
milestone67.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 1523495 - Adjust shadow blur target sizes to avoid down-scaling artifacts. r=gw Differential Revision: https://phabricator.services.mozilla.com/D18856
gfx/wr/webrender/src/picture.rs
gfx/wr/webrender/src/render_task.rs
--- a/gfx/wr/webrender/src/picture.rs
+++ b/gfx/wr/webrender/src/picture.rs
@@ -2955,29 +2955,32 @@ impl PicturePrimitive {
 
                 surfaces[surface_index.0].tasks.push(render_task_id);
 
                 PictureSurface::RenderTask(render_task_id)
             }
             PictureCompositeMode::Filter(FilterOp::DropShadow(offset, blur_radius, color)) => {
                 let blur_std_deviation = blur_radius * frame_context.device_pixel_scale.0;
                 let blur_range = (blur_std_deviation * BLUR_SAMPLE_SCALE).ceil() as i32;
-
+                let rounded_std_dev = blur_std_deviation.round();
                 // 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
                 // blur results, inflate that clipped area by the blur range, and
                 // then intersect with the total screen rect, to minimize the
                 // allocation size.
-                let device_rect = clipped
-                    .inflate(blur_range, blur_range)
-                    .intersection(&unclipped.to_i32())
-                    .unwrap();
+                let mut device_rect = clipped.inflate(blur_range, blur_range)
+                        .intersection(&unclipped.to_i32())
+                        .unwrap();
+                device_rect.size = RenderTask::adjusted_blur_source_size(
+                    device_rect.size,
+                    rounded_std_dev,
+                );
 
                 let uv_rect_kind = calculate_uv_rect_kind(
                     &pic_rect,
                     &transform,
                     &device_rect,
                     frame_context.device_pixel_scale,
                     true,
                 );
@@ -2991,17 +2994,17 @@ impl PicturePrimitive {
                     uv_rect_kind,
                     pic_context.raster_spatial_node_index,
                 );
                 picture_task.mark_for_saving();
 
                 let picture_task_id = frame_state.render_tasks.add(picture_task);
 
                 let blur_render_task = RenderTask::new_blur(
-                    blur_std_deviation.round(),
+                    rounded_std_dev,
                     picture_task_id,
                     frame_state.render_tasks,
                     RenderTargetKind::Color,
                     ClearMode::Transparent,
                 );
 
                 self.secondary_render_task_id = Some(picture_task_id);
 
--- a/gfx/wr/webrender/src/render_task.rs
+++ b/gfx/wr/webrender/src/render_task.rs
@@ -621,16 +621,35 @@ impl RenderTask {
             RenderTaskKind::ClipRegion(ClipRegionTask {
                 clip_data_address,
                 local_pos,
             }),
             ClearMode::One,
         )
     }
 
+    // In order to do the blur down-scaling passes without introducing errors, we need the
+    // source of each down-scale pass to be a multuple of two. If need be, this inflates
+    // the source size so that each down-scale pass will sample correctly.
+    pub fn adjusted_blur_source_size(original_size: DeviceIntSize, mut std_dev: f32) -> DeviceIntSize {
+        let mut adjusted_size = original_size;
+        let mut scale_factor = 1.0;
+        while std_dev > MAX_BLUR_STD_DEVIATION {
+            if adjusted_size.width < MIN_DOWNSCALING_RT_SIZE ||
+               adjusted_size.height < MIN_DOWNSCALING_RT_SIZE {
+                break;
+            }
+            std_dev *= 0.5;
+            scale_factor *= 2.0;
+            adjusted_size = (original_size.to_f32() / scale_factor).ceil().to_i32();
+        }
+
+        adjusted_size * scale_factor as i32
+    }
+
     // Construct a render task to apply a blur to a primitive.
     // The render task chain that is constructed looks like:
     //
     //    PrimitiveCacheTask: Draw the primitives.
     //           ^
     //           |
     //    DownscalingTask(s): Each downscaling task reduces the size of render target to
     //           ^            half. Also reduce the std deviation to half until the std