Skip to content

Commit 929691f

Browse files
committed
Bug 1941838 - more robust render task size clamping to resolve a rare panic r=gw,gfx-reviewers
Differential Revision: https://phabricator.services.mozilla.com/D235728
1 parent 03cb17a commit 929691f

File tree

3 files changed

+40
-17
lines changed

3 files changed

+40
-17
lines changed

webrender/src/picture.rs

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8050,7 +8050,11 @@ fn get_surface_rects(
80508050
}
80518051
};
80528052

8053+
// We need to put the clipped, unclipped and source rects in the chosen
8054+
// raster spatial node if possible, so that it will be rendered at the
8055+
// proper pixel scale with antialiasing, otherwise it would be blurry.
80538056
let (mut clipped, mut unclipped, mut source) = if surface.raster_spatial_node_index != surface.surface_spatial_node_index {
8057+
// Transform surface into the chosen raster spatial node
80548058
assert_eq!(surface.device_pixel_scale.0, 1.0);
80558059

80568060
let local_to_world = SpaceMapper::new_with_target(
@@ -8060,21 +8064,32 @@ fn get_surface_rects(
80608064
spatial_tree,
80618065
);
80628066

8063-
let clipped = (local_to_world.map(&clipped_local.cast_unit()).unwrap() * surface.device_pixel_scale).round_out();
8067+
let clipped = local_to_world.map(&clipped_local.cast_unit()).unwrap() * surface.device_pixel_scale;
80648068
let unclipped = local_to_world.map(&unclipped_local).unwrap() * surface.device_pixel_scale;
8065-
let source = (local_to_world.map(&source_local.cast_unit()).unwrap() * surface.device_pixel_scale).round_out();
8069+
let source = local_to_world.map(&source_local.cast_unit()).unwrap() * surface.device_pixel_scale;
80668070

80678071
(clipped, unclipped, source)
80688072
} else {
8069-
let clipped = (clipped_local.cast_unit() * surface.device_pixel_scale).round_out();
8073+
// Surface is already in the chosen raster spatial node
8074+
let clipped = clipped_local.cast_unit() * surface.device_pixel_scale;
80708075
let unclipped = unclipped_local.cast_unit() * surface.device_pixel_scale;
8071-
let source = (source_local.cast_unit() * surface.device_pixel_scale).round_out();
8076+
let source = source_local.cast_unit() * surface.device_pixel_scale;
80728077

80738078
(clipped, unclipped, source)
80748079
};
80758080

8076-
// Limit rendering extremely large pictures to something the hardware can
8077-
// handle, considering both clipped (target subregion) and source subregion.
8081+
// We need to make sure the surface size does not exceed max_surface_size,
8082+
// if it would exceed it we actually want to keep the surface in its local
8083+
// space and stop worrying about it being a little blurry.
8084+
//
8085+
// Use slightly less than max_surface_size to be safe as we're not using the
8086+
// rounded rect (which depending on subpixel alignment could add 1 or 2 to
8087+
// width), and leave room for SVGFEGraph to add a 1 pixel inflate border on
8088+
// all sides, so that it is less likely to have to do its own scaling on
8089+
// intermediates which would just add more layers of blurriness.
8090+
//
8091+
// Since both clipped and source are subject to the same limit, we can just
8092+
// pick the largest axis from all rects involved.
80788093
//
80798094
// If you change this, test with:
80808095
// ./mach crashtest layout/svg/crashtests/387290-1.svg
@@ -8084,28 +8099,36 @@ fn get_surface_rects(
80848099
source.width().max(
80858100
source.height()
80868101
))).ceil();
8087-
if max_dimension > max_surface_size {
8102+
let max_allowed_dimension = max_surface_size - 4.0;
8103+
if max_dimension > max_allowed_dimension {
8104+
// We have to recalculate max_dimension for the local space we'll be using
80888105
let max_dimension =
80898106
clipped_local.width().max(
80908107
clipped_local.height().max(
80918108
source_local.width().max(
80928109
source_local.height()
80938110
))).ceil();
80948111
surface.raster_spatial_node_index = surface.surface_spatial_node_index;
8095-
surface.device_pixel_scale = Scale::new(max_surface_size / max_dimension);
8112+
surface.device_pixel_scale = Scale::new(max_allowed_dimension / max_dimension);
80968113
surface.local_scale = (1.0, 1.0);
80978114

8098-
clipped = (clipped_local.cast_unit() * surface.device_pixel_scale).round();
8115+
clipped = clipped_local.cast_unit() * surface.device_pixel_scale;
80998116
unclipped = unclipped_local.cast_unit() * surface.device_pixel_scale;
8100-
source = (source_local.cast_unit() * surface.device_pixel_scale).round();
8117+
source = source_local.cast_unit() * surface.device_pixel_scale;
81018118
}
81028119

8103-
let task_size = clipped.size().to_i32();
8104-
debug_assert!(task_size.width <= max_surface_size as i32);
8105-
debug_assert!(task_size.height <= max_surface_size as i32);
8120+
let source = source.round_out();
8121+
let clipped_snapped = clipped.round_out();
8122+
let task_size = clipped_snapped.size().to_i32();
8123+
assert!(
8124+
task_size.width <= max_surface_size as i32 &&
8125+
task_size.height <= max_surface_size as i32,
8126+
"task_size {:?} must be within max_surface_size {}",
8127+
task_size,
8128+
max_surface_size);
81068129

81078130
let uv_rect_kind = calculate_uv_rect_kind(
8108-
clipped,
8131+
clipped_snapped,
81098132
unclipped,
81108133
);
81118134

@@ -8125,7 +8148,7 @@ fn get_surface_rects(
81258148
Some(SurfaceAllocInfo {
81268149
task_size,
81278150
needs_scissor_rect,
8128-
clipped,
8151+
clipped: clipped_snapped,
81298152
unclipped,
81308153
source,
81318154
clipped_local,

wrench/reftests/filters/reftest.list

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ fuzzy(12,10000) == svgfe-subregion-offset-stacking-context.yaml svgfe-subregion-
1111
== filter-grayscale.yaml filter-grayscale-ref.yaml
1212
platform(linux,mac) == draw_calls(7) color_targets(7) alpha_targets(0) filter-blur.yaml filter-blur.png
1313
platform(linux,mac) == filter-blur-downscale-fractional.yaml filter-blur-downscale-fractional.png
14-
max_surface_size(1024) fuzzy(9,41354) == filter-blur-downscaled-task.yaml filter-blur-downscaled-task-ref.yaml
14+
max_surface_size(1024) fuzzy(9,43152) == filter-blur-downscaled-task.yaml filter-blur-downscaled-task-ref.yaml
1515
== isolated.yaml isolated-ref.yaml
1616
== invisible.yaml invisible-ref.yaml
1717
fuzzy-if(platform(swgl),1,10000) == opacity.yaml opacity-ref.yaml

wrench/reftests/transforms/reftest.list

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ fuzzy(1,10) == flatten-all-flat.yaml flatten-all-flat-ref.yaml
4444
== strange-w.yaml strange-w-ref.yaml
4545
== big-axis-aligned-scale.yaml big-axis-aligned-scale-ref.yaml
4646
# Compare ~8K raster root (>MAX_SURFACE_SIZE) with ~2K raster root. fuzzy due to lerping on edges.
47-
skip_on(android) fuzzy(56,804) == raster_root_A_8192.yaml raster_root_A_ref.yaml
47+
skip_on(android) fuzzy(59,804) == raster_root_A_8192.yaml raster_root_A_ref.yaml
4848
# Same as large-raster-root.yaml but resulting in a 10302×100 raster root (= >4096) vs 4000x100 in ref:
4949
skip_on(android) fuzzy(60,917) == raster_root_B_8192.yaml raster_root_B_ref.yaml
5050
# Make sure we don't panic

0 commit comments

Comments
 (0)