Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# these and list no features. Needs cargo-nextest.
[alias]
# The features CI adds to the default build; the one place they are listed.
ci-nextest = "nextest run --workspace --features jitv2,rex-gpu,rex-jit"
ci-nextest = "nextest run --workspace --features jitv2,rex-jit,gputrace"
ci-test = "ci-nextest --profile ci"
# The default features alone: the only run of the real-cache path that tcache
# (implied by jitv2) compiles out.
Expand Down
11 changes: 6 additions & 5 deletions src/wgpu/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -506,11 +506,12 @@ impl Gpu {

/// Block until `submission` has finished (or everything, with None).
pub fn wait(&self, submission: Option<wgpu::SubmissionIndex>) -> Result<(), String> {
self.device
.poll(wgpu::PollType::Wait { submission_index: submission, timeout: Some(Duration::from_secs(30)) })
.map(|_| ())
.map_err(|e| format!("wait for GPU: {e}"))?;
self.check()
let waited = self.device.poll(wgpu::PollType::Wait { submission_index: submission, timeout: Some(Duration::from_secs(30)) });
// wgpu cannot wait for a submission it refused (a pipeline that
// failed to build, a lost device); the error that refused it is
// the one to report.
self.check()?;
waited.map(|_| ()).map_err(|e| format!("wait for GPU: {e}"))
}

/// Let callbacks run without blocking.
Expand Down
29 changes: 29 additions & 0 deletions src/wgpu/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,3 +378,32 @@ fn empty_flush_is_a_no_op() {
assert!(board.batch.flush(&board.pipelines, &[&board.vram_group]).is_none());
assert!(board.plane().iter().all(|&w| w == 0));
}

/// A pipeline that fails to build makes the submission that uses it fail,
/// and wgpu cannot wait for a failed submission. The wait reports the build
/// error, not the missing submission.
#[test]
fn a_refused_submission_reports_why() {
let Some(gpu) = gpu() else { return };
let module = gpu.device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("refused"),
source: wgpu::ShaderSource::Wgsl("@compute @workgroup_size(1) fn main() { let x: u32 = 1.5; }".into()),
});
let pipeline = gpu.device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
label: Some("refused"),
layout: None,
module: &module,
entry_point: Some("main"),
compilation_options: Default::default(),
cache: None,
});
let mut encoder = gpu.encoder("refused");
{
let mut pass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor::default());
pass.set_pipeline(&pipeline);
pass.dispatch_workgroups(1, 1, 1);
}
let index = gpu.submit(encoder);
let err = gpu.wait(Some(index)).unwrap_err();
assert!(err.starts_with("wgpu error"), "{err}");
}