[backdrop_dyn] Handle upstream pipeline failure (#553)
Following #537 it is possible for the flatten stage to fail and flag a
failure. In some cases this can cause invalid / corrupt bounding box
data to propagate downstream, leading to a hang in the per-tile backdrop
calculation loop.
Triggering this is highly subtle, so I don't have a test case as part of
vello scenes that can reliably reproduce this. Regardless, it makes
sense to check for the upstream failures and terminate the work in
general.
I made backdrop_dyn check for any upstream failure and I didn't make it
signal its own failure flag. I also didn't change the logic in the CPU
shader since the other stages I checked (flatten, coarse) do not
implement error signaling in their CPU counterparts. Let me know if
you'd like me to work on those.
diff --git a/crates/shaders/src/cpu/backdrop.rs b/crates/shaders/src/cpu/backdrop.rs
index 9e60c52..41303e1 100644
--- a/crates/shaders/src/cpu/backdrop.rs
+++ b/crates/shaders/src/cpu/backdrop.rs
@@ -1,11 +1,11 @@
// Copyright 2023 the Vello Authors
// SPDX-License-Identifier: Apache-2.0 OR MIT OR Unlicense
-use vello_encoding::{ConfigUniform, Path, Tile};
+use vello_encoding::{BumpAllocators, ConfigUniform, Path, Tile};
use super::CpuBinding;
-fn backdrop_main(config: &ConfigUniform, paths: &[Path], tiles: &mut [Tile]) {
+fn backdrop_main(config: &ConfigUniform, _: &BumpAllocators, paths: &[Path], tiles: &mut [Tile]) {
for drawobj_ix in 0..config.layout.n_draw_objects {
let path = paths[drawobj_ix as usize];
let width = path.bbox[2] - path.bbox[0];
@@ -24,7 +24,8 @@
pub fn backdrop(_n_wg: u32, resources: &[CpuBinding]) {
let config = resources[0].as_typed();
- let paths = resources[1].as_slice();
- let mut tiles = resources[2].as_slice_mut();
- backdrop_main(&config, &paths, &mut tiles);
+ let bump = resources[1].as_typed();
+ let paths = resources[2].as_slice();
+ let mut tiles = resources[3].as_slice_mut();
+ backdrop_main(&config, &bump, &paths, &mut tiles);
}
diff --git a/shader/backdrop_dyn.wgsl b/shader/backdrop_dyn.wgsl
index 2664f6c..7bdf5c7 100644
--- a/shader/backdrop_dyn.wgsl
+++ b/shader/backdrop_dyn.wgsl
@@ -3,6 +3,7 @@
// Prefix sum for dynamically allocated backdrops
+#import bump
#import config
#import tile
@@ -10,9 +11,12 @@
var<uniform> config: Config;
@group(0) @binding(1)
-var<storage> paths: array<Path>;
+var<storage, read_write> bump: BumpAllocators;
@group(0) @binding(2)
+var<storage> paths: array<Path>;
+
+@group(0) @binding(3)
var<storage, read_write> tiles: array<Tile>;
let WG_SIZE = 256u;
@@ -26,6 +30,14 @@
@builtin(global_invocation_id) global_id: vec3<u32>,
@builtin(local_invocation_id) local_id: vec3<u32>,
) {
+ // Abort if any of the prior stages failed.
+ if local_id.x == 0u {
+ sh_row_count[0] = atomicLoad(&bump.failed);
+ }
+ let failed = workgroupUniformLoad(&sh_row_count[0]);
+ if failed != 0u {
+ return;
+ }
let drawobj_ix = global_id.x;
var row_count = 0u;
if drawobj_ix < config.n_drawobj {
@@ -34,6 +46,9 @@
sh_row_width[local_id.x] = path.bbox.z - path.bbox.x;
row_count = path.bbox.w - path.bbox.y;
sh_offset[local_id.x] = path.tiles;
+ } else {
+ // Explicitly zero the row width, just in case.
+ sh_row_width[local_id.x] = 0u;
}
sh_row_count[local_id.x] = row_count;
diff --git a/src/render.rs b/src/render.rs
index ab44615..a248de3 100644
--- a/src/render.rs
+++ b/src/render.rs
@@ -358,7 +358,7 @@
recording.dispatch(
shaders.backdrop,
wg_counts.backdrop,
- [config_buf, path_buf, tile_buf],
+ [config_buf, bump_buf, path_buf, tile_buf],
);
recording.dispatch(
shaders.coarse,
diff --git a/src/shaders.rs b/src/shaders.rs
index 2e3a699..7b9cdb9 100644
--- a/src/shaders.rs
+++ b/src/shaders.rs
@@ -180,7 +180,7 @@
);
let backdrop = add_shader!(
backdrop_dyn,
- [Uniform, BufReadOnly, Buffer],
+ [Uniform, Buffer, BufReadOnly, Buffer],
CpuShaderType::Present(vello_shaders::cpu::backdrop)
);
let coarse = add_shader!(