From ad625f433f682a8b8d866eb3482465832780c601 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Sat, 13 Jan 2024 12:34:51 -0500 Subject: [PATCH] Convert Tests to Use Async Poll (#5053) * Convert Tests to Use Async Poll * Update examples/src/repeated_compute/mod.rs Co-authored-by: Andreas Reich --------- Co-authored-by: Andreas Reich --- deno_webgpu/buffer.rs | 2 +- examples/src/framework.rs | 4 +- examples/src/hello_compute/mod.rs | 2 +- examples/src/hello_synchronization/mod.rs | 2 +- examples/src/hello_workgroups/mod.rs | 2 +- examples/src/mipmap/mod.rs | 2 +- examples/src/render_to_texture/mod.rs | 2 +- examples/src/repeated_compute/mod.rs | 7 +- examples/src/storage_texture/mod.rs | 2 +- examples/src/timestamp_queries/mod.rs | 2 +- player/src/bin/play.rs | 4 +- player/tests/test.rs | 3 +- tests/src/image.rs | 44 +++-- tests/src/lib.rs | 1 + tests/src/poll.rs | 8 + tests/src/run.rs | 11 +- tests/tests/bgra8unorm_storage.rs | 6 +- tests/tests/bind_group_layout_dedup.rs | 8 +- tests/tests/buffer.rs | 30 ++-- tests/tests/buffer_usages.rs | 18 +- tests/tests/clear_texture.rs | 54 +++--- tests/tests/device.rs | 13 +- tests/tests/external_texture.rs | 4 +- tests/tests/life_cycle.rs | 164 ++++++++++-------- tests/tests/mem_leaks.rs | 9 +- tests/tests/occlusion_query/mod.rs | 6 +- tests/tests/partially_bounded_arrays/mod.rs | 5 +- tests/tests/poll.rs | 64 ++++--- tests/tests/push_constants.rs | 8 +- tests/tests/regression/issue_3349.rs | 6 +- tests/tests/regression/issue_3457.rs | 4 +- tests/tests/regression/issue_4024.rs | 6 +- tests/tests/regression/issue_4122.rs | 15 +- tests/tests/scissor_tests/mod.rs | 51 +++--- tests/tests/shader/mod.rs | 4 +- tests/tests/shader/numeric_builtins.rs | 4 +- tests/tests/shader/struct_layout.rs | 12 +- tests/tests/shader/zero_init_workgroup_mem.rs | 4 +- tests/tests/shader_primitive_index/mod.rs | 10 +- tests/tests/shader_view_format/mod.rs | 14 +- tests/tests/vertex_indices/mod.rs | 12 +- tests/tests/write_texture.rs | 12 +- .../tests/zero_init_texture_after_discard.rs | 20 +-- wgpu-types/src/lib.rs | 43 ++++- wgpu/src/backend/direct.rs | 11 +- wgpu/src/backend/web.rs | 4 +- wgpu/src/context.rs | 16 +- wgpu/src/lib.rs | 27 +-- 48 files changed, 458 insertions(+), 304 deletions(-) create mode 100644 tests/src/poll.rs diff --git a/deno_webgpu/buffer.rs b/deno_webgpu/buffer.rs index 0eec61209e..171642e1dc 100644 --- a/deno_webgpu/buffer.rs +++ b/deno_webgpu/buffer.rs @@ -123,7 +123,7 @@ pub async fn op_webgpu_buffer_get_map_async( { let state = state.borrow(); let instance = state.borrow::(); - gfx_select!(device => instance.device_poll(device, wgpu_types::Maintain::Wait)) + gfx_select!(device => instance.device_poll(device, wgpu_types::Maintain::wait())) .unwrap(); } tokio::time::sleep(Duration::from_millis(10)).await; diff --git a/examples/src/framework.rs b/examples/src/framework.rs index a014495171..dd2c2ee6d1 100644 --- a/examples/src/framework.rs +++ b/examples/src/framework.rs @@ -612,7 +612,9 @@ impl From> let dst_buffer_slice = dst_buffer.slice(..); dst_buffer_slice.map_async(wgpu::MapMode::Read, |_| ()); - ctx.device.poll(wgpu::Maintain::Wait); + ctx.async_poll(wgpu::Maintain::wait()) + .await + .panic_on_timeout(); let bytes = dst_buffer_slice.get_mapped_range().to_vec(); wgpu_test::image::compare_image_output( diff --git a/examples/src/hello_compute/mod.rs b/examples/src/hello_compute/mod.rs index 6b7cfa18e0..ef452bf023 100644 --- a/examples/src/hello_compute/mod.rs +++ b/examples/src/hello_compute/mod.rs @@ -152,7 +152,7 @@ async fn execute_gpu_inner( // Poll the device in a blocking manner so that our future resolves. // In an actual application, `device.poll(...)` should // be called in an event loop or on another thread. - device.poll(wgpu::Maintain::Wait); + device.poll(wgpu::Maintain::wait()).panic_on_timeout(); // Awaits until `buffer_future` can be read from if let Ok(Ok(())) = receiver.recv_async().await { diff --git a/examples/src/hello_synchronization/mod.rs b/examples/src/hello_synchronization/mod.rs index 4b1dc6a871..c2a6fe8b26 100644 --- a/examples/src/hello_synchronization/mod.rs +++ b/examples/src/hello_synchronization/mod.rs @@ -183,7 +183,7 @@ async fn get_data( let buffer_slice = staging_buffer.slice(..); let (sender, receiver) = flume::bounded(1); buffer_slice.map_async(wgpu::MapMode::Read, move |r| sender.send(r).unwrap()); - device.poll(wgpu::Maintain::Wait); + device.poll(wgpu::Maintain::wait()).panic_on_timeout(); receiver.recv_async().await.unwrap().unwrap(); output.copy_from_slice(bytemuck::cast_slice(&buffer_slice.get_mapped_range()[..])); staging_buffer.unmap(); diff --git a/examples/src/hello_workgroups/mod.rs b/examples/src/hello_workgroups/mod.rs index 8334de5b35..3e5795048f 100644 --- a/examples/src/hello_workgroups/mod.rs +++ b/examples/src/hello_workgroups/mod.rs @@ -172,7 +172,7 @@ async fn get_data( let buffer_slice = staging_buffer.slice(..); let (sender, receiver) = flume::bounded(1); buffer_slice.map_async(wgpu::MapMode::Read, move |r| sender.send(r).unwrap()); - device.poll(wgpu::Maintain::Wait); + device.poll(wgpu::Maintain::wait()).panic_on_timeout(); receiver.recv_async().await.unwrap().unwrap(); output.copy_from_slice(bytemuck::cast_slice(&buffer_slice.get_mapped_range()[..])); staging_buffer.unmap(); diff --git a/examples/src/mipmap/mod.rs b/examples/src/mipmap/mod.rs index c6dc7fa251..a4600753e9 100644 --- a/examples/src/mipmap/mod.rs +++ b/examples/src/mipmap/mod.rs @@ -410,7 +410,7 @@ impl crate::framework::Example for Example { .slice(..) .map_async(wgpu::MapMode::Read, |_| ()); // Wait for device to be done rendering mipmaps - device.poll(wgpu::Maintain::Wait); + device.poll(wgpu::Maintain::wait()).panic_on_timeout(); // This is guaranteed to be ready. let timestamp_view = query_sets .mapping_buffer diff --git a/examples/src/render_to_texture/mod.rs b/examples/src/render_to_texture/mod.rs index 2bd831cc12..75d22dfe87 100644 --- a/examples/src/render_to_texture/mod.rs +++ b/examples/src/render_to_texture/mod.rs @@ -131,7 +131,7 @@ async fn run(_path: Option) { let buffer_slice = output_staging_buffer.slice(..); let (sender, receiver) = flume::bounded(1); buffer_slice.map_async(wgpu::MapMode::Read, move |r| sender.send(r).unwrap()); - device.poll(wgpu::Maintain::Wait); + device.poll(wgpu::Maintain::wait()).panic_on_timeout(); receiver.recv_async().await.unwrap().unwrap(); log::info!("Output buffer mapped."); { diff --git a/examples/src/repeated_compute/mod.rs b/examples/src/repeated_compute/mod.rs index fa80b69652..596de7297d 100644 --- a/examples/src/repeated_compute/mod.rs +++ b/examples/src/repeated_compute/mod.rs @@ -108,8 +108,11 @@ async fn compute(local_buffer: &mut [u32], context: &WgpuContext) { // In order for the mapping to be completed, one of three things must happen. // One of those can be calling `Device::poll`. This isn't necessary on the web as devices // are polled automatically but natively, we need to make sure this happens manually. - // `Maintain::Wait` will cause the thread to wait on native but not the web. - context.device.poll(wgpu::Maintain::Wait); + // `Maintain::Wait` will cause the thread to wait on native but not on WebGpu. + context + .device + .poll(wgpu::Maintain::wait()) + .panic_on_timeout(); log::info!("Device polled."); // Now we await the receiving and panic if anything went wrong because we're lazy. receiver.recv_async().await.unwrap().unwrap(); diff --git a/examples/src/storage_texture/mod.rs b/examples/src/storage_texture/mod.rs index 6498670817..d389ce139e 100644 --- a/examples/src/storage_texture/mod.rs +++ b/examples/src/storage_texture/mod.rs @@ -143,7 +143,7 @@ async fn run(_path: Option) { let buffer_slice = output_staging_buffer.slice(..); let (sender, receiver) = flume::bounded(1); buffer_slice.map_async(wgpu::MapMode::Read, move |r| sender.send(r).unwrap()); - device.poll(wgpu::Maintain::Wait); + device.poll(wgpu::Maintain::wait()).panic_on_timeout(); receiver.recv_async().await.unwrap().unwrap(); log::info!("Output buffer mapped"); { diff --git a/examples/src/timestamp_queries/mod.rs b/examples/src/timestamp_queries/mod.rs index 877659e697..beccac73b2 100644 --- a/examples/src/timestamp_queries/mod.rs +++ b/examples/src/timestamp_queries/mod.rs @@ -159,7 +159,7 @@ impl Queries { self.destination_buffer .slice(..) .map_async(wgpu::MapMode::Read, |_| ()); - device.poll(wgpu::Maintain::Wait); + device.poll(wgpu::Maintain::wait()).panic_on_timeout(); let timestamps = { let timestamp_view = self diff --git a/player/src/bin/play.rs b/player/src/bin/play.rs index cc62010fbb..f91b1b6615 100644 --- a/player/src/bin/play.rs +++ b/player/src/bin/play.rs @@ -114,7 +114,7 @@ fn main() { } gfx_select!(device => global.device_stop_capture(device)); - gfx_select!(device => global.device_poll(device, wgt::Maintain::Wait)).unwrap(); + gfx_select!(device => global.device_poll(device, wgt::Maintain::wait())).unwrap(); } #[cfg(feature = "winit")] { @@ -196,7 +196,7 @@ fn main() { }, Event::LoopExiting => { log::info!("Closing"); - gfx_select!(device => global.device_poll(device, wgt::Maintain::Wait)).unwrap(); + gfx_select!(device => global.device_poll(device, wgt::Maintain::wait())).unwrap(); } _ => {} } diff --git a/player/tests/test.rs b/player/tests/test.rs index a622742b67..196777d0b2 100644 --- a/player/tests/test.rs +++ b/player/tests/test.rs @@ -121,7 +121,8 @@ impl Test<'_> { } println!("\t\t\tWaiting..."); - wgc::gfx_select!(device_id => global.device_poll(device_id, wgt::Maintain::Wait)).unwrap(); + wgc::gfx_select!(device_id => global.device_poll(device_id, wgt::Maintain::wait())) + .unwrap(); for expect in self.expectations { println!("\t\t\tChecking {}", expect.name); diff --git a/tests/src/image.rs b/tests/src/image.rs index d555332bf7..08e30ae2ef 100644 --- a/tests/src/image.rs +++ b/tests/src/image.rs @@ -5,6 +5,8 @@ use std::{borrow::Cow, ffi::OsStr, path::Path}; use wgpu::util::{align_to, DeviceExt}; use wgpu::*; +use crate::TestingContext; + #[cfg(not(target_arch = "wasm32"))] async fn read_png(path: impl AsRef, width: u32, height: u32) -> Option> { let data = match std::fs::read(&path) { @@ -563,15 +565,15 @@ impl ReadbackBuffers { copy_texture_to_buffer(device, encoder, texture, &self.buffer, &self.buffer_stencil); } - fn retrieve_buffer( + async fn retrieve_buffer( &self, - device: &Device, + ctx: &TestingContext, buffer: &Buffer, aspect: Option, ) -> Vec { let buffer_slice = buffer.slice(..); buffer_slice.map_async(MapMode::Read, |_| ()); - device.poll(Maintain::Wait); + ctx.async_poll(Maintain::wait()).await.panic_on_timeout(); let (block_width, block_height) = self.texture_format.block_dimensions(); let expected_bytes_per_row = (self.texture_width / block_width) * self.texture_format.block_copy_size(aspect).unwrap_or(4); @@ -600,26 +602,36 @@ impl ReadbackBuffers { } } - pub fn are_zero(&self, device: &Device) -> bool { - let is_zero = |device: &Device, buffer: &Buffer, aspect: Option| -> bool { - let is_zero = self - .retrieve_buffer(device, buffer, aspect) - .iter() - .all(|b| *b == 0); - buffer.unmap(); - is_zero - }; + async fn is_zero( + &self, + ctx: &TestingContext, + buffer: &Buffer, + aspect: Option, + ) -> bool { + let is_zero = self + .retrieve_buffer(ctx, buffer, aspect) + .await + .iter() + .all(|b| *b == 0); + buffer.unmap(); + is_zero + } - let buffer_zero = is_zero(device, &self.buffer, self.buffer_aspect()); + pub async fn are_zero(&self, ctx: &TestingContext) -> bool { + let buffer_zero = self.is_zero(ctx, &self.buffer, self.buffer_aspect()).await; let mut stencil_buffer_zero = true; if let Some(buffer) = &self.buffer_stencil { - stencil_buffer_zero = is_zero(device, buffer, Some(TextureAspect::StencilOnly)); + stencil_buffer_zero = self + .is_zero(ctx, buffer, Some(TextureAspect::StencilOnly)) + .await; }; buffer_zero && stencil_buffer_zero } - pub fn assert_buffer_contents(&self, device: &Device, expected_data: &[u8]) { - let result_buffer = self.retrieve_buffer(device, &self.buffer, self.buffer_aspect()); + pub async fn assert_buffer_contents(&self, ctx: &TestingContext, expected_data: &[u8]) { + let result_buffer = self + .retrieve_buffer(ctx, &self.buffer, self.buffer_aspect()) + .await; assert!( result_buffer.len() >= expected_data.len(), "Result buffer ({}) smaller than expected buffer ({})", diff --git a/tests/src/lib.rs b/tests/src/lib.rs index 1e93d76eef..08f464e5aa 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -7,6 +7,7 @@ mod init; mod isolation; pub mod native; mod params; +mod poll; mod report; mod run; diff --git a/tests/src/poll.rs b/tests/src/poll.rs new file mode 100644 index 0000000000..399cb71393 --- /dev/null +++ b/tests/src/poll.rs @@ -0,0 +1,8 @@ +use crate::TestingContext; + +impl TestingContext { + /// Utility to allow future asynchronous polling. + pub async fn async_poll(&self, maintain: wgpu::Maintain) -> wgpu::MaintainResult { + self.device.poll(maintain) + } +} diff --git a/tests/src/run.rs b/tests/src/run.rs index 85189de571..e19615bdb2 100644 --- a/tests/src/run.rs +++ b/tests/src/run.rs @@ -1,4 +1,4 @@ -use std::panic::AssertUnwindSafe; +use std::{panic::AssertUnwindSafe, sync::Arc}; use futures_lite::FutureExt; use wgpu::{Adapter, Device, Instance, Queue}; @@ -18,7 +18,7 @@ pub struct TestingContext { pub adapter: Adapter, pub adapter_info: wgpu::AdapterInfo, pub adapter_downlevel_capabilities: wgpu::DownlevelCapabilities, - pub device: Device, + pub device: Arc, pub device_features: wgpu::Features, pub device_limits: wgpu::Limits, pub queue: Queue, @@ -58,6 +58,9 @@ pub async fn execute_test( return; } + // Print the name of the test. + log::info!("TEST: {}", config.name); + let (device, queue) = pollster::block_on(initialize_device( &adapter, config.params.required_features, @@ -69,7 +72,7 @@ pub async fn execute_test( adapter, adapter_info, adapter_downlevel_capabilities, - device, + device: Arc::new(device), device_features: config.params.required_features, device_limits: config.params.required_limits.clone(), queue, @@ -109,4 +112,6 @@ pub async fn execute_test( if expectations_match_failures(&test_info.failures, failures) == ExpectationMatchResult::Panic { panic!(); } + // Print the name of the test. + log::info!("TEST FINISHED: {}", config.name); } diff --git a/tests/tests/bgra8unorm_storage.rs b/tests/tests/bgra8unorm_storage.rs index 91f7b49280..b1ca3b8362 100644 --- a/tests/tests/bgra8unorm_storage.rs +++ b/tests/tests/bgra8unorm_storage.rs @@ -23,7 +23,7 @@ static BGRA8_UNORM_STORAGE: GpuTestConfiguration = GpuTestConfiguration::new() }) .features(wgpu::Features::BGRA8UNORM_STORAGE), ) - .run_sync(|ctx| { + .run_async(|ctx| async move { let device = &ctx.device; let texture = ctx.device.create_texture(&wgpu::TextureDescriptor { label: None, @@ -139,7 +139,9 @@ static BGRA8_UNORM_STORAGE: GpuTestConfiguration = GpuTestConfiguration::new() let buffer_slice = readback_buffer.slice(..); buffer_slice.map_async(wgpu::MapMode::Read, Result::unwrap); - device.poll(wgpu::Maintain::Wait); + ctx.async_poll(wgpu::Maintain::wait()) + .await + .panic_on_timeout(); { let texels = buffer_slice.get_mapped_range(); diff --git a/tests/tests/bind_group_layout_dedup.rs b/tests/tests/bind_group_layout_dedup.rs index 66ea687f2a..8da284b41b 100644 --- a/tests/tests/bind_group_layout_dedup.rs +++ b/tests/tests/bind_group_layout_dedup.rs @@ -31,9 +31,9 @@ const ENTRY: wgpu::BindGroupLayoutEntry = wgpu::BindGroupLayoutEntry { #[gpu_test] static BIND_GROUP_LAYOUT_DEDUPLICATION: GpuTestConfiguration = GpuTestConfiguration::new() .parameters(TestParameters::default().test_features_limits()) - .run_sync(bgl_dedupe); + .run_async(bgl_dedupe); -fn bgl_dedupe(ctx: TestingContext) { +async fn bgl_dedupe(ctx: TestingContext) { let entries_1 = &[]; let entries_2 = &[ENTRY]; @@ -126,7 +126,9 @@ fn bgl_dedupe(ctx: TestingContext) { } } - ctx.device.poll(wgpu::Maintain::Wait); + ctx.async_poll(wgpu::Maintain::wait()) + .await + .panic_on_timeout(); if ctx.adapter_info.backend != wgt::Backend::BrowserWebGpu { // Now all of the BGL ids should be dead, so we should get the same ids again. diff --git a/tests/tests/buffer.rs b/tests/tests/buffer.rs index 9913a0d6b8..c3b1dbea58 100644 --- a/tests/tests/buffer.rs +++ b/tests/tests/buffer.rs @@ -1,6 +1,6 @@ use wgpu_test::{gpu_test, FailureCase, GpuTestConfiguration, TestParameters, TestingContext}; -fn test_empty_buffer_range(ctx: &TestingContext, buffer_size: u64, label: &str) { +async fn test_empty_buffer_range(ctx: &TestingContext, buffer_size: u64, label: &str) { let r = wgpu::BufferUsages::MAP_READ; let rw = wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::MAP_WRITE; for usage in [r, rw] { @@ -14,7 +14,9 @@ fn test_empty_buffer_range(ctx: &TestingContext, buffer_size: u64, label: &str) b0.slice(0..0) .map_async(wgpu::MapMode::Read, Result::unwrap); - ctx.device.poll(wgpu::MaintainBase::Wait); + ctx.async_poll(wgpu::Maintain::wait()) + .await + .panic_on_timeout(); { let view = b0.slice(0..0).get_mapped_range(); @@ -48,7 +50,9 @@ fn test_empty_buffer_range(ctx: &TestingContext, buffer_size: u64, label: &str) b0.slice(0..0) .map_async(wgpu::MapMode::Write, Result::unwrap); - ctx.device.poll(wgpu::MaintainBase::Wait); + ctx.async_poll(wgpu::Maintain::wait()) + .await + .panic_on_timeout(); //{ // let view = b0.slice(0..0).get_mapped_range_mut(); @@ -77,19 +81,21 @@ fn test_empty_buffer_range(ctx: &TestingContext, buffer_size: u64, label: &str) b1.unmap(); - ctx.device.poll(wgpu::MaintainBase::Wait); + ctx.async_poll(wgpu::Maintain::wait()) + .await + .panic_on_timeout(); } #[gpu_test] static EMPTY_BUFFER: GpuTestConfiguration = GpuTestConfiguration::new() .parameters(TestParameters::default().expect_fail(FailureCase::always())) - .run_sync(|ctx| { - test_empty_buffer_range(&ctx, 2048, "regular buffer"); - test_empty_buffer_range(&ctx, 0, "zero-sized buffer"); + .run_async(|ctx| async move { + test_empty_buffer_range(&ctx, 2048, "regular buffer").await; + test_empty_buffer_range(&ctx, 0, "zero-sized buffer").await; }); #[gpu_test] -static MAP_OFFSET: GpuTestConfiguration = GpuTestConfiguration::new().run_sync(|ctx| { +static MAP_OFFSET: GpuTestConfiguration = GpuTestConfiguration::new().run_async(|ctx| async move { // This test writes 16 bytes at the beginning of buffer mapped mapped with // an offset of 32 bytes. Then the buffer is copied into another buffer that // is read back and we check that the written bytes are correctly placed at @@ -116,7 +122,9 @@ static MAP_OFFSET: GpuTestConfiguration = GpuTestConfiguration::new().run_sync(| result.unwrap(); }); - ctx.device.poll(wgpu::MaintainBase::Wait); + ctx.async_poll(wgpu::Maintain::wait()) + .await + .panic_on_timeout(); { let slice = write_buf.slice(32..48); @@ -140,7 +148,9 @@ static MAP_OFFSET: GpuTestConfiguration = GpuTestConfiguration::new().run_sync(| .slice(..) .map_async(wgpu::MapMode::Read, Result::unwrap); - ctx.device.poll(wgpu::MaintainBase::Wait); + ctx.async_poll(wgpu::Maintain::wait()) + .await + .panic_on_timeout(); let slice = read_buf.slice(..); let view = slice.get_mapped_range(); diff --git a/tests/tests/buffer_usages.rs b/tests/tests/buffer_usages.rs index 194ed0ec2f..d002b8f074 100644 --- a/tests/tests/buffer_usages.rs +++ b/tests/tests/buffer_usages.rs @@ -1,7 +1,7 @@ //! Tests for buffer usages validation. use wgpu::{BufferUsages as Bu, MapMode as Ma}; -use wgpu_test::{fail_if, gpu_test, GpuTestConfiguration, TestParameters}; +use wgpu_test::{fail_if, gpu_test, GpuTestConfiguration, TestParameters, TestingContext}; use wgt::BufferAddress; const BUFFER_SIZE: BufferAddress = 1234; @@ -26,7 +26,7 @@ const NEEDS_MAPPABLE_PRIMARY_BUFFERS: &[Bu; 7] = &[ const INVALID_BITS: Bu = Bu::from_bits_retain(0b1111111111111); const ALWAYS_FAIL: &[Bu; 2] = &[Bu::empty(), INVALID_BITS]; -fn try_create(ctx: wgpu_test::TestingContext, usages: &[(bool, &[wgpu::BufferUsages])]) { +fn try_create(ctx: TestingContext, usages: &[(bool, &[wgpu::BufferUsages])]) { for (expect_validation_error, usage) in usages .iter() .flat_map(|&(expect_error, usages)| usages.iter().copied().map(move |u| (expect_error, u))) @@ -69,7 +69,7 @@ static BUFFER_USAGE_MAPPABLE_PRIMARY_BUFFERS: GpuTestConfiguration = GpuTestConf }); async fn map_test( - device: &wgpu::Device, + ctx: &TestingContext, usage_type: &str, map_mode_type: Ma, before_unmap: bool, @@ -89,8 +89,8 @@ async fn map_test( let mut buffer = None; - fail_if(device, buffer_creation_validation_error, || { - buffer = Some(device.create_buffer(&wgpu::BufferDescriptor { + fail_if(&ctx.device, buffer_creation_validation_error, || { + buffer = Some(ctx.device.create_buffer(&wgpu::BufferDescriptor { label: None, size, usage, @@ -107,7 +107,7 @@ async fn map_test( || (map_mode_type == Ma::Read && !usage.contains(Bu::MAP_READ)) || (map_mode_type == Ma::Write && !usage.contains(Bu::MAP_WRITE)); - fail_if(device, map_async_validation_error, || { + fail_if(&ctx.device, map_async_validation_error, || { buffer.slice(0..size).map_async(map_mode_type, |_| {}); }); @@ -123,7 +123,9 @@ async fn map_test( buffer.destroy(); } - device.poll(wgpu::MaintainBase::Wait); + ctx.async_poll(wgpu::Maintain::wait()) + .await + .panic_on_timeout(); if !before_unmap && !before_destroy { { @@ -152,7 +154,7 @@ static BUFFER_MAP_ASYNC_MAP_STATE: GpuTestConfiguration = GpuTestConfiguration:: for after_unmap in [false, true] { for after_destroy in [false, true] { map_test( - &ctx.device, + &ctx, usage_type, map_mode_type, before_unmap, diff --git a/tests/tests/clear_texture.rs b/tests/tests/clear_texture.rs index a9364b6e51..3e7484ab56 100644 --- a/tests/tests/clear_texture.rs +++ b/tests/tests/clear_texture.rs @@ -203,7 +203,7 @@ static TEXTURE_FORMATS_ASTC: &[wgpu::TextureFormat] = &[ }, ]; -fn single_texture_clear_test( +async fn single_texture_clear_test( ctx: &TestingContext, format: wgpu::TextureFormat, size: wgpu::Extent3d, @@ -259,12 +259,12 @@ fn single_texture_clear_test( ctx.queue.submit([encoder.finish()]); assert!( - readback_buffers.are_zero(&ctx.device), + readback_buffers.are_zero(ctx).await, "texture with format {format:?} was not fully cleared" ); } -fn clear_texture_tests(ctx: &TestingContext, formats: &[wgpu::TextureFormat]) { +async fn clear_texture_tests(ctx: TestingContext, formats: &'static [wgpu::TextureFormat]) { for &format in formats { let (block_width, block_height) = format.block_dimensions(); let rounded_width = block_width * wgpu::COPY_BYTES_PER_ROW_ALIGNMENT; @@ -278,7 +278,7 @@ fn clear_texture_tests(ctx: &TestingContext, formats: &[wgpu::TextureFormat]) { // 1D texture if supports_1d { single_texture_clear_test( - ctx, + &ctx, format, wgpu::Extent3d { width: rounded_width, @@ -286,11 +286,12 @@ fn clear_texture_tests(ctx: &TestingContext, formats: &[wgpu::TextureFormat]) { depth_or_array_layers: 1, }, wgpu::TextureDimension::D1, - ); + ) + .await; } // 2D texture single_texture_clear_test( - ctx, + &ctx, format, wgpu::Extent3d { width: rounded_width, @@ -298,10 +299,11 @@ fn clear_texture_tests(ctx: &TestingContext, formats: &[wgpu::TextureFormat]) { depth_or_array_layers: 1, }, wgpu::TextureDimension::D2, - ); + ) + .await; // 2D array texture single_texture_clear_test( - ctx, + &ctx, format, wgpu::Extent3d { width: rounded_width, @@ -309,11 +311,12 @@ fn clear_texture_tests(ctx: &TestingContext, formats: &[wgpu::TextureFormat]) { depth_or_array_layers: 4, }, wgpu::TextureDimension::D2, - ); + ) + .await; if supports_3d { // volume texture single_texture_clear_test( - ctx, + &ctx, format, wgpu::Extent3d { width: rounded_width, @@ -321,7 +324,8 @@ fn clear_texture_tests(ctx: &TestingContext, formats: &[wgpu::TextureFormat]) { depth_or_array_layers: 16, }, wgpu::TextureDimension::D3, - ); + ) + .await; } } } @@ -333,9 +337,7 @@ static CLEAR_TEXTURE_UNCOMPRESSED_GLES: GpuTestConfiguration = GpuTestConfigurat .features(wgpu::Features::CLEAR_TEXTURE) .skip(FailureCase::webgl2()), ) - .run_sync(|ctx| { - clear_texture_tests(&ctx, TEXTURE_FORMATS_UNCOMPRESSED_GLES_COMPAT); - }); + .run_async(|ctx| clear_texture_tests(ctx, TEXTURE_FORMATS_UNCOMPRESSED_GLES_COMPAT)); #[gpu_test] static CLEAR_TEXTURE_UNCOMPRESSED: GpuTestConfiguration = GpuTestConfiguration::new() @@ -350,9 +352,7 @@ static CLEAR_TEXTURE_UNCOMPRESSED: GpuTestConfiguration = GpuTestConfiguration:: ) .features(wgpu::Features::CLEAR_TEXTURE), ) - .run_sync(|ctx| { - clear_texture_tests(&ctx, TEXTURE_FORMATS_UNCOMPRESSED); - }); + .run_async(|ctx| clear_texture_tests(ctx, TEXTURE_FORMATS_UNCOMPRESSED)); #[gpu_test] static CLEAR_TEXTURE_DEPTH: GpuTestConfiguration = GpuTestConfiguration::new() @@ -368,9 +368,7 @@ static CLEAR_TEXTURE_DEPTH: GpuTestConfiguration = GpuTestConfiguration::new() .limits(wgpu::Limits::downlevel_defaults()) .features(wgpu::Features::CLEAR_TEXTURE), ) - .run_sync(|ctx| { - clear_texture_tests(&ctx, TEXTURE_FORMATS_DEPTH); - }); + .run_async(|ctx| clear_texture_tests(ctx, TEXTURE_FORMATS_DEPTH)); #[gpu_test] static CLEAR_TEXTURE_DEPTH32_STENCIL8: GpuTestConfiguration = GpuTestConfiguration::new() @@ -380,9 +378,7 @@ static CLEAR_TEXTURE_DEPTH32_STENCIL8: GpuTestConfiguration = GpuTestConfigurati // https://github.com/gfx-rs/wgpu/issues/5016 .skip(FailureCase::adapter("Apple Paravirtual device")), ) - .run_sync(|ctx| { - clear_texture_tests(&ctx, &[wgpu::TextureFormat::Depth32FloatStencil8]); - }); + .run_async(|ctx| clear_texture_tests(ctx, &[wgpu::TextureFormat::Depth32FloatStencil8])); #[gpu_test] static CLEAR_TEXTURE_COMPRESSED_BCN: GpuTestConfiguration = GpuTestConfiguration::new() @@ -394,9 +390,7 @@ static CLEAR_TEXTURE_COMPRESSED_BCN: GpuTestConfiguration = GpuTestConfiguration // compressed texture copy to buffer not yet implemented .expect_fail(FailureCase::backend(wgpu::Backends::GL)), ) - .run_sync(|ctx| { - clear_texture_tests(&ctx, TEXTURE_FORMATS_BC); - }); + .run_async(|ctx| clear_texture_tests(ctx, TEXTURE_FORMATS_BC)); #[gpu_test] static CLEAR_TEXTURE_COMPRESSED_ASTC: GpuTestConfiguration = GpuTestConfiguration::new() @@ -412,9 +406,7 @@ static CLEAR_TEXTURE_COMPRESSED_ASTC: GpuTestConfiguration = GpuTestConfiguratio // compressed texture copy to buffer not yet implemented .expect_fail(FailureCase::backend(wgpu::Backends::GL)), ) - .run_sync(|ctx| { - clear_texture_tests(&ctx, TEXTURE_FORMATS_ASTC); - }); + .run_async(|ctx| clear_texture_tests(ctx, TEXTURE_FORMATS_ASTC)); #[gpu_test] static CLEAR_TEXTURE_COMPRESSED_ETC2: GpuTestConfiguration = GpuTestConfiguration::new() @@ -426,6 +418,4 @@ static CLEAR_TEXTURE_COMPRESSED_ETC2: GpuTestConfiguration = GpuTestConfiguratio // compressed texture copy to buffer not yet implemented .expect_fail(FailureCase::backend(wgpu::Backends::GL)), ) - .run_sync(|ctx| { - clear_texture_tests(&ctx, TEXTURE_FORMATS_ETC2); - }); + .run_async(|ctx| clear_texture_tests(ctx, TEXTURE_FORMATS_ETC2)); diff --git a/tests/tests/device.rs b/tests/tests/device.rs index 52438670e6..b6070de14f 100644 --- a/tests/tests/device.rs +++ b/tests/tests/device.rs @@ -3,7 +3,7 @@ use wgpu_test::{fail, gpu_test, FailureCase, GpuTestConfiguration, TestParameter #[gpu_test] static CROSS_DEVICE_BIND_GROUP_USAGE: GpuTestConfiguration = GpuTestConfiguration::new() .parameters(TestParameters::default().expect_fail(FailureCase::always())) - .run_sync(|ctx| { + .run_async(|ctx| async move { // Create a bind group uisng a layout from another device. This should be a validation // error but currently crashes. let (device2, _) = @@ -23,7 +23,9 @@ static CROSS_DEVICE_BIND_GROUP_USAGE: GpuTestConfiguration = GpuTestConfiguratio }); } - ctx.device.poll(wgpu::Maintain::Poll); + ctx.async_poll(wgpu::Maintain::Poll) + .await + .panic_on_timeout(); }); #[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))] @@ -483,7 +485,7 @@ static DEVICE_DESTROY_THEN_MORE: GpuTestConfiguration = GpuTestConfiguration::ne #[gpu_test] static DEVICE_DESTROY_THEN_LOST: GpuTestConfiguration = GpuTestConfiguration::new() .parameters(TestParameters::default()) - .run_sync(|ctx| { + .run_async(|ctx| async move { // This test checks that when device.destroy is called, the provided // DeviceLostClosure is called with reason DeviceLostReason::Destroyed. let was_called = std::sync::Arc::::new(false.into()); @@ -504,7 +506,10 @@ static DEVICE_DESTROY_THEN_LOST: GpuTestConfiguration = GpuTestConfiguration::ne // Make sure the device queues are empty, which ensures that the closure // has been called. - assert!(ctx.device.poll(wgpu::Maintain::Wait)); + assert!(ctx + .async_poll(wgpu::Maintain::wait()) + .await + .is_queue_empty()); assert!( was_called.load(std::sync::atomic::Ordering::SeqCst), diff --git a/tests/tests/external_texture.rs b/tests/tests/external_texture.rs index 18a5d193af..f518bf8666 100644 --- a/tests/tests/external_texture.rs +++ b/tests/tests/external_texture.rs @@ -323,7 +323,9 @@ static IMAGE_BITMAP_IMPORT: GpuTestConfiguration = readback_buffer .slice(..) .map_async(wgpu::MapMode::Read, |_| ()); - ctx.device.poll(wgpu::Maintain::Wait); + ctx.async_poll(wgpu::Maintain::wait()) + .await + .panic_on_timeout(); let buffer = readback_buffer.slice(..).get_mapped_range(); diff --git a/tests/tests/life_cycle.rs b/tests/tests/life_cycle.rs index c838dea143..e465402431 100644 --- a/tests/tests/life_cycle.rs +++ b/tests/tests/life_cycle.rs @@ -1,95 +1,111 @@ use wgpu_test::{fail, gpu_test, GpuTestConfiguration}; #[gpu_test] -static BUFFER_DESTROY: GpuTestConfiguration = GpuTestConfiguration::new().run_sync(|ctx| { - let buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor { - label: None, - size: 256, - usage: wgpu::BufferUsages::MAP_WRITE | wgpu::BufferUsages::COPY_SRC, - mapped_at_creation: false, - }); - - buffer.destroy(); - - buffer.destroy(); +static BUFFER_DESTROY: GpuTestConfiguration = + GpuTestConfiguration::new().run_async(|ctx| async move { + let buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor { + label: None, + size: 256, + usage: wgpu::BufferUsages::MAP_WRITE | wgpu::BufferUsages::COPY_SRC, + mapped_at_creation: false, + }); - ctx.device.poll(wgpu::MaintainBase::Wait); - - fail(&ctx.device, || { - buffer - .slice(..) - .map_async(wgpu::MapMode::Write, move |_| {}); - }); + buffer.destroy(); - buffer.destroy(); + buffer.destroy(); - ctx.device.poll(wgpu::MaintainBase::Wait); + ctx.async_poll(wgpu::Maintain::wait()) + .await + .panic_on_timeout(); - buffer.destroy(); + fail(&ctx.device, || { + buffer + .slice(..) + .map_async(wgpu::MapMode::Write, move |_| {}); + }); - buffer.destroy(); + buffer.destroy(); - let descriptor = wgpu::BufferDescriptor { - label: None, - size: 256, - usage: wgpu::BufferUsages::MAP_WRITE | wgpu::BufferUsages::COPY_SRC, - mapped_at_creation: false, - }; + ctx.async_poll(wgpu::Maintain::wait()) + .await + .panic_on_timeout(); - // Scopes to mix up the drop/poll ordering. - { - let buffer = ctx.device.create_buffer(&descriptor); buffer.destroy(); - let buffer = ctx.device.create_buffer(&descriptor); + buffer.destroy(); - } - let buffer = ctx.device.create_buffer(&descriptor); - buffer.destroy(); - ctx.device.poll(wgpu::MaintainBase::Wait); - let buffer = ctx.device.create_buffer(&descriptor); - buffer.destroy(); - { + + let descriptor = wgpu::BufferDescriptor { + label: None, + size: 256, + usage: wgpu::BufferUsages::MAP_WRITE | wgpu::BufferUsages::COPY_SRC, + mapped_at_creation: false, + }; + + // Scopes to mix up the drop/poll ordering. + { + let buffer = ctx.device.create_buffer(&descriptor); + buffer.destroy(); + let buffer = ctx.device.create_buffer(&descriptor); + buffer.destroy(); + } let buffer = ctx.device.create_buffer(&descriptor); buffer.destroy(); + ctx.async_poll(wgpu::Maintain::wait()) + .await + .panic_on_timeout(); let buffer = ctx.device.create_buffer(&descriptor); buffer.destroy(); + { + let buffer = ctx.device.create_buffer(&descriptor); + buffer.destroy(); + let buffer = ctx.device.create_buffer(&descriptor); + buffer.destroy(); + let buffer = ctx.device.create_buffer(&descriptor); + ctx.async_poll(wgpu::Maintain::wait()) + .await + .panic_on_timeout(); + buffer.destroy(); + } let buffer = ctx.device.create_buffer(&descriptor); - ctx.device.poll(wgpu::MaintainBase::Wait); buffer.destroy(); - } - let buffer = ctx.device.create_buffer(&descriptor); - buffer.destroy(); - ctx.device.poll(wgpu::MaintainBase::Wait); -}); + ctx.async_poll(wgpu::Maintain::wait()) + .await + .panic_on_timeout(); + }); #[gpu_test] -static TEXTURE_DESTROY: GpuTestConfiguration = GpuTestConfiguration::new().run_sync(|ctx| { - let texture = ctx.device.create_texture(&wgpu::TextureDescriptor { - label: None, - size: wgpu::Extent3d { - width: 128, - height: 128, - depth_or_array_layers: 1, - }, - mip_level_count: 1, - sample_count: 1, // multisampling is not supported for clear - dimension: wgpu::TextureDimension::D2, - format: wgpu::TextureFormat::Rgba8Snorm, - usage: wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::TEXTURE_BINDING, - view_formats: &[], +static TEXTURE_DESTROY: GpuTestConfiguration = + GpuTestConfiguration::new().run_async(|ctx| async move { + let texture = ctx.device.create_texture(&wgpu::TextureDescriptor { + label: None, + size: wgpu::Extent3d { + width: 128, + height: 128, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, // multisampling is not supported for clear + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8Snorm, + usage: wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::TEXTURE_BINDING, + view_formats: &[], + }); + + texture.destroy(); + + texture.destroy(); + + ctx.async_poll(wgpu::Maintain::wait()) + .await + .panic_on_timeout(); + + texture.destroy(); + + ctx.async_poll(wgpu::Maintain::wait()) + .await + .panic_on_timeout(); + + texture.destroy(); + + texture.destroy(); }); - - texture.destroy(); - - texture.destroy(); - - ctx.device.poll(wgpu::MaintainBase::Wait); - - texture.destroy(); - - ctx.device.poll(wgpu::MaintainBase::Wait); - - texture.destroy(); - - texture.destroy(); -}); diff --git a/tests/tests/mem_leaks.rs b/tests/tests/mem_leaks.rs index 52082e99f7..5b5f0ce820 100644 --- a/tests/tests/mem_leaks.rs +++ b/tests/tests/mem_leaks.rs @@ -3,7 +3,7 @@ target_os = "emscripten", feature = "webgl" ))] -fn draw_test_with_reports( +async fn draw_test_with_reports( ctx: wgpu_test::TestingContext, expected: &[u32], function: impl FnOnce(&mut wgpu::RenderPass<'_>), @@ -241,8 +241,9 @@ fn draw_test_with_reports( let report = global_report.hub_report(ctx.adapter_info.backend); assert_eq!(report.command_buffers.num_allocated, 0); - ctx.device - .poll(wgpu::Maintain::WaitForSubmissionIndex(submit_index)); + ctx.async_poll(wgpu::Maintain::wait_for(submit_index)) + .await + .panic_on_timeout(); let global_report = ctx.instance.generate_report(); let report = global_report.hub_report(ctx.adapter_info.backend); @@ -285,7 +286,7 @@ static SIMPLE_DRAW_CHECK_MEM_LEAKS: wgpu_test::GpuTestConfiguration = .test_features_limits() .features(wgpu::Features::VERTEX_WRITABLE_STORAGE), ) - .run_sync(|ctx| { + .run_async(|ctx| { draw_test_with_reports(ctx, &[0, 1, 2, 3, 4, 5], |cmb| { cmb.draw(0..6, 0..1); }) diff --git a/tests/tests/occlusion_query/mod.rs b/tests/tests/occlusion_query/mod.rs index 7a7f3fa9a2..0c3f3072a5 100644 --- a/tests/tests/occlusion_query/mod.rs +++ b/tests/tests/occlusion_query/mod.rs @@ -4,7 +4,7 @@ use wgpu_test::{gpu_test, FailureCase, GpuTestConfiguration, TestParameters}; #[gpu_test] static OCCLUSION_QUERY: GpuTestConfiguration = GpuTestConfiguration::new() .parameters(TestParameters::default().expect_fail(FailureCase::webgl2())) - .run_sync(|ctx| { + .run_async(|ctx| async move { // Create depth texture let depth_texture = ctx.device.create_texture(&wgpu::TextureDescriptor { label: Some("Depth texture"), @@ -117,7 +117,9 @@ static OCCLUSION_QUERY: GpuTestConfiguration = GpuTestConfiguration::new() mapping_buffer .slice(..) .map_async(wgpu::MapMode::Read, |_| ()); - ctx.device.poll(wgpu::Maintain::Wait); + ctx.async_poll(wgpu::Maintain::wait()) + .await + .panic_on_timeout(); let query_buffer_view = mapping_buffer.slice(..).get_mapped_range(); let query_data: &[u64; 3] = bytemuck::from_bytes(&query_buffer_view); diff --git a/tests/tests/partially_bounded_arrays/mod.rs b/tests/tests/partially_bounded_arrays/mod.rs index 5a41ae8f29..a1350718f5 100644 --- a/tests/tests/partially_bounded_arrays/mod.rs +++ b/tests/tests/partially_bounded_arrays/mod.rs @@ -14,7 +14,7 @@ static PARTIALLY_BOUNDED_ARRAY: GpuTestConfiguration = GpuTestConfiguration::new ) .limits(wgpu::Limits::downlevel_defaults()), ) - .run_sync(|ctx| { + .run_async(|ctx| async move { let device = &ctx.device; let texture_extent = wgpu::Extent3d { @@ -98,5 +98,6 @@ static PARTIALLY_BOUNDED_ARRAY: GpuTestConfiguration = GpuTestConfiguration::new ctx.queue.submit(Some(encoder.finish())); readback_buffers - .assert_buffer_contents(device, bytemuck::bytes_of(&[4.0f32, 3.0, 2.0, 1.0])); + .assert_buffer_contents(&ctx, bytemuck::bytes_of(&[4.0f32, 3.0, 2.0, 1.0])) + .await; }); diff --git a/tests/tests/poll.rs b/tests/tests/poll.rs index b832237501..740618f23c 100644 --- a/tests/tests/poll.rs +++ b/tests/tests/poll.rs @@ -68,48 +68,60 @@ impl DummyWorkData { } #[gpu_test] -static WAIT: GpuTestConfiguration = GpuTestConfiguration::new().run_sync(|ctx| { +static WAIT: GpuTestConfiguration = GpuTestConfiguration::new().run_async(|ctx| async move { let data = DummyWorkData::new(&ctx); ctx.queue.submit(Some(data.cmd_buf)); - ctx.device.poll(Maintain::Wait); + ctx.async_poll(Maintain::wait()).await.panic_on_timeout(); }); #[gpu_test] -static DOUBLE_WAIT: GpuTestConfiguration = GpuTestConfiguration::new().run_sync(|ctx| { - let data = DummyWorkData::new(&ctx); +static DOUBLE_WAIT: GpuTestConfiguration = + GpuTestConfiguration::new().run_async(|ctx| async move { + let data = DummyWorkData::new(&ctx); - ctx.queue.submit(Some(data.cmd_buf)); - ctx.device.poll(Maintain::Wait); - ctx.device.poll(Maintain::Wait); -}); + ctx.queue.submit(Some(data.cmd_buf)); + ctx.async_poll(Maintain::wait()).await.panic_on_timeout(); + ctx.async_poll(Maintain::wait()).await.panic_on_timeout(); + }); #[gpu_test] -static WAIT_ON_SUBMISSION: GpuTestConfiguration = GpuTestConfiguration::new().run_sync(|ctx| { - let data = DummyWorkData::new(&ctx); +static WAIT_ON_SUBMISSION: GpuTestConfiguration = + GpuTestConfiguration::new().run_async(|ctx| async move { + let data = DummyWorkData::new(&ctx); - let index = ctx.queue.submit(Some(data.cmd_buf)); - ctx.device.poll(Maintain::WaitForSubmissionIndex(index)); -}); + let index = ctx.queue.submit(Some(data.cmd_buf)); + ctx.async_poll(Maintain::wait_for(index)) + .await + .panic_on_timeout(); + }); #[gpu_test] static DOUBLE_WAIT_ON_SUBMISSION: GpuTestConfiguration = - GpuTestConfiguration::new().run_sync(|ctx| { + GpuTestConfiguration::new().run_async(|ctx| async move { let data = DummyWorkData::new(&ctx); let index = ctx.queue.submit(Some(data.cmd_buf)); - ctx.device - .poll(Maintain::WaitForSubmissionIndex(index.clone())); - ctx.device.poll(Maintain::WaitForSubmissionIndex(index)); + ctx.async_poll(Maintain::wait_for(index.clone())) + .await + .panic_on_timeout(); + ctx.async_poll(Maintain::wait_for(index)) + .await + .panic_on_timeout(); }); #[gpu_test] -static WAIT_OUT_OF_ORDER: GpuTestConfiguration = GpuTestConfiguration::new().run_sync(|ctx| { - let data1 = DummyWorkData::new(&ctx); - let data2 = DummyWorkData::new(&ctx); - - let index1 = ctx.queue.submit(Some(data1.cmd_buf)); - let index2 = ctx.queue.submit(Some(data2.cmd_buf)); - ctx.device.poll(Maintain::WaitForSubmissionIndex(index2)); - ctx.device.poll(Maintain::WaitForSubmissionIndex(index1)); -}); +static WAIT_OUT_OF_ORDER: GpuTestConfiguration = + GpuTestConfiguration::new().run_async(|ctx| async move { + let data1 = DummyWorkData::new(&ctx); + let data2 = DummyWorkData::new(&ctx); + + let index1 = ctx.queue.submit(Some(data1.cmd_buf)); + let index2 = ctx.queue.submit(Some(data2.cmd_buf)); + ctx.async_poll(Maintain::wait_for(index2)) + .await + .panic_on_timeout(); + ctx.async_poll(Maintain::wait_for(index1)) + .await + .panic_on_timeout(); + }); diff --git a/tests/tests/push_constants.rs b/tests/tests/push_constants.rs index e39000173c..489d9a10af 100644 --- a/tests/tests/push_constants.rs +++ b/tests/tests/push_constants.rs @@ -19,7 +19,7 @@ static PARTIAL_UPDATE: GpuTestConfiguration = GpuTestConfiguration::new() ..Default::default() }), ) - .run_sync(partial_update_test); + .run_async(partial_update_test); const SHADER: &str = r#" struct Pc { @@ -38,7 +38,7 @@ const SHADER: &str = r#" } "#; -fn partial_update_test(ctx: TestingContext) { +async fn partial_update_test(ctx: TestingContext) { let sm = ctx .device .create_shader_module(wgpu::ShaderModuleDescriptor { @@ -139,7 +139,9 @@ fn partial_update_test(ctx: TestingContext) { encoder.copy_buffer_to_buffer(&gpu_buffer, 0, &cpu_buffer, 0, 32); ctx.queue.submit([encoder.finish()]); cpu_buffer.slice(..).map_async(wgpu::MapMode::Read, |_| ()); - ctx.device.poll(wgpu::Maintain::Wait); + ctx.async_poll(wgpu::Maintain::wait()) + .await + .panic_on_timeout(); let data = cpu_buffer.slice(..).get_mapped_range(); diff --git a/tests/tests/regression/issue_3349.rs b/tests/tests/regression/issue_3349.rs index 5db5575ddf..2d94d56920 100644 --- a/tests/tests/regression/issue_3349.rs +++ b/tests/tests/regression/issue_3349.rs @@ -32,9 +32,9 @@ static MULTI_STAGE_DATA_BINDING: GpuTestConfiguration = GpuTestConfiguration::ne ..Default::default() }), ) - .run_sync(multi_stage_data_binding_test); + .run_async(multi_stage_data_binding_test); -fn multi_stage_data_binding_test(ctx: TestingContext) { +async fn multi_stage_data_binding_test(ctx: TestingContext) { // We use different shader modules to allow us to use different // types for the uniform and push constant blocks between stages. let vs_sm = ctx @@ -174,5 +174,5 @@ fn multi_stage_data_binding_test(ctx: TestingContext) { ctx.queue.submit([encoder.finish()]); let result = input_as_unorm.repeat(4); - buffers.assert_buffer_contents(&ctx.device, &result); + buffers.assert_buffer_contents(&ctx, &result).await; } diff --git a/tests/tests/regression/issue_3457.rs b/tests/tests/regression/issue_3457.rs index d7ea0e5bb9..cc811b3e33 100644 --- a/tests/tests/regression/issue_3457.rs +++ b/tests/tests/regression/issue_3457.rs @@ -16,7 +16,7 @@ use wgpu::*; /// that we unset the correct locations (see PR #3706). #[gpu_test] static PASS_RESET_VERTEX_BUFFER: GpuTestConfiguration = - GpuTestConfiguration::new().run_sync(|ctx| { + GpuTestConfiguration::new().run_async(|ctx| async move { let module = ctx .device .create_shader_module(include_wgsl!("issue_3457.wgsl")); @@ -160,7 +160,7 @@ static PASS_RESET_VERTEX_BUFFER: GpuTestConfiguration = drop(vertex_buffer2); // Make sure the buffers are actually deleted. - ctx.device.poll(Maintain::Wait); + ctx.async_poll(Maintain::wait()).await.panic_on_timeout(); let mut encoder2 = ctx .device diff --git a/tests/tests/regression/issue_4024.rs b/tests/tests/regression/issue_4024.rs index eaf761f316..f4fccfa657 100644 --- a/tests/tests/regression/issue_4024.rs +++ b/tests/tests/regression/issue_4024.rs @@ -14,7 +14,7 @@ use wgpu::*; /// to add them to. This is incorrect, as we do not immediatley invoke map_async callbacks. #[gpu_test] static QUEUE_SUBMITTED_CALLBACK_ORDERING: GpuTestConfiguration = GpuTestConfiguration::new() - .run_sync(|ctx| { + .run_async(|ctx| async move { // Create a mappable buffer let buffer = ctx.device.create_buffer(&BufferDescriptor { label: Some("mappable buffer"), @@ -36,7 +36,7 @@ static QUEUE_SUBMITTED_CALLBACK_ORDERING: GpuTestConfiguration = GpuTestConfigur // Submit the work. ctx.queue.submit(Some(encoder.finish())); // Ensure the work is finished. - ctx.device.poll(MaintainBase::Wait); + ctx.async_poll(Maintain::wait()).await.panic_on_timeout(); #[derive(Debug)] struct OrderingContext { @@ -74,7 +74,7 @@ static QUEUE_SUBMITTED_CALLBACK_ORDERING: GpuTestConfiguration = GpuTestConfigur }); // No GPU work is happening at this point, but we want to process callbacks. - ctx.device.poll(MaintainBase::Poll); + ctx.async_poll(MaintainBase::Poll).await.panic_on_timeout(); // Extract the ordering out of the arc. let ordering = Arc::into_inner(ordering).unwrap().into_inner(); diff --git a/tests/tests/regression/issue_4122.rs b/tests/tests/regression/issue_4122.rs index b3301610be..1dc32f6528 100644 --- a/tests/tests/regression/issue_4122.rs +++ b/tests/tests/regression/issue_4122.rs @@ -1,8 +1,8 @@ use std::ops::Range; -use wgpu_test::{gpu_test, GpuTestConfiguration, TestingContext}; +use wgpu_test::{gpu_test, GpuTestConfiguration, TestParameters, TestingContext}; -fn fill_test(ctx: &TestingContext, range: Range, size: u64) -> bool { +async fn fill_test(ctx: &TestingContext, range: Range, size: u64) -> bool { let gpu_buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor { label: Some("gpu_buffer"), size, @@ -32,7 +32,9 @@ fn fill_test(ctx: &TestingContext, range: Range, size: u64) -> bool { ctx.queue.submit(Some(encoder.finish())); cpu_buffer.slice(..).map_async(wgpu::MapMode::Read, |_| ()); - ctx.device.poll(wgpu::Maintain::Wait); + ctx.async_poll(wgpu::Maintain::wait()) + .await + .panic_on_timeout(); let buffer_slice = cpu_buffer.slice(..); let buffer_data = buffer_slice.get_mapped_range(); @@ -84,8 +86,9 @@ fn fill_test(ctx: &TestingContext, range: Range, size: u64) -> bool { /// /// This test will fail on nvidia if the bug is not properly worked around. #[gpu_test] -static CLEAR_BUFFER_RANGE_RESPECTED: GpuTestConfiguration = - GpuTestConfiguration::new().run_sync(|ctx| { +static CLEAR_BUFFER_RANGE_RESPECTED: GpuTestConfiguration = GpuTestConfiguration::new() + .parameters(TestParameters::default()) + .run_async(|ctx| async move { // This hits most of the cases in nvidia's clear buffer bug let mut succeeded = true; for power in 4..14 { @@ -93,7 +96,7 @@ static CLEAR_BUFFER_RANGE_RESPECTED: GpuTestConfiguration = for start_offset in (0..=36).step_by(4) { for size_offset in (0..=36).step_by(4) { let range = start_offset..size + size_offset + start_offset; - let result = fill_test(&ctx, range, 1 << 16); + let result = fill_test(&ctx, range, 1 << 16).await; succeeded &= result; } diff --git a/tests/tests/scissor_tests/mod.rs b/tests/tests/scissor_tests/mod.rs index 40801a343a..11b72ba7a4 100644 --- a/tests/tests/scissor_tests/mod.rs +++ b/tests/tests/scissor_tests/mod.rs @@ -11,7 +11,11 @@ const TEXTURE_HEIGHT: u32 = 2; const TEXTURE_WIDTH: u32 = 2; const BUFFER_SIZE: usize = (TEXTURE_WIDTH * TEXTURE_HEIGHT * 4) as usize; -fn scissor_test_impl(ctx: &TestingContext, scissor_rect: Rect, expected_data: [u8; BUFFER_SIZE]) { +async fn scissor_test_impl( + ctx: &TestingContext, + scissor_rect: Rect, + expected_data: [u8; BUFFER_SIZE], +) { let texture = ctx.device.create_texture(&wgpu::TextureDescriptor { label: Some("Offscreen texture"), size: wgpu::Extent3d { @@ -94,26 +98,30 @@ fn scissor_test_impl(ctx: &TestingContext, scissor_rect: Rect, expected_data: [u readback_buffer.copy_from(&ctx.device, &mut encoder, &texture); ctx.queue.submit(Some(encoder.finish())); } - readback_buffer.assert_buffer_contents(&ctx.device, &expected_data); + readback_buffer + .assert_buffer_contents(ctx, &expected_data) + .await; } #[gpu_test] -static SCISSOR_TEST_FULL_RECT: GpuTestConfiguration = GpuTestConfiguration::new().run_sync(|ctx| { - scissor_test_impl( - &ctx, - Rect { - x: 0, - y: 0, - width: TEXTURE_WIDTH, - height: TEXTURE_HEIGHT, - }, - [255; BUFFER_SIZE], - ); -}); +static SCISSOR_TEST_FULL_RECT: GpuTestConfiguration = + GpuTestConfiguration::new().run_async(|ctx| async move { + scissor_test_impl( + &ctx, + Rect { + x: 0, + y: 0, + width: TEXTURE_WIDTH, + height: TEXTURE_HEIGHT, + }, + [255; BUFFER_SIZE], + ) + .await + }); #[gpu_test] static SCISSOR_TEST_EMPTY_RECT: GpuTestConfiguration = - GpuTestConfiguration::new().run_sync(|ctx| { + GpuTestConfiguration::new().run_async(|ctx| async move { scissor_test_impl( &ctx, Rect { @@ -123,12 +131,13 @@ static SCISSOR_TEST_EMPTY_RECT: GpuTestConfiguration = height: 0, }, [0; BUFFER_SIZE], - ); + ) + .await; }); #[gpu_test] static SCISSOR_TEST_EMPTY_RECT_WITH_OFFSET: GpuTestConfiguration = GpuTestConfiguration::new() - .run_sync(|ctx| { + .run_async(|ctx| async move { scissor_test_impl( &ctx, Rect { @@ -138,12 +147,13 @@ static SCISSOR_TEST_EMPTY_RECT_WITH_OFFSET: GpuTestConfiguration = GpuTestConfig height: 0, }, [0; BUFFER_SIZE], - ); + ) + .await }); #[gpu_test] static SCISSOR_TEST_CUSTOM_RECT: GpuTestConfiguration = - GpuTestConfiguration::new().run_sync(|ctx| { + GpuTestConfiguration::new().run_async(|ctx| async move { let mut expected_result = [0; BUFFER_SIZE]; expected_result[((3 * BUFFER_SIZE) / 4)..][..BUFFER_SIZE / 4] .copy_from_slice(&[255; BUFFER_SIZE / 4]); @@ -157,5 +167,6 @@ static SCISSOR_TEST_CUSTOM_RECT: GpuTestConfiguration = height: TEXTURE_HEIGHT / 2, }, expected_result, - ); + ) + .await; }); diff --git a/tests/tests/shader/mod.rs b/tests/tests/shader/mod.rs index 48800bfb35..1a981971f7 100644 --- a/tests/tests/shader/mod.rs +++ b/tests/tests/shader/mod.rs @@ -177,7 +177,7 @@ impl ShaderTest { const MAX_BUFFER_SIZE: u64 = 128; /// Runs the given shader tests with the given storage_type for the input_buffer. -fn shader_input_output_test( +async fn shader_input_output_test( ctx: TestingContext, storage_type: InputStorageType, tests: Vec, @@ -355,7 +355,7 @@ fn shader_input_output_test( ctx.queue.submit(Some(encoder.finish())); mapping_buffer.slice(..).map_async(MapMode::Read, |_| ()); - ctx.device.poll(Maintain::Wait); + ctx.async_poll(Maintain::wait()).await.panic_on_timeout(); let mapped = mapping_buffer.slice(..).get_mapped_range(); diff --git a/tests/tests/shader/numeric_builtins.rs b/tests/tests/shader/numeric_builtins.rs index 7463e7a505..26c2a89d92 100644 --- a/tests/tests/shader/numeric_builtins.rs +++ b/tests/tests/shader/numeric_builtins.rs @@ -44,10 +44,10 @@ static NUMERIC_BUILTINS: GpuTestConfiguration = GpuTestConfiguration::new() .downlevel_flags(DownlevelFlags::COMPUTE_SHADERS) .limits(Limits::downlevel_defaults()), ) - .run_sync(|ctx| { + .run_async(|ctx| { shader_input_output_test( ctx, InputStorageType::Storage, create_numeric_builtin_test(), - ); + ) }); diff --git a/tests/tests/shader/struct_layout.rs b/tests/tests/shader/struct_layout.rs index 6377df730d..f5acde971c 100644 --- a/tests/tests/shader/struct_layout.rs +++ b/tests/tests/shader/struct_layout.rs @@ -231,12 +231,12 @@ static UNIFORM_INPUT: GpuTestConfiguration = GpuTestConfiguration::new() ) .limits(Limits::downlevel_defaults()), ) - .run_sync(|ctx| { + .run_async(|ctx| { shader_input_output_test( ctx, InputStorageType::Uniform, create_struct_layout_tests(InputStorageType::Uniform), - ); + ) }); #[gpu_test] @@ -246,12 +246,12 @@ static STORAGE_INPUT: GpuTestConfiguration = GpuTestConfiguration::new() .downlevel_flags(DownlevelFlags::COMPUTE_SHADERS) .limits(Limits::downlevel_defaults()), ) - .run_sync(|ctx| { + .run_async(|ctx| { shader_input_output_test( ctx, InputStorageType::Storage, create_struct_layout_tests(InputStorageType::Storage), - ); + ) }); #[gpu_test] @@ -265,10 +265,10 @@ static PUSH_CONSTANT_INPUT: GpuTestConfiguration = GpuTestConfiguration::new() ..Limits::downlevel_defaults() }), ) - .run_sync(|ctx| { + .run_async(|ctx| { shader_input_output_test( ctx, InputStorageType::PushConstant, create_struct_layout_tests(InputStorageType::PushConstant), - ); + ) }); diff --git a/tests/tests/shader/zero_init_workgroup_mem.rs b/tests/tests/shader/zero_init_workgroup_mem.rs index 86462f1d74..6774f1aac1 100644 --- a/tests/tests/shader/zero_init_workgroup_mem.rs +++ b/tests/tests/shader/zero_init_workgroup_mem.rs @@ -24,7 +24,7 @@ static ZERO_INIT_WORKGROUP_MEMORY: GpuTestConfiguration = GpuTestConfiguration:: ..FailureCase::default() }), ) - .run_sync(|ctx| { + .run_async(|ctx| async move { let bgl = ctx .device .create_bind_group_layout(&BindGroupLayoutDescriptor { @@ -134,7 +134,7 @@ static ZERO_INIT_WORKGROUP_MEMORY: GpuTestConfiguration = GpuTestConfiguration:: ctx.queue.submit(Some(encoder.finish())); mapping_buffer.slice(..).map_async(MapMode::Read, |_| ()); - ctx.device.poll(Maintain::Wait); + ctx.async_poll(Maintain::wait()).await.panic_on_timeout(); let mapped = mapping_buffer.slice(..).get_mapped_range(); diff --git a/tests/tests/shader_primitive_index/mod.rs b/tests/tests/shader_primitive_index/mod.rs index 13ba76a328..096df9c0f7 100644 --- a/tests/tests/shader_primitive_index/mod.rs +++ b/tests/tests/shader_primitive_index/mod.rs @@ -43,7 +43,7 @@ static DRAW: GpuTestConfiguration = GpuTestConfiguration::new() .test_features_limits() .features(wgpu::Features::SHADER_PRIMITIVE_INDEX), ) - .run_sync(|ctx| { + .run_async(|ctx| async move { // // +-----+-----+ // |white|blue | @@ -57,6 +57,7 @@ static DRAW: GpuTestConfiguration = GpuTestConfiguration::new() pulling_common(ctx, &expected, |rpass| { rpass.draw(0..6, 0..1); }) + .await; }); #[gpu_test] @@ -66,7 +67,7 @@ static DRAW_INDEXED: GpuTestConfiguration = GpuTestConfiguration::new() .test_features_limits() .features(wgpu::Features::SHADER_PRIMITIVE_INDEX), ) - .run_sync(|ctx| { + .run_async(|ctx| async move { // // +-----+-----+ // |white| red | @@ -80,9 +81,10 @@ static DRAW_INDEXED: GpuTestConfiguration = GpuTestConfiguration::new() pulling_common(ctx, &expected, |rpass| { rpass.draw_indexed(0..6, 0, 0..1); }) + .await; }); -fn pulling_common( +async fn pulling_common( ctx: TestingContext, expected: &[u8], draw_command: impl FnOnce(&mut wgpu::RenderPass<'_>), @@ -192,5 +194,5 @@ fn pulling_common( } readback_buffer.copy_from(&ctx.device, &mut encoder, &color_texture); ctx.queue.submit(Some(encoder.finish())); - readback_buffer.assert_buffer_contents(&ctx.device, expected); + readback_buffer.assert_buffer_contents(&ctx, expected).await; } diff --git a/tests/tests/shader_view_format/mod.rs b/tests/tests/shader_view_format/mod.rs index 1be6be0a34..842388763b 100644 --- a/tests/tests/shader_view_format/mod.rs +++ b/tests/tests/shader_view_format/mod.rs @@ -8,7 +8,7 @@ static REINTERPRET_SRGB: GpuTestConfiguration = GpuTestConfiguration::new() .downlevel_flags(DownlevelFlags::VIEW_FORMATS) .limits(Limits::downlevel_defaults()), ) - .run_sync(|ctx| { + .run_async(|ctx| async move { let unorm_data: [[u8; 4]; 4] = [ [180, 0, 0, 255], [0, 84, 0, 127], @@ -41,7 +41,8 @@ static REINTERPRET_SRGB: GpuTestConfiguration = GpuTestConfiguration::new() TextureFormat::Rgba8UnormSrgb, &unorm_data, &srgb_data, - ); + ) + .await; // Reinterpret Rgba8UnormSrgb back to Rgba8Unorm reinterpret( @@ -52,10 +53,11 @@ static REINTERPRET_SRGB: GpuTestConfiguration = GpuTestConfiguration::new() TextureFormat::Rgba8Unorm, &srgb_data, &unorm_data, - ); + ) + .await; }); -fn reinterpret( +async fn reinterpret( ctx: &TestingContext, shader: &wgpu::ShaderModule, size: wgpu::Extent3d, @@ -178,7 +180,9 @@ fn reinterpret( let slice = read_buffer.slice(..); slice.map_async(wgpu::MapMode::Read, |_| ()); - ctx.device.poll(wgpu::Maintain::Wait); + ctx.async_poll(wgpu::Maintain::wait()) + .await + .panic_on_timeout(); let data: Vec = slice.get_mapped_range().to_vec(); let tolerance_data: [[u8; 4]; 4] = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [1, 1, 1, 0]]; diff --git a/tests/tests/vertex_indices/mod.rs b/tests/tests/vertex_indices/mod.rs index 063975bda7..156df2d06f 100644 --- a/tests/tests/vertex_indices/mod.rs +++ b/tests/tests/vertex_indices/mod.rs @@ -225,7 +225,7 @@ impl Test { } } -fn vertex_index_common(ctx: TestingContext) { +async fn vertex_index_common(ctx: TestingContext) { let identity_buffer = ctx.device.create_buffer_init(&BufferInitDescriptor { label: Some("identity buffer"), contents: bytemuck::cast_slice(&[0u32, 1, 2, 3, 4, 5, 6, 7, 8]), @@ -428,11 +428,15 @@ fn vertex_index_common(ctx: TestingContext) { // See https://github.com/gfx-rs/wgpu/issues/4732 for why this is split between two submissions // with a hard wait in between. ctx.queue.submit([encoder1.finish()]); - ctx.device.poll(wgpu::Maintain::Wait); + ctx.async_poll(wgpu::Maintain::wait()) + .await + .panic_on_timeout(); ctx.queue.submit([encoder2.finish()]); let slice = cpu_buffer.slice(..); slice.map_async(wgpu::MapMode::Read, |_| ()); - ctx.device.poll(wgpu::Maintain::Wait); + ctx.async_poll(wgpu::Maintain::wait()) + .await + .panic_on_timeout(); let data: Vec = bytemuck::cast_slice(&slice.get_mapped_range()).to_vec(); if data != expected { @@ -463,4 +467,4 @@ static VERTEX_INDICES: GpuTestConfiguration = GpuTestConfiguration::new() .test_features_limits() .features(wgpu::Features::VERTEX_WRITABLE_STORAGE), ) - .run_sync(vertex_index_common); + .run_async(vertex_index_common); diff --git a/tests/tests/write_texture.rs b/tests/tests/write_texture.rs index c6f431737c..f8d99d6d14 100644 --- a/tests/tests/write_texture.rs +++ b/tests/tests/write_texture.rs @@ -4,7 +4,7 @@ use wgpu_test::{gpu_test, GpuTestConfiguration}; #[gpu_test] static WRITE_TEXTURE_SUBSET_2D: GpuTestConfiguration = - GpuTestConfiguration::new().run_sync(|ctx| { + GpuTestConfiguration::new().run_async(|ctx| async move { let size = 256; let tex = ctx.device.create_texture(&wgpu::TextureDescriptor { @@ -84,7 +84,9 @@ static WRITE_TEXTURE_SUBSET_2D: GpuTestConfiguration = let slice = read_buffer.slice(..); slice.map_async(wgpu::MapMode::Read, |_| ()); - ctx.device.poll(wgpu::Maintain::Wait); + ctx.async_poll(wgpu::Maintain::wait()) + .await + .panic_on_timeout(); let data: Vec = slice.get_mapped_range().to_vec(); for byte in &data[..(size as usize * 2)] { @@ -97,7 +99,7 @@ static WRITE_TEXTURE_SUBSET_2D: GpuTestConfiguration = #[gpu_test] static WRITE_TEXTURE_SUBSET_3D: GpuTestConfiguration = - GpuTestConfiguration::new().run_sync(|ctx| { + GpuTestConfiguration::new().run_async(|ctx| async move { let size = 256; let depth = 4; let tex = ctx.device.create_texture(&wgpu::TextureDescriptor { @@ -177,7 +179,9 @@ static WRITE_TEXTURE_SUBSET_3D: GpuTestConfiguration = let slice = read_buffer.slice(..); slice.map_async(wgpu::MapMode::Read, |_| ()); - ctx.device.poll(wgpu::Maintain::Wait); + ctx.async_poll(wgpu::Maintain::wait()) + .await + .panic_on_timeout(); let data: Vec = slice.get_mapped_range().to_vec(); for byte in &data[..((size * size) as usize * 2)] { diff --git a/tests/tests/zero_init_texture_after_discard.rs b/tests/tests/zero_init_texture_after_discard.rs index 82d6ba85d5..d947006d1d 100644 --- a/tests/tests/zero_init_texture_after_discard.rs +++ b/tests/tests/zero_init_texture_after_discard.rs @@ -9,7 +9,7 @@ use wgpu_test::{ static DISCARDING_COLOR_TARGET_RESETS_TEXTURE_INIT_STATE_CHECK_VISIBLE_ON_COPY_AFTER_SUBMIT: GpuTestConfiguration = GpuTestConfiguration::new() .parameters(TestParameters::default().expect_fail(FailureCase::webgl2())) - .run_sync(|mut ctx| { + .run_async(|mut ctx| async move { let mut case = TestCase::new(&mut ctx, TextureFormat::Rgba8UnormSrgb); case.create_command_encoder(); case.discard(); @@ -19,21 +19,21 @@ static DISCARDING_COLOR_TARGET_RESETS_TEXTURE_INIT_STATE_CHECK_VISIBLE_ON_COPY_A case.copy_texture_to_buffer(); case.submit_command_encoder(); - case.assert_buffers_are_zero(); + case.assert_buffers_are_zero().await; }); #[gpu_test] static DISCARDING_COLOR_TARGET_RESETS_TEXTURE_INIT_STATE_CHECK_VISIBLE_ON_COPY_IN_SAME_ENCODER: GpuTestConfiguration = GpuTestConfiguration::new() .parameters(TestParameters::default().expect_fail(FailureCase::webgl2())) - .run_sync(|mut ctx| { + .run_async(|mut ctx| async move { let mut case = TestCase::new(&mut ctx, TextureFormat::Rgba8UnormSrgb); case.create_command_encoder(); case.discard(); case.copy_texture_to_buffer(); case.submit_command_encoder(); - case.assert_buffers_are_zero(); + case.assert_buffers_are_zero().await; }); #[gpu_test] @@ -46,7 +46,7 @@ static DISCARDING_DEPTH_TARGET_RESETS_TEXTURE_INIT_STATE_CHECK_VISIBLE_ON_COPY_I ) .limits(Limits::downlevel_defaults()), ) - .run_sync(|mut ctx| { + .run_async(|mut ctx| async move { for format in [ TextureFormat::Stencil8, TextureFormat::Depth16Unorm, @@ -60,7 +60,7 @@ static DISCARDING_DEPTH_TARGET_RESETS_TEXTURE_INIT_STATE_CHECK_VISIBLE_ON_COPY_I case.copy_texture_to_buffer(); case.submit_command_encoder(); - case.assert_buffers_are_zero(); + case.assert_buffers_are_zero().await; } }); @@ -75,7 +75,7 @@ static DISCARDING_EITHER_DEPTH_OR_STENCIL_ASPECT_TEST: GpuTestConfiguration = ) .limits(Limits::downlevel_defaults()), ) - .run_sync(|mut ctx| { + .run_async(|mut ctx| async move { for format in [ TextureFormat::Stencil8, TextureFormat::Depth16Unorm, @@ -96,7 +96,7 @@ static DISCARDING_EITHER_DEPTH_OR_STENCIL_ASPECT_TEST: GpuTestConfiguration = case.copy_texture_to_buffer(); case.submit_command_encoder(); - case.assert_buffers_are_zero(); + case.assert_buffers_are_zero().await; } }); @@ -310,9 +310,9 @@ impl<'ctx> TestCase<'ctx> { ); } - pub fn assert_buffers_are_zero(&mut self) { + pub async fn assert_buffers_are_zero(&mut self) { assert!( - self.readback_buffers.are_zero(&self.ctx.device), + self.readback_buffers.are_zero(self.ctx).await, "texture was not fully cleared" ); } diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 43c0f465ee..ac8992d25b 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -4280,10 +4280,10 @@ impl Default for ColorWrites { /// Passed to `Device::poll` to control how and if it should block. #[derive(Clone)] pub enum Maintain { - /// On native backends, block until the given submission has + /// On wgpu-core based backends, block until the given submission has /// completed execution, and any callbacks have been invoked. /// - /// On the web, this has no effect. Callbacks are invoked from the + /// On WebGPU, this has no effect. Callbacks are invoked from the /// window event loop. WaitForSubmissionIndex(T), /// Same as WaitForSubmissionIndex but waits for the most recent submission. @@ -4293,6 +4293,22 @@ pub enum Maintain { } impl Maintain { + /// Construct a wait variant + pub fn wait() -> Self { + // This function seems a little silly, but it is useful to allow + // to be split up, as + // it has meaning in that PR. + Self::Wait + } + + /// Construct a WaitForSubmissionIndex variant + pub fn wait_for(submission_index: T) -> Self { + // This function seems a little silly, but it is useful to allow + // to be split up, as + // it has meaning in that PR. + Self::WaitForSubmissionIndex(submission_index) + } + /// This maintain represents a wait of some kind. pub fn is_wait(&self) -> bool { match *self { @@ -4314,6 +4330,29 @@ impl Maintain { } } +/// Result of a maintain operation. +pub enum MaintainResult { + /// There are no active submissions in flight as of the beginning of the poll call. + /// Other submissions may have been queued on other threads at the same time. + /// + /// This implies that the given poll is complete. + SubmissionQueueEmpty, + /// More information coming soon + Ok, +} + +impl MaintainResult { + /// Returns true if the result is [`Self::SubmissionQueueEmpty`]`. + pub fn is_queue_empty(&self) -> bool { + matches!(self, Self::SubmissionQueueEmpty) + } + + /// Panics if the MaintainResult is not Ok. + pub fn panic_on_timeout(self) { + let _ = self; + } +} + /// State of the stencil operation (fixed-pipeline stage). /// /// For use in [`DepthStencilState`]. diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index 05a0db4263..7a59f2f8f9 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -1403,8 +1403,8 @@ impl crate::Context for Context { #[cfg(any(native, emscripten))] { let global = &self.0; - match wgc::gfx_select!(device => global.device_poll(*device, wgt::Maintain::Wait)) { - Ok(_) => (), + match wgc::gfx_select!(device => global.device_poll(*device, wgt::Maintain::wait())) { + Ok(_) => {} Err(err) => self.handle_error_fatal(err, "Device::drop"), } wgc::gfx_select!(device => global.device_drop(*device)); @@ -1445,14 +1445,17 @@ impl crate::Context for Context { device: &Self::DeviceId, _device_data: &Self::DeviceData, maintain: crate::Maintain, - ) -> bool { + ) -> wgt::MaintainResult { let global = &self.0; let maintain_inner = maintain.map_index(|i| *i.1.as_ref().downcast_ref().unwrap()); match wgc::gfx_select!(device => global.device_poll( *device, maintain_inner )) { - Ok(queue_empty) => queue_empty, + Ok(done) => match done { + true => wgt::MaintainResult::SubmissionQueueEmpty, + false => wgt::MaintainResult::Ok, + }, Err(err) => self.handle_error_fatal(err, "Device::poll"), } } diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index 705d33dcca..749a7ba329 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -1950,9 +1950,9 @@ impl crate::context::Context for Context { _device: &Self::DeviceId, _device_data: &Self::DeviceData, _maintain: crate::Maintain, - ) -> bool { + ) -> crate::MaintainResult { // Device is polled automatically - true + crate::MaintainResult::SubmissionQueueEmpty } fn device_on_uncaptured_error( diff --git a/wgpu/src/context.rs b/wgpu/src/context.rs index 2221921623..cec51a57ba 100644 --- a/wgpu/src/context.rs +++ b/wgpu/src/context.rs @@ -10,8 +10,8 @@ use wgt::{ use crate::{ AnyWasmNotSendSync, BindGroupDescriptor, BindGroupLayoutDescriptor, Buffer, BufferAsyncError, BufferDescriptor, CommandEncoderDescriptor, ComputePassDescriptor, ComputePipelineDescriptor, - DeviceDescriptor, Error, ErrorFilter, ImageCopyBuffer, ImageCopyTexture, Maintain, MapMode, - PipelineLayoutDescriptor, QuerySetDescriptor, RenderBundleDescriptor, + DeviceDescriptor, Error, ErrorFilter, ImageCopyBuffer, ImageCopyTexture, Maintain, + MaintainResult, MapMode, PipelineLayoutDescriptor, QuerySetDescriptor, RenderBundleDescriptor, RenderBundleEncoderDescriptor, RenderPassDescriptor, RenderPipelineDescriptor, RequestAdapterOptions, RequestDeviceError, SamplerDescriptor, ShaderModuleDescriptor, ShaderModuleDescriptorSpirV, SurfaceTargetUnsafe, Texture, TextureDescriptor, @@ -287,7 +287,7 @@ pub trait Context: Debug + WasmNotSendSync + Sized { device: &Self::DeviceId, device_data: &Self::DeviceData, maintain: Maintain, - ) -> bool; + ) -> MaintainResult; fn device_on_uncaptured_error( &self, device: &Self::DeviceId, @@ -1309,8 +1309,12 @@ pub(crate) trait DynContext: Debug + WasmNotSendSync { fn device_destroy(&self, device: &ObjectId, device_data: &crate::Data); fn device_mark_lost(&self, device: &ObjectId, device_data: &crate::Data, message: &str); fn queue_drop(&self, queue: &ObjectId, queue_data: &crate::Data); - fn device_poll(&self, device: &ObjectId, device_data: &crate::Data, maintain: Maintain) - -> bool; + fn device_poll( + &self, + device: &ObjectId, + device_data: &crate::Data, + maintain: Maintain, + ) -> MaintainResult; fn device_on_uncaptured_error( &self, device: &ObjectId, @@ -2399,7 +2403,7 @@ where device: &ObjectId, device_data: &crate::Data, maintain: Maintain, - ) -> bool { + ) -> MaintainResult { let device = ::from(*device); let device_data = downcast_ref(device_data); Context::device_poll(self, &device, device_data, maintain) diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 0c65a43100..89fbb23a48 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -85,16 +85,17 @@ pub use wgt::{ DepthStencilState, DeviceLostReason, DeviceType, DownlevelCapabilities, DownlevelFlags, Dx12Compiler, DynamicOffset, Extent3d, Face, Features, FilterMode, FrontFace, Gles3MinorVersion, ImageDataLayout, ImageSubresourceRange, IndexFormat, InstanceDescriptor, - InstanceFlags, Limits, MultisampleState, Origin2d, Origin3d, PipelineStatisticsTypes, - PolygonMode, PowerPreference, PredefinedColorSpace, PresentMode, PresentationTimestamp, - PrimitiveState, PrimitiveTopology, PushConstantRange, QueryType, RenderBundleDepthStencil, - SamplerBindingType, SamplerBorderColor, ShaderLocation, ShaderModel, ShaderStages, - StencilFaceState, StencilOperation, StencilState, StorageTextureAccess, SurfaceCapabilities, - SurfaceStatus, TextureAspect, TextureDimension, TextureFormat, TextureFormatFeatureFlags, - TextureFormatFeatures, TextureSampleType, TextureUsages, TextureViewDimension, VertexAttribute, - VertexFormat, VertexStepMode, WasmNotSend, WasmNotSendSync, WasmNotSync, COPY_BUFFER_ALIGNMENT, - COPY_BYTES_PER_ROW_ALIGNMENT, MAP_ALIGNMENT, PUSH_CONSTANT_ALIGNMENT, - QUERY_RESOLVE_BUFFER_ALIGNMENT, QUERY_SET_MAX_QUERIES, QUERY_SIZE, VERTEX_STRIDE_ALIGNMENT, + InstanceFlags, Limits, MaintainResult, MultisampleState, Origin2d, Origin3d, + PipelineStatisticsTypes, PolygonMode, PowerPreference, PredefinedColorSpace, PresentMode, + PresentationTimestamp, PrimitiveState, PrimitiveTopology, PushConstantRange, QueryType, + RenderBundleDepthStencil, SamplerBindingType, SamplerBorderColor, ShaderLocation, ShaderModel, + ShaderStages, StencilFaceState, StencilOperation, StencilState, StorageTextureAccess, + SurfaceCapabilities, SurfaceStatus, TextureAspect, TextureDimension, TextureFormat, + TextureFormatFeatureFlags, TextureFormatFeatures, TextureSampleType, TextureUsages, + TextureViewDimension, VertexAttribute, VertexFormat, VertexStepMode, WasmNotSend, + WasmNotSendSync, WasmNotSync, COPY_BUFFER_ALIGNMENT, COPY_BYTES_PER_ROW_ALIGNMENT, + MAP_ALIGNMENT, PUSH_CONSTANT_ALIGNMENT, QUERY_RESOLVE_BUFFER_ALIGNMENT, QUERY_SET_MAX_QUERIES, + QUERY_SIZE, VERTEX_STRIDE_ALIGNMENT, }; #[cfg(not(webgpu))] @@ -2205,7 +2206,7 @@ impl Adapter { } impl Device { - /// Check for resource cleanups and mapping callbacks. + /// Check for resource cleanups and mapping callbacks. Will block if [`Maintain::Wait`] is passed. /// /// Return `true` if the queue is empty, or `false` if there are more queue /// submissions still in flight. (Note that, unless access to the [`Queue`] is @@ -2213,8 +2214,8 @@ impl Device { /// the caller receives it. `Queue`s can be shared between threads, so /// other threads could submit new work at any time.) /// - /// On the web, this is a no-op. `Device`s are automatically polled. - pub fn poll(&self, maintain: Maintain) -> bool { + /// When running on WebGPU, this is a no-op. `Device`s are automatically polled. + pub fn poll(&self, maintain: Maintain) -> MaintainResult { DynContext::device_poll(&*self.context, &self.id, self.data.as_ref(), maintain) }