Skip to content
Merged
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
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,15 @@ One other breaking change worth noting is that in WGSL `@builtin(view_index)` no

By @SupaMaggie70Incorporated in [#8206](https://github.com/gfx-rs/wgpu/pull/8206).

#### Error Scopes are now thread-local
#### Error scopes now use guards and are thread-local.

```diff
- device.push_error_scope(wgpu::ErrorFilter::Validation);
+ let scope = device.push_error_scope(wgpu::ErrorFilter::Validation);
// ... perform operations on the device ...
- let error: Option<Error> = device.pop_error_scope().await;
+ let error: Option<Error> = scope.pop().await;
```

Device error scopes now operate on a per-thread basis. This allows them to be used easily within multithreaded contexts,
without having the error scope capture errors from other threads.
Expand Down
2 changes: 0 additions & 2 deletions examples/features/src/ray_cube_compute/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -420,8 +420,6 @@ impl crate::framework::Example for Example {
}

fn render(&mut self, view: &wgpu::TextureView, device: &wgpu::Device, queue: &wgpu::Queue) {
device.push_error_scope(wgpu::ErrorFilter::Validation);

let anim_time = self.animation_timer.time();

self.tlas[0].as_mut().unwrap().transform =
Expand Down
2 changes: 0 additions & 2 deletions examples/features/src/ray_cube_fragment/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,6 @@ impl crate::framework::Example for Example {
}

fn render(&mut self, view: &wgpu::TextureView, device: &wgpu::Device, queue: &wgpu::Queue) {
device.push_error_scope(wgpu::ErrorFilter::Validation);

// scene update
{
let dist = 12.0;
Expand Down
2 changes: 0 additions & 2 deletions examples/features/src/ray_cube_normals/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -406,8 +406,6 @@ impl crate::framework::Example for Example {
}

fn render(&mut self, view: &wgpu::TextureView, device: &wgpu::Device, queue: &wgpu::Queue) {
device.push_error_scope(wgpu::ErrorFilter::Validation);

let anim_time = self.animation_timer.time();

self.tlas[0].as_mut().unwrap().transform =
Expand Down
2 changes: 0 additions & 2 deletions examples/features/src/ray_scene/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,8 +464,6 @@ impl crate::framework::Example for Example {
}

fn render(&mut self, view: &wgpu::TextureView, device: &wgpu::Device, queue: &wgpu::Queue) {
device.push_error_scope(wgpu::ErrorFilter::Validation);

// scene update
{
let dist = 3.5;
Expand Down
1 change: 0 additions & 1 deletion examples/features/src/srgb_blend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,6 @@ impl<const SRGB: bool> crate::framework::Example for Example<SRGB> {
}

fn render(&mut self, view: &wgpu::TextureView, device: &wgpu::Device, queue: &wgpu::Queue) {
device.push_error_scope(wgpu::ErrorFilter::Validation);
let mut encoder =
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
{
Expand Down
4 changes: 2 additions & 2 deletions examples/standalone/custom_backend/src/custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,11 +251,11 @@ impl DeviceInterface for CustomDevice {
unimplemented!()
}

fn push_error_scope(&self, _filter: wgpu::ErrorFilter) {
fn push_error_scope(&self, _filter: wgpu::ErrorFilter) -> u32 {
unimplemented!()
}

fn pop_error_scope(&self) -> Pin<Box<dyn wgpu::custom::PopErrorScopeFuture>> {
fn pop_error_scope(&self, _index: u32) -> Pin<Box<dyn wgpu::custom::PopErrorScopeFuture>> {
unimplemented!()
}

Expand Down
1 change: 1 addition & 0 deletions tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,5 @@ wasm-bindgen.workspace = true
web-sys = { workspace = true, features = ["CanvasRenderingContext2d", "Blob"] }

[lints.clippy]
bool_assert_comparison = "allow"
disallowed_types = "allow"
12 changes: 6 additions & 6 deletions tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ pub fn fail<T>(
callback: impl FnOnce() -> T,
expected_msg_substring: Option<&str>,
) -> T {
device.push_error_scope(wgpu::ErrorFilter::Validation);
let scope = device.push_error_scope(wgpu::ErrorFilter::Validation);
let result = callback();
let validation_error = pollster::block_on(device.pop_error_scope())
let validation_error = pollster::block_on(scope.pop())
.expect("expected validation error in callback, but no validation error was emitted");
if let Some(expected_msg_substring) = expected_msg_substring {
let lowered_expected = expected_msg_substring.to_lowercase();
Expand All @@ -63,9 +63,9 @@ pub fn fail<T>(
/// Run some code in an error scope and assert that validation succeeds.
#[track_caller]
pub fn valid<T>(device: &wgpu::Device, callback: impl FnOnce() -> T) -> T {
device.push_error_scope(wgpu::ErrorFilter::Validation);
let scope = device.push_error_scope(wgpu::ErrorFilter::Validation);
let result = callback();
if let Some(error) = pollster::block_on(device.pop_error_scope()) {
if let Some(error) = pollster::block_on(scope.pop()) {
panic!(
"`valid` block at {} encountered wgpu error:\n{error}",
std::panic::Location::caller()
Expand Down Expand Up @@ -95,9 +95,9 @@ fn did_fill_error_scope<T>(
callback: impl FnOnce() -> T,
filter: wgpu::ErrorFilter,
) -> (bool, T) {
device.push_error_scope(filter);
let scope = device.push_error_scope(filter);
let result = callback();
let validation_error = pollster::block_on(device.pop_error_scope());
let validation_error = pollster::block_on(scope.pop());
let failed = validation_error.is_some();

(failed, result)
Expand Down
8 changes: 4 additions & 4 deletions tests/tests/wgpu-gpu/dispatch_workgroups_indirect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ static RESET_BIND_GROUPS: GpuTestConfiguration = GpuTestConfiguration::new()
}).enable_noop(),
)
.run_async(|ctx| async move {
ctx.device.push_error_scope(wgpu::ErrorFilter::Validation);
let scope = ctx.device.push_error_scope(wgpu::ErrorFilter::Validation);

let test_resources = TestResources::new(&ctx);

Expand All @@ -98,7 +98,7 @@ static RESET_BIND_GROUPS: GpuTestConfiguration = GpuTestConfiguration::new()
}
ctx.queue.submit(Some(encoder.finish()));

let error = pollster::block_on(ctx.device.pop_error_scope());
let error = pollster::block_on(scope.pop());
assert!(error.is_some_and(|error| {
format!("{error}").contains("The current set ComputePipeline with '' label expects a BindGroup to be set at index 0")
}));
Expand All @@ -120,7 +120,7 @@ static ZERO_SIZED_BUFFER: GpuTestConfiguration = GpuTestConfiguration::new()
.enable_noop(),
)
.run_async(|ctx| async move {
ctx.device.push_error_scope(wgpu::ErrorFilter::Validation);
let scope = ctx.device.push_error_scope(wgpu::ErrorFilter::Validation);

let test_resources = TestResources::new(&ctx);

Expand All @@ -141,7 +141,7 @@ static ZERO_SIZED_BUFFER: GpuTestConfiguration = GpuTestConfiguration::new()
}
ctx.queue.submit(Some(encoder.finish()));

let error = pollster::block_on(ctx.device.pop_error_scope());
let error = pollster::block_on(scope.pop());
assert!(error.is_some_and(|error| {
format!("{error}").contains(
"Indirect buffer uses bytes 0..12 which overruns indirect buffer of size 0",
Expand Down
5 changes: 4 additions & 1 deletion tests/tests/wgpu-gpu/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ fn encoder_operations_fail_while_pass_alive(ctx: TestingContext) {

let pass = create_pass(&mut encoder, pass_type);

ctx.device.push_error_scope(wgpu::ErrorFilter::Validation);
let _scope = ctx.device.push_error_scope(wgpu::ErrorFilter::Validation);

log::info!("Testing operation {op_name:?} on a locked command encoder while a {pass_type:?} pass is active");
op(&mut encoder);
Expand All @@ -341,6 +341,9 @@ fn encoder_operations_fail_while_pass_alive(ctx: TestingContext) {
drop(pass);

fail(&ctx.device, || encoder.finish(), Some("encoder is locked"));

// We don't care about any errors that happen outside of a `fail` call.
drop(_scope);
}
}
}
24 changes: 12 additions & 12 deletions tests/tests/wgpu-gpu/oom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ static TEXTURE_OOM_TEST: GpuTestConfiguration = GpuTestConfiguration::new()
.run_async(|ctx| async move {
let mut textures = Vec::new();
for _ in 0..LOOP_BOUND {
ctx.device.push_error_scope(ErrorFilter::OutOfMemory);
let scope = ctx.device.push_error_scope(ErrorFilter::OutOfMemory);
let texture = ctx.device.create_texture(&TextureDescriptor {
label: None,
size: Extent3d {
Expand All @@ -61,7 +61,7 @@ static TEXTURE_OOM_TEST: GpuTestConfiguration = GpuTestConfiguration::new()
usage: TextureUsages::RENDER_ATTACHMENT,
view_formats: &[],
});
if let Some(err) = ctx.device.pop_error_scope().await {
if let Some(err) = scope.pop().await {
match err {
Error::OutOfMemory { .. } => {
return;
Expand All @@ -85,14 +85,14 @@ static BUFFER_OOM_TEST: GpuTestConfiguration = GpuTestConfiguration::new()
.run_async(|ctx| async move {
let mut buffers = Vec::new();
for _ in 0..LOOP_BOUND {
ctx.device.push_error_scope(ErrorFilter::OutOfMemory);
let scope = ctx.device.push_error_scope(ErrorFilter::OutOfMemory);
let buffer = ctx.device.create_buffer(&BufferDescriptor {
label: None,
size: 256 * 1024 * 1024,
usage: BufferUsages::STORAGE,
mapped_at_creation: false,
});
if let Some(err) = ctx.device.pop_error_scope().await {
if let Some(err) = scope.pop().await {
match err {
Error::OutOfMemory { .. } => {
return;
Expand All @@ -116,14 +116,14 @@ static MAPPING_BUFFER_OOM_TEST: GpuTestConfiguration = GpuTestConfiguration::new
.run_async(|ctx| async move {
let mut buffers = Vec::new();
for _ in 0..LOOP_BOUND {
ctx.device.push_error_scope(ErrorFilter::OutOfMemory);
let scope = ctx.device.push_error_scope(ErrorFilter::OutOfMemory);
let buffer = ctx.device.create_buffer(&BufferDescriptor {
label: None,
size: 256 * 1024 * 1024,
usage: BufferUsages::COPY_SRC | BufferUsages::MAP_WRITE,
mapped_at_creation: false,
});
if let Some(err) = ctx.device.pop_error_scope().await {
if let Some(err) = scope.pop().await {
match err {
Error::OutOfMemory { .. } => {
return;
Expand All @@ -148,13 +148,13 @@ static QUERY_SET_OOM_TEST: GpuTestConfiguration = GpuTestConfiguration::new()
.run_async(|ctx| async move {
let mut query_sets = Vec::new();
for _ in 0..LOOP_BOUND {
ctx.device.push_error_scope(ErrorFilter::OutOfMemory);
let scope = ctx.device.push_error_scope(ErrorFilter::OutOfMemory);
let query_set = ctx.device.create_query_set(&QuerySetDescriptor {
label: None,
ty: QueryType::Occlusion,
count: 4096,
});
if let Some(err) = ctx.device.pop_error_scope().await {
if let Some(err) = scope.pop().await {
match err {
Error::OutOfMemory { .. } => {
return;
Expand All @@ -179,7 +179,7 @@ static BLAS_OOM_TEST: GpuTestConfiguration = GpuTestConfiguration::new()
.run_async(|ctx| async move {
let mut blases = Vec::new();
for _ in 0..LOOP_BOUND {
ctx.device.push_error_scope(ErrorFilter::OutOfMemory);
let scope = ctx.device.push_error_scope(ErrorFilter::OutOfMemory);
let blas = ctx.device.create_blas(
&CreateBlasDescriptor {
label: None,
Expand All @@ -196,7 +196,7 @@ static BLAS_OOM_TEST: GpuTestConfiguration = GpuTestConfiguration::new()
}],
},
);
if let Some(err) = ctx.device.pop_error_scope().await {
if let Some(err) = scope.pop().await {
match err {
Error::OutOfMemory { .. } => {
return;
Expand All @@ -221,14 +221,14 @@ static TLAS_OOM_TEST: GpuTestConfiguration = GpuTestConfiguration::new()
.run_async(|ctx| async move {
let mut tlases = Vec::new();
for _ in 0..LOOP_BOUND {
ctx.device.push_error_scope(ErrorFilter::OutOfMemory);
let scope = ctx.device.push_error_scope(ErrorFilter::OutOfMemory);
let tlas = ctx.device.create_tlas(&CreateTlasDescriptor {
label: None,
max_instances: 1024 * 1024,
flags: AccelerationStructureFlags::PREFER_FAST_TRACE,
update_mode: AccelerationStructureUpdateMode::Build,
});
if let Some(err) = ctx.device.pop_error_scope().await {
if let Some(err) = scope.pop().await {
match err {
Error::OutOfMemory { .. } => {
return;
Expand Down
8 changes: 0 additions & 8 deletions tests/tests/wgpu-gpu/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ static COMPUTE_PIPELINE_DEFAULT_LAYOUT_BAD_MODULE: GpuTestConfiguration =
GpuTestConfiguration::new()
.parameters(TestParameters::default().enable_noop())
.run_sync(|ctx| {
ctx.device.push_error_scope(wgpu::ErrorFilter::Validation);

fail(
&ctx.device,
|| {
Expand Down Expand Up @@ -78,8 +76,6 @@ static COMPUTE_PIPELINE_DEFAULT_LAYOUT_BAD_BGL_INDEX: GpuTestConfiguration =
.enable_noop(),
)
.run_sync(|ctx| {
ctx.device.push_error_scope(wgpu::ErrorFilter::Validation);

fail(
&ctx.device,
|| {
Expand Down Expand Up @@ -107,8 +103,6 @@ static RENDER_PIPELINE_DEFAULT_LAYOUT_BAD_MODULE: GpuTestConfiguration =
GpuTestConfiguration::new()
.parameters(TestParameters::default().enable_noop())
.run_sync(|ctx| {
ctx.device.push_error_scope(wgpu::ErrorFilter::Validation);

fail(
&ctx.device,
|| {
Expand Down Expand Up @@ -148,8 +142,6 @@ static RENDER_PIPELINE_DEFAULT_LAYOUT_BAD_BGL_INDEX: GpuTestConfiguration =
.enable_noop(),
)
.run_sync(|ctx| {
ctx.device.push_error_scope(wgpu::ErrorFilter::Validation);

fail(
&ctx.device,
|| {
Expand Down
4 changes: 2 additions & 2 deletions tests/tests/wgpu-gpu/query_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ static DROP_FAILED_TIMESTAMP_QUERY_SET: GpuTestConfiguration = GpuTestConfigurat
.run_sync(|ctx| {
// Enter an error scope, so the validation catch-all doesn't
// report the error too early.
ctx.device.push_error_scope(wgpu::ErrorFilter::Validation);
let scope = ctx.device.push_error_scope(wgpu::ErrorFilter::Validation);

// Creating this query set should fail, since we didn't include
// TIMESTAMP_QUERY in our required features.
Expand All @@ -23,5 +23,5 @@ static DROP_FAILED_TIMESTAMP_QUERY_SET: GpuTestConfiguration = GpuTestConfigurat
// Dropping this should not panic.
drop(bad_query_set);

assert!(pollster::block_on(ctx.device.pop_error_scope()).is_some());
assert!(pollster::block_on(scope.pop()).is_some());
});
4 changes: 2 additions & 2 deletions tests/tests/wgpu-gpu/shader/compilation_messages/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ static SHADER_COMPILE_SUCCESS: GpuTestConfiguration = GpuTestConfiguration::new(
static SHADER_COMPILE_ERROR: GpuTestConfiguration = GpuTestConfiguration::new()
.parameters(TestParameters::default().enable_noop())
.run_async(|ctx| async move {
ctx.device.push_error_scope(wgpu::ErrorFilter::Validation);
let scope = ctx.device.push_error_scope(wgpu::ErrorFilter::Validation);
let sm = ctx
.device
.create_shader_module(include_wgsl!("error_shader.wgsl"));
assert!(pollster::block_on(ctx.device.pop_error_scope()).is_some());
assert!(pollster::block_on(scope.pop()).is_some());

let compilation_info = sm.get_compilation_info().await;
let error_message = compilation_info
Expand Down
Loading
Loading