From c5a0b0b7b461e4eb4ea5da9e0906a8b6fd142003 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 14 Jan 2024 23:48:30 -0500 Subject: [PATCH 001/101] Bump the patch-updates group with 12 updates (#5061) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 88 +++++++++++++++++++------------------------ Cargo.toml | 8 ++-- wgpu-core/Cargo.toml | 2 +- wgpu-hal/Cargo.toml | 4 +- wgpu-types/Cargo.toml | 4 +- 5 files changed, 47 insertions(+), 59 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 86d5534198..0d317e1476 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -105,9 +105,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.5" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" +checksum = "4cd2405b3ac1faab2990b74d728624cd9fd115651fcecc7c2d8daf01376275ba" dependencies = [ "anstyle", "anstyle-parse", @@ -273,9 +273,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.6" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c79fed4cdb43e993fcdadc7e58a09fd0e3e649c4436fa11da71c9f1f3ee7feb9" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64-simd" @@ -502,9 +502,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.14" +version = "4.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e92c5c1a78c62968ec57dbc2440366a2d6e5a23faf829970ff1585dc6b18e2" +checksum = "58e54881c004cec7895b0068a0a954cd5d62da01aef83fa35b1e594497bf5445" dependencies = [ "clap_builder", "clap_derive", @@ -512,9 +512,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.14" +version = "4.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4323769dc8a61e2c39ad7dc26f6f2800524691a44d74fe3d1071a5c24db6370" +checksum = "59cb82d7f531603d2fd1f507441cdd35184fa81beff7bd489570de7f773460bb" dependencies = [ "anstream", "anstyle", @@ -1747,14 +1747,13 @@ checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" [[package]] name = "image" -version = "0.24.7" +version = "0.24.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711" +checksum = "034bbe799d1909622a74d1193aa50147769440040ff36cb2baa947609b0a4e23" dependencies = [ "bytemuck", "byteorder", "color_quant", - "num-rational", "num-traits", "png", ] @@ -1842,9 +1841,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.66" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" +checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" dependencies = [ "wasm-bindgen", ] @@ -2275,17 +2274,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-rational" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.17" @@ -2608,9 +2596,9 @@ dependencies = [ [[package]] name = "png" -version = "0.17.10" +version = "0.17.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd75bf2d8dd3702b9707cdbc56a5b9ef42cec752eb8b3bafc01234558442aa64" +checksum = "1f6c3c3e617595665b8ea2ff95a86066be38fb121ff920a9c0eb282abcd1da5a" dependencies = [ "bitflags 1.3.2", "crc32fast", @@ -2621,9 +2609,9 @@ dependencies = [ [[package]] name = "polling" -version = "3.3.1" +version = "3.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf63fa624ab313c11656b4cda960bfc46c410187ad493c41f6ba2d8c1e991c9e" +checksum = "545c980a3880efd47b2e262f6a4bb6daad6555cf3367aa9c4e52895f69537a41" dependencies = [ "cfg-if", "concurrent-queue", @@ -2907,9 +2895,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.28" +version = "0.38.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" dependencies = [ "bitflags 2.4.1", "errno", @@ -3119,9 +3107,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.2" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +checksum = "2593d31f82ead8df961d8bd23a64c2ccf2eb5dd34b0a34bfb4dd54011c72009e" [[package]] name = "smithay-client-toolkit" @@ -3669,9 +3657,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3679,9 +3667,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" dependencies = [ "bumpalo", "log", @@ -3694,9 +3682,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.39" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" +checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" dependencies = [ "cfg-if", "js-sys", @@ -3706,9 +3694,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3716,9 +3704,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" dependencies = [ "proc-macro2", "quote", @@ -3729,15 +3717,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" +checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" [[package]] name = "wasm-bindgen-test" -version = "0.3.39" +version = "0.3.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cf9242c0d27999b831eae4767b2a146feb0b27d332d553e605864acd2afd403" +checksum = "139bd73305d50e1c1c4333210c0db43d989395b64a237bd35c10ef3832a7f70c" dependencies = [ "console_error_panic_hook", "js-sys", @@ -3749,9 +3737,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.39" +version = "0.3.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "794645f5408c9a039fd09f4d113cdfb2e7eba5ff1956b07bcf701cf4b394fe89" +checksum = "70072aebfe5da66d2716002c729a14e4aec4da0e23cc2ea66323dac541c93928" dependencies = [ "proc-macro2", "quote", @@ -3952,9 +3940,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.66" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index bb6be1f1c9..8c9c056803 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -105,7 +105,7 @@ pico-args = { version = "0.5.0", features = [ "short-space-opt", "combined-flags", ] } -png = "0.17.10" +png = "0.17.11" pollster = "0.3" profiling = { version = "1", default-features = false } raw-window-handle = "0.6" @@ -156,11 +156,11 @@ glutin = "0.29.1" # wasm32 dependencies console_error_panic_hook = "0.1.7" console_log = "1" -js-sys = "0.3.66" +js-sys = "0.3.67" wasm-bindgen = "0.2.87" -wasm-bindgen-futures = "0.4.39" +wasm-bindgen-futures = "0.4.40" wasm-bindgen-test = "0.3" -web-sys = "0.3.66" +web-sys = "0.3.67" web-time = "0.2.4" # deno dependencies diff --git a/wgpu-core/Cargo.toml b/wgpu-core/Cargo.toml index eed57cc406..5c2b430338 100644 --- a/wgpu-core/Cargo.toml +++ b/wgpu-core/Cargo.toml @@ -124,7 +124,7 @@ version = "0.18.0" default_features = false [target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies] -web-sys = { version = "0.3.66", features = [ +web-sys = { version = "0.3.67", features = [ "HtmlCanvasElement", "OffscreenCanvas", ] } diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index 36796b33d8..b85a518dc4 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -141,13 +141,13 @@ core-graphics-types = "0.1" [target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies] wasm-bindgen = "0.2.87" -web-sys = { version = "0.3.66", features = [ +web-sys = { version = "0.3.67", features = [ "Window", "HtmlCanvasElement", "WebGl2RenderingContext", "OffscreenCanvas", ] } -js-sys = "0.3.66" +js-sys = "0.3.67" [target.'cfg(unix)'.dependencies] libc = "0.2" diff --git a/wgpu-types/Cargo.toml b/wgpu-types/Cargo.toml index 1b306d0672..90846873b2 100644 --- a/wgpu-types/Cargo.toml +++ b/wgpu-types/Cargo.toml @@ -38,8 +38,8 @@ bitflags = "2" serde = { version = "1", features = ["serde_derive"], optional = true } [target.'cfg(target_arch = "wasm32")'.dependencies] -js-sys = "0.3.66" -web-sys = { version = "0.3.66", features = [ +js-sys = "0.3.67" +web-sys = { version = "0.3.67", features = [ "ImageBitmap", "HtmlVideoElement", "HtmlCanvasElement", From 1da093f7d6b5efc4088399bff2856435ce4e1ef3 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Mon, 15 Jan 2024 12:16:23 +0100 Subject: [PATCH 002/101] Fix cases in which instance creation may not create any context (#5059) * Fix cases in which instance creation may not create any context * split condition steps on picking webgpu instance * comment formulation fix on backend availability Co-authored-by: daxpedda --------- Co-authored-by: daxpedda --- wgpu/src/lib.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 5a518d3c8a..4120894b9b 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -1718,6 +1718,7 @@ impl Instance { /// /// Which feature makes this method return true depends on the target platform: /// * MacOS/iOS: `metal`, `vulkan-portability` or `angle` + /// * Wasm32: `webgpu`, `webgl` or Emscripten target. /// * All other: Always returns true /// /// TODO: Right now it's otherwise not possible yet to opt-out of all features on most platforms. @@ -1735,7 +1736,7 @@ impl Instance { || cfg!(feature = "angle") // On the web, either WebGPU or WebGL must be enabled. } else if cfg!(target_arch = "wasm32") { - cfg!(feature = "webgpu") || cfg!(feature = "webgl") + cfg!(feature = "webgpu") || cfg!(feature = "webgl") || cfg!(target_os = "emscripten") } else { true } @@ -1771,12 +1772,17 @@ impl Instance { } #[cfg(webgpu)] - if _instance_desc.backends.contains(Backends::BROWSER_WEBGPU) - && crate::backend::get_browser_gpu_property().map_or(false, |gpu| !gpu.is_undefined()) { - return Self { - context: Arc::from(crate::backend::ContextWebGpu::init(_instance_desc)), - }; + let is_only_available_backend = !cfg!(wgpu_core); + let requested_webgpu = _instance_desc.backends.contains(Backends::BROWSER_WEBGPU); + let support_webgpu = + crate::backend::get_browser_gpu_property().map_or(false, |gpu| !gpu.is_undefined()); + + if is_only_available_backend || (requested_webgpu && support_webgpu) { + return Self { + context: Arc::from(crate::backend::ContextWebGpu::init(_instance_desc)), + }; + } } #[cfg(wgpu_core)] From 445fa6019b47079c9d336881dbee1c3be3ed4c38 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Mon, 15 Jan 2024 16:43:30 +0100 Subject: [PATCH 003/101] d3d12: Propagate descriptor heap and handle allocation errors (#5065) --- wgpu-hal/src/dx12/descriptor.rs | 54 ++++++++++++++++------------ wgpu-hal/src/dx12/device.rs | 64 +++++++++++++++++---------------- 2 files changed, 65 insertions(+), 53 deletions(-) diff --git a/wgpu-hal/src/dx12/descriptor.rs b/wgpu-hal/src/dx12/descriptor.rs index 2a6d545e72..8833c1adf4 100644 --- a/wgpu-hal/src/dx12/descriptor.rs +++ b/wgpu-hal/src/dx12/descriptor.rs @@ -117,32 +117,40 @@ struct FixedSizeHeap { } impl FixedSizeHeap { - fn new(device: &d3d12::Device, ty: d3d12::DescriptorHeapType) -> Self { - let (heap, _hr) = device.create_descriptor_heap( - HEAP_SIZE_FIXED as _, - ty, - d3d12::DescriptorHeapFlags::empty(), - 0, - ); + fn new( + device: &d3d12::Device, + ty: d3d12::DescriptorHeapType, + ) -> Result { + let heap = device + .create_descriptor_heap( + HEAP_SIZE_FIXED as _, + ty, + d3d12::DescriptorHeapFlags::empty(), + 0, + ) + .into_device_result("Descriptor heap creation")?; - Self { + Ok(Self { handle_size: device.get_descriptor_increment_size(ty) as _, availability: !0, // all free! start: heap.start_cpu_descriptor(), _raw: heap, - } + }) } - fn alloc_handle(&mut self) -> d3d12::CpuDescriptor { + fn alloc_handle(&mut self) -> Result { // Find first free slot. let slot = self.availability.trailing_zeros() as usize; - assert!(slot < HEAP_SIZE_FIXED); + if slot >= HEAP_SIZE_FIXED { + log::error!("Failed to allocate a handle form a fixed size heap"); + return Err(crate::DeviceError::OutOfMemory); + } // Set the slot as occupied. self.availability ^= 1 << slot; - d3d12::CpuDescriptor { + Ok(d3d12::CpuDescriptor { ptr: self.start.ptr + self.handle_size * slot, - } + }) } fn free_handle(&mut self, handle: d3d12::CpuDescriptor) { @@ -189,29 +197,29 @@ impl CpuPool { } } - pub(super) fn alloc_handle(&mut self) -> Handle { + pub(super) fn alloc_handle(&mut self) -> Result { let heap_index = self .avaliable_heap_indices .iter() .next() - .unwrap_or_else(|| { - // Allocate a new heap - let id = self.heaps.len(); - self.heaps.push(FixedSizeHeap::new(&self.device, self.ty)); - self.avaliable_heap_indices.insert(id); - id - }); + .unwrap_or(self.heaps.len()); + + // Allocate a new heap + if heap_index == self.heaps.len() { + self.heaps.push(FixedSizeHeap::new(&self.device, self.ty)?); + self.avaliable_heap_indices.insert(heap_index); + } let heap = &mut self.heaps[heap_index]; let handle = Handle { - raw: heap.alloc_handle(), + raw: heap.alloc_handle()?, heap_index, }; if heap.is_full() { self.avaliable_heap_indices.remove(heap_index); } - handle + Ok(handle) } pub(super) fn free_handle(&mut self, handle: Handle) { diff --git a/wgpu-hal/src/dx12/device.rs b/wgpu-hal/src/dx12/device.rs index 2346dff266..0c1977203f 100644 --- a/wgpu-hal/src/dx12/device.rs +++ b/wgpu-hal/src/dx12/device.rs @@ -138,7 +138,7 @@ impl super::Device { }; let mut rtv_pool = descriptor::CpuPool::new(raw.clone(), d3d12::DescriptorHeapType::Rtv); - let null_rtv_handle = rtv_pool.alloc_handle(); + let null_rtv_handle = rtv_pool.alloc_handle()?; // A null pResource is used to initialize a null descriptor, // which guarantees D3D11-like null binding behavior (reading 0s, writes are discarded) raw.create_render_target_view( @@ -476,43 +476,47 @@ impl crate::Device for super::Device { texture.calc_subresource(desc.range.base_mip_level, desc.range.base_array_layer, 0), ), handle_srv: if desc.usage.intersects(crate::TextureUses::RESOURCE) { - let raw_desc = unsafe { view_desc.to_srv() }; - raw_desc.map(|raw_desc| { - let handle = self.srv_uav_pool.lock().alloc_handle(); - unsafe { - self.raw.CreateShaderResourceView( - texture.resource.as_mut_ptr(), - &raw_desc, - handle.raw, - ) - }; - handle - }) + match unsafe { view_desc.to_srv() } { + Some(raw_desc) => { + let handle = self.srv_uav_pool.lock().alloc_handle()?; + unsafe { + self.raw.CreateShaderResourceView( + texture.resource.as_mut_ptr(), + &raw_desc, + handle.raw, + ) + }; + Some(handle) + } + None => None, + } } else { None }, handle_uav: if desc.usage.intersects( crate::TextureUses::STORAGE_READ | crate::TextureUses::STORAGE_READ_WRITE, ) { - let raw_desc = unsafe { view_desc.to_uav() }; - raw_desc.map(|raw_desc| { - let handle = self.srv_uav_pool.lock().alloc_handle(); - unsafe { - self.raw.CreateUnorderedAccessView( - texture.resource.as_mut_ptr(), - ptr::null_mut(), - &raw_desc, - handle.raw, - ) - }; - handle - }) + match unsafe { view_desc.to_uav() } { + Some(raw_desc) => { + let handle = self.srv_uav_pool.lock().alloc_handle()?; + unsafe { + self.raw.CreateUnorderedAccessView( + texture.resource.as_mut_ptr(), + ptr::null_mut(), + &raw_desc, + handle.raw, + ); + } + Some(handle) + } + None => None, + } } else { None }, handle_rtv: if desc.usage.intersects(crate::TextureUses::COLOR_TARGET) { let raw_desc = unsafe { view_desc.to_rtv() }; - let handle = self.rtv_pool.lock().alloc_handle(); + let handle = self.rtv_pool.lock().alloc_handle()?; unsafe { self.raw.CreateRenderTargetView( texture.resource.as_mut_ptr(), @@ -529,7 +533,7 @@ impl crate::Device for super::Device { .intersects(crate::TextureUses::DEPTH_STENCIL_READ) { let raw_desc = unsafe { view_desc.to_dsv(true) }; - let handle = self.dsv_pool.lock().alloc_handle(); + let handle = self.dsv_pool.lock().alloc_handle()?; unsafe { self.raw.CreateDepthStencilView( texture.resource.as_mut_ptr(), @@ -546,7 +550,7 @@ impl crate::Device for super::Device { .intersects(crate::TextureUses::DEPTH_STENCIL_WRITE) { let raw_desc = unsafe { view_desc.to_dsv(false) }; - let handle = self.dsv_pool.lock().alloc_handle(); + let handle = self.dsv_pool.lock().alloc_handle()?; unsafe { self.raw.CreateDepthStencilView( texture.resource.as_mut_ptr(), @@ -588,7 +592,7 @@ impl crate::Device for super::Device { &self, desc: &crate::SamplerDescriptor, ) -> Result { - let handle = self.sampler_pool.lock().alloc_handle(); + let handle = self.sampler_pool.lock().alloc_handle()?; let reduction = match desc.compare { Some(_) => d3d12_ty::D3D12_FILTER_REDUCTION_TYPE_COMPARISON, From 90b078f0371f3938219dea60ab042f469c92c333 Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Tue, 16 Jan 2024 11:15:56 +0100 Subject: [PATCH 004/101] Improve ergonomics of gfx_select! (#5069) --- deno_webgpu/binding.rs | 6 +- deno_webgpu/buffer.rs | 3 +- deno_webgpu/bundle.rs | 3 +- deno_webgpu/command_encoder.rs | 6 +- deno_webgpu/lib.rs | 27 ++-- deno_webgpu/pipeline.rs | 9 +- deno_webgpu/sampler.rs | 3 +- deno_webgpu/shader.rs | 3 +- deno_webgpu/texture.rs | 3 +- wgpu-core/src/error.rs | 30 ++-- wgpu-core/src/lib.rs | 22 ++- wgpu/src/backend/wgpu_core.rs | 271 +++++++++++---------------------- 12 files changed, 147 insertions(+), 239 deletions(-) diff --git a/deno_webgpu/binding.rs b/deno_webgpu/binding.rs index 5d582e900f..5f1abde2b8 100644 --- a/deno_webgpu/binding.rs +++ b/deno_webgpu/binding.rs @@ -21,8 +21,7 @@ impl Resource for WebGpuBindGroupLayout { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.bind_group_layout_drop(self.1)); + gfx_select!(self.1 => self.0.bind_group_layout_drop(self.1)); } } @@ -36,8 +35,7 @@ impl Resource for WebGpuBindGroup { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.bind_group_drop(self.1)); + gfx_select!(self.1 => self.0.bind_group_drop(self.1)); } } diff --git a/deno_webgpu/buffer.rs b/deno_webgpu/buffer.rs index 171642e1dc..b46ceb1973 100644 --- a/deno_webgpu/buffer.rs +++ b/deno_webgpu/buffer.rs @@ -26,8 +26,7 @@ impl Resource for WebGpuBuffer { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.buffer_drop(self.1, true)); + gfx_select!(self.1 => self.0.buffer_drop(self.1, true)); } } diff --git a/deno_webgpu/bundle.rs b/deno_webgpu/bundle.rs index b053cf265c..7e37bc649e 100644 --- a/deno_webgpu/bundle.rs +++ b/deno_webgpu/bundle.rs @@ -30,8 +30,7 @@ impl Resource for WebGpuRenderBundle { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.render_bundle_drop(self.1)); + gfx_select!(self.1 => self.0.render_bundle_drop(self.1)); } } diff --git a/deno_webgpu/command_encoder.rs b/deno_webgpu/command_encoder.rs index 7079fd96cf..33f271ce97 100644 --- a/deno_webgpu/command_encoder.rs +++ b/deno_webgpu/command_encoder.rs @@ -23,8 +23,7 @@ impl Resource for WebGpuCommandEncoder { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.command_encoder_drop(self.1)); + gfx_select!(self.1 => self.0.command_encoder_drop(self.1)); } } @@ -39,8 +38,7 @@ impl Resource for WebGpuCommandBuffer { fn close(self: Rc) { if let Some(id) = *self.1.borrow() { - let instance = &self.0; - gfx_select!(id => instance.command_buffer_drop(id)); + gfx_select!(id => self.0.command_buffer_drop(id)); } } } diff --git a/deno_webgpu/lib.rs b/deno_webgpu/lib.rs index 15151ce952..bc6d7a2ae5 100644 --- a/deno_webgpu/lib.rs +++ b/deno_webgpu/lib.rs @@ -22,23 +22,31 @@ use error::WebGpuResult; #[macro_use] mod macros { macro_rules! gfx_select { - ($id:expr => $global:ident.$method:ident( $($param:expr),* )) => { + ($id:expr => $p0:ident.$p1:tt.$method:ident $params:tt) => { + gfx_select!($id => {$p0.$p1}, $method $params) + }; + + ($id:expr => $p0:ident.$method:ident $params:tt) => { + gfx_select!($id => {$p0}, $method $params) + }; + + ($id:expr => {$($c:tt)*}, $method:ident $params:tt) => { match $id.backend() { #[cfg(any( all(not(target_arch = "wasm32"), not(target_os = "ios"), not(target_os = "macos")), feature = "vulkan-portability" ))] - wgpu_types::Backend::Vulkan => $global.$method::( $($param),* ), + wgpu_types::Backend::Vulkan => $($c)*.$method:: $params, #[cfg(all(not(target_arch = "wasm32"), any(target_os = "ios", target_os = "macos")))] - wgpu_types::Backend::Metal => $global.$method::( $($param),* ), + wgpu_types::Backend::Metal => $($c)*.$method:: $params, #[cfg(all(not(target_arch = "wasm32"), windows))] - wgpu_types::Backend::Dx12 => $global.$method::( $($param),* ), + wgpu_types::Backend::Dx12 => $($c)*.$method:: $params, #[cfg(any( all(unix, not(target_os = "macos"), not(target_os = "ios")), feature = "angle", target_arch = "wasm32" ))] - wgpu_types::Backend::Gl => $global.$method::( $($param),+ ), + wgpu_types::Backend::Gl => $($c)*.$method:: $params, other => panic!("Unexpected backend {:?}", other), } }; @@ -98,8 +106,7 @@ impl Resource for WebGpuAdapter { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.adapter_drop(self.1)); + gfx_select!(self.1 => self.0.adapter_drop(self.1)); } } @@ -110,8 +117,7 @@ impl Resource for WebGpuDevice { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.device_drop(self.1)); + gfx_select!(self.1 => self.0.device_drop(self.1)); } } @@ -122,8 +128,7 @@ impl Resource for WebGpuQuerySet { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.query_set_drop(self.1)); + gfx_select!(self.1 => self.0.query_set_drop(self.1)); } } diff --git a/deno_webgpu/pipeline.rs b/deno_webgpu/pipeline.rs index e0555b9d1e..bf98b690b7 100644 --- a/deno_webgpu/pipeline.rs +++ b/deno_webgpu/pipeline.rs @@ -25,8 +25,7 @@ impl Resource for WebGpuPipelineLayout { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.pipeline_layout_drop(self.1)); + gfx_select!(self.1 => self.0.pipeline_layout_drop(self.1)); } } @@ -40,8 +39,7 @@ impl Resource for WebGpuComputePipeline { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.compute_pipeline_drop(self.1)); + gfx_select!(self.1 => self.0.compute_pipeline_drop(self.1)); } } @@ -55,8 +53,7 @@ impl Resource for WebGpuRenderPipeline { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.render_pipeline_drop(self.1)); + gfx_select!(self.1 => self.0.render_pipeline_drop(self.1)); } } diff --git a/deno_webgpu/sampler.rs b/deno_webgpu/sampler.rs index 6f9b66ad4d..5876498b29 100644 --- a/deno_webgpu/sampler.rs +++ b/deno_webgpu/sampler.rs @@ -21,8 +21,7 @@ impl Resource for WebGpuSampler { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.sampler_drop(self.1)); + gfx_select!(self.1 => self.0.sampler_drop(self.1)); } } diff --git a/deno_webgpu/shader.rs b/deno_webgpu/shader.rs index f7cce24281..f091b15f8f 100644 --- a/deno_webgpu/shader.rs +++ b/deno_webgpu/shader.rs @@ -20,8 +20,7 @@ impl Resource for WebGpuShaderModule { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.shader_module_drop(self.1)); + gfx_select!(self.1 => self.0.shader_module_drop(self.1)); } } diff --git a/deno_webgpu/texture.rs b/deno_webgpu/texture.rs index 5eadd5b3c2..8e1afa492f 100644 --- a/deno_webgpu/texture.rs +++ b/deno_webgpu/texture.rs @@ -39,8 +39,7 @@ impl Resource for WebGpuTextureView { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.texture_view_drop(self.1, true)).unwrap(); + gfx_select!(self.1 => self.0.texture_view_drop(self.1, true)).unwrap(); } } diff --git a/wgpu-core/src/error.rs b/wgpu-core/src/error.rs index a6e3d31587..4a33207ca8 100644 --- a/wgpu-core/src/error.rs +++ b/wgpu-core/src/error.rs @@ -24,32 +24,27 @@ impl<'a> ErrorFormatter<'a> { } pub fn bind_group_label(&mut self, id: &crate::id::BindGroupId) { - let global = self.global; - let label: String = gfx_select!(id => global.bind_group_label(*id)); + let label: String = gfx_select!(id => self.global.bind_group_label(*id)); self.label("bind group", &label); } pub fn bind_group_layout_label(&mut self, id: &crate::id::BindGroupLayoutId) { - let global = self.global; - let label: String = gfx_select!(id => global.bind_group_layout_label(*id)); + let label: String = gfx_select!(id => self.global.bind_group_layout_label(*id)); self.label("bind group layout", &label); } pub fn render_pipeline_label(&mut self, id: &crate::id::RenderPipelineId) { - let global = self.global; - let label: String = gfx_select!(id => global.render_pipeline_label(*id)); + let label: String = gfx_select!(id => self.global.render_pipeline_label(*id)); self.label("render pipeline", &label); } pub fn compute_pipeline_label(&mut self, id: &crate::id::ComputePipelineId) { - let global = self.global; - let label: String = gfx_select!(id => global.compute_pipeline_label(*id)); + let label: String = gfx_select!(id => self.global.compute_pipeline_label(*id)); self.label("compute pipeline", &label); } pub fn buffer_label_with_key(&mut self, id: &crate::id::BufferId, key: &str) { - let global = self.global; - let label: String = gfx_select!(id => global.buffer_label(*id)); + let label: String = gfx_select!(id => self.global.buffer_label(*id)); self.label(key, &label); } @@ -58,8 +53,7 @@ impl<'a> ErrorFormatter<'a> { } pub fn texture_label_with_key(&mut self, id: &crate::id::TextureId, key: &str) { - let global = self.global; - let label: String = gfx_select!(id => global.texture_label(*id)); + let label: String = gfx_select!(id => self.global.texture_label(*id)); self.label(key, &label); } @@ -68,8 +62,7 @@ impl<'a> ErrorFormatter<'a> { } pub fn texture_view_label_with_key(&mut self, id: &crate::id::TextureViewId, key: &str) { - let global = self.global; - let label: String = gfx_select!(id => global.texture_view_label(*id)); + let label: String = gfx_select!(id => self.global.texture_view_label(*id)); self.label(key, &label); } @@ -78,20 +71,17 @@ impl<'a> ErrorFormatter<'a> { } pub fn sampler_label(&mut self, id: &crate::id::SamplerId) { - let global = self.global; - let label: String = gfx_select!(id => global.sampler_label(*id)); + let label: String = gfx_select!(id => self.global.sampler_label(*id)); self.label("sampler", &label); } pub fn command_buffer_label(&mut self, id: &crate::id::CommandBufferId) { - let global = self.global; - let label: String = gfx_select!(id => global.command_buffer_label(*id)); + let label: String = gfx_select!(id => self.global.command_buffer_label(*id)); self.label("command buffer", &label); } pub fn query_set_label(&mut self, id: &crate::id::QuerySetId) { - let global = self.global; - let label: String = gfx_select!(id => global.query_set_label(*id)); + let label: String = gfx_select!(id => self.global.query_set_label(*id)); self.label("query set", &label); } } diff --git a/wgpu-core/src/lib.rs b/wgpu-core/src/lib.rs index a35fcacec2..4fd2845377 100644 --- a/wgpu-core/src/lib.rs +++ b/wgpu-core/src/lib.rs @@ -307,13 +307,23 @@ define_backend_caller! { gfx_if_empty, gfx_if_empty_hidden, "empty" if all( /// [`Id`]: id::Id #[macro_export] macro_rules! gfx_select { - ($id:expr => $global:ident.$method:ident( $($param:expr),* )) => { + // Simple two-component expression, like `self.0.method(..)`. + ($id:expr => $c0:ident.$c1:tt.$method:ident $params:tt) => { + $crate::gfx_select!($id => {$c0.$c1}, $method $params) + }; + + // Simple identifier-only expression, like `global.method(..)`. + ($id:expr => $c0:ident.$method:ident $params:tt) => { + $crate::gfx_select!($id => {$c0}, $method $params) + }; + + ($id:expr => {$($c:tt)*}, $method:ident $params:tt) => { match $id.backend() { - wgt::Backend::Vulkan => $crate::gfx_if_vulkan!($global.$method::<$crate::api::Vulkan>( $($param),* )), - wgt::Backend::Metal => $crate::gfx_if_metal!($global.$method::<$crate::api::Metal>( $($param),* )), - wgt::Backend::Dx12 => $crate::gfx_if_dx12!($global.$method::<$crate::api::Dx12>( $($param),* )), - wgt::Backend::Gl => $crate::gfx_if_gles!($global.$method::<$crate::api::Gles>( $($param),+ )), - wgt::Backend::Empty => $crate::gfx_if_empty!($global.$method::<$crate::api::Empty>( $($param),+ )), + wgt::Backend::Vulkan => $crate::gfx_if_vulkan!($($c)*.$method::<$crate::api::Vulkan> $params), + wgt::Backend::Metal => $crate::gfx_if_metal!($($c)*.$method::<$crate::api::Metal> $params), + wgt::Backend::Dx12 => $crate::gfx_if_dx12!($($c)*.$method::<$crate::api::Dx12> $params), + wgt::Backend::Gl => $crate::gfx_if_gles!($($c)*.$method::<$crate::api::Gles> $params), + wgt::Backend::Empty => $crate::gfx_if_empty!($($c)*.$method::<$crate::api::Empty> $params), other => panic!("Unexpected backend {:?}", other), } }; diff --git a/wgpu/src/backend/wgpu_core.rs b/wgpu/src/backend/wgpu_core.rs index c141eddb67..3d5fd1d149 100644 --- a/wgpu/src/backend/wgpu_core.rs +++ b/wgpu/src/backend/wgpu_core.rs @@ -107,9 +107,8 @@ impl ContextWgpuCore { desc: &crate::DeviceDescriptor<'_>, trace_dir: Option<&std::path::Path>, ) -> Result<(Device, Queue), crate::RequestDeviceError> { - let global = &self.0; let (device_id, queue_id, error) = unsafe { - global.create_device_from_hal( + self.0.create_device_from_hal( *adapter, hal_device, &desc.map_label(|l| l.map(Borrowed)), @@ -141,9 +140,10 @@ impl ContextWgpuCore { desc: &TextureDescriptor<'_>, ) -> Texture { let descriptor = desc.map_label_and_view_formats(|l| l.map(Borrowed), |v| v.to_vec()); - let global = &self.0; - let (id, error) = - unsafe { global.create_texture_from_hal::(hal_texture, device.id, &descriptor, ()) }; + let (id, error) = unsafe { + self.0 + .create_texture_from_hal::(hal_texture, device.id, &descriptor, ()) + }; if let Some(cause) = error { self.handle_error( &device.error_sink, @@ -165,9 +165,8 @@ impl ContextWgpuCore { device: &Device, desc: &BufferDescriptor<'_>, ) -> (wgc::id::BufferId, Buffer) { - let global = &self.0; let (id, error) = unsafe { - global.create_buffer_from_hal::( + self.0.create_buffer_from_hal::( hal_buffer, device.id, &desc.map_label(|l| l.map(Borrowed)), @@ -585,8 +584,7 @@ impl crate::Context for ContextWgpuCore { desc: &crate::DeviceDescriptor<'_>, trace_dir: Option<&std::path::Path>, ) -> Self::RequestDeviceFuture { - let global = &self.0; - let (device_id, queue_id, error) = wgc::gfx_select!(*adapter => global.adapter_request_device( + let (device_id, queue_id, error) = wgc::gfx_select!(*adapter => self.0.adapter_request_device( *adapter, &desc.map_label(|l| l.map(Borrowed)), trace_dir, @@ -610,8 +608,7 @@ impl crate::Context for ContextWgpuCore { } fn instance_poll_all_devices(&self, force_wait: bool) -> bool { - let global = &self.0; - match global.poll_all_devices(force_wait) { + match self.0.poll_all_devices(force_wait) { Ok(all_queue_empty) => all_queue_empty, Err(err) => self.handle_error_fatal(err, "Device::poll"), } @@ -624,8 +621,7 @@ impl crate::Context for ContextWgpuCore { surface: &Self::SurfaceId, _surface_data: &Self::SurfaceData, ) -> bool { - let global = &self.0; - match wgc::gfx_select!(adapter => global.adapter_is_surface_supported(*adapter, *surface)) { + match wgc::gfx_select!(adapter => self.0.adapter_is_surface_supported(*adapter, *surface)) { Ok(result) => result, Err(err) => self.handle_error_fatal(err, "Adapter::is_surface_supported"), } @@ -636,8 +632,7 @@ impl crate::Context for ContextWgpuCore { adapter: &Self::AdapterId, _adapter_data: &Self::AdapterData, ) -> Features { - let global = &self.0; - match wgc::gfx_select!(*adapter => global.adapter_features(*adapter)) { + match wgc::gfx_select!(*adapter => self.0.adapter_features(*adapter)) { Ok(features) => features, Err(err) => self.handle_error_fatal(err, "Adapter::features"), } @@ -648,8 +643,7 @@ impl crate::Context for ContextWgpuCore { adapter: &Self::AdapterId, _adapter_data: &Self::AdapterData, ) -> Limits { - let global = &self.0; - match wgc::gfx_select!(*adapter => global.adapter_limits(*adapter)) { + match wgc::gfx_select!(*adapter => self.0.adapter_limits(*adapter)) { Ok(limits) => limits, Err(err) => self.handle_error_fatal(err, "Adapter::limits"), } @@ -660,8 +654,7 @@ impl crate::Context for ContextWgpuCore { adapter: &Self::AdapterId, _adapter_data: &Self::AdapterData, ) -> DownlevelCapabilities { - let global = &self.0; - match wgc::gfx_select!(*adapter => global.adapter_downlevel_capabilities(*adapter)) { + match wgc::gfx_select!(*adapter => self.0.adapter_downlevel_capabilities(*adapter)) { Ok(downlevel) => downlevel, Err(err) => self.handle_error_fatal(err, "Adapter::downlevel_properties"), } @@ -672,8 +665,7 @@ impl crate::Context for ContextWgpuCore { adapter: &wgc::id::AdapterId, _adapter_data: &Self::AdapterData, ) -> AdapterInfo { - let global = &self.0; - match wgc::gfx_select!(*adapter => global.adapter_get_info(*adapter)) { + match wgc::gfx_select!(*adapter => self.0.adapter_get_info(*adapter)) { Ok(info) => info, Err(err) => self.handle_error_fatal(err, "Adapter::get_info"), } @@ -685,8 +677,7 @@ impl crate::Context for ContextWgpuCore { _adapter_data: &Self::AdapterData, format: wgt::TextureFormat, ) -> wgt::TextureFormatFeatures { - let global = &self.0; - match wgc::gfx_select!(*adapter => global.adapter_get_texture_format_features(*adapter, format)) + match wgc::gfx_select!(*adapter => self.0.adapter_get_texture_format_features(*adapter, format)) { Ok(info) => info, Err(err) => self.handle_error_fatal(err, "Adapter::get_texture_format_features"), @@ -698,8 +689,7 @@ impl crate::Context for ContextWgpuCore { adapter: &Self::AdapterId, _adapter_data: &Self::AdapterData, ) -> wgt::PresentationTimestamp { - let global = &self.0; - match wgc::gfx_select!(*adapter => global.adapter_get_presentation_timestamp(*adapter)) { + match wgc::gfx_select!(*adapter => self.0.adapter_get_presentation_timestamp(*adapter)) { Ok(timestamp) => timestamp, Err(err) => self.handle_error_fatal(err, "Adapter::correlate_presentation_timestamp"), } @@ -712,8 +702,7 @@ impl crate::Context for ContextWgpuCore { adapter: &Self::AdapterId, _adapter_data: &Self::AdapterData, ) -> wgt::SurfaceCapabilities { - let global = &self.0; - match wgc::gfx_select!(adapter => global.surface_get_capabilities(*surface, *adapter)) { + match wgc::gfx_select!(adapter => self.0.surface_get_capabilities(*surface, *adapter)) { Ok(caps) => caps, Err(wgc::instance::GetSurfaceSupportError::Unsupported) => { wgt::SurfaceCapabilities::default() @@ -730,8 +719,7 @@ impl crate::Context for ContextWgpuCore { _device_data: &Self::DeviceData, config: &crate::SurfaceConfiguration, ) { - let global = &self.0; - let error = wgc::gfx_select!(device => global.surface_configure(*surface, *device, config)); + let error = wgc::gfx_select!(device => self.0.surface_configure(*surface, *device, config)); if let Some(e) = error { self.handle_error_fatal(e, "Surface::configure"); } else { @@ -749,13 +737,12 @@ impl crate::Context for ContextWgpuCore { SurfaceStatus, Self::SurfaceOutputDetail, ) { - let global = &self.0; let device_id = surface_data .configured_device .lock() .expect("Surface was not configured?"); match wgc::gfx_select!( - device_id => global.surface_get_current_texture(*surface, ()) + device_id => self.0.surface_get_current_texture(*surface, ()) ) { Ok(wgc::present::SurfaceOutput { status, texture_id }) => { let (id, data) = { @@ -782,8 +769,7 @@ impl crate::Context for ContextWgpuCore { } fn surface_present(&self, texture: &Self::TextureId, detail: &Self::SurfaceOutputDetail) { - let global = &self.0; - match wgc::gfx_select!(texture => global.surface_present(detail.surface_id)) { + match wgc::gfx_select!(texture => self.0.surface_present(detail.surface_id)) { Ok(_status) => (), Err(err) => self.handle_error_fatal(err, "Surface::present"), } @@ -794,8 +780,7 @@ impl crate::Context for ContextWgpuCore { texture: &Self::TextureId, detail: &Self::SurfaceOutputDetail, ) { - let global = &self.0; - match wgc::gfx_select!(texture => global.surface_texture_discard(detail.surface_id)) { + match wgc::gfx_select!(texture => self.0.surface_texture_discard(detail.surface_id)) { Ok(_status) => (), Err(err) => self.handle_error_fatal(err, "Surface::discard_texture"), } @@ -806,16 +791,14 @@ impl crate::Context for ContextWgpuCore { device: &Self::DeviceId, _device_data: &Self::DeviceData, ) -> Features { - let global = &self.0; - match wgc::gfx_select!(device => global.device_features(*device)) { + match wgc::gfx_select!(device => self.0.device_features(*device)) { Ok(features) => features, Err(err) => self.handle_error_fatal(err, "Device::features"), } } fn device_limits(&self, device: &Self::DeviceId, _device_data: &Self::DeviceData) -> Limits { - let global = &self.0; - match wgc::gfx_select!(device => global.device_limits(*device)) { + match wgc::gfx_select!(device => self.0.device_limits(*device)) { Ok(limits) => limits, Err(err) => self.handle_error_fatal(err, "Device::limits"), } @@ -826,8 +809,7 @@ impl crate::Context for ContextWgpuCore { device: &Self::DeviceId, _device_data: &Self::DeviceData, ) -> DownlevelCapabilities { - let global = &self.0; - match wgc::gfx_select!(device => global.device_downlevel_properties(*device)) { + match wgc::gfx_select!(device => self.0.device_downlevel_properties(*device)) { Ok(limits) => limits, Err(err) => self.handle_error_fatal(err, "Device::downlevel_properties"), } @@ -849,7 +831,6 @@ impl crate::Context for ContextWgpuCore { desc: ShaderModuleDescriptor<'_>, shader_bound_checks: wgt::ShaderBoundChecks, ) -> (Self::ShaderModuleId, Self::ShaderModuleData) { - let global = &self.0; let descriptor = wgc::pipeline::ShaderModuleDescriptor { label: desc.label.map(Borrowed), shader_bound_checks, @@ -890,7 +871,7 @@ impl crate::Context for ContextWgpuCore { ShaderSource::Dummy(_) => panic!("found `ShaderSource::Dummy`"), }; let (id, error) = wgc::gfx_select!( - device => global.device_create_shader_module(*device, &descriptor, source, ()) + device => self.0.device_create_shader_module(*device, &descriptor, source, ()) ); if let Some(cause) = error { self.handle_error( @@ -910,7 +891,6 @@ impl crate::Context for ContextWgpuCore { device_data: &Self::DeviceData, desc: &ShaderModuleDescriptorSpirV<'_>, ) -> (Self::ShaderModuleId, Self::ShaderModuleData) { - let global = &self.0; let descriptor = wgc::pipeline::ShaderModuleDescriptor { label: desc.label.map(Borrowed), // Doesn't matter the value since spirv shaders aren't mutated to include @@ -918,7 +898,7 @@ impl crate::Context for ContextWgpuCore { shader_bound_checks: unsafe { wgt::ShaderBoundChecks::unchecked() }, }; let (id, error) = wgc::gfx_select!( - device => global.device_create_shader_module_spirv(*device, &descriptor, Borrowed(&desc.source), ()) + device => self.0.device_create_shader_module_spirv(*device, &descriptor, Borrowed(&desc.source), ()) ); if let Some(cause) = error { self.handle_error( @@ -938,13 +918,12 @@ impl crate::Context for ContextWgpuCore { device_data: &Self::DeviceData, desc: &BindGroupLayoutDescriptor<'_>, ) -> (Self::BindGroupLayoutId, Self::BindGroupLayoutData) { - let global = &self.0; let descriptor = wgc::binding_model::BindGroupLayoutDescriptor { label: desc.label.map(Borrowed), entries: Borrowed(desc.entries), }; let (id, error) = wgc::gfx_select!( - device => global.device_create_bind_group_layout(*device, &descriptor, ()) + device => self.0.device_create_bind_group_layout(*device, &descriptor, ()) ); if let Some(cause) = error { self.handle_error( @@ -1055,8 +1034,7 @@ impl crate::Context for ContextWgpuCore { entries: Borrowed(&entries), }; - let global = &self.0; - let (id, error) = wgc::gfx_select!(device => global.device_create_bind_group( + let (id, error) = wgc::gfx_select!(device => self.0.device_create_bind_group( *device, &descriptor, () @@ -1098,8 +1076,7 @@ impl crate::Context for ContextWgpuCore { push_constant_ranges: Borrowed(desc.push_constant_ranges), }; - let global = &self.0; - let (id, error) = wgc::gfx_select!(device => global.device_create_pipeline_layout( + let (id, error) = wgc::gfx_select!(device => self.0.device_create_pipeline_layout( *device, &descriptor, () @@ -1164,8 +1141,7 @@ impl crate::Context for ContextWgpuCore { multiview: desc.multiview, }; - let global = &self.0; - let (id, error) = wgc::gfx_select!(device => global.device_create_render_pipeline( + let (id, error) = wgc::gfx_select!(device => self.0.device_create_render_pipeline( *device, &descriptor, (), @@ -1210,8 +1186,7 @@ impl crate::Context for ContextWgpuCore { }, }; - let global = &self.0; - let (id, error) = wgc::gfx_select!(device => global.device_create_compute_pipeline( + let (id, error) = wgc::gfx_select!(device => self.0.device_create_compute_pipeline( *device, &descriptor, (), @@ -1242,8 +1217,7 @@ impl crate::Context for ContextWgpuCore { device_data: &Self::DeviceData, desc: &crate::BufferDescriptor<'_>, ) -> (Self::BufferId, Self::BufferData) { - let global = &self.0; - let (id, error) = wgc::gfx_select!(device => global.device_create_buffer( + let (id, error) = wgc::gfx_select!(device => self.0.device_create_buffer( *device, &desc.map_label(|l| l.map(Borrowed)), () @@ -1271,8 +1245,7 @@ impl crate::Context for ContextWgpuCore { desc: &TextureDescriptor<'_>, ) -> (Self::TextureId, Self::TextureData) { let wgt_desc = desc.map_label_and_view_formats(|l| l.map(Borrowed), |v| v.to_vec()); - let global = &self.0; - let (id, error) = wgc::gfx_select!(device => global.device_create_texture( + let (id, error) = wgc::gfx_select!(device => self.0.device_create_texture( *device, &wgt_desc, () @@ -1317,8 +1290,7 @@ impl crate::Context for ContextWgpuCore { border_color: desc.border_color, }; - let global = &self.0; - let (id, error) = wgc::gfx_select!(device => global.device_create_sampler( + let (id, error) = wgc::gfx_select!(device => self.0.device_create_sampler( *device, &descriptor, () @@ -1340,8 +1312,7 @@ impl crate::Context for ContextWgpuCore { device_data: &Self::DeviceData, desc: &wgt::QuerySetDescriptor>, ) -> (Self::QuerySetId, Self::QuerySetData) { - let global = &self.0; - let (id, error) = wgc::gfx_select!(device => global.device_create_query_set( + let (id, error) = wgc::gfx_select!(device => self.0.device_create_query_set( *device, &desc.map_label(|l| l.map(Borrowed)), () @@ -1357,8 +1328,7 @@ impl crate::Context for ContextWgpuCore { device_data: &Self::DeviceData, desc: &CommandEncoderDescriptor<'_>, ) -> (Self::CommandEncoderId, Self::CommandEncoderData) { - let global = &self.0; - let (id, error) = wgc::gfx_select!(device => global.device_create_command_encoder( + let (id, error) = wgc::gfx_select!(device => self.0.device_create_command_encoder( *device, &desc.map_label(|l| l.map(Borrowed)), () @@ -1402,18 +1372,16 @@ impl crate::Context for ContextWgpuCore { fn device_drop(&self, device: &Self::DeviceId, _device_data: &Self::DeviceData) { #[cfg(any(native, Emscripten))] { - let global = &self.0; - match wgc::gfx_select!(device => global.device_poll(*device, wgt::Maintain::wait())) { + match wgc::gfx_select!(device => self.0.device_poll(*device, wgt::Maintain::wait())) { Ok(_) => {} Err(err) => self.handle_error_fatal(err, "Device::drop"), } - wgc::gfx_select!(device => global.device_drop(*device)); + wgc::gfx_select!(device => self.0.device_drop(*device)); } } #[cfg_attr(target_arch = "wasm32", allow(unused))] fn queue_drop(&self, queue: &Self::QueueId, _device_data: &Self::QueueData) { - let global = &self.0; - wgc::gfx_select!(queue => global.queue_drop(*queue)); + wgc::gfx_select!(queue => self.0.queue_drop(*queue)); } fn device_set_device_lost_callback( &self, @@ -1421,13 +1389,11 @@ impl crate::Context for ContextWgpuCore { _device_data: &Self::DeviceData, device_lost_callback: crate::context::DeviceLostCallback, ) { - let global = &self.0; let device_lost_closure = DeviceLostClosure::from_rust(device_lost_callback); - wgc::gfx_select!(device => global.device_set_device_lost_closure(*device, device_lost_closure)); + wgc::gfx_select!(device => self.0.device_set_device_lost_closure(*device, device_lost_closure)); } fn device_destroy(&self, device: &Self::DeviceId, _device_data: &Self::DeviceData) { - let global = &self.0; - wgc::gfx_select!(device => global.device_destroy(*device)); + wgc::gfx_select!(device => self.0.device_destroy(*device)); } fn device_mark_lost( &self, @@ -1437,8 +1403,7 @@ impl crate::Context for ContextWgpuCore { ) { // We do not provide a reason to device_lose, because all reasons other than // destroyed (which this is not) are "unknown". - let global = &self.0; - wgc::gfx_select!(device => global.device_mark_lost(*device, message)); + wgc::gfx_select!(device => self.0.device_mark_lost(*device, message)); } fn device_poll( &self, @@ -1446,9 +1411,8 @@ impl crate::Context for ContextWgpuCore { _device_data: &Self::DeviceData, maintain: crate::Maintain, ) -> 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( + match wgc::gfx_select!(device => self.0.device_poll( *device, maintain_inner )) { @@ -1511,8 +1475,7 @@ impl crate::Context for ContextWgpuCore { ))), }; - let global = &self.0; - match wgc::gfx_select!(buffer => global.buffer_map_async(*buffer, range, operation)) { + match wgc::gfx_select!(buffer => self.0.buffer_map_async(*buffer, range, operation)) { Ok(()) => (), Err(cause) => { self.handle_error_nolabel(&buffer_data.error_sink, cause, "Buffer::map_async") @@ -1526,8 +1489,7 @@ impl crate::Context for ContextWgpuCore { sub_range: Range, ) -> Box { let size = sub_range.end - sub_range.start; - let global = &self.0; - match wgc::gfx_select!(buffer => global.buffer_get_mapped_range( + match wgc::gfx_select!(buffer => self.0.buffer_get_mapped_range( *buffer, sub_range.start, Some(size) @@ -1541,8 +1503,7 @@ impl crate::Context for ContextWgpuCore { } fn buffer_unmap(&self, buffer: &Self::BufferId, buffer_data: &Self::BufferData) { - let global = &self.0; - match wgc::gfx_select!(buffer => global.buffer_unmap(*buffer)) { + match wgc::gfx_select!(buffer => self.0.buffer_unmap(*buffer)) { Ok(()) => (), Err(cause) => { self.handle_error_nolabel(&buffer_data.error_sink, cause, "Buffer::buffer_unmap") @@ -1568,9 +1529,8 @@ impl crate::Context for ContextWgpuCore { array_layer_count: desc.array_layer_count, }, }; - let global = &self.0; let (id, error) = wgc::gfx_select!( - texture => global.texture_create_view(*texture, &descriptor, ()) + texture => self.0.texture_create_view(*texture, &descriptor, ()) ); if let Some(cause) = error { self.handle_error( @@ -1589,30 +1549,25 @@ impl crate::Context for ContextWgpuCore { } fn adapter_drop(&self, adapter: &Self::AdapterId, _adapter_data: &Self::AdapterData) { - let global = &self.0; - wgc::gfx_select!(*adapter => global.adapter_drop(*adapter)) + wgc::gfx_select!(*adapter => self.0.adapter_drop(*adapter)) } fn buffer_destroy(&self, buffer: &Self::BufferId, _buffer_data: &Self::BufferData) { // Per spec, no error to report. Even calling destroy multiple times is valid. - let global = &self.0; - let _ = wgc::gfx_select!(buffer => global.buffer_destroy(*buffer)); + let _ = wgc::gfx_select!(buffer => self.0.buffer_destroy(*buffer)); } fn buffer_drop(&self, buffer: &Self::BufferId, _buffer_data: &Self::BufferData) { - let global = &self.0; - wgc::gfx_select!(buffer => global.buffer_drop(*buffer, false)) + wgc::gfx_select!(buffer => self.0.buffer_drop(*buffer, false)) } fn texture_destroy(&self, texture: &Self::TextureId, _texture_data: &Self::TextureData) { // Per spec, no error to report. Even calling destroy multiple times is valid. - let global = &self.0; - let _ = wgc::gfx_select!(texture => global.texture_destroy(*texture)); + let _ = wgc::gfx_select!(texture => self.0.texture_destroy(*texture)); } fn texture_drop(&self, texture: &Self::TextureId, _texture_data: &Self::TextureData) { - let global = &self.0; - wgc::gfx_select!(texture => global.texture_drop(*texture, false)) + wgc::gfx_select!(texture => self.0.texture_drop(*texture, false)) } fn texture_view_drop( @@ -1620,18 +1575,15 @@ impl crate::Context for ContextWgpuCore { texture_view: &Self::TextureViewId, __texture_view_data: &Self::TextureViewData, ) { - let global = &self.0; - let _ = wgc::gfx_select!(*texture_view => global.texture_view_drop(*texture_view, false)); + let _ = wgc::gfx_select!(*texture_view => self.0.texture_view_drop(*texture_view, false)); } fn sampler_drop(&self, sampler: &Self::SamplerId, _sampler_data: &Self::SamplerData) { - let global = &self.0; - wgc::gfx_select!(*sampler => global.sampler_drop(*sampler)) + wgc::gfx_select!(*sampler => self.0.sampler_drop(*sampler)) } fn query_set_drop(&self, query_set: &Self::QuerySetId, _query_set_data: &Self::QuerySetData) { - let global = &self.0; - wgc::gfx_select!(*query_set => global.query_set_drop(*query_set)) + wgc::gfx_select!(*query_set => self.0.query_set_drop(*query_set)) } fn bind_group_drop( @@ -1639,8 +1591,7 @@ impl crate::Context for ContextWgpuCore { bind_group: &Self::BindGroupId, _bind_group_data: &Self::BindGroupData, ) { - let global = &self.0; - wgc::gfx_select!(*bind_group => global.bind_group_drop(*bind_group)) + wgc::gfx_select!(*bind_group => self.0.bind_group_drop(*bind_group)) } fn bind_group_layout_drop( @@ -1648,8 +1599,7 @@ impl crate::Context for ContextWgpuCore { bind_group_layout: &Self::BindGroupLayoutId, _bind_group_layout_data: &Self::BindGroupLayoutData, ) { - let global = &self.0; - wgc::gfx_select!(*bind_group_layout => global.bind_group_layout_drop(*bind_group_layout)) + wgc::gfx_select!(*bind_group_layout => self.0.bind_group_layout_drop(*bind_group_layout)) } fn pipeline_layout_drop( @@ -1657,16 +1607,14 @@ impl crate::Context for ContextWgpuCore { pipeline_layout: &Self::PipelineLayoutId, _pipeline_layout_data: &Self::PipelineLayoutData, ) { - let global = &self.0; - wgc::gfx_select!(*pipeline_layout => global.pipeline_layout_drop(*pipeline_layout)) + wgc::gfx_select!(*pipeline_layout => self.0.pipeline_layout_drop(*pipeline_layout)) } fn shader_module_drop( &self, shader_module: &Self::ShaderModuleId, _shader_module_data: &Self::ShaderModuleData, ) { - let global = &self.0; - wgc::gfx_select!(*shader_module => global.shader_module_drop(*shader_module)) + wgc::gfx_select!(*shader_module => self.0.shader_module_drop(*shader_module)) } fn command_encoder_drop( &self, @@ -1674,8 +1622,7 @@ impl crate::Context for ContextWgpuCore { command_encoder_data: &Self::CommandEncoderData, ) { if command_encoder_data.open { - let global = &self.0; - wgc::gfx_select!(command_encoder => global.command_encoder_drop(*command_encoder)) + wgc::gfx_select!(command_encoder => self.0.command_encoder_drop(*command_encoder)) } } @@ -1684,8 +1631,7 @@ impl crate::Context for ContextWgpuCore { command_buffer: &Self::CommandBufferId, _command_buffer_data: &Self::CommandBufferData, ) { - let global = &self.0; - wgc::gfx_select!(*command_buffer => global.command_buffer_drop(*command_buffer)) + wgc::gfx_select!(*command_buffer => self.0.command_buffer_drop(*command_buffer)) } fn render_bundle_drop( @@ -1693,8 +1639,7 @@ impl crate::Context for ContextWgpuCore { render_bundle: &Self::RenderBundleId, _render_bundle_data: &Self::RenderBundleData, ) { - let global = &self.0; - wgc::gfx_select!(*render_bundle => global.render_bundle_drop(*render_bundle)) + wgc::gfx_select!(*render_bundle => self.0.render_bundle_drop(*render_bundle)) } fn compute_pipeline_drop( @@ -1702,8 +1647,7 @@ impl crate::Context for ContextWgpuCore { pipeline: &Self::ComputePipelineId, _pipeline_data: &Self::ComputePipelineData, ) { - let global = &self.0; - wgc::gfx_select!(*pipeline => global.compute_pipeline_drop(*pipeline)) + wgc::gfx_select!(*pipeline => self.0.compute_pipeline_drop(*pipeline)) } fn render_pipeline_drop( @@ -1711,8 +1655,7 @@ impl crate::Context for ContextWgpuCore { pipeline: &Self::RenderPipelineId, _pipeline_data: &Self::RenderPipelineData, ) { - let global = &self.0; - wgc::gfx_select!(*pipeline => global.render_pipeline_drop(*pipeline)) + wgc::gfx_select!(*pipeline => self.0.render_pipeline_drop(*pipeline)) } fn compute_pipeline_get_bind_group_layout( @@ -1721,8 +1664,7 @@ impl crate::Context for ContextWgpuCore { _pipeline_data: &Self::ComputePipelineData, index: u32, ) -> (Self::BindGroupLayoutId, Self::BindGroupLayoutData) { - let global = &self.0; - let (id, error) = wgc::gfx_select!(*pipeline => global.compute_pipeline_get_bind_group_layout(*pipeline, index, ())); + let (id, error) = wgc::gfx_select!(*pipeline => self.0.compute_pipeline_get_bind_group_layout(*pipeline, index, ())); if let Some(err) = error { panic!("Error reflecting bind group {index}: {err}"); } @@ -1735,8 +1677,7 @@ impl crate::Context for ContextWgpuCore { _pipeline_data: &Self::RenderPipelineData, index: u32, ) -> (Self::BindGroupLayoutId, Self::BindGroupLayoutData) { - let global = &self.0; - let (id, error) = wgc::gfx_select!(*pipeline => global.render_pipeline_get_bind_group_layout(*pipeline, index, ())); + let (id, error) = wgc::gfx_select!(*pipeline => self.0.render_pipeline_get_bind_group_layout(*pipeline, index, ())); if let Some(err) = error { panic!("Error reflecting bind group {index}: {err}"); } @@ -1755,8 +1696,7 @@ impl crate::Context for ContextWgpuCore { destination_offset: wgt::BufferAddress, copy_size: wgt::BufferAddress, ) { - let global = &self.0; - if let Err(cause) = wgc::gfx_select!(encoder => global.command_encoder_copy_buffer_to_buffer( + if let Err(cause) = wgc::gfx_select!(encoder => self.0.command_encoder_copy_buffer_to_buffer( *encoder, *source, source_offset, @@ -1780,8 +1720,7 @@ impl crate::Context for ContextWgpuCore { destination: crate::ImageCopyTexture<'_>, copy_size: wgt::Extent3d, ) { - let global = &self.0; - if let Err(cause) = wgc::gfx_select!(encoder => global.command_encoder_copy_buffer_to_texture( + if let Err(cause) = wgc::gfx_select!(encoder => self.0.command_encoder_copy_buffer_to_texture( *encoder, &map_buffer_copy_view(source), &map_texture_copy_view(destination), @@ -1803,8 +1742,7 @@ impl crate::Context for ContextWgpuCore { destination: crate::ImageCopyBuffer<'_>, copy_size: wgt::Extent3d, ) { - let global = &self.0; - if let Err(cause) = wgc::gfx_select!(encoder => global.command_encoder_copy_texture_to_buffer( + if let Err(cause) = wgc::gfx_select!(encoder => self.0.command_encoder_copy_texture_to_buffer( *encoder, &map_texture_copy_view(source), &map_buffer_copy_view(destination), @@ -1826,8 +1764,7 @@ impl crate::Context for ContextWgpuCore { destination: crate::ImageCopyTexture<'_>, copy_size: wgt::Extent3d, ) { - let global = &self.0; - if let Err(cause) = wgc::gfx_select!(encoder => global.command_encoder_copy_texture_to_texture( + if let Err(cause) = wgc::gfx_select!(encoder => self.0.command_encoder_copy_texture_to_texture( *encoder, &map_texture_copy_view(source), &map_texture_copy_view(destination), @@ -1874,11 +1811,10 @@ impl crate::Context for ContextWgpuCore { _pass: &mut Self::ComputePassId, pass_data: &mut Self::ComputePassData, ) { - let global = &self.0; if let Err(cause) = wgc::gfx_select!( - encoder => global.command_encoder_run_compute_pass(*encoder, pass_data) + encoder => self.0.command_encoder_run_compute_pass(*encoder, pass_data) ) { - let name = wgc::gfx_select!(encoder => global.command_buffer_label(*encoder)); + let name = wgc::gfx_select!(encoder => self.0.command_buffer_label(*encoder)); self.handle_error( &encoder_data.error_sink, cause, @@ -1958,11 +1894,10 @@ impl crate::Context for ContextWgpuCore { _pass: &mut Self::RenderPassId, pass_data: &mut Self::RenderPassData, ) { - let global = &self.0; if let Err(cause) = - wgc::gfx_select!(encoder => global.command_encoder_run_render_pass(*encoder, pass_data)) + wgc::gfx_select!(encoder => self.0.command_encoder_run_render_pass(*encoder, pass_data)) { - let name = wgc::gfx_select!(encoder => global.command_buffer_label(*encoder)); + let name = wgc::gfx_select!(encoder => self.0.command_buffer_label(*encoder)); self.handle_error( &encoder_data.error_sink, cause, @@ -1980,9 +1915,8 @@ impl crate::Context for ContextWgpuCore { ) -> (Self::CommandBufferId, Self::CommandBufferData) { let descriptor = wgt::CommandBufferDescriptor::default(); encoder_data.open = false; // prevent the drop - let global = &self.0; let (id, error) = - wgc::gfx_select!(encoder => global.command_encoder_finish(encoder, &descriptor)); + wgc::gfx_select!(encoder => self.0.command_encoder_finish(encoder, &descriptor)); if let Some(cause) = error { self.handle_error_nolabel(&encoder_data.error_sink, cause, "a CommandEncoder"); } @@ -1996,8 +1930,7 @@ impl crate::Context for ContextWgpuCore { texture: &crate::Texture, subresource_range: &wgt::ImageSubresourceRange, ) { - let global = &self.0; - if let Err(cause) = wgc::gfx_select!(encoder => global.command_encoder_clear_texture( + if let Err(cause) = wgc::gfx_select!(encoder => self.0.command_encoder_clear_texture( *encoder, texture.id.into(), subresource_range @@ -2018,8 +1951,7 @@ impl crate::Context for ContextWgpuCore { offset: wgt::BufferAddress, size: Option, ) { - let global = &self.0; - if let Err(cause) = wgc::gfx_select!(encoder => global.command_encoder_clear_buffer( + if let Err(cause) = wgc::gfx_select!(encoder => self.0.command_encoder_clear_buffer( *encoder, buffer.id.into(), offset, size @@ -2038,9 +1970,8 @@ impl crate::Context for ContextWgpuCore { encoder_data: &Self::CommandEncoderData, label: &str, ) { - let global = &self.0; if let Err(cause) = - wgc::gfx_select!(encoder => global.command_encoder_insert_debug_marker(*encoder, label)) + wgc::gfx_select!(encoder => self.0.command_encoder_insert_debug_marker(*encoder, label)) { self.handle_error_nolabel( &encoder_data.error_sink, @@ -2056,9 +1987,8 @@ impl crate::Context for ContextWgpuCore { encoder_data: &Self::CommandEncoderData, label: &str, ) { - let global = &self.0; if let Err(cause) = - wgc::gfx_select!(encoder => global.command_encoder_push_debug_group(*encoder, label)) + wgc::gfx_select!(encoder => self.0.command_encoder_push_debug_group(*encoder, label)) { self.handle_error_nolabel( &encoder_data.error_sink, @@ -2073,9 +2003,8 @@ impl crate::Context for ContextWgpuCore { encoder: &Self::CommandEncoderId, encoder_data: &Self::CommandEncoderData, ) { - let global = &self.0; if let Err(cause) = - wgc::gfx_select!(encoder => global.command_encoder_pop_debug_group(*encoder)) + wgc::gfx_select!(encoder => self.0.command_encoder_pop_debug_group(*encoder)) { self.handle_error_nolabel( &encoder_data.error_sink, @@ -2093,8 +2022,7 @@ impl crate::Context for ContextWgpuCore { _query_set_data: &Self::QuerySetData, query_index: u32, ) { - let global = &self.0; - if let Err(cause) = wgc::gfx_select!(encoder => global.command_encoder_write_timestamp( + if let Err(cause) = wgc::gfx_select!(encoder => self.0.command_encoder_write_timestamp( *encoder, *query_set, query_index @@ -2119,8 +2047,7 @@ impl crate::Context for ContextWgpuCore { _destination_data: &Self::BufferData, destination_offset: wgt::BufferAddress, ) { - let global = &self.0; - if let Err(cause) = wgc::gfx_select!(encoder => global.command_encoder_resolve_query_set( + if let Err(cause) = wgc::gfx_select!(encoder => self.0.command_encoder_resolve_query_set( *encoder, *query_set, first_query, @@ -2142,8 +2069,7 @@ impl crate::Context for ContextWgpuCore { encoder_data: Self::RenderBundleEncoderData, desc: &crate::RenderBundleDescriptor<'_>, ) -> (Self::RenderBundleId, Self::RenderBundleData) { - let global = &self.0; - let (id, error) = wgc::gfx_select!(encoder_data.parent() => global.render_bundle_encoder_finish( + let (id, error) = wgc::gfx_select!(encoder_data.parent() => self.0.render_bundle_encoder_finish( encoder_data, &desc.map_label(|l| l.map(Borrowed)), () @@ -2163,9 +2089,8 @@ impl crate::Context for ContextWgpuCore { offset: wgt::BufferAddress, data: &[u8], ) { - let global = &self.0; match wgc::gfx_select!( - *queue => global.queue_write_buffer(*queue, *buffer, offset, data) + *queue => self.0.queue_write_buffer(*queue, *buffer, offset, data) ) { Ok(()) => (), Err(err) => { @@ -2183,9 +2108,8 @@ impl crate::Context for ContextWgpuCore { offset: wgt::BufferAddress, size: wgt::BufferSize, ) -> Option<()> { - let global = &self.0; match wgc::gfx_select!( - *queue => global.queue_validate_write_buffer(*queue, *buffer, offset, size.get()) + *queue => self.0.queue_validate_write_buffer(*queue, *buffer, offset, size.get()) ) { Ok(()) => Some(()), Err(err) => { @@ -2201,9 +2125,8 @@ impl crate::Context for ContextWgpuCore { queue_data: &Self::QueueData, size: wgt::BufferSize, ) -> Option> { - let global = &self.0; match wgc::gfx_select!( - *queue => global.queue_create_staging_buffer(*queue, size, ()) + *queue => self.0.queue_create_staging_buffer(*queue, size, ()) ) { Ok((buffer_id, ptr)) => Some(Box::new(QueueWriteBuffer { buffer_id, @@ -2228,13 +2151,12 @@ impl crate::Context for ContextWgpuCore { offset: wgt::BufferAddress, staging_buffer: &dyn crate::context::QueueWriteBuffer, ) { - let global = &self.0; let staging_buffer = staging_buffer .as_any() .downcast_ref::() .unwrap(); match wgc::gfx_select!( - *queue => global.queue_write_staging_buffer(*queue, *buffer, offset, staging_buffer.buffer_id) + *queue => self.0.queue_write_staging_buffer(*queue, *buffer, offset, staging_buffer.buffer_id) ) { Ok(()) => (), Err(err) => { @@ -2252,8 +2174,7 @@ impl crate::Context for ContextWgpuCore { data_layout: wgt::ImageDataLayout, size: wgt::Extent3d, ) { - let global = &self.0; - match wgc::gfx_select!(*queue => global.queue_write_texture( + match wgc::gfx_select!(*queue => self.0.queue_write_texture( *queue, &map_texture_copy_view(texture), data, @@ -2276,8 +2197,7 @@ impl crate::Context for ContextWgpuCore { dest: crate::ImageCopyTextureTagged<'_>, size: wgt::Extent3d, ) { - let global = &self.0; - match wgc::gfx_select!(*queue => global.queue_copy_external_image_to_texture( + match wgc::gfx_select!(*queue => self.0.queue_copy_external_image_to_texture( *queue, source, map_texture_tagged_copy_view(dest), @@ -2302,8 +2222,7 @@ impl crate::Context for ContextWgpuCore { .map(|(i, _)| i) .collect::>(); - let global = &self.0; - let index = match wgc::gfx_select!(*queue => global.queue_submit(*queue, &temp_command_buffers)) + let index = match wgc::gfx_select!(*queue => self.0.queue_submit(*queue, &temp_command_buffers)) { Ok(index) => index, Err(err) => self.handle_error_fatal(err, "Queue::submit"), @@ -2317,8 +2236,7 @@ impl crate::Context for ContextWgpuCore { queue: &Self::QueueId, _queue_data: &Self::QueueData, ) -> f32 { - let global = &self.0; - let res = wgc::gfx_select!(queue => global.queue_get_timestamp_period( + let res = wgc::gfx_select!(queue => self.0.queue_get_timestamp_period( *queue )); match res { @@ -2337,21 +2255,18 @@ impl crate::Context for ContextWgpuCore { ) { let closure = wgc::device::queue::SubmittedWorkDoneClosure::from_rust(callback); - let global = &self.0; - let res = wgc::gfx_select!(queue => global.queue_on_submitted_work_done(*queue, closure)); + let res = wgc::gfx_select!(queue => self.0.queue_on_submitted_work_done(*queue, closure)); if let Err(cause) = res { self.handle_error_fatal(cause, "Queue::on_submitted_work_done"); } } fn device_start_capture(&self, device: &Self::DeviceId, _device_data: &Self::DeviceData) { - let global = &self.0; - wgc::gfx_select!(device => global.device_start_capture(*device)); + wgc::gfx_select!(device => self.0.device_start_capture(*device)); } fn device_stop_capture(&self, device: &Self::DeviceId, _device_data: &Self::DeviceData) { - let global = &self.0; - wgc::gfx_select!(device => global.device_stop_capture(*device)); + wgc::gfx_select!(device => self.0.device_stop_capture(*device)); } fn compute_pass_set_pipeline( From 6c86b557647336694c44a9c7a08301d5f658f8e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Jan 2024 11:37:27 -0500 Subject: [PATCH 005/101] Bump Swatinem/rust-cache from 2.7.1 to 2.7.3 (#5060) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andreas Reich --- .github/workflows/ci.yml | 15 +++++---------- .github/workflows/shaders.yml | 9 +++------ 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f6d9a3e366..48a67b7926 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -161,8 +161,7 @@ jobs: debug = false" >> .cargo/config.toml - name: caching - # Pin to 2.7.1 due to a bug in github actions cache action https://github.com/Swatinem/rust-cache/issues/182 - uses: Swatinem/rust-cache@3cf7f8cc28d1b4e7d01e3783be10a97d55d483c8 + uses: Swatinem/rust-cache@v2 with: key: clippy-${{ matrix.target }}-${{ matrix.kind }}-${{ env.CACHE_SUFFIX }} @@ -278,8 +277,7 @@ jobs: debug = false" >> .cargo/config.toml - name: caching - # Pin to 2.7.1 due to a bug in github actions cache action https://github.com/Swatinem/rust-cache/issues/182 - uses: Swatinem/rust-cache@3cf7f8cc28d1b4e7d01e3783be10a97d55d483c8 + uses: Swatinem/rust-cache@v2 with: key: msrv-check-${{ matrix.target }}-${{ env.CACHE_SUFFIX }} @@ -410,8 +408,7 @@ jobs: # Cache step must go before warp and mesa install on windows as they write into the # target directory, and rust-cache will overwrite the entirety of the target directory. - name: caching - # Pin to 2.7.1 due to a bug in github actions cache action https://github.com/Swatinem/rust-cache/issues/182 - uses: Swatinem/rust-cache@3cf7f8cc28d1b4e7d01e3783be10a97d55d483c8 + uses: Swatinem/rust-cache@v2 with: key: test-${{ matrix.os }}-${{ env.CACHE_SUFFIX }} workspaces: | @@ -582,8 +579,7 @@ jobs: debug = 1" >> .cargo/config.toml - name: caching - # Pin to 2.7.1 due to a bug in github actions cache action https://github.com/Swatinem/rust-cache/issues/182 - uses: Swatinem/rust-cache@3cf7f8cc28d1b4e7d01e3783be10a97d55d483c8 + uses: Swatinem/rust-cache@v2 with: key: doctests-${{ env.CACHE_SUFFIX }} @@ -640,8 +636,7 @@ jobs: debug = 1" >> .cargo/config.toml - name: caching - # Pin to 2.7.1 due to a bug in github actions cache action https://github.com/Swatinem/rust-cache/issues/182 - uses: Swatinem/rust-cache@3cf7f8cc28d1b4e7d01e3783be10a97d55d483c8 + uses: Swatinem/rust-cache@v2 with: key: cts-runner-${{ env.CACHE_SUFFIX }} diff --git a/.github/workflows/shaders.yml b/.github/workflows/shaders.yml index 7e4fe1aa72..d598e3ce75 100644 --- a/.github/workflows/shaders.yml +++ b/.github/workflows/shaders.yml @@ -21,8 +21,7 @@ jobs: steps: - uses: actions/checkout@v4 - # Pin to 2.7.1 due to a bug in github actions cache action https://github.com/Swatinem/rust-cache/issues/182 - - uses: Swatinem/rust-cache@3cf7f8cc28d1b4e7d01e3783be10a97d55d483c8 + - uses: Swatinem/rust-cache@v2 with: workspaces: | naga/xtask -> naga/xtask/target @@ -67,8 +66,7 @@ jobs: steps: - uses: actions/checkout@v4 - # Pin to 2.7.1 due to a bug in github actions cache action https://github.com/Swatinem/rust-cache/issues/182 - - uses: Swatinem/rust-cache@3cf7f8cc28d1b4e7d01e3783be10a97d55d483c8 + - uses: Swatinem/rust-cache@v2 with: workspaces: | naga/xtask -> naga/xtask/target @@ -86,8 +84,7 @@ jobs: - name: Install tools run: sudo apt-get install spirv-tools glslang-tools graphviz - # Pin to 2.7.1 due to a bug in github actions cache action https://github.com/Swatinem/rust-cache/issues/182 - - uses: Swatinem/rust-cache@3cf7f8cc28d1b4e7d01e3783be10a97d55d483c8 + - uses: Swatinem/rust-cache@v2 with: workspaces: | naga/xtask -> naga/xtask/target From 2e3818795447f9f0c87bf710da4eea9b95efec2d Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Tue, 16 Jan 2024 14:21:51 -0500 Subject: [PATCH 006/101] Re-export public dependencies (#5063) --- CHANGELOG.md | 14 +++++++ wgpu-core/src/lib.rs | 1 + wgpu/Cargo.toml | 9 ++--- wgpu/build.rs | 5 ++- wgpu/src/backend/webgpu.rs | 6 +-- wgpu/src/backend/wgpu_core.rs | 4 +- wgpu/src/lib.rs | 75 +++++++++++++++++++++++++++-------- wgpu/src/util/init.rs | 8 ++-- 8 files changed, 90 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bdb11de29..96c289ce92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,20 @@ Bottom level categories: ## Unreleased +### All Public Dependencies Are Re-Exported + +All of wgpu's public dependencies are now re-exported at the top level so that users don't need to take their own dependencies. +This includes: +- wgpu-core +- wgpu-hal +- naga +- raw_window_handle +- web_sys + +### `naga-ir` Shaders Have Dedicated Feature + +The `naga-ir` feature has been added to allow you to add naga module shaders without guessing about what other features needed to be enabled to get access to it. + ### Direct3D 11 backend removal This backend had no functionality, and with the recent support for GL on Desktop, which allows wgpu to run on older devices, there is no need to keep the backend. diff --git a/wgpu-core/src/lib.rs b/wgpu-core/src/lib.rs index 4fd2845377..74c27bd960 100644 --- a/wgpu-core/src/lib.rs +++ b/wgpu-core/src/lib.rs @@ -105,6 +105,7 @@ mod track; pub mod validation; pub use hal::{api, MAX_BIND_GROUPS, MAX_COLOR_ATTACHMENTS, MAX_VERTEX_BUFFERS}; +pub use naga; use std::{borrow::Cow, os::raw::c_char}; diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index 8848371b9d..813bc71f57 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -45,7 +45,7 @@ angle = ["wgc?/gles"] vulkan-portability = ["wgc?/vulkan"] ## Enables the WebGPU backend on Wasm. Disabled when targeting `emscripten`. -webgpu = [] +webgpu = ["naga?/wgsl-out"] ## Enables the GLES backend on Wasm ## @@ -64,6 +64,9 @@ glsl = ["naga/glsl-in"] ## Enable accepting WGSL shaders as input. wgsl = ["wgc?/wgsl"] +## Enable accepting naga IR shaders as input. +naga-ir = ["naga"] + #! ### Logging & Tracing # -------------------------------------------------------------------- #! The following features do not have any effect on the WebGPU backend. @@ -178,10 +181,6 @@ cfg_aliases.workspace = true workspace = true features = ["wgsl-in"] -[target.'cfg(target_arch = "wasm32")'.dependencies.naga] -workspace = true -features = ["wgsl-out"] - [target.'cfg(target_arch = "wasm32")'.dependencies] web-sys = { workspace = true, features = [ "Document", diff --git a/wgpu/build.rs b/wgpu/build.rs index 6f3d0f58ab..1f07f7ebba 100644 --- a/wgpu/build.rs +++ b/wgpu/build.rs @@ -10,6 +10,9 @@ fn main() { all(feature = "fragile-send-sync-non-atomic-wasm", not(target_feature = "atomics")) ) }, dx12: { all(target_os = "windows", feature = "dx12") }, - metal: { all(any(target_os = "ios", target_os = "macos"), feature = "metal") } + metal: { all(any(target_os = "ios", target_os = "macos"), feature = "metal") }, + // This alias is _only_ if _we_ need naga in the wrapper. wgpu-core provides + // its own re-export of naga, which can be used in other situations + naga: { any(feature = "naga-ir", feature = "spirv", feature = "glsl") }, } } diff --git a/wgpu/src/backend/webgpu.rs b/wgpu/src/backend/webgpu.rs index f8a3380c99..91115c3e07 100644 --- a/wgpu/src/backend/webgpu.rs +++ b/wgpu/src/backend/webgpu.rs @@ -1400,7 +1400,7 @@ impl crate::context::Context for ContextWebGpu { feature = "spirv", feature = "glsl", feature = "wgsl", - feature = "naga" + feature = "naga-ir" )), allow(unreachable_code, unused_variables) )] @@ -1411,7 +1411,7 @@ impl crate::context::Context for ContextWebGpu { desc: crate::ShaderModuleDescriptor<'_>, _shader_bound_checks: wgt::ShaderBoundChecks, ) -> (Self::ShaderModuleId, Self::ShaderModuleData) { - let mut descriptor = match desc.source { + let mut descriptor: web_sys::GpuShaderModuleDescriptor = match desc.source { #[cfg(feature = "spirv")] crate::ShaderSource::SpirV(ref spv) => { use naga::{back, front, valid}; @@ -1465,7 +1465,7 @@ impl crate::context::Context for ContextWebGpu { } #[cfg(feature = "wgsl")] crate::ShaderSource::Wgsl(ref code) => web_sys::GpuShaderModuleDescriptor::new(code), - #[cfg(feature = "naga")] + #[cfg(feature = "naga-ir")] crate::ShaderSource::Naga(module) => { use naga::{back, valid}; diff --git a/wgpu/src/backend/wgpu_core.rs b/wgpu/src/backend/wgpu_core.rs index 3d5fd1d149..1d4139e73f 100644 --- a/wgpu/src/backend/wgpu_core.rs +++ b/wgpu/src/backend/wgpu_core.rs @@ -820,7 +820,7 @@ impl crate::Context for ContextWgpuCore { feature = "spirv", feature = "glsl", feature = "wgsl", - feature = "naga" + feature = "naga-ir" )), allow(unreachable_code, unused_variables) )] @@ -866,7 +866,7 @@ impl crate::Context for ContextWgpuCore { } #[cfg(feature = "wgsl")] ShaderSource::Wgsl(ref code) => wgc::pipeline::ShaderModuleSource::Wgsl(Borrowed(code)), - #[cfg(feature = "naga")] + #[cfg(feature = "naga-ir")] ShaderSource::Naga(module) => wgc::pipeline::ShaderModuleSource::Naga(module), ShaderSource::Dummy(_) => panic!("found `ShaderSource::Dummy`"), }; diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 4120894b9b..f12892dfb0 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -7,25 +7,28 @@ //! //! ### Backends //! -//! ⚠️ WIP: Not all backends can be manually configured today. On Windows & Linux the Vulkan & GLES -//! backends are always enabled. See [#3514](https://github.com/gfx-rs/wgpu/issues/3514) for more +//! ⚠️ WIP: Not all backends can be manually configured today. On Windows & Linux the **Vulkan & GLES +//! backends are always enabled**. See [#3514](https://github.com/gfx-rs/wgpu/issues/3514) for more //! details. //! //! - **`dx12`** _(enabled by default)_ --- Enables the DX12 backend on Windows. //! - **`metal`** _(enabled by default)_ --- Enables the Metal backend on macOS & iOS. -//! - **`angle`** --- Enables the GLES backend via [ANGLE](https://github.com/google/angle) on macOS -//! using. +//! - **`webgpu`** _(enabled by default)_ --- Enables the WebGPU backend on Wasm. Disabled when targeting `emscripten`. +//! - **`angle`** --- Enables the GLES backend via [ANGLE](https://github.com/google/angle) on macOS. //! - **`vulkan-portability`** --- Enables the Vulkan backend on macOS & iOS. -//! - **`webgpu`** --- Enables the WebGPU backend on Wasm. Disabled when targeting `emscripten`. -//! - **`webgl`** --- Enables the GLES backend on Wasm -//! +//! - **`webgl`** --- Enables the GLES backend on Wasm. //! - ⚠️ WIP: Currently will also enable GLES dependencies on any other targets. //! +//! **Note:** In the documentation, if you see that an item depends on a backend, +//! it means that the item is only available when that backend is enabled _and_ the backend +//! is supported on the current platform. +//! //! ### Shading language support //! +//! - **`wgsl`** _(enabled by default)_ --- Enable accepting WGSL shaders as input. //! - **`spirv`** --- Enable accepting SPIR-V shaders as input. //! - **`glsl`** --- Enable accepting GLSL shaders as input. -//! - **`wgsl`** _(enabled by default)_ --- Enable accepting WGSL shaders as input. +//! - **`naga-ir`** --- Enable accepting Naga IR shaders as input. //! //! ### Logging & Tracing //! @@ -49,6 +52,14 @@ //! code. This is technically _very_ unsafe in a multithreaded environment, but on a wasm binary //! compiled without atomics we know we are definitely not in a multithreaded environment. //! +//! ### Feature Aliases +//! +//! These features aren't actually features on the crate itself, but a convenient shorthand for +//! complicated cases. +//! +//! - **`wgpu_core`** --- Enabled when there is any non-webgpu backend enabled on the platform. +//! - **`naga`** ---- Enabled when any non-wgsl shader input is enabled. +//! #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![doc(html_logo_url = "https://raw.githubusercontent.com/gfx-rs/wgpu/trunk/logo.png")] @@ -100,15 +111,45 @@ pub use wgt::{ QUERY_SIZE, VERTEX_STRIDE_ALIGNMENT, }; -#[cfg(not(webgpu))] -#[doc(hidden)] -pub use ::hal; -#[cfg(feature = "naga")] -pub use ::naga; -#[cfg(not(webgpu))] -#[doc(hidden)] +/// Re-export of our `wgpu-core` dependency. +/// +#[cfg(wgpu_core)] +#[doc(inline)] pub use ::wgc as core; +/// Re-export of our `wgpu-hal` dependency. +/// +/// +#[cfg(wgpu_core)] +#[doc(inline)] +pub use ::hal; + +/// Re-export of our `naga` dependency. +/// +#[cfg(wgpu_core)] +#[cfg_attr(docsrs, doc(cfg(any(wgpu_core, naga))))] +#[doc(inline)] +// We re-export wgpu-core's re-export of naga, as we may not have direct access to it. +pub use ::wgc::naga; +/// Re-export of our `naga` dependency. +/// +#[cfg(all(not(wgpu_core), naga))] +#[cfg_attr(docsrs, doc(cfg(any(wgpu_core, naga))))] +#[doc(inline)] +// If that's not available, we re-export our own. +pub use naga; + +#[doc(inline)] +/// Re-export of our `raw-window-handle` dependency. +/// +pub use raw_window_handle as rwh; + +/// Re-export of our `web-sys` dependency. +/// +#[cfg(any(webgl, webgpu))] +#[doc(inline)] +pub use web_sys; + // wasm-only types, we try to keep as many types non-platform // specific, but these need to depend on web-sys. #[cfg(any(webgpu, webgl))] @@ -644,7 +685,7 @@ impl Drop for ShaderModule { /// /// This type is unique to the Rust API of `wgpu`. In the WebGPU specification, /// only WGSL source code strings are accepted. -#[cfg_attr(feature = "naga", allow(clippy::large_enum_variant))] +#[cfg_attr(feature = "naga-ir", allow(clippy::large_enum_variant))] #[derive(Clone, Debug)] #[non_exhaustive] pub enum ShaderSource<'a> { @@ -669,7 +710,7 @@ pub enum ShaderSource<'a> { #[cfg(feature = "wgsl")] Wgsl(Cow<'a, str>), /// Naga module. - #[cfg(feature = "naga")] + #[cfg(feature = "naga-ir")] Naga(Cow<'static, naga::Module>), /// Dummy variant because `Naga` doesn't have a lifetime and without enough active features it /// could be the last one active. diff --git a/wgpu/src/util/init.rs b/wgpu/src/util/init.rs index 016ce5f7f9..55154242e1 100644 --- a/wgpu/src/util/init.rs +++ b/wgpu/src/util/init.rs @@ -2,13 +2,13 @@ use wgt::{Backends, PowerPreference, RequestAdapterOptions}; use crate::{Adapter, Instance, Surface}; -#[cfg(not(webgpu))] +#[cfg(wgpu_core)] #[cfg_attr(docsrs, doc(cfg(all())))] pub use wgc::instance::parse_backends_from_comma_list; -/// Always returns WEBGPU on wasm over webgpu. -#[cfg(webgpu)] +/// Just return ALL, if wgpu_core is not enabled. +#[cfg(not(wgpu_core))] pub fn parse_backends_from_comma_list(_string: &str) -> Backends { - Backends::BROWSER_WEBGPU + Backends::all() } /// Get a set of backend bits from the environment variable WGPU_BACKEND. From b8f27c7284b95809e26069a9ace0282cc5904006 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Wed, 17 Jan 2024 18:46:34 +0100 Subject: [PATCH 007/101] Expose maximum_frame_latency (#4899) Co-authored-by: Emil Ernerfeldt --- CHANGELOG.md | 1 + examples/src/framework.rs | 1 + examples/src/hello_triangle/mod.rs | 13 +++--------- examples/src/hello_windows/mod.rs | 17 ++++----------- examples/src/uniform_values/mod.rs | 12 +++-------- wgpu-core/src/device/global.rs | 9 ++++---- wgpu-core/src/present.rs | 3 --- wgpu-hal/examples/halmark/main.rs | 8 +++---- wgpu-hal/examples/ray-traced-triangle/main.rs | 8 +++---- wgpu-hal/src/dx12/adapter.rs | 4 ++-- wgpu-hal/src/dx12/mod.rs | 15 ++++++++----- wgpu-hal/src/gles/adapter.rs | 2 +- wgpu-hal/src/lib.rs | 17 ++++++++------- wgpu-hal/src/metal/adapter.rs | 11 +++++----- wgpu-hal/src/metal/surface.rs | 2 +- wgpu-hal/src/vulkan/adapter.rs | 6 +++++- wgpu-hal/src/vulkan/device.rs | 2 +- wgpu-types/src/lib.rs | 21 +++++++++++++++++++ wgpu/src/lib.rs | 1 + 19 files changed, 83 insertions(+), 70 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 96c289ce92..e3a5afa4f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -98,6 +98,7 @@ By @wumpf in [#5044](https://github.com/gfx-rs/wgpu/pull/5044) - Added support for the float32-filterable feature. By @almarklein in [#4759](https://github.com/gfx-rs/wgpu/pull/4759) - GPU buffer memory is released during "lose the device". By @bradwerth in [#4851](https://github.com/gfx-rs/wgpu/pull/4851) - wgpu and wgpu-core features are now documented on docs.rs. By @wumpf in [#4886](https://github.com/gfx-rs/wgpu/pull/4886) +- `SurfaceConfiguration` now exposes `desired_maximum_frame_latency` which was previously hard-coded to 2. By setting it to 1 you can reduce latency under the risk of making GPU & CPU work sequential. Currently, on DX12 this affects the `MaximumFrameLatency`, on all other backends except OpenGL the size of the swapchain (on OpenGL this has no effect). By @emilk & @wumpf in [#4899](https://github.com/gfx-rs/wgpu/pull/4899) - DeviceLostClosure is guaranteed to be invoked exactly once. By @bradwerth in [#4862](https://github.com/gfx-rs/wgpu/pull/4862) #### OpenGL diff --git a/examples/src/framework.rs b/examples/src/framework.rs index dd2c2ee6d1..a22f9c1113 100644 --- a/examples/src/framework.rs +++ b/examples/src/framework.rs @@ -571,6 +571,7 @@ impl From> format, width: params.width, height: params.height, + desired_maximum_frame_latency: 2, present_mode: wgpu::PresentMode::Fifo, alpha_mode: wgpu::CompositeAlphaMode::Auto, view_formats: vec![format], diff --git a/examples/src/hello_triangle/mod.rs b/examples/src/hello_triangle/mod.rs index 40cb805c28..faa1db8f8b 100644 --- a/examples/src/hello_triangle/mod.rs +++ b/examples/src/hello_triangle/mod.rs @@ -72,16 +72,9 @@ async fn run(event_loop: EventLoop<()>, window: Window) { multiview: None, }); - let mut config = wgpu::SurfaceConfiguration { - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - format: swapchain_format, - width: size.width, - height: size.height, - present_mode: wgpu::PresentMode::Fifo, - alpha_mode: swapchain_capabilities.alpha_modes[0], - view_formats: vec![], - }; - + let mut config = surface + .get_default_config(&adapter, size.width, size.height) + .unwrap(); surface.configure(&device, &config); let window = &window; diff --git a/examples/src/hello_windows/mod.rs b/examples/src/hello_windows/mod.rs index 9a42b9afbd..7d81dbef7b 100644 --- a/examples/src/hello_windows/mod.rs +++ b/examples/src/hello_windows/mod.rs @@ -30,20 +30,11 @@ impl ViewportDesc { fn build(self, adapter: &wgpu::Adapter, device: &wgpu::Device) -> Viewport { let size = self.window.inner_size(); - - let caps = self.surface.get_capabilities(adapter); - let config = wgpu::SurfaceConfiguration { - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - format: caps.formats[0], - width: size.width, - height: size.height, - present_mode: wgpu::PresentMode::Fifo, - alpha_mode: caps.alpha_modes[0], - view_formats: vec![], - }; - + let config = self + .surface + .get_default_config(adapter, size.width, size.height) + .unwrap(); self.surface.configure(device, &config); - Viewport { desc: self, config } } } diff --git a/examples/src/uniform_values/mod.rs b/examples/src/uniform_values/mod.rs index de71ce5067..4a31ddc069 100644 --- a/examples/src/uniform_values/mod.rs +++ b/examples/src/uniform_values/mod.rs @@ -192,15 +192,9 @@ impl WgpuContext { multiview: None, }); - let surface_config = wgpu::SurfaceConfiguration { - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - format: swapchain_format, - width: size.width, - height: size.height, - present_mode: wgpu::PresentMode::Fifo, - alpha_mode: swapchain_capabilities.alpha_modes[0], - view_formats: vec![], - }; + let surface_config = surface + .get_default_config(&adapter, size.width, size.height) + .unwrap(); surface.configure(&device, &surface_config); // (5) diff --git a/wgpu-core/src/device/global.rs b/wgpu-core/src/device/global.rs index fa0c4d7dbe..f7cfc1da15 100644 --- a/wgpu-core/src/device/global.rs +++ b/wgpu-core/src/device/global.rs @@ -1982,10 +1982,12 @@ impl Global { } } - let num_frames = present::DESIRED_NUM_FRAMES - .clamp(*caps.swap_chain_sizes.start(), *caps.swap_chain_sizes.end()); + let maximum_frame_latency = config.desired_maximum_frame_latency.clamp( + *caps.maximum_frame_latency.start(), + *caps.maximum_frame_latency.end(), + ); let mut hal_config = hal::SurfaceConfiguration { - swap_chain_size: num_frames, + maximum_frame_latency, present_mode: config.present_mode, composite_alpha_mode: config.alpha_mode, format: config.format, @@ -2056,7 +2058,6 @@ impl Global { *presentation = Some(present::Presentation { device: super::any_device::AnyDevice::new(device.clone()), config: config.clone(), - num_frames, acquired_texture: None, }); } diff --git a/wgpu-core/src/present.rs b/wgpu-core/src/present.rs index 00dc049679..d7b34497a2 100644 --- a/wgpu-core/src/present.rs +++ b/wgpu-core/src/present.rs @@ -37,14 +37,11 @@ use thiserror::Error; use wgt::SurfaceStatus as Status; const FRAME_TIMEOUT_MS: u32 = 1000; -pub const DESIRED_NUM_FRAMES: u32 = 3; #[derive(Debug)] pub(crate) struct Presentation { pub(crate) device: AnyDevice, pub(crate) config: wgt::SurfaceConfiguration>, - #[allow(unused)] - pub(crate) num_frames: u32, pub(crate) acquired_texture: Option, } diff --git a/wgpu-hal/examples/halmark/main.rs b/wgpu-hal/examples/halmark/main.rs index 18f283d8e7..7bc8013415 100644 --- a/wgpu-hal/examples/halmark/main.rs +++ b/wgpu-hal/examples/halmark/main.rs @@ -23,7 +23,7 @@ const BUNNY_SIZE: f32 = 0.15 * 256.0; const GRAVITY: f32 = -9.8 * 100.0; const MAX_VELOCITY: f32 = 750.0; const COMMAND_BUFFER_PER_CONTEXT: usize = 100; -const DESIRED_FRAMES: u32 = 3; +const DESIRED_MAX_LATENCY: u32 = 2; #[repr(C)] #[derive(Clone, Copy)] @@ -132,9 +132,9 @@ impl Example { let window_size: (u32, u32) = window.inner_size().into(); let surface_config = hal::SurfaceConfiguration { - swap_chain_size: DESIRED_FRAMES.clamp( - *surface_caps.swap_chain_sizes.start(), - *surface_caps.swap_chain_sizes.end(), + maximum_frame_latency: DESIRED_MAX_LATENCY.clamp( + *surface_caps.maximum_frame_latency.start(), + *surface_caps.maximum_frame_latency.end(), ), present_mode: wgt::PresentMode::Fifo, composite_alpha_mode: wgt::CompositeAlphaMode::Opaque, diff --git a/wgpu-hal/examples/ray-traced-triangle/main.rs b/wgpu-hal/examples/ray-traced-triangle/main.rs index 6454cb8998..01a0968f3d 100644 --- a/wgpu-hal/examples/ray-traced-triangle/main.rs +++ b/wgpu-hal/examples/ray-traced-triangle/main.rs @@ -14,7 +14,7 @@ use std::{ use winit::window::WindowButtons; const COMMAND_BUFFER_PER_CONTEXT: usize = 100; -const DESIRED_FRAMES: u32 = 3; +const DESIRED_MAX_LATENCY: u32 = 2; /// [D3D12_RAYTRACING_INSTANCE_DESC](https://microsoft.github.io/DirectX-Specs/d3d/Raytracing.html#d3d12_raytracing_instance_desc) /// [VkAccelerationStructureInstanceKHR](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkAccelerationStructureInstanceKHR.html) @@ -264,9 +264,9 @@ impl Example { *surface_caps.formats.first().unwrap() }; let surface_config = hal::SurfaceConfiguration { - swap_chain_size: DESIRED_FRAMES - .max(*surface_caps.swap_chain_sizes.start()) - .min(*surface_caps.swap_chain_sizes.end()), + maximum_frame_latency: DESIRED_MAX_LATENCY + .max(*surface_caps.maximum_frame_latency.start()) + .min(*surface_caps.maximum_frame_latency.end()), present_mode: wgt::PresentMode::Fifo, composite_alpha_mode: wgt::CompositeAlphaMode::Opaque, format: surface_format, diff --git a/wgpu-hal/src/dx12/adapter.rs b/wgpu-hal/src/dx12/adapter.rs index 1db9b0877d..f6027014d2 100644 --- a/wgpu-hal/src/dx12/adapter.rs +++ b/wgpu-hal/src/dx12/adapter.rs @@ -626,8 +626,8 @@ impl crate::Adapter for super::Adapter { wgt::TextureFormat::Rgb10a2Unorm, wgt::TextureFormat::Rgba16Float, ], - // we currently use a flip effect which supports 2..=16 buffers - swap_chain_sizes: 2..=16, + // See https://learn.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgidevice1-setmaximumframelatency + maximum_frame_latency: 1..=16, current_extent, usage: crate::TextureUses::COLOR_TARGET | crate::TextureUses::COPY_SRC diff --git a/wgpu-hal/src/dx12/mod.rs b/wgpu-hal/src/dx12/mod.rs index e0cd1c15cf..af8d5a8c01 100644 --- a/wgpu-hal/src/dx12/mod.rs +++ b/wgpu-hal/src/dx12/mod.rs @@ -660,13 +660,18 @@ impl crate::Surface for Surface { let non_srgb_format = auxil::dxgi::conv::map_texture_format_nosrgb(config.format); + // Nvidia recommends to use 1-2 more buffers than the maximum latency + // https://developer.nvidia.com/blog/advanced-api-performance-swap-chains/ + // For high latency extra buffers seems excessive, so go with a minimum of 3 and beyond that add 1. + let swap_chain_buffer = (config.maximum_frame_latency + 1).min(3); + let swap_chain = match self.swap_chain.write().take() { //Note: this path doesn't properly re-initialize all of the things Some(sc) => { let raw = unsafe { sc.release_resources() }; let result = unsafe { raw.ResizeBuffers( - config.swap_chain_size, + swap_chain_buffer, config.extent.width, config.extent.height, non_srgb_format, @@ -693,7 +698,7 @@ impl crate::Surface for Surface { quality: 0, }, buffer_usage: dxgitype::DXGI_USAGE_RENDER_TARGET_OUTPUT, - buffer_count: config.swap_chain_size, + buffer_count: swap_chain_buffer, scaling: d3d12::Scaling::Stretch, swap_effect: d3d12::SwapEffect::FlipDiscard, flags, @@ -797,11 +802,11 @@ impl crate::Surface for Surface { | SurfaceTarget::SwapChainPanel(_) => {} } - unsafe { swap_chain.SetMaximumFrameLatency(config.swap_chain_size) }; + unsafe { swap_chain.SetMaximumFrameLatency(config.maximum_frame_latency) }; let waitable = unsafe { swap_chain.GetFrameLatencyWaitableObject() }; - let mut resources = Vec::with_capacity(config.swap_chain_size as usize); - for i in 0..config.swap_chain_size { + let mut resources = Vec::with_capacity(config.maximum_frame_latency as usize); + for i in 0..config.maximum_frame_latency { let mut resource = d3d12::Resource::null(); unsafe { swap_chain.GetBuffer(i, &d3d12_ty::ID3D12Resource::uuidof(), resource.mut_void()) diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 5f92d2c4ab..afa4023797 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -1138,7 +1138,7 @@ impl crate::Adapter for super::Adapter { vec![wgt::PresentMode::Fifo] //TODO }, composite_alpha_modes: vec![wgt::CompositeAlphaMode::Opaque], //TODO - swap_chain_sizes: 2..=2, + maximum_frame_latency: 2..=2, //TODO, unused currently current_extent: None, usage: crate::TextureUses::COLOR_TARGET, }) diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 7bd6eb77bb..7961a4ed8e 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -922,11 +922,14 @@ pub struct SurfaceCapabilities { /// Must be at least one. pub formats: Vec, - /// Range for the swap chain sizes. + /// Range for the number of queued frames. /// - /// - `swap_chain_sizes.start` must be at least 1. - /// - `swap_chain_sizes.end` must be larger or equal to `swap_chain_sizes.start`. - pub swap_chain_sizes: RangeInclusive, + /// This adjusts either the swapchain frame count to value + 1 - or sets SetMaximumFrameLatency to the value given, + /// or uses a wait-for-present in the acquire method to limit rendering such that it acts like it's a value + 1 swapchain frame set. + /// + /// - `maximum_frame_latency.start` must be at least 1. + /// - `maximum_frame_latency.end` must be larger or equal to `maximum_frame_latency.start`. + pub maximum_frame_latency: RangeInclusive, /// Current extent of the surface, if known. pub current_extent: Option, @@ -1252,9 +1255,9 @@ pub struct RenderPipelineDescriptor<'a, A: Api> { #[derive(Debug, Clone)] pub struct SurfaceConfiguration { - /// Number of textures in the swap chain. Must be in - /// `SurfaceCapabilities::swap_chain_size` range. - pub swap_chain_size: u32, + /// Maximum number of queued frames. Must be in + /// `SurfaceCapabilities::maximum_frame_latency` range. + pub maximum_frame_latency: u32, /// Vertical synchronization mode. pub present_mode: wgt::PresentMode, /// Alpha composition mode. diff --git a/wgpu-hal/src/metal/adapter.rs b/wgpu-hal/src/metal/adapter.rs index 3d8f6f3e57..a946ce5819 100644 --- a/wgpu-hal/src/metal/adapter.rs +++ b/wgpu-hal/src/metal/adapter.rs @@ -320,13 +320,14 @@ impl crate::Adapter for super::Adapter { let pc = &self.shared.private_caps; Some(crate::SurfaceCapabilities { formats, - //Note: this is hardcoded in `CAMetalLayer` documentation - swap_chain_sizes: if pc.can_set_maximum_drawables_count { - 2..=3 + // We use this here to govern the maximum number of drawables + 1. + // See https://developer.apple.com/documentation/quartzcore/cametallayer/2938720-maximumdrawablecount + maximum_frame_latency: if pc.can_set_maximum_drawables_count { + 1..=2 } else { - // 3 is the default in `CAMetalLayer` documentation + // 3 is the default value for maximum drawables in `CAMetalLayer` documentation // iOS 10.3 was tested to use 3 on iphone5s - 3..=3 + 2..=2 }, present_modes: if pc.can_set_display_sync { vec![wgt::PresentMode::Fifo, wgt::PresentMode::Immediate] diff --git a/wgpu-hal/src/metal/surface.rs b/wgpu-hal/src/metal/surface.rs index e54a176da5..a97eff0aae 100644 --- a/wgpu-hal/src/metal/surface.rs +++ b/wgpu-hal/src/metal/surface.rs @@ -221,7 +221,7 @@ impl crate::Surface for super::Surface { } // this gets ignored on iOS for certain OS/device combinations (iphone5s iOS 10.3) - render_layer.set_maximum_drawable_count(config.swap_chain_size as _); + render_layer.set_maximum_drawable_count(config.maximum_frame_latency as u64 + 1); render_layer.set_drawable_size(drawable_size); if caps.can_set_next_drawable_timeout { let () = msg_send![*render_layer, setAllowsNextDrawableTimeout:false]; diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index 477d166c70..85e620d23c 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -1848,7 +1848,11 @@ impl crate::Adapter for super::Adapter { .collect(); Some(crate::SurfaceCapabilities { formats, - swap_chain_sizes: caps.min_image_count..=max_image_count, + // TODO: Right now we're always trunkating the swap chain + // (presumably - we're actually setting the min image count which isn't necessarily the swap chain size) + // Instead, we should use extensions when available to wait in present. + // See https://github.com/gfx-rs/wgpu/issues/2869 + maximum_frame_latency: (caps.min_image_count - 1)..=(max_image_count - 1), // Note this can't underflow since both `min_image_count` is at least one and we already patched `max_image_count`. current_extent, usage: conv::map_vk_image_usage(caps.supported_usage_flags), present_modes: raw_present_modes diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index a37017a9e6..23182b440c 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -579,7 +579,7 @@ impl super::Device { let mut info = vk::SwapchainCreateInfoKHR::builder() .flags(raw_flags) .surface(surface.raw) - .min_image_count(config.swap_chain_size) + .min_image_count(config.maximum_frame_latency + 1) // TODO: https://github.com/gfx-rs/wgpu/issues/2869 .image_format(original_format) .image_color_space(color_space) .image_extent(vk::Extent2D { diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 2b800a35c0..cfc2af253e 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -5151,6 +5151,26 @@ pub struct SurfaceConfiguration { /// AutoNoVsync will gracefully do a designed sets of fallbacks if their primary modes are /// unsupported. pub present_mode: PresentMode, + /// Desired maximum number of frames that the presentation engine should queue in advance. + /// + /// This is a hint to the backend implementation and will always be clamped to the supported range. + /// As a consequence, either the maximum frame latency is set directly on the swap chain, + /// or waits on present are scheduled to avoid exceeding the maximum frame latency if supported, + /// or the swap chain size is set to (max-latency + 1). + /// + /// Defaults to 2 when created via `wgpu::Surface::get_default_config`. + /// + /// Typical values range from 3 to 1, but higher values are possible: + /// * Choose 2 or higher for potentially smoother frame display, as it allows to be at least one frame + /// to be queued up. This typically avoids starving the GPU's work queue. + /// Higher values are useful for achieving a constant flow of frames to the display under varying load. + /// * Choose 1 for low latency from frame recording to frame display. + /// ⚠️ If the backend does not support waiting on present, this will cause the CPU to wait for the GPU + /// to finish all work related to the previous frame when calling `wgpu::Surface::get_current_texture`, + /// causing CPU-GPU serialization (i.e. when `wgpu::Surface::get_current_texture` returns, the GPU might be idle). + /// It is currently not possible to query this. See . + /// * A value of 0 is generally not supported and always clamped to a higher value. + pub desired_maximum_frame_latency: u32, /// Specifies how the alpha channel of the textures should be handled during compositing. pub alpha_mode: CompositeAlphaMode, /// Specifies what view formats will be allowed when calling create_view() on texture returned by get_current_texture(). @@ -5170,6 +5190,7 @@ impl SurfaceConfiguration { width: self.width, height: self.height, present_mode: self.present_mode, + desired_maximum_frame_latency: self.desired_maximum_frame_latency, alpha_mode: self.alpha_mode, view_formats: fun(self.view_formats.clone()), } diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index f12892dfb0..e94d45561f 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -4793,6 +4793,7 @@ impl Surface<'_> { format: *caps.formats.get(0)?, width, height, + desired_maximum_frame_latency: 2, present_mode: *caps.present_modes.get(0)?, alpha_mode: wgt::CompositeAlphaMode::Auto, view_formats: vec![], From 4c18e283d195f7d1bedfdcf2bc3d0fe8db01ee9f Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Wed, 17 Jan 2024 19:24:43 +0100 Subject: [PATCH 008/101] polish changelog for upcoming release (#5078) Co-authored-by: Connor Fitzgerald --- CHANGELOG.md | 285 +++++++++++++++++++++++++++------------------------ 1 file changed, 149 insertions(+), 136 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3a5afa4f4..5ec8568774 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,7 +39,15 @@ Bottom level categories: ## Unreleased -### All Public Dependencies Are Re-Exported +### Improved Multithreading through internal use of Reference Counting + +Large refactoring of wgpu’s internals aiming at reducing lock contention, and providing better performance when using wgpu on multiple threads. + +[Check the blog post!](https://gfx-rs.github.io/2023/11/24/arcanization.html) + +By @gents83 in [#3626](https://github.com/gfx-rs/wgpu/pull/3626) and thanks also to @jimblandy, @nical, @Wumpf, @Elabajaba & @cwfitzgerald + +### All Public Dependencies are Re-Exported All of wgpu's public dependencies are now re-exported at the top level so that users don't need to take their own dependencies. This includes: @@ -49,176 +57,179 @@ This includes: - raw_window_handle - web_sys -### `naga-ir` Shaders Have Dedicated Feature +### Feature Flag Changes -The `naga-ir` feature has been added to allow you to add naga module shaders without guessing about what other features needed to be enabled to get access to it. +#### WebGPU & WebGL in the same Binary -### Direct3D 11 backend removal +Enabling `webgl` no longer removes the `webgpu` backend. -This backend had no functionality, and with the recent support for GL on Desktop, which allows wgpu to run on older devices, there is no need to keep the backend. +Instead, there's a new (default enabled) `webgpu` feature that allows to explicitly opt-out of `webgpu` if so desired. +If both `webgl` & `webgpu` are enabled, `wgpu::Instance` decides upon creation whether to target wgpu-core/WebGL or WebGPU. +This means that adapter selection is not handled as with regular adapters, but still allows to decide at runtime whether +`webgpu` or the `webgl` backend should be used using a single wasm binary. +By @wumpf in [#5044](https://github.com/gfx-rs/wgpu/pull/5044) -### `WGPU_ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER` environment variable +#### `naga-ir` Dedicated Feature -This adds a way to allow a Vulkan driver which is non-compliant per VK_KHR_driver_properties to be enumerated. This is intended for testing new Vulkan drivers which are not Vulkan compliant yet. +The `naga-ir` feature has been added to allow you to add naga module shaders without guessing about what other features needed to be enabled to get access to it. +By @cwfitzgerald in [#5063](https://github.com/gfx-rs/wgpu/pull/5063). -### `DeviceExt::create_texture_with_data` Allows Mip-Major Data +#### `expose-ids` Feature available unconditionally -Previously, `DeviceExt::create_texture_with_data` only allowed data to be provided in layer major order. There is now a `order` parameter which allows you to specify if the data is in layer major or mip major order. +This feature allowed you to call `global_id` on any wgpu opaque handle to get a unique hashable identity for the given resource. This is now available without the feature flag. +By @cwfitzgerald in [#4841](https://github.com/gfx-rs/wgpu/pull/4841). -### `expose-ids` feature now available unconditionally +#### `dx12` and `metal` Backend Crate Features -This feature allowed you to call `global_id` on any wgpu opaque handle to get a unique hashable identity for the given resource. This is now available without the feature flag. By @cwfitzgerald in [#4841](https://github.com/gfx-rs/wgpu/pull/4841) +wgpu now exposes backend feature for the Direct3D 12 (`dx12`) and Metal (`metal`) backend. These are enabled by default, but don't do anything when not targeting the corresponding OS. +By @daxpedda in [#4815](https://github.com/gfx-rs/wgpu/pull/4815). -### `dx12` and `metal` backend crate features +### Direct3D 11 Backend Removal -Wgpu now exposes backend feature for the Direct3D 12 (`dx12`) and Metal (`metal`) backend. These are enabled by default, but don't do anything when not targetting the corresponding OS. By @daxpedda in [#4815](https://github.com/gfx-rs/wgpu/pull/4815) +This backend had no functionality, and with the recent support for GL on Desktop, which allows wgpu to run on older devices, there was no need to keep this backend. +By @valaphee in [#4828](https://github.com/gfx-rs/wgpu/pull/4828). -### Unified surface creation +### `WGPU_ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER` Environment Variable -Previously, there were various specialized surface creation functions for various platform specific handles. -Now, `wgpu::Instance::create_surface` & `wgpu::Instance::create_surface_unsafe` instead each take a value that can be converted to the unified `wgpu::SurfaceTarget`/`wgpu::SurfaceTargetUnsafe` enums. -Conversion to `wgpu::SurfaceTarget` is automatic for anything implementing `raw-window-handle`'s `HasWindowHandle` & `HasDisplayHandle` traits, -meaning that you can continue to e.g. pass references to winit windows as before. -By @wumpf in [#4984](https://github.com/gfx-rs/wgpu/pull/4984) +This adds a way to allow a Vulkan driver which is non-compliant per `VK_KHR_driver_properties` to be enumerated. This is intended for testing new Vulkan drivers which are not Vulkan compliant yet. +By @i509VCB in [#4754](https://github.com/gfx-rs/wgpu/pull/4754). -### WebGPU & WebGL in the same binary +### `DeviceExt::create_texture_with_data` allows Mip-Major Data -Enabling `webgl` no longer removes the `webgpu` backend. -Instead, there's a new (default enabled) `webgpu` feature that allows to explicitly opt-out of `webgpu` if so desired. -If both `webgl` & `webgpu` are enabled, `wgpu::Instance` decides upon creation whether to target wgpu-core/WebGL or WebGPU. -This means that adapter selection is not handled as with regular adapters, but still allows to decide at runtime whether -`webgpu` or the `webgl` backend should be used using a single wasm binary. -By @wumpf in [#5044](https://github.com/gfx-rs/wgpu/pull/5044) +Previously, `DeviceExt::create_texture_with_data` only allowed data to be provided in layer major order. There is now a `order` parameter which allows you to specify if the data is in layer major or mip major order. +```diff + let tex = ctx.device.create_texture_with_data( + &queue, + &descriptor, ++ wgpu::util::TextureDataOrder::LayerMajor, + src_data, + ); +``` -### New Features +By @cwfitzgerald in [#4780](https://github.com/gfx-rs/wgpu/pull/4780). -#### General -- Added `DownlevelFlags::VERTEX_AND_INSTANCE_INDEX_RESPECTS_RESPECTIVE_FIRST_VALUE_IN_INDIRECT_DRAW` to know if `@builtin(vertex_index)` and `@builtin(instance_index)` will respect the `first_vertex` / `first_instance` in indirect calls. If this is not present, both will always start counting from 0. Currently enabled on all backends except DX12. By @cwfitzgerald in [#4722](https://github.com/gfx-rs/wgpu/pull/4722) -- No longer validate surfaces against their allowed extent range on configure. This caused warnings that were almost impossible to avoid. As before, the resulting behavior depends on the compositor. By @wumpf in [#4796](https://github.com/gfx-rs/wgpu/pull/4796) -- Added support for the float32-filterable feature. By @almarklein in [#4759](https://github.com/gfx-rs/wgpu/pull/4759) -- GPU buffer memory is released during "lose the device". By @bradwerth in [#4851](https://github.com/gfx-rs/wgpu/pull/4851) -- wgpu and wgpu-core features are now documented on docs.rs. By @wumpf in [#4886](https://github.com/gfx-rs/wgpu/pull/4886) -- `SurfaceConfiguration` now exposes `desired_maximum_frame_latency` which was previously hard-coded to 2. By setting it to 1 you can reduce latency under the risk of making GPU & CPU work sequential. Currently, on DX12 this affects the `MaximumFrameLatency`, on all other backends except OpenGL the size of the swapchain (on OpenGL this has no effect). By @emilk & @wumpf in [#4899](https://github.com/gfx-rs/wgpu/pull/4899) -- DeviceLostClosure is guaranteed to be invoked exactly once. By @bradwerth in [#4862](https://github.com/gfx-rs/wgpu/pull/4862) +### Safe & unified Surface Creation -#### OpenGL -- `@builtin(instance_index)` now properly reflects the range provided in the draw call instead of always counting from 0. By @cwfitzgerald in [#4722](https://github.com/gfx-rs/wgpu/pull/4722). -- Desktop GL now supports `POLYGON_MODE_LINE` and `POLYGON_MODE_POINT`. By @valaphee in [#4836](https://github.com/gfx-rs/wgpu/pull/4836) +It is now possible to safely create a `wgpu::Surface` with `wgpu::Instance::create_surface()` by letting `wgpu::Surface` hold a lifetime to `window`. +Passing an owned value `window` to `Surface` will return a `wgpu::Surface<'static>`. -#### Naga +All possible safe variants (owned windows and web canvases) are grouped using `wgpu::SurfaceTarget`. +Conversion to `wgpu::SurfaceTarget` is automatic for any type implementing `raw-window-handle`'s `HasWindowHandle` & `HasDisplayHandle` traits, i.e. most window types. +For web canvas types this has to be done explicitly: +```rust +let surface: wgpu::Surface<'static> = instance.create_surface(wgpu::SurfaceTarget::Canvas(my_canvas))?; +``` -- Naga's WGSL front end now allows operators to produce values with abstract types, rather than concretizing thir operands. By @jimblandy in [#4850](https://github.com/gfx-rs/wgpu/pull/4850) and [#4870](https://github.com/gfx-rs/wgpu/pull/4870). +All unsafe variants are now grouped under `wgpu::Instance::create_surface_unsafe` which takes the +`wgpu::SurfaceTargetUnsafe` enum and always returns `wgpu::Surface<'static>`. -- Naga's WGSL front and back ends now have experimental support for 64-bit floating-point literals: `1.0lf` denotes an `f64` value. There has been experimental support for an `f64` type for a while, but until now there was no syntax for writing literals with that type. As before, Naga module validation rejects `f64` values unless `naga::valid::Capabilities::FLOAT64` is requested. By @jimblandy in [#4747](https://github.com/gfx-rs/wgpu/pull/4747). +In order to create a `wgpu::Surface<'static>` without passing ownership of the window use +`wgpu::SurfaceTargetUnsafe::from_window`: +```rust +let surface = unsafe { + instance.create_surface_unsafe(wgpu::SurfaceTargetUnsafe::from_window(&my_window))? +}; +``` +The easiest way to make this code safe is to use shared ownership: +```rust +let window: Arc; +// ... +let surface = instance.create_surface(my_window.clone())?; +``` -- Naga constant evaluation can now process binary operators whose operands are both vectors. By @jimblandy in [#4861](https://github.com/gfx-rs/wgpu/pull/4861). +All platform specific surface creation using points have moved into `SurfaceTargetUnsafe` as well. +For example: -- Add `--bulk-validate` option to Naga CLI. By @jimblandy in [#4871](https://github.com/gfx-rs/wgpu/pull/4871). +Safety by @daxpedda in [#4597](https://github.com/gfx-rs/wgpu/pull/4597) +Unification by @wumpf in [#4984](https://github.com/gfx-rs/wgpu/pull/4984) -- Naga's `cargo xtask validate` now runs validation jobs in parallel, using the [jobserver](https://crates.io/crates/jobserver) protocol to limit concurrency, and offers a `validate all` subcommand, which runs all available validation types. By @jimblandy in [#4902](https://github.com/gfx-rs/wgpu/pull/4902). +### Add partial Support for WGSL Abstract Types -### Changes +Abstract types make numeric literals easier to use, by +automatically converting literals and other constant expressions +from abstract numeric types to concrete types when safe and +necessary. For example, to build a vector of floating-point +numbers, Naga previously made you write: +```rust +vec3(1.0, 2.0, 3.0) +``` +With this change, you can now simply write: +```rust +vec3(1, 2, 3) +``` +Even though the literals are abstract integers, Naga recognizes +that it is safe and necessary to convert them to `f32` values in +order to build the vector. You can also use abstract values as +initializers for global constants and global and local variables, +like this: +```rust +var unit_x: vec2 = vec2(1, 0); +``` +The literals `1` and `0` are abstract integers, and the expression +`vec2(1, 0)` is an abstract vector. However, Naga recognizes that +it can convert that to the concrete type `vec2` to satisfy +the given type of `unit_x`. +The WGSL specification permits abstract integers and +floating-point values in almost all contexts, but Naga's support +for this is still incomplete. Many WGSL operators and builtin +functions are specified to produce abstract results when applied +to abstract inputs, but for now Naga simply concretizes them all +before applying the operation. We will expand Naga's abstract type +support in subsequent pull requests. +As part of this work, the public types `naga::ScalarKind` and +`naga::Literal` now have new variants, `AbstractInt` and `AbstractFloat`. + +By @jimblandy in [#4743](https://github.com/gfx-rs/wgpu/pull/4743), [#4755](https://github.com/gfx-rs/wgpu/pull/4755). -- Arcanization of wgpu core resources: By @gents83 in [#3626](https://github.com/gfx-rs/wgpu/pull/3626) and thanks also to @jimblandy, @nical, @Wumpf, @Elabajaba & @cwfitzgerald - - Removed Token and LifeTime related management - - Removed RefCount and MultiRefCount in favour of using only Arc internal reference count - - Removing mut from resources and added instead internal members locks on demand or atomics operations - - Resources now implement Drop and destroy stuff when last Arc resources is released - - Resources hold an Arc in order to be able to implement Drop - - Resources have an utility to retrieve the id of the resource itself - - Remove all guards and just retrive the Arc needed on-demand to unlock registry of resources asap - - Verify correct resources release when unused or not needed - - Check Web and Metal compliation (thanks to @niklaskorz) - - Fix tests on all platforms - - Test a multithreaded scenario - - Storage is now holding only user-land resources, but Arc is keeping refcount for resources - - When user unregister a resource, it's not dropped if still in use due to refcount inside wgpu - - IdentityManager is now unique and free is called on resource drop instead of storage unregister - - Identity changes due to Arcanization and Registry being just the user reference - - Added MemLeaks test and fixing mem leaks +### New Features #### General - -- Log vulkan validation layer messages during instance creation and destruction: By @exrook in [#4586](https://github.com/gfx-rs/wgpu/pull/4586) -- `TextureFormat::block_size` is deprecated, use `TextureFormat::block_copy_size` instead: By @wumpf in [#4647](https://github.com/gfx-rs/wgpu/pull/4647) +- Added `DownlevelFlags::VERTEX_AND_INSTANCE_INDEX_RESPECTS_RESPECTIVE_FIRST_VALUE_IN_INDIRECT_DRAW` to know if `@builtin(vertex_index)` and `@builtin(instance_index)` will respect the `first_vertex` / `first_instance` in indirect calls. If this is not present, both will always start counting from 0. Currently enabled on all backends except DX12. By @cwfitzgerald in [#4722](https://github.com/gfx-rs/wgpu/pull/4722). +- Added support for the `FLOAT32_FILTERABLE` feature (web and native, corresponds to WebGPU's `float32-filterable`). By @almarklein in [#4759](https://github.com/gfx-rs/wgpu/pull/4759). +- GPU buffer memory is released during "lose the device". By @bradwerth in [#4851](https://github.com/gfx-rs/wgpu/pull/4851). +- wgpu and wgpu-core cargo feature flags are now documented on docs.rs. By @wumpf in [#4886](https://github.com/gfx-rs/wgpu/pull/4886). +- DeviceLostClosure is guaranteed to be invoked exactly once. By @bradwerth in [#4862](https://github.com/gfx-rs/wgpu/pull/4862). +- Log vulkan validation layer messages during instance creation and destruction: By @exrook in [#4586](https://github.com/gfx-rs/wgpu/pull/4586). +- `TextureFormat::block_size` is deprecated, use `TextureFormat::block_copy_size` instead: By @wumpf in [#4647](https://github.com/gfx-rs/wgpu/pull/4647). - Rename of `DispatchIndirect`, `DrawIndexedIndirect`, and `DrawIndirect` types in the `wgpu::util` module to `DispatchIndirectArgs`, `DrawIndexedIndirectArgs`, and `DrawIndirectArgs`. By @cwfitzgerald in [#4723](https://github.com/gfx-rs/wgpu/pull/4723). -- Make the size parameter of `encoder.clear_buffer` an `Option` instead of `Option>`. By @nical in [#4737](https://github.com/gfx-rs/wgpu/pull/4737) +- Make the size parameter of `encoder.clear_buffer` an `Option` instead of `Option>`. By @nical in [#4737](https://github.com/gfx-rs/wgpu/pull/4737). - Reduce the `info` log level noise. By @nical in [#4769](https://github.com/gfx-rs/wgpu/pull/4769), [#4711](https://github.com/gfx-rs/wgpu/pull/4711) and [#4772](https://github.com/gfx-rs/wgpu/pull/4772) -- Rename `features` & `limits` fields of `DeviceDescriptor` to `required_features` & `required_limits`. By @teoxoy in [#4803](https://github.com/gfx-rs/wgpu/pull/4803) - -#### Safe `Surface` creation - -It is now possible to safely create a `wgpu::Surface` with `Surface::create_surface()` by letting `Surface` hold a lifetime to `window`. - -Passing an owned value `window` to `Surface` will return a `Surface<'static>`. Shared ownership over `window` can still be achieved with e.g. an `Arc`. Alternatively a reference could be passed, which will return a `Surface<'window>`. +- Rename `features` & `limits` fields of `DeviceDescriptor` to `required_features` & `required_limits`. By @teoxoy in [#4803](https://github.com/gfx-rs/wgpu/pull/4803). +- `SurfaceConfiguration` now exposes `desired_maximum_frame_latency` which was previously hard-coded to 2. By setting it to 1 you can reduce latency under the risk of making GPU & CPU work sequential. Currently, on DX12 this affects the `MaximumFrameLatency`, on all other backends except OpenGL the size of the swapchain (on OpenGL this has no effect). By @emilk & @wumpf in [#4899](https://github.com/gfx-rs/wgpu/pull/4899) -`Surface::create_surface_from_raw()` can be used to continue producing a `Surface<'static>` without any lifetime requirements over `window`, which also remains `unsafe`. +#### OpenGL +- `@builtin(instance_index)` now properly reflects the range provided in the draw call instead of always counting from 0. By @cwfitzgerald in [#4722](https://github.com/gfx-rs/wgpu/pull/4722). +- Desktop GL now supports `POLYGON_MODE_LINE` and `POLYGON_MODE_POINT`. By @valaphee in [#4836](https://github.com/gfx-rs/wgpu/pull/4836). #### Naga -- Remove `span` and `validate` features. Always fully validate shader modules, and always track source positions for use in error messages. By @teoxoy in [#4706](https://github.com/gfx-rs/wgpu/pull/4706) +- Naga's WGSL front end now allows operators to produce values with abstract types, rather than concretizing thir operands. By @jimblandy in [#4850](https://github.com/gfx-rs/wgpu/pull/4850) and [#4870](https://github.com/gfx-rs/wgpu/pull/4870). +- Naga's WGSL front and back ends now have experimental support for 64-bit floating-point literals: `1.0lf` denotes an `f64` value. There has been experimental support for an `f64` type for a while, but until now there was no syntax for writing literals with that type. As before, Naga module validation rejects `f64` values unless `naga::valid::Capabilities::FLOAT64` is requested. By @jimblandy in [#4747](https://github.com/gfx-rs/wgpu/pull/4747). +- Naga constant evaluation can now process binary operators whose operands are both vectors. By @jimblandy in [#4861](https://github.com/gfx-rs/wgpu/pull/4861). +- Add `--bulk-validate` option to Naga CLI. By @jimblandy in [#4871](https://github.com/gfx-rs/wgpu/pull/4871). +- Naga's `cargo xtask validate` now runs validation jobs in parallel, using the [jobserver](https://crates.io/crates/jobserver) protocol to limit concurrency, and offers a `validate all` subcommand, which runs all available validation types. By @jimblandy in [#4902](https://github.com/gfx-rs/wgpu/pull/4902). +- Remove `span` and `validate` features. Always fully validate shader modules, and always track source positions for use in error messages. By @teoxoy in [#4706](https://github.com/gfx-rs/wgpu/pull/4706). - Introduce a new `Scalar` struct type for use in Naga's IR, and update all frontend, middle, and backend code appropriately. By @jimblandy in [#4673](https://github.com/gfx-rs/wgpu/pull/4673). - Add more metal keywords. By @fornwall in [#4707](https://github.com/gfx-rs/wgpu/pull/4707). - -- Add partial support for WGSL abstract types (@jimblandy in [#4743](https://github.com/gfx-rs/wgpu/pull/4743), [#4755](https://github.com/gfx-rs/wgpu/pull/4755)). - - Abstract types make numeric literals easier to use, by - automatically converting literals and other constant expressions - from abstract numeric types to concrete types when safe and - necessary. For example, to build a vector of floating-point - numbers, Naga previously made you write: - - vec3(1.0, 2.0, 3.0) - - With this change, you can now simply write: - - vec3(1, 2, 3) - - Even though the literals are abstract integers, Naga recognizes - that it is safe and necessary to convert them to `f32` values in - order to build the vector. You can also use abstract values as - initializers for global constants and global and local variables, - like this: - - var unit_x: vec2 = vec2(1, 0); - - The literals `1` and `0` are abstract integers, and the expression - `vec2(1, 0)` is an abstract vector. However, Naga recognizes that - it can convert that to the concrete type `vec2` to satisfy - the given type of `unit_x`. - - The WGSL specification permits abstract integers and - floating-point values in almost all contexts, but Naga's support - for this is still incomplete. Many WGSL operators and builtin - functions are specified to produce abstract results when applied - to abstract inputs, but for now Naga simply concretizes them all - before applying the operation. We will expand Naga's abstract type - support in subsequent pull requests. - - As part of this work, the public types `naga::ScalarKind` and - `naga::Literal` now have new variants, `AbstractInt` and `AbstractFloat`. - -- Add a new `naga::Literal` variant, `I64`, for signed 64-bit literals. [#4711](https://github.com/gfx-rs/wgpu/pull/4711) - +- Add a new `naga::Literal` variant, `I64`, for signed 64-bit literals. [#4711](https://github.com/gfx-rs/wgpu/pull/4711). - Emit and init `struct` member padding always. By @ErichDonGubler in [#4701](https://github.com/gfx-rs/wgpu/pull/4701). - - In WGSL output, always include the `i` suffix on `i32` literals. By @jimblandy in [#4863](https://github.com/gfx-rs/wgpu/pull/4863). - - In WGSL output, always include the `f` suffix on `f32` literals. By @jimblandy in [#4869](https://github.com/gfx-rs/wgpu/pull/4869). ### Bug Fixes #### General -- `BufferMappedRange` trait is now `WasmNotSendSync`, i.e. it is `Send`/`Sync` if not on wasm or `fragile-send-sync-non-atomic-wasm` is enabled. By @wumpf in [#4818](https://github.com/gfx-rs/wgpu/pull/4818) -- Align `wgpu_types::CompositeAlphaMode` serde serialization to spec. By @littledivy in [#4940](https://github.com/gfx-rs/wgpu/pull/4940) -- Fix error message of `ConfigureSurfaceError::TooLarge`. By @Dinnerbone in [#4960](https://github.com/gfx-rs/wgpu/pull/4960) -- Fix dropping of `DeviceLostCallbackC` params. By @bradwerth in [#5032](https://github.com/gfx-rs/wgpu/pull/5032) -- Fixed a number of panics. by @nical in [#4999](https://github.com/gfx-rs/wgpu/pull/4999), [#5014](https://github.com/gfx-rs/wgpu/pull/5014), [#5024](https://github.com/gfx-rs/wgpu/pull/5024), [#5025](https://github.com/gfx-rs/wgpu/pull/5025), [#5026](https://github.com/gfx-rs/wgpu/pull/5026), [#5027](https://github.com/gfx-rs/wgpu/pull/5027), [#5028](https://github.com/gfx-rs/wgpu/pull/5028) and [#5042](https://github.com/gfx-rs/wgpu/pull/5042). +- `BufferMappedRange` trait is now `WasmNotSendSync`, i.e. it is `Send`/`Sync` if not on wasm or `fragile-send-sync-non-atomic-wasm` is enabled. By @wumpf in [#4818](https://github.com/gfx-rs/wgpu/pull/4818). +- Align `wgpu_types::CompositeAlphaMode` serde serialization to spec. By @littledivy in [#4940](https://github.com/gfx-rs/wgpu/pull/4940). +- Fix error message of `ConfigureSurfaceError::TooLarge`. By @Dinnerbone in [#4960](https://github.com/gfx-rs/wgpu/pull/4960). +- Fix dropping of `DeviceLostCallbackC` params. By @bradwerth in [#5032](https://github.com/gfx-rs/wgpu/pull/5032). +- Fixed a number of panics. By @nical in [#4999](https://github.com/gfx-rs/wgpu/pull/4999), [#5014](https://github.com/gfx-rs/wgpu/pull/5014), [#5024](https://github.com/gfx-rs/wgpu/pull/5024), [#5025](https://github.com/gfx-rs/wgpu/pull/5025), [#5026](https://github.com/gfx-rs/wgpu/pull/5026), [#5027](https://github.com/gfx-rs/wgpu/pull/5027), [#5028](https://github.com/gfx-rs/wgpu/pull/5028) and [#5042](https://github.com/gfx-rs/wgpu/pull/5042). +- No longer validate surfaces against their allowed extent range on configure. This caused warnings that were almost impossible to avoid. As before, the resulting behavior depends on the compositor. By @wumpf in [#4796](https://github.com/gfx-rs/wgpu/pull/4796). #### DX12 -- Fixed D3D12_SUBRESOURCE_FOOTPRINT calculation for block compressed textures which caused a crash with `Queue::write_texture` on DX12. By @DTZxPorter in [#4990](https://github.com/gfx-rs/wgpu/pull/4990) +- Fixed D3D12_SUBRESOURCE_FOOTPRINT calculation for block compressed textures which caused a crash with `Queue::write_texture` on DX12. By @DTZxPorter in [#4990](https://github.com/gfx-rs/wgpu/pull/4990). #### Vulkan @@ -226,26 +237,19 @@ Passing an owned value `window` to `Surface` will return a `Surface<'static>`. S #### WebGPU -- Allow calling `BufferSlice::get_mapped_range` multiple times on the same buffer slice (instead of throwing a Javascript exception): By @DouglasDwyer in [#4726](https://github.com/gfx-rs/wgpu/pull/4726) +- Allow calling `BufferSlice::get_mapped_range` multiple times on the same buffer slice (instead of throwing a Javascript exception). By @DouglasDwyer in [#4726](https://github.com/gfx-rs/wgpu/pull/4726). #### WGL -- Create a hidden window per `wgpu::Instance` instead of sharing a global one. +- Create a hidden window per `wgpu::Instance` instead of sharing a global one. By @Zoxc in [#4603](https://github.com/gfx-rs/wgpu/issues/4603) #### Naga - Make module compaction preserve the module's named types, even if they are unused. By @jimblandy in [#4734](https://github.com/gfx-rs/wgpu/pull/4734). - - Improve algorithm used by module compaction. By @jimblandy in [#4662](https://github.com/gfx-rs/wgpu/pull/4662). - - When reading GLSL, fix the argument types of the double-precision floating-point overloads of the `dot`, `reflect`, `distance`, and `ldexp` builtin functions. Correct the WGSL generated for constructing 64-bit floating-point matrices. Add tests for all the above. By @jimblandy in [#4684](https://github.com/gfx-rs/wgpu/pull/4684). - - Allow Naga's IR types to represent matrices with elements elements of any scalar kind. This makes it possible for Naga IR types to represent WGSL abstract matrices. By @jimblandy in [#4735](https://github.com/gfx-rs/wgpu/pull/4735). - -- When evaluating const-expressions and generating SPIR-V, properly handle `Compose` expressions whose operands are `Splat` expressions. Such expressions are created and marked as constant by the constant evaluator. By @jimblandy in [#4695](https://github.com/gfx-rs/wgpu/pull/4695). - - Preserve the source spans for constants and expressions correctly across module compaction. By @jimblandy in [#4696](https://github.com/gfx-rs/wgpu/pull/4696). - - Record the names of WGSL `alias` declarations in Naga IR `Type`s. By @jimblandy in [#4733](https://github.com/gfx-rs/wgpu/pull/4733). #### Metal @@ -254,9 +258,18 @@ Passing an owned value `window` to `Surface` will return a `Surface<'static>`. S ### Examples -- remove winit dependency from hello-compute example by @psvri in [#4699](https://github.com/gfx-rs/wgpu/pull/4699) -- hello-compute example fix failure with "wgpu error: Validation Error" if arguments are missing by @vilcans in [#4939](https://github.com/gfx-rs/wgpu/pull/4939) -- Made the examples page not crash on Chrome on Android, and responsive to screen sizes by @Dinnerbone in [#4958](https://github.com/gfx-rs/wgpu/pull/4958) +- remove winit dependency from hello-compute example. By @psvri in [#4699](https://github.com/gfx-rs/wgpu/pull/4699) +- hello-compute example fix failure with `wgpu error: Validation Error` if arguments are missing. By @vilcans in [#4939](https://github.com/gfx-rs/wgpu/pull/4939). +- Made the examples page not crash on Chrome on Android, and responsive to screen sizes. By @Dinnerbone in [#4958](https://github.com/gfx-rs/wgpu/pull/4958). + +## v0.18.2 (2023-12-06) + +This release includes `naga` version 0.14.2. The crates `wgpu-core`, `wgpu-hal` are still at `0.18.1` and the crates `wgpu` and `wgpu-types` are still at `0.18.0`. + +### Bug Fixes + +#### Naga +- When evaluating const-expressions and generating SPIR-V, properly handle `Compose` expressions whose operands are `Splat` expressions. Such expressions are created and marked as constant by the constant evaluator. By @jimblandy in [#4695](https://github.com/gfx-rs/wgpu/pull/4695). ## v0.18.1 (2023-11-15) From 8b2098bd4eaf1a4e4793cd4684f7b2e4ec64b39d Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 17 Jan 2024 14:42:11 -0500 Subject: [PATCH 009/101] Release 0.19 (#5082) --- CHANGELOG.md | 35 ++++++++++++++++++++++++++++++++++- Cargo.lock | 28 ++++++++++++++-------------- Cargo.toml | 22 +++++++++++----------- d3d12/Cargo.toml | 2 +- deno_webgpu/Cargo.toml | 2 +- naga-cli/Cargo.toml | 4 ++-- naga/Cargo.toml | 2 +- naga/fuzz/Cargo.toml | 2 +- wgpu-core/Cargo.toml | 8 ++++---- wgpu-hal/Cargo.toml | 10 +++++----- wgpu-types/Cargo.toml | 2 +- 11 files changed, 75 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ec8568774..c4361ea48a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,7 +37,17 @@ Bottom level categories: - Hal --> -## Unreleased +## v0.19.0 (2024-01-17) + +This release includes: +- `wgpu` +- `wgpu-core` +- `wgpu-hal` +- `wgpu-types` +- `wgpu-info` +- `naga` (skipped from 0.14 to 0.19) +- `naga-cli` (skipped from 0.14 to 0.19) +- `d3d12` (skipped from 0.7 to 0.19) ### Improved Multithreading through internal use of Reference Counting @@ -181,6 +191,29 @@ As part of this work, the public types `naga::ScalarKind` and By @jimblandy in [#4743](https://github.com/gfx-rs/wgpu/pull/4743), [#4755](https://github.com/gfx-rs/wgpu/pull/4755). +### `Instance::enumerate_adapters` now returns `Vec` instead of an `ExactSizeIterator` + +This allows us to support WebGPU and WebGL in the same binary. + +```diff +- let adapters: Vec = instance.enumerate_adapters(wgpu::Backends::all()).collect(); ++ let adapters: Vec = instance.enumerate_adapters(wgpu::Backends::all()); +``` + +By @wumpf in [#5044](https://github.com/gfx-rs/wgpu/pull/5044) + +### `device.poll()` now returns a `MaintainResult` instead of a `bool` + +This is a forward looking change, as we plan to add more information to the `MaintainResult` in the future. +This enum has the same data as the boolean, but with some useful helper functions. + +```diff +- let queue_finished: bool = device.poll(wgpu::Maintain::Wait); ++ let queue_finished: bool = device.poll(wgpu::Maintain::Wait).is_queue_empty(); +``` + +By @cwfitzgerald in [#5053](https://github.com/gfx-rs/wgpu/pull/5053) + ### New Features #### General diff --git a/Cargo.lock b/Cargo.lock index 0d317e1476..41fb4c90e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -895,10 +895,10 @@ checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" [[package]] name = "d3d12" -version = "0.7.0" +version = "0.19.0" dependencies = [ "bitflags 2.4.1", - "libloading 0.8.1", + "libloading 0.7.4", "winapi", ] @@ -2051,7 +2051,7 @@ dependencies = [ [[package]] name = "naga" -version = "0.14.2" +version = "0.19.0" dependencies = [ "arbitrary", "bincode", @@ -2080,7 +2080,7 @@ dependencies = [ [[package]] name = "naga-cli" -version = "0.14.0" +version = "0.19.0" dependencies = [ "argh", "bincode", @@ -2554,7 +2554,7 @@ checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" [[package]] name = "player" -version = "0.18.0" +version = "0.19.0" dependencies = [ "env_logger", "log", @@ -3960,7 +3960,7 @@ dependencies = [ [[package]] name = "wgpu" -version = "0.18.0" +version = "0.19.0" dependencies = [ "arrayvec 0.7.4", "cfg-if", @@ -3984,7 +3984,7 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "0.18.0" +version = "0.19.0" dependencies = [ "arrayvec 0.7.4", "bit-vec", @@ -4010,7 +4010,7 @@ dependencies = [ [[package]] name = "wgpu-examples" -version = "0.18.0" +version = "0.19.0" dependencies = [ "bytemuck", "cfg-if", @@ -4043,7 +4043,7 @@ dependencies = [ [[package]] name = "wgpu-hal" -version = "0.18.0" +version = "0.19.0" dependencies = [ "android_system_properties", "arrayvec 0.7.4", @@ -4067,7 +4067,7 @@ dependencies = [ "js-sys", "khronos-egl", "libc", - "libloading 0.8.1", + "libloading 0.7.4", "log", "metal", "naga", @@ -4090,7 +4090,7 @@ dependencies = [ [[package]] name = "wgpu-info" -version = "0.18.0" +version = "0.19.0" dependencies = [ "anyhow", "bitflags 2.4.1", @@ -4104,7 +4104,7 @@ dependencies = [ [[package]] name = "wgpu-macros" -version = "0.18.0" +version = "0.19.0" dependencies = [ "heck", "quote", @@ -4113,7 +4113,7 @@ dependencies = [ [[package]] name = "wgpu-test" -version = "0.18.0" +version = "0.19.0" dependencies = [ "anyhow", "arrayvec 0.7.4", @@ -4149,7 +4149,7 @@ dependencies = [ [[package]] name = "wgpu-types" -version = "0.18.0" +version = "0.19.0" dependencies = [ "bitflags 2.4.1", "js-sys", diff --git a/Cargo.toml b/Cargo.toml index 8c9c056803..ebc5b8f72b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,27 +45,27 @@ keywords = ["graphics"] license = "MIT OR Apache-2.0" homepage = "https://wgpu.rs/" repository = "https://github.com/gfx-rs/wgpu" -version = "0.18.0" +version = "0.19.0" authors = ["gfx-rs developers"] [workspace.dependencies.wgc] package = "wgpu-core" path = "./wgpu-core" -version = "0.18.0" +version = "0.19.0" [workspace.dependencies.wgt] package = "wgpu-types" path = "./wgpu-types" -version = "0.18.0" +version = "0.19.0" [workspace.dependencies.hal] package = "wgpu-hal" path = "./wgpu-hal" -version = "0.18.0" +version = "0.19.0" [workspace.dependencies.naga] path = "./naga" -version = "0.14.0" +version = "0.19.0" [workspace.dependencies] anyhow = "1.0" @@ -117,12 +117,12 @@ serde_json = "1.0.111" smallvec = "1" static_assertions = "1.1.0" thiserror = "1" -wgpu = { version = "0.18.0", path = "./wgpu" } -wgpu-core = { version = "0.18.0", path = "./wgpu-core" } -wgpu-example = { version = "0.18.0", path = "./examples/common" } -wgpu-macros = { version = "0.18.0", path = "./wgpu-macros" } -wgpu-test = { version = "0.18.0", path = "./tests" } -wgpu-types = { version = "0.18.0", path = "./wgpu-types" } +wgpu = { version = "0.19.0", path = "./wgpu" } +wgpu-core = { version = "0.19.0", path = "./wgpu-core" } +wgpu-example = { version = "0.19.0", path = "./examples/common" } +wgpu-macros = { version = "0.19.0", path = "./wgpu-macros" } +wgpu-test = { version = "0.19.0", path = "./tests" } +wgpu-types = { version = "0.19.0", path = "./wgpu-types" } winit = { version = "0.29", features = ["android-native-activity"] } # Metal dependencies diff --git a/d3d12/Cargo.toml b/d3d12/Cargo.toml index 91f3542948..10c68eab77 100644 --- a/d3d12/Cargo.toml +++ b/d3d12/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "d3d12" -version = "0.7.0" +version = "0.19.0" authors = ["gfx-rs developers"] description = "Low level D3D12 API wrapper" repository = "https://github.com/gfx-rs/wgpu/tree/trunk/d3d12" diff --git a/deno_webgpu/Cargo.toml b/deno_webgpu/Cargo.toml index b9d281f04d..d1097c658d 100644 --- a/deno_webgpu/Cargo.toml +++ b/deno_webgpu/Cargo.toml @@ -40,7 +40,7 @@ workspace = true features = ["dx12"] [target.'cfg(windows)'.dependencies.wgpu-hal] -version = "0.18.0" +version = "0.19.0" path = "../wgpu-hal" features = ["windows_rs"] diff --git a/naga-cli/Cargo.toml b/naga-cli/Cargo.toml index 7b8c3024f1..9fe22e3461 100644 --- a/naga-cli/Cargo.toml +++ b/naga-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "naga-cli" -version = "0.14.0" +version = "0.19.0" authors = ["gfx-rs developers"] edition = "2021" description = "Shader translation command line tool" @@ -25,7 +25,7 @@ env_logger = "0.10" argh = "0.1.5" [dependencies.naga] -version = "0.14" +version = "0.19" path = "../naga" features = [ "compact", diff --git a/naga/Cargo.toml b/naga/Cargo.toml index 094c4779a5..1d44729c9f 100644 --- a/naga/Cargo.toml +++ b/naga/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "naga" -version = "0.14.2" +version = "0.19.0" authors = ["gfx-rs developers"] edition = "2021" description = "Shader translation infrastructure" diff --git a/naga/fuzz/Cargo.toml b/naga/fuzz/Cargo.toml index 4285142c06..1f1c1814ba 100644 --- a/naga/fuzz/Cargo.toml +++ b/naga/fuzz/Cargo.toml @@ -15,7 +15,7 @@ libfuzzer-sys = "0.4" [target.'cfg(not(any(target_arch = "wasm32", target_os = "ios")))'.dependencies.naga] path = ".." -version = "0.14.0" +version = "0.19.0" features = ["arbitrary", "spv-in", "wgsl-in", "glsl-in"] [[bin]] diff --git a/wgpu-core/Cargo.toml b/wgpu-core/Cargo.toml index 5c2b430338..28edac35b5 100644 --- a/wgpu-core/Cargo.toml +++ b/wgpu-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wgpu-core" -version = "0.18.0" +version = "0.19.0" authors = ["gfx-rs developers"] edition = "2021" description = "WebGPU core logic on wgpu-hal" @@ -109,18 +109,18 @@ thiserror = "1" [dependencies.naga] path = "../naga" -version = "0.14.0" +version = "0.19.0" features = ["clone"] [dependencies.wgt] package = "wgpu-types" path = "../wgpu-types" -version = "0.18.0" +version = "0.19.0" [dependencies.hal] package = "wgpu-hal" path = "../wgpu-hal" -version = "0.18.0" +version = "0.19.0" default_features = false [target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies] diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index b85a518dc4..4d542afed7 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wgpu-hal" -version = "0.18.0" +version = "0.19.0" authors = ["gfx-rs developers"] edition = "2021" description = "WebGPU hardware abstraction layer" @@ -90,7 +90,7 @@ glow = { version = "0.13", git = "https://github.com/grovesNL/glow.git", rev = " [dependencies.wgt] package = "wgpu-types" path = "../wgpu-types" -version = "0.18.0" +version = "0.19.0" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] # backend: Vulkan @@ -127,7 +127,7 @@ winapi = { version = "0.3", features = [ "winuser", "dcomp", ] } -d3d12 = { path = "../d3d12/", version = "0.7.0", optional = true, features = [ +d3d12 = { path = "../d3d12/", version = "0.19.0", optional = true, features = [ "libloading", ] } @@ -157,7 +157,7 @@ android_system_properties = "0.1.1" [dependencies.naga] path = "../naga" -version = "0.14.0" +version = "0.19.0" features = ["clone"] [build-dependencies] @@ -166,7 +166,7 @@ cfg_aliases.workspace = true # DEV dependencies [dev-dependencies.naga] path = "../naga" -version = "0.14.0" +version = "0.19.0" features = ["wgsl-in"] [dev-dependencies] diff --git a/wgpu-types/Cargo.toml b/wgpu-types/Cargo.toml index 90846873b2..7528b18c0a 100644 --- a/wgpu-types/Cargo.toml +++ b/wgpu-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wgpu-types" -version = "0.18.0" +version = "0.19.0" authors = ["gfx-rs developers"] edition = "2021" description = "WebGPU types" From 7eac4cec5b5768b9e8c221eb3ab1b5b0173bcba7 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 17 Jan 2024 14:47:13 -0500 Subject: [PATCH 010/101] Fix naga release --- naga/Cargo.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/naga/Cargo.toml b/naga/Cargo.toml index 1d44729c9f..a13e4f9196 100644 --- a/naga/Cargo.toml +++ b/naga/Cargo.toml @@ -68,7 +68,10 @@ criterion = { version = "0.5", features = [] } bincode = "1" diff = "0.1" env_logger = "0.10" -hlsl-snapshots = { version = "0.1.0", path = "./hlsl-snapshots" } +# This _cannot_ have a version specified. If it does, crates.io will look +# for a version of the package on crates when we publish naga. Path dependencies +# are allowed through though. +hlsl-snapshots = { path = "./hlsl-snapshots" } # Require at least version 0.7.1 of ron, this version changed how floating points are # serialized by forcing them to always have the decimal part, this makes it backwards # incompatible with our tests because we do a syntatic diff and not a semantic one. From 484457d95993b00b91905fae0e539a093423cc28 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 17 Jan 2024 15:23:50 -0500 Subject: [PATCH 011/101] Fix wgpu-hal build --- .deny.toml | 3 ++- Cargo.lock | 9 +++++---- wgpu-hal/Cargo.toml | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.deny.toml b/.deny.toml index 9c8f96c6b4..5f1dd13487 100644 --- a/.deny.toml +++ b/.deny.toml @@ -6,8 +6,10 @@ skip-tree = [ { name = "rustc_version", version = "0.2.3" }, ] skip = [ + { name = "hlsl-snapshots", version = "0.1.0" }, ] wildcards = "deny" +allow-wildcard-paths = true [licenses] allow = [ @@ -26,7 +28,6 @@ allow = [ [sources] allow-git = [ # Waiting on releases; used in examples only - "https://github.com/SiegeEngine/ddsfile", "https://github.com/Razaekel/noise-rs", "https://github.com/grovesNL/glow", diff --git a/Cargo.lock b/Cargo.lock index 41fb4c90e2..c8d235b287 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -898,7 +898,7 @@ name = "d3d12" version = "0.19.0" dependencies = [ "bitflags 2.4.1", - "libloading 0.7.4", + "libloading 0.8.1", "winapi", ] @@ -1505,8 +1505,9 @@ checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3" [[package]] name = "glow" -version = "0.13.0" -source = "git+https://github.com/grovesNL/glow.git?rev=29ff917a2b2ff7ce0a81b2cc5681de6d4735b36e#29ff917a2b2ff7ce0a81b2cc5681de6d4735b36e" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1" dependencies = [ "js-sys", "slotmap", @@ -4067,7 +4068,7 @@ dependencies = [ "js-sys", "khronos-egl", "libc", - "libloading 0.7.4", + "libloading 0.8.1", "log", "metal", "naga", diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index 4d542afed7..376ff8da27 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -85,7 +85,7 @@ rustc-hash = "1.1" log = "0.4" # backend: Gles -glow = { version = "0.13", git = "https://github.com/grovesNL/glow.git", rev = "29ff917a2b2ff7ce0a81b2cc5681de6d4735b36e", optional = true } +glow = { version = "0.13.1", optional = true } [dependencies.wgt] package = "wgpu-types" From 3716b8a1bc284bb543fa40f76df76e58bfabadc1 Mon Sep 17 00:00:00 2001 From: Josh Groves Date: Wed, 17 Jan 2024 17:24:10 -0330 Subject: [PATCH 012/101] Update glow to 0.13.1 (#5083) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ebc5b8f72b..bde4e8451a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -150,7 +150,7 @@ hassle-rs = "0.11.0" # Gles dependencies khronos-egl = "6" -glow = "0.12.3" +glow = "0.13.1" glutin = "0.29.1" # wasm32 dependencies From adf1e3b6c546098e936f49602c4e39c0e416e1d6 Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Wed, 17 Jan 2024 22:50:39 +0100 Subject: [PATCH 013/101] Improve test feedback and implementation (#5068) --- tests/src/expectations.rs | 179 +++++++++++++++++++++++++------------- tests/src/image.rs | 4 +- tests/src/run.rs | 20 +++-- 3 files changed, 132 insertions(+), 71 deletions(-) diff --git a/tests/src/expectations.rs b/tests/src/expectations.rs index ee48e83aa8..4049f910b6 100644 --- a/tests/src/expectations.rs +++ b/tests/src/expectations.rs @@ -1,3 +1,5 @@ +use core::fmt; + /// Conditions under which a test should fail or be skipped. /// /// By passing a `FailureCase` to [`TestParameters::expect_fail`][expect_fail], you can @@ -15,7 +17,7 @@ /// vendor: None, /// adapter: Some("RTX"), /// driver: None, -/// reasons: vec![FailureReason::ValidationError(Some("Some error substring"))], +/// reasons: vec![FailureReason::validation_error().with_message("Some error substring")], /// behavior: FailureBehavior::AssertFailure, /// } /// # ; @@ -158,7 +160,7 @@ impl FailureCase { /// Return the reasons why this case should fail. pub fn reasons(&self) -> &[FailureReason] { if self.reasons.is_empty() { - std::array::from_ref(&FailureReason::Any) + std::array::from_ref(&FailureReason::ANY) } else { &self.reasons } @@ -170,7 +172,8 @@ impl FailureCase { /// /// If multiple reasons are pushed, will match any of them. pub fn validation_error(mut self, msg: &'static str) -> Self { - self.reasons.push(FailureReason::ValidationError(Some(msg))); + self.reasons + .push(FailureReason::validation_error().with_message(msg)); self } @@ -180,7 +183,7 @@ impl FailureCase { /// /// If multiple reasons are pushed, will match any of them. pub fn panic(mut self, msg: &'static str) -> Self { - self.reasons.push(FailureReason::Panic(Some(msg))); + self.reasons.push(FailureReason::panic().with_message(msg)); self } @@ -247,43 +250,16 @@ impl FailureCase { /// Returns true if the given failure "satisfies" this failure case. pub(crate) fn matches_failure(&self, failure: &FailureResult) -> bool { for reason in self.reasons() { - let result = match (reason, failure) { - (FailureReason::Any, _) => { - log::error!("Matched failure case: Wildcard"); - true - } - (FailureReason::ValidationError(None), FailureResult::ValidationError(_)) => { - log::error!("Matched failure case: Any Validation Error"); - true - } - ( - FailureReason::ValidationError(Some(expected)), - FailureResult::ValidationError(Some(actual)), - ) => { - let result = actual.to_lowercase().contains(&expected.to_lowercase()); - if result { - log::error!( - "Matched failure case: Validation Error containing \"{}\"", - expected - ); - } - result - } - (FailureReason::Panic(None), FailureResult::Panic(_)) => { - log::error!("Matched failure case: Any Panic"); - true - } - (FailureReason::Panic(Some(expected)), FailureResult::Panic(Some(actual))) => { - let result = actual.to_lowercase().contains(&expected.to_lowercase()); - if result { - log::error!("Matched failure case: Panic containing \"{}\"", expected); - } - result - } - _ => false, - }; - - if result { + let kind_matched = reason.kind.map_or(true, |kind| kind == failure.kind); + + let message_matched = + reason + .message + .map_or(true, |message| matches!(&failure.message, Some(actual) if actual.to_lowercase().contains(&message.to_lowercase()))); + + if kind_matched && message_matched { + let message = failure.message.as_deref().unwrap_or("*no message*"); + log::error!("Matched {} {message}", failure.kind); return true; } } @@ -308,18 +284,54 @@ bitflags::bitflags! { /// /// If the test fails for a different reason, the given FailureCase will be ignored. #[derive(Default, Debug, Clone, PartialEq)] -pub enum FailureReason { - /// Matches any failure. - #[default] - Any, - /// Matches validation errors raised from the backend validation. +pub struct FailureReason { + /// Match a particular kind of failure result. /// - /// If a string is provided, matches only validation errors that contain the string. - ValidationError(Option<&'static str>), - /// A panic was raised. + /// If `None`, match any result kind. + kind: Option, + /// Match a particular message of a failure result. /// - /// If a string is provided, matches only panics that contain the string. - Panic(Option<&'static str>), + /// If `None`, matches any message. If `Some`, a case-insensitive sub-string + /// test is performed. Allowing `"error occured"` to match a message like + /// `"An unexpected Error occured!"`. + message: Option<&'static str>, +} + +impl FailureReason { + /// Match any failure reason. + const ANY: Self = Self { + kind: None, + message: None, + }; + + /// Match a validation error. + #[allow(dead_code)] // Not constructed on wasm + pub fn validation_error() -> Self { + Self { + kind: Some(FailureResultKind::ValidationError), + message: None, + } + } + + /// Match a panic. + pub fn panic() -> Self { + Self { + kind: Some(FailureResultKind::Panic), + message: None, + } + } + + /// Match an error with a message. + /// + /// If specified, a case-insensitive sub-string test is performed. Allowing + /// `"error occured"` to match a message like `"An unexpected Error + /// occured!"`. + pub fn with_message(self, message: &'static str) -> Self { + Self { + message: Some(message), + ..self + } + } } #[derive(Default, Clone)] @@ -336,11 +348,53 @@ pub enum FailureBehavior { Ignore, } +#[derive(Debug, Clone, Copy, PartialEq)] +pub(crate) enum FailureResultKind { + #[allow(dead_code)] // Not constructed on wasm + ValidationError, + Panic, +} + +impl fmt::Display for FailureResultKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + FailureResultKind::ValidationError => write!(f, "Validation Error"), + FailureResultKind::Panic => write!(f, "Panic"), + } + } +} + #[derive(Debug)] -pub(crate) enum FailureResult { +pub(crate) struct FailureResult { + kind: FailureResultKind, + message: Option, +} + +impl FailureResult { + /// Failure result is a panic. + pub(super) fn panic() -> Self { + Self { + kind: FailureResultKind::Panic, + message: None, + } + } + + /// Failure result is a validation error. #[allow(dead_code)] // Not constructed on wasm - ValidationError(Option), - Panic(Option), + pub(super) fn validation_error() -> Self { + Self { + kind: FailureResultKind::ValidationError, + message: None, + } + } + + /// Message associated with a failure result. + pub(super) fn with_message(self, message: impl fmt::Display) -> Self { + Self { + kind: self.kind, + message: Some(message.to_string()), + } + } } #[derive(PartialEq, Clone, Copy, Debug)] @@ -393,7 +447,8 @@ pub(crate) fn expectations_match_failures( if !actual.is_empty() { result = ExpectationMatchResult::Panic; for failure in actual { - log::error!("Unexpected failure due to: {:?}", failure); + let message = failure.message.as_deref().unwrap_or("*no message*"); + log::error!("{}: {message}", failure.kind); } } @@ -409,11 +464,11 @@ mod test { }; fn validation_err(msg: &'static str) -> FailureResult { - FailureResult::ValidationError(Some(String::from(msg))) + FailureResult::validation_error().with_message(msg) } fn panic(msg: &'static str) -> FailureResult { - FailureResult::Panic(Some(String::from(msg))) + FailureResult::panic().with_message(msg) } #[test] @@ -423,7 +478,7 @@ mod test { // -- Unexpected failure -- let expectation = vec![]; - let actual = vec![FailureResult::ValidationError(None)]; + let actual = vec![FailureResult::validation_error()]; assert_eq!( super::expectations_match_failures(&expectation, actual), @@ -443,7 +498,7 @@ mod test { // -- Expected failure (validation) -- let expectation = vec![FailureCase::always()]; - let actual = vec![FailureResult::ValidationError(None)]; + let actual = vec![FailureResult::validation_error()]; assert_eq!( super::expectations_match_failures(&expectation, actual), @@ -453,7 +508,7 @@ mod test { // -- Expected failure (panic) -- let expectation = vec![FailureCase::always()]; - let actual = vec![FailureResult::Panic(None)]; + let actual = vec![FailureResult::panic()]; assert_eq!( super::expectations_match_failures(&expectation, actual), @@ -469,9 +524,9 @@ mod test { let expectation: Vec = vec![FailureCase::always().validation_error("Some StrIng")]; - let actual = vec![FailureResult::ValidationError(Some(String::from( + let actual = vec![FailureResult::validation_error().with_message( "a very long string that contains sOmE sTrInG of different capitalization", - )))]; + )]; assert_eq!( super::expectations_match_failures(&expectation, actual), diff --git a/tests/src/image.rs b/tests/src/image.rs index 08e30ae2ef..4c1f6b8b74 100644 --- a/tests/src/image.rs +++ b/tests/src/image.rs @@ -238,7 +238,7 @@ pub async fn compare_image_output( ) .await; write_png( - difference_path, + &difference_path, width, height, &magma_image_with_alpha, @@ -247,7 +247,7 @@ pub async fn compare_image_output( .await; if !all_passed { - panic!("Image data mismatch!") + panic!("Image data mismatch: {}", difference_path.display()) } } diff --git a/tests/src/run.rs b/tests/src/run.rs index e19615bdb2..f56651b574 100644 --- a/tests/src/run.rs +++ b/tests/src/run.rs @@ -86,23 +86,29 @@ pub async fn execute_test( .await; if let Err(panic) = panic_res { - let panic_str = panic.downcast_ref::<&'static str>(); - let panic_string = if let Some(&panic_str) = panic_str { - Some(panic_str.to_string()) + let message = panic + .downcast_ref::<&str>() + .copied() + .or_else(|| panic.downcast_ref::().map(String::as_str)); + + let result = FailureResult::panic(); + + let result = if let Some(panic_str) = message { + result.with_message(panic_str) } else { - panic.downcast_ref::().cloned() + result }; - failures.push(FailureResult::Panic(panic_string)) + failures.push(result) } // Check whether any validation errors were reported during the test run. cfg_if::cfg_if!( if #[cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))] { - failures.extend(wgpu::hal::VALIDATION_CANARY.get_and_reset().into_iter().map(|msg| FailureResult::ValidationError(Some(msg)))); + failures.extend(wgpu::hal::VALIDATION_CANARY.get_and_reset().into_iter().map(|msg| FailureResult::validation_error().with_message(msg))); } else if #[cfg(all(target_arch = "wasm32", feature = "webgl"))] { if _surface_guard.unwrap().check_for_unreported_errors() { - failures.push(FailureResult::ValidationError(None)); + failures.push(FailureResult::validation_error()); } } else { } From c2058487ca35d68aed99f18d42c18f262383df78 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Thu, 4 Jan 2024 16:58:38 -0500 Subject: [PATCH 014/101] chore: run `rustfmt` in `naga` --- naga/src/proc/constant_evaluator.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 82efeece4e..45dffbd4a0 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -1144,7 +1144,12 @@ impl<'a> ConstantEvaluator<'a> { return self.cast(expr, target, span); }; - let crate::TypeInner::Array { base: _, size, stride: _ } = self.types[ty].inner else { + let crate::TypeInner::Array { + base: _, + size, + stride: _, + } = self.types[ty].inner + else { return self.cast(expr, target, span); }; From 5c900f25680a37502c255cfde8360dd8c697bde2 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Thu, 14 Dec 2023 10:37:43 -0500 Subject: [PATCH 015/101] refactor(const_eval): add `component_wise_float` helper, reimpl. `math_pow` --- Cargo.lock | 1 + naga/Cargo.toml | 1 + naga/src/lib.rs | 4 + naga/src/proc/constant_evaluator.rs | 259 +++++++++++++++++++++------- 4 files changed, 207 insertions(+), 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c8d235b287..240dec3584 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2055,6 +2055,7 @@ name = "naga" version = "0.19.0" dependencies = [ "arbitrary", + "arrayvec 0.7.4", "bincode", "bit-set", "bitflags 2.4.1", diff --git a/naga/Cargo.toml b/naga/Cargo.toml index a13e4f9196..8e53d457f2 100644 --- a/naga/Cargo.toml +++ b/naga/Cargo.toml @@ -60,6 +60,7 @@ petgraph = { version = "0.6", optional = true } pp-rs = { version = "0.2.1", optional = true } hexf-parse = { version = "0.2.1", optional = true } unicode-xid = { version = "0.2.3", optional = true } +arrayvec.workspace = true [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] criterion = { version = "0.5", features = [] } diff --git a/naga/src/lib.rs b/naga/src/lib.rs index b27ebc6764..bfd8359d88 100644 --- a/naga/src/lib.rs +++ b/naga/src/lib.rs @@ -458,6 +458,10 @@ pub enum VectorSize { Quad = 4, } +impl VectorSize { + const MAX: usize = Self::Quad as u8 as usize; +} + /// Primitive type for a scalar. #[repr(u8)] #[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 45dffbd4a0..e020c1692d 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -1,9 +1,209 @@ +use std::iter; + +use arrayvec::ArrayVec; + use crate::{ arena::{Arena, Handle, UniqueArena}, ArraySize, BinaryOperator, Constant, Expression, Literal, ScalarKind, Span, Type, TypeInner, UnaryOperator, }; +/// A macro that allows dollar signs (`$`) to be emitted by other macros. Useful for generating +/// `macro_rules!` items that, in turn, emit their own `macro_rules!` items. +/// +/// Technique stolen directly from +/// . +macro_rules! with_dollar_sign { + ($($body:tt)*) => { + macro_rules! __with_dollar_sign { $($body)* } + __with_dollar_sign!($); + } +} + +macro_rules! gen_component_wise_extractor { + ( + $ident:ident -> $target:ident, + literals: [$( $literal:ident => $mapping:ident: $ty:ident ),+ $(,)?], + scalar_kinds: [$( $scalar_kind:ident ),* $(,)?], + ) => { + /// A subset of [`Literal`]s intended to be used for implementing numeric built-ins. + enum $target { + $( + #[doc = concat!( + "Maps to [`Literal::", + stringify!($mapping), + "`]", + )] + $mapping([$ty; N]), + )+ + } + + impl From<$target<1>> for Expression { + fn from(value: $target<1>) -> Self { + match value { + $( + $target::$mapping([value]) => { + Expression::Literal(Literal::$literal(value)) + } + )+ + } + } + } + + #[doc = concat!( + "Attempts to evaluate multiple `exprs` as a combined [`", + stringify!($target), + "`] to pass to `handler`. ", + )] + /// If `exprs` are vectors of the same length, `handler` is called for each corresponding + /// component of each vector. + /// + /// `handler`'s output is registered as a new expression. If `exprs` are vectors of the + /// same length, a new vector expression is registered, composed of each component emitted + /// by `handler`. + fn $ident( + eval: &mut ConstantEvaluator<'_>, + span: Span, + exprs: [Handle; N], + mut handler: F, + ) -> Result, ConstantEvaluatorError> + where + $target: Into, + F: FnMut($target) -> Result<$target, ConstantEvaluatorError> + Clone, + { + assert!(N > 0); + let err = ConstantEvaluatorError::InvalidMathArg; + let mut exprs = exprs.into_iter(); + + macro_rules! sanitize { + ($expr:expr) => { + eval.eval_zero_value_and_splat($expr, span) + .map(|expr| &eval.expressions[expr]) + }; + } + + let new_expr = match sanitize!(exprs.next().unwrap())? { + $( + &Expression::Literal(Literal::$literal(x)) => iter::once(Ok(x)) + .chain(exprs.map(|expr| { + sanitize!(expr).and_then(|expr| match expr { + &Expression::Literal(Literal::$literal(x)) => Ok(x), + _ => Err(err.clone()), + }) + })) + .collect::, _>>() + .map(|a| a.into_inner().unwrap()) + .map($target::$mapping) + .and_then(|comps| Ok(handler(comps)?.into())), + )+ + &Expression::Compose { ty, ref components } => match &eval.types[ty].inner { + &TypeInner::Vector { size: _, scalar } => match scalar.kind { + $(ScalarKind::$scalar_kind)|* => { + let first_ty = ty; + let mut component_groups = + ArrayVec::, N>::new(); + component_groups.push(crate::proc::flatten_compose( + first_ty, + components, + eval.expressions, + eval.types, + ).collect()); + component_groups.extend( + exprs + .map(|expr| { + sanitize!(expr).and_then(|expr| match expr { + &Expression::Compose { ty, ref components } + if &eval.types[ty].inner + == &eval.types[first_ty].inner => + { + Ok(crate::proc::flatten_compose( + ty, + components, + eval.expressions, + eval.types, + ).collect()) + } + _ => Err(err.clone()), + }) + }) + .collect::, _>>( + )?, + ); + let component_groups = component_groups.into_inner().unwrap(); + let mut new_components = + ArrayVec::<_, { crate::VectorSize::MAX }>::new(); + for idx in 0..N { + let group = component_groups + .iter() + .map(|cs| cs[idx]) + .collect::>() + .into_inner() + .unwrap(); + new_components.push($ident( + eval, + span, + group, + handler.clone(), + )?); + } + Ok(Expression::Compose { + ty: first_ty, + components: new_components.into_iter().collect(), + }) + } + _ => return Err(err), + }, + _ => return Err(err), + }, + _ => return Err(err), + }?; + eval.register_evaluated_expr(new_expr, span) + } + + with_dollar_sign! { + ($d:tt) => { + #[allow(unused)] + #[doc = concat!( + "A convenience macro for using the same RHS for each [`", + stringify!($target), + "`] variant in a call to [`", + stringify!($ident), + "`].", + )] + macro_rules! $ident { + ( + $eval:expr, + $span:expr, + [$d ($d expr:expr),+ $d (,)?], + |$d ($d arg:ident),+| $d tt:tt + ) => { + $ident($eval, $span, [$d ($d expr),+], |args| match args { + $( + $target::$mapping([$d ($d arg),+]) => { + let res = $d tt; + Result::map(res, $target::$mapping) + }, + )+ + }) + }; + } + }; + } + }; +} + +gen_component_wise_extractor! { + component_wise_float -> Float, + literals: [ + AbstractFloat => Abstract: f64, + F32 => F32: f32, + ], + scalar_kinds: [ + Float, + AbstractFloat, + ], +} + #[derive(Debug)] enum Behavior { Wgsl, @@ -606,64 +806,7 @@ impl<'a> ConstantEvaluator<'a> { e2: Handle, span: Span, ) -> Result, ConstantEvaluatorError> { - let e1 = self.eval_zero_value_and_splat(e1, span)?; - let e2 = self.eval_zero_value_and_splat(e2, span)?; - - let expr = match (&self.expressions[e1], &self.expressions[e2]) { - (&Expression::Literal(Literal::F32(a)), &Expression::Literal(Literal::F32(b))) => { - Expression::Literal(Literal::F32(a.powf(b))) - } - ( - &Expression::Compose { - components: ref src_components0, - ty: ty0, - }, - &Expression::Compose { - components: ref src_components1, - ty: ty1, - }, - ) if ty0 == ty1 - && matches!( - self.types[ty0].inner, - crate::TypeInner::Vector { - scalar: crate::Scalar { - kind: ScalarKind::Float, - .. - }, - .. - } - ) => - { - let mut components: Vec<_> = crate::proc::flatten_compose( - ty0, - src_components0, - self.expressions, - self.types, - ) - .chain(crate::proc::flatten_compose( - ty1, - src_components1, - self.expressions, - self.types, - )) - .collect(); - - let mid = components.len() / 2; - let (first, last) = components.split_at_mut(mid); - for (a, b) in first.iter_mut().zip(&*last) { - *a = self.math_pow(*a, *b, span)?; - } - components.truncate(mid); - - Expression::Compose { - ty: ty0, - components, - } - } - _ => return Err(ConstantEvaluatorError::InvalidMathArg), - }; - - self.register_evaluated_expr(expr, span) + component_wise_float!(self, span, [e1, e2], |e1, e2| { Ok([e1.powf(e2)]) }) } fn math_clamp( From fc27b08dcacb9dbbeb4408a282c78946b00bb17c Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Wed, 10 Jan 2024 17:30:24 -0500 Subject: [PATCH 016/101] feat(const_eval): impl. `abs` with new `component_wise_scalar` --- CHANGELOG.md | 8 ++ naga/src/proc/constant_evaluator.rs | 27 ++++ .../glsl/math-functions.main.Fragment.glsl | 6 +- naga/tests/out/hlsl/math-functions.hlsl | 6 +- naga/tests/out/msl/math-functions.msl | 11 +- naga/tests/out/spv/math-functions.spvasm | 115 +++++++++--------- naga/tests/out/wgsl/math-functions.wgsl | 2 +- 7 files changed, 104 insertions(+), 71 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4361ea48a..604399bdcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,14 @@ Bottom level categories: - Hal --> +## Unreleased + +### New features + +- Many numeric built-ins have had a constant evaluation implementation added for them, which allows them to be used in a `const` context: + - [#4879](https://github.com/gfx-rs/wgpu/pull/4879) by @ErichDonGubler: + - `abs` + ## v0.19.0 (2024-01-17) This release includes: diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index e020c1692d..13b4dd7cef 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -192,6 +192,24 @@ macro_rules! gen_component_wise_extractor { }; } +gen_component_wise_extractor! { + component_wise_scalar -> Scalar, + literals: [ + AbstractFloat => AbstractFloat: f64, + F32 => F32: f32, + AbstractInt => AbstractInt: i64, + U32 => U32: u32, + I32 => I32: i32, + ], + scalar_kinds: [ + Float, + AbstractFloat, + Sint, + Uint, + AbstractInt, + ], +} + gen_component_wise_extractor! { component_wise_float -> Float, literals: [ @@ -792,6 +810,15 @@ impl<'a> ConstantEvaluator<'a> { } match fun { + crate::MathFunction::Abs => { + component_wise_scalar(self, span, [arg], |args| match args { + Scalar::AbstractFloat([e]) => Ok(Scalar::AbstractFloat([e.abs()])), + Scalar::F32([e]) => Ok(Scalar::F32([e.abs()])), + Scalar::AbstractInt([e]) => Ok(Scalar::AbstractInt([e.abs()])), + Scalar::I32([e]) => Ok(Scalar::I32([e.wrapping_abs()])), + Scalar::U32([e]) => Ok(Scalar::U32([e])), // TODO: just re-use the expression, ezpz + }) + } crate::MathFunction::Pow => self.math_pow(arg, arg1.unwrap(), span), crate::MathFunction::Clamp => self.math_clamp(arg, arg1.unwrap(), arg2.unwrap(), span), fun => Err(ConstantEvaluatorError::NotImplemented(format!( diff --git a/naga/tests/out/glsl/math-functions.main.Fragment.glsl b/naga/tests/out/glsl/math-functions.main.Fragment.glsl index ed81535ab5..bf0561f12e 100644 --- a/naga/tests/out/glsl/math-functions.main.Fragment.glsl +++ b/naga/tests/out/glsl/math-functions.main.Fragment.glsl @@ -67,7 +67,7 @@ void main() { float sign_c = sign(-1.0); vec4 sign_d = sign(vec4(-1.0)); int const_dot = ( + ivec2(0).x * ivec2(0).x + ivec2(0).y * ivec2(0).y); - uint first_leading_bit_abs = uint(findMSB(uint(abs(int(0u))))); + uint first_leading_bit_abs = uint(findMSB(0u)); int flb_a = findMSB(-1); ivec2 flb_b = findMSB(ivec2(-1)); uvec2 flb_c = uvec2(findMSB(uvec2(1u))); @@ -85,8 +85,8 @@ void main() { ivec2 ctz_h = ivec2(min(uvec2(findLSB(ivec2(1))), uvec2(32u))); int clz_a = (-1 < 0 ? 0 : 31 - findMSB(-1)); uint clz_b = uint(31 - findMSB(1u)); - ivec2 _e68 = ivec2(-1); - ivec2 clz_c = mix(ivec2(31) - findMSB(_e68), ivec2(0), lessThan(_e68, ivec2(0))); + ivec2 _e67 = ivec2(-1); + ivec2 clz_c = mix(ivec2(31) - findMSB(_e67), ivec2(0), lessThan(_e67, ivec2(0))); uvec2 clz_d = uvec2(ivec2(31) - findMSB(uvec2(1u))); float lde_a = ldexp(1.0, 2); vec2 lde_b = ldexp(vec2(1.0, 2.0), ivec2(3, 4)); diff --git a/naga/tests/out/hlsl/math-functions.hlsl b/naga/tests/out/hlsl/math-functions.hlsl index 53d3acf0c1..5da3461dae 100644 --- a/naga/tests/out/hlsl/math-functions.hlsl +++ b/naga/tests/out/hlsl/math-functions.hlsl @@ -77,7 +77,7 @@ void main() float sign_c = sign(-1.0); float4 sign_d = sign((-1.0).xxxx); int const_dot = dot((int2)0, (int2)0); - uint first_leading_bit_abs = firstbithigh(abs(0u)); + uint first_leading_bit_abs = firstbithigh(0u); int flb_a = asint(firstbithigh(-1)); int2 flb_b = asint(firstbithigh((-1).xx)); uint2 flb_c = firstbithigh((1u).xx); @@ -95,8 +95,8 @@ void main() int2 ctz_h = asint(min((32u).xx, firstbitlow((1).xx))); int clz_a = (-1 < 0 ? 0 : 31 - asint(firstbithigh(-1))); uint clz_b = (31u - firstbithigh(1u)); - int2 _expr68 = (-1).xx; - int2 clz_c = (_expr68 < (0).xx ? (0).xx : (31).xx - asint(firstbithigh(_expr68))); + int2 _expr67 = (-1).xx; + int2 clz_c = (_expr67 < (0).xx ? (0).xx : (31).xx - asint(firstbithigh(_expr67))); uint2 clz_d = ((31u).xx - firstbithigh((1u).xx)); float lde_a = ldexp(1.0, 2); float2 lde_b = ldexp(float2(1.0, 2.0), int2(3, 4)); diff --git a/naga/tests/out/msl/math-functions.msl b/naga/tests/out/msl/math-functions.msl index d93e502dc6..45fbcd00a1 100644 --- a/naga/tests/out/msl/math-functions.msl +++ b/naga/tests/out/msl/math-functions.msl @@ -70,13 +70,12 @@ fragment void main_( float sign_c = metal::sign(-1.0); metal::float4 sign_d = metal::sign(metal::float4(-1.0)); int const_dot = ( + metal::int2 {}.x * metal::int2 {}.x + metal::int2 {}.y * metal::int2 {}.y); - uint _e23 = metal::abs(0u); - uint first_leading_bit_abs = metal::select(31 - metal::clz(_e23), uint(-1), _e23 == 0 || _e23 == -1); + uint first_leading_bit_abs = metal::select(31 - metal::clz(0u), uint(-1), 0u == 0 || 0u == -1); int flb_a = metal::select(31 - metal::clz(metal::select(-1, ~-1, -1 < 0)), int(-1), -1 == 0 || -1 == -1); - metal::int2 _e28 = metal::int2(-1); - metal::int2 flb_b = metal::select(31 - metal::clz(metal::select(_e28, ~_e28, _e28 < 0)), int2(-1), _e28 == 0 || _e28 == -1); - metal::uint2 _e31 = metal::uint2(1u); - metal::uint2 flb_c = metal::select(31 - metal::clz(_e31), uint2(-1), _e31 == 0 || _e31 == -1); + metal::int2 _e27 = metal::int2(-1); + metal::int2 flb_b = metal::select(31 - metal::clz(metal::select(_e27, ~_e27, _e27 < 0)), int2(-1), _e27 == 0 || _e27 == -1); + metal::uint2 _e30 = metal::uint2(1u); + metal::uint2 flb_c = metal::select(31 - metal::clz(_e30), uint2(-1), _e30 == 0 || _e30 == -1); int ftb_a = (((metal::ctz(-1) + 1) % 33) - 1); uint ftb_b = (((metal::ctz(1u) + 1) % 33) - 1); metal::int2 ftb_c = (((metal::ctz(metal::int2(-1)) + 1) % 33) - 1); diff --git a/naga/tests/out/spv/math-functions.spvasm b/naga/tests/out/spv/math-functions.spvasm index ba3e7cffb9..bbbf370970 100644 --- a/naga/tests/out/spv/math-functions.spvasm +++ b/naga/tests/out/spv/math-functions.spvasm @@ -1,7 +1,7 @@ ; SPIR-V ; Version: 1.1 ; Generator: rspirv -; Bound: 126 +; Bound: 125 OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 @@ -61,10 +61,10 @@ OpMemberDecorate %13 1 Offset 16 %45 = OpConstantComposite %3 %43 %43 %43 %43 %52 = OpConstantComposite %3 %17 %17 %17 %17 %59 = OpConstantNull %6 -%77 = OpConstant %25 32 -%86 = OpConstantComposite %29 %77 %77 -%95 = OpConstant %6 31 -%100 = OpConstantComposite %5 %95 %95 +%76 = OpConstant %25 32 +%85 = OpConstantComposite %29 %76 %76 +%94 = OpConstant %6 31 +%99 = OpConstantComposite %5 %94 %94 %15 = OpFunction %2 None %16 %14 = OpLabel OpBranch %46 @@ -87,60 +87,59 @@ OpBranch %46 %65 = OpCompositeExtract %6 %24 1 %66 = OpIMul %6 %64 %65 %58 = OpIAdd %6 %63 %66 -%67 = OpCopyObject %25 %26 -%68 = OpExtInst %25 %1 FindUMsb %67 -%69 = OpExtInst %6 %1 FindSMsb %20 -%70 = OpExtInst %5 %1 FindSMsb %27 -%71 = OpExtInst %29 %1 FindUMsb %30 -%72 = OpExtInst %6 %1 FindILsb %20 -%73 = OpExtInst %25 %1 FindILsb %28 -%74 = OpExtInst %5 %1 FindILsb %27 -%75 = OpExtInst %29 %1 FindILsb %30 -%78 = OpExtInst %25 %1 FindILsb %26 -%76 = OpExtInst %25 %1 UMin %77 %78 -%80 = OpExtInst %6 %1 FindILsb %31 -%79 = OpExtInst %6 %1 UMin %77 %80 -%82 = OpExtInst %25 %1 FindILsb %32 -%81 = OpExtInst %25 %1 UMin %77 %82 -%84 = OpExtInst %6 %1 FindILsb %20 -%83 = OpExtInst %6 %1 UMin %77 %84 -%87 = OpExtInst %29 %1 FindILsb %33 -%85 = OpExtInst %29 %1 UMin %86 %87 -%89 = OpExtInst %5 %1 FindILsb %34 -%88 = OpExtInst %5 %1 UMin %86 %89 -%91 = OpExtInst %29 %1 FindILsb %30 -%90 = OpExtInst %29 %1 UMin %86 %91 -%93 = OpExtInst %5 %1 FindILsb %36 -%92 = OpExtInst %5 %1 UMin %86 %93 -%96 = OpExtInst %6 %1 FindUMsb %20 -%94 = OpISub %6 %95 %96 -%98 = OpExtInst %6 %1 FindUMsb %28 -%97 = OpISub %25 %95 %98 -%101 = OpExtInst %5 %1 FindUMsb %27 -%99 = OpISub %5 %100 %101 -%103 = OpExtInst %5 %1 FindUMsb %30 -%102 = OpISub %29 %100 %103 -%104 = OpExtInst %4 %1 Ldexp %17 %37 -%105 = OpExtInst %7 %1 Ldexp %39 %42 +%67 = OpExtInst %25 %1 FindUMsb %26 +%68 = OpExtInst %6 %1 FindSMsb %20 +%69 = OpExtInst %5 %1 FindSMsb %27 +%70 = OpExtInst %29 %1 FindUMsb %30 +%71 = OpExtInst %6 %1 FindILsb %20 +%72 = OpExtInst %25 %1 FindILsb %28 +%73 = OpExtInst %5 %1 FindILsb %27 +%74 = OpExtInst %29 %1 FindILsb %30 +%77 = OpExtInst %25 %1 FindILsb %26 +%75 = OpExtInst %25 %1 UMin %76 %77 +%79 = OpExtInst %6 %1 FindILsb %31 +%78 = OpExtInst %6 %1 UMin %76 %79 +%81 = OpExtInst %25 %1 FindILsb %32 +%80 = OpExtInst %25 %1 UMin %76 %81 +%83 = OpExtInst %6 %1 FindILsb %20 +%82 = OpExtInst %6 %1 UMin %76 %83 +%86 = OpExtInst %29 %1 FindILsb %33 +%84 = OpExtInst %29 %1 UMin %85 %86 +%88 = OpExtInst %5 %1 FindILsb %34 +%87 = OpExtInst %5 %1 UMin %85 %88 +%90 = OpExtInst %29 %1 FindILsb %30 +%89 = OpExtInst %29 %1 UMin %85 %90 +%92 = OpExtInst %5 %1 FindILsb %36 +%91 = OpExtInst %5 %1 UMin %85 %92 +%95 = OpExtInst %6 %1 FindUMsb %20 +%93 = OpISub %6 %94 %95 +%97 = OpExtInst %6 %1 FindUMsb %28 +%96 = OpISub %25 %94 %97 +%100 = OpExtInst %5 %1 FindUMsb %27 +%98 = OpISub %5 %99 %100 +%102 = OpExtInst %5 %1 FindUMsb %30 +%101 = OpISub %29 %99 %102 +%103 = OpExtInst %4 %1 Ldexp %17 %37 +%104 = OpExtInst %7 %1 Ldexp %39 %42 +%105 = OpExtInst %8 %1 ModfStruct %43 %106 = OpExtInst %8 %1 ModfStruct %43 -%107 = OpExtInst %8 %1 ModfStruct %43 -%108 = OpCompositeExtract %4 %107 0 -%109 = OpExtInst %8 %1 ModfStruct %43 -%110 = OpCompositeExtract %4 %109 1 -%111 = OpExtInst %9 %1 ModfStruct %44 -%112 = OpExtInst %10 %1 ModfStruct %45 -%113 = OpCompositeExtract %3 %112 1 -%114 = OpCompositeExtract %4 %113 0 -%115 = OpExtInst %9 %1 ModfStruct %44 -%116 = OpCompositeExtract %7 %115 0 -%117 = OpCompositeExtract %4 %116 1 +%107 = OpCompositeExtract %4 %106 0 +%108 = OpExtInst %8 %1 ModfStruct %43 +%109 = OpCompositeExtract %4 %108 1 +%110 = OpExtInst %9 %1 ModfStruct %44 +%111 = OpExtInst %10 %1 ModfStruct %45 +%112 = OpCompositeExtract %3 %111 1 +%113 = OpCompositeExtract %4 %112 0 +%114 = OpExtInst %9 %1 ModfStruct %44 +%115 = OpCompositeExtract %7 %114 0 +%116 = OpCompositeExtract %4 %115 1 +%117 = OpExtInst %11 %1 FrexpStruct %43 %118 = OpExtInst %11 %1 FrexpStruct %43 -%119 = OpExtInst %11 %1 FrexpStruct %43 -%120 = OpCompositeExtract %4 %119 0 -%121 = OpExtInst %11 %1 FrexpStruct %43 -%122 = OpCompositeExtract %6 %121 1 -%123 = OpExtInst %13 %1 FrexpStruct %45 -%124 = OpCompositeExtract %12 %123 1 -%125 = OpCompositeExtract %6 %124 0 +%119 = OpCompositeExtract %4 %118 0 +%120 = OpExtInst %11 %1 FrexpStruct %43 +%121 = OpCompositeExtract %6 %120 1 +%122 = OpExtInst %13 %1 FrexpStruct %45 +%123 = OpCompositeExtract %12 %122 1 +%124 = OpCompositeExtract %6 %123 0 OpReturn OpFunctionEnd \ No newline at end of file diff --git a/naga/tests/out/wgsl/math-functions.wgsl b/naga/tests/out/wgsl/math-functions.wgsl index 92f391038d..ce38fee986 100644 --- a/naga/tests/out/wgsl/math-functions.wgsl +++ b/naga/tests/out/wgsl/math-functions.wgsl @@ -12,7 +12,7 @@ fn main() { let sign_c = sign(-1f); let sign_d = sign(vec4(-1f)); let const_dot = dot(vec2(), vec2()); - let first_leading_bit_abs = firstLeadingBit(abs(0u)); + let first_leading_bit_abs = firstLeadingBit(0u); let flb_a = firstLeadingBit(-1i); let flb_b = firstLeadingBit(vec2(-1i)); let flb_c = firstLeadingBit(vec2(1u)); From 87dafb645a4ee0c367e8f68c60cbf4d19d5a9ad8 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Thu, 14 Dec 2023 10:41:22 -0500 Subject: [PATCH 017/101] feat(const_eval): impl. `round` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 604399bdcb..0528f88f7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ Bottom level categories: - Many numeric built-ins have had a constant evaluation implementation added for them, which allows them to be used in a `const` context: - [#4879](https://github.com/gfx-rs/wgpu/pull/4879) by @ErichDonGubler: - `abs` + - `round` ## v0.19.0 (2024-01-17) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 13b4dd7cef..b472937d09 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -821,6 +821,32 @@ impl<'a> ConstantEvaluator<'a> { } crate::MathFunction::Pow => self.math_pow(arg, arg1.unwrap(), span), crate::MathFunction::Clamp => self.math_clamp(arg, arg1.unwrap(), arg2.unwrap(), span), + crate::MathFunction::Round => { + // TODO: Use `f{32,64}.round_ties_even()` when available on stable. This polyfill + // is shamelessly [~~stolen from~~ inspired by `ndarray-image`][polyfill source], + // which has licensing compatible with ours. See also + // . + // + // [polyfill source]: https://github.com/imeka/ndarray-ndimage/blob/8b14b4d6ecfbc96a8a052f802e342a7049c68d8f/src/lib.rs#L98 + fn round_ties_even(x: f64) -> f64 { + let i = x as i64; + let f = (x - i as f64).abs(); + if f == 0.5 { + if i & 1 == 1 { + // -1.5, 1.5, 3.5, ... + (x.abs() + 0.5).copysign(x) + } else { + (x.abs() - 0.5).copysign(x) + } + } else { + x.round() + } + } + component_wise_float(self, span, [arg], |e| match e { + Float::Abstract([e]) => Ok(Float::Abstract([round_ties_even(e)])), + Float::F32([e]) => Ok(Float::F32([(round_ties_even(e as f64) as f32)])), + }) + } fun => Err(ConstantEvaluatorError::NotImplemented(format!( "{fun:?} built-in function" ))), From 5dc10381241eb2e5b348aa0dfa1e9c1316f72f99 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Thu, 14 Dec 2023 10:41:29 -0500 Subject: [PATCH 018/101] feat(const_eval): impl. `saturate` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0528f88f7f..c033e572f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ Bottom level categories: - [#4879](https://github.com/gfx-rs/wgpu/pull/4879) by @ErichDonGubler: - `abs` - `round` + - `saturate` ## v0.19.0 (2024-01-17) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index b472937d09..e89c1dd2c7 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -847,6 +847,9 @@ impl<'a> ConstantEvaluator<'a> { Float::F32([e]) => Ok(Float::F32([(round_ties_even(e as f64) as f32)])), }) } + crate::MathFunction::Saturate => { + component_wise_float!(self, span, [arg], |e| { Ok([e.clamp(0., 1.)]) }) + } fun => Err(ConstantEvaluatorError::NotImplemented(format!( "{fun:?} built-in function" ))), From 99a38c7b7cb09235dde702aaba44dabec20dbd1c Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Thu, 14 Dec 2023 10:41:35 -0500 Subject: [PATCH 019/101] feat(const_eval): impl. `sin` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 3 + .../tests/out/spv/debug-symbol-terrain.spvasm | 64 +++++++++---------- 3 files changed, 36 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c033e572f0..587c7c9e6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ Bottom level categories: - `abs` - `round` - `saturate` + - `sin` ## v0.19.0 (2024-01-17) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index e89c1dd2c7..33002d5c47 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -850,6 +850,9 @@ impl<'a> ConstantEvaluator<'a> { crate::MathFunction::Saturate => { component_wise_float!(self, span, [arg], |e| { Ok([e.clamp(0., 1.)]) }) } + crate::MathFunction::Sin => { + component_wise_float!(self, span, [arg], |e| { Ok([e.sin()]) }) + } fun => Err(ConstantEvaluatorError::NotImplemented(format!( "{fun:?} built-in function" ))), diff --git a/naga/tests/out/spv/debug-symbol-terrain.spvasm b/naga/tests/out/spv/debug-symbol-terrain.spvasm index 623b8dc2c1..a818ee6fea 100644 --- a/naga/tests/out/spv/debug-symbol-terrain.spvasm +++ b/naga/tests/out/spv/debug-symbol-terrain.spvasm @@ -366,10 +366,10 @@ OpName %91 "x12" OpName %94 "m" OpName %203 "p" OpName %204 "fbm" -OpName %209 "x" -OpName %211 "v" -OpName %213 "a" -OpName %214 "i" +OpName %210 "x" +OpName %212 "v" +OpName %214 "a" +OpName %215 "i" OpName %255 "p" OpName %256 "min_max_height" OpName %257 "terrain_point" @@ -575,9 +575,10 @@ OpDecorate %582 Location 0 %206 = OpConstant %5 0.01 %207 = OpConstant %5 100.0 %208 = OpConstantComposite %6 %207 %207 -%210 = OpConstantNull %6 -%212 = OpTypePointer Function %5 -%215 = OpTypePointer Function %8 +%209 = OpConstant %5 0.47942555 +%211 = OpConstantNull %6 +%213 = OpTypePointer Function %5 +%216 = OpTypePointer Function %8 %258 = OpTypeFunction %4 %6 %6 %271 = OpTypeFunction %14 %6 %6 %272 = OpConstant %5 0.1 @@ -835,22 +836,21 @@ OpFunctionEnd %204 = OpFunction %5 None %68 %203 = OpFunctionParameter %6 %202 = OpLabel -%211 = OpVariable %212 Function %74 -%214 = OpVariable %215 Function %135 -%209 = OpVariable %87 Function %210 -%213 = OpVariable %212 Function %78 -OpBranch %216 -%216 = OpLabel +%212 = OpVariable %213 Function %74 +%215 = OpVariable %216 Function %135 +%210 = OpVariable %87 Function %211 +%214 = OpVariable %213 Function %78 +OpBranch %217 +%217 = OpLabel OpLine %3 36 13 -%217 = OpVectorTimesScalar %6 %203 %206 +%218 = OpVectorTimesScalar %6 %203 %206 OpLine %3 36 5 -OpStore %209 %217 +OpStore %210 %218 OpLine %3 39 17 OpLine %3 40 24 -%218 = OpExtInst %5 %1 Cos %78 +%219 = OpExtInst %5 %1 Cos %78 OpLine %3 40 14 -%219 = OpExtInst %5 %1 Sin %78 -%220 = OpCompositeConstruct %6 %218 %219 +%220 = OpCompositeConstruct %6 %219 %209 OpLine %3 41 15 %221 = OpCompositeExtract %5 %220 0 %222 = OpCompositeExtract %5 %220 1 @@ -867,7 +867,7 @@ OpLoopMerge %230 %232 None OpBranch %231 %231 = OpLabel OpLine %3 43 22 -%233 = OpLoad %8 %214 +%233 = OpLoad %8 %215 %234 = OpULessThan %112 %233 %205 OpLine %3 43 21 OpSelectionMerge %235 None @@ -878,44 +878,44 @@ OpBranch %230 OpBranch %237 %237 = OpLabel OpLine %3 1 1 -%239 = OpLoad %5 %211 -%240 = OpLoad %5 %213 -%241 = OpLoad %6 %209 +%239 = OpLoad %5 %212 +%240 = OpLoad %5 %214 +%241 = OpLoad %6 %210 OpLine %3 44 21 %242 = OpFunctionCall %5 %67 %241 OpLine %3 44 13 %243 = OpFMul %5 %240 %242 %244 = OpFAdd %5 %239 %243 OpLine %3 44 9 -OpStore %211 %244 +OpStore %212 %244 OpLine %3 45 13 -%245 = OpLoad %6 %209 +%245 = OpLoad %6 %210 %246 = OpMatrixTimesVector %6 %228 %245 OpLine %3 45 13 %247 = OpVectorTimesScalar %6 %246 %81 %248 = OpFAdd %6 %247 %208 OpLine %3 45 9 -OpStore %209 %248 +OpStore %210 %248 OpLine %3 1 1 -%249 = OpLoad %5 %213 +%249 = OpLoad %5 %214 OpLine %3 46 13 %250 = OpFMul %5 %249 %78 OpLine %3 46 9 -OpStore %213 %250 +OpStore %214 %250 OpBranch %238 %238 = OpLabel OpBranch %232 %232 = OpLabel OpLine %3 1 1 -%251 = OpLoad %8 %214 +%251 = OpLoad %8 %215 OpLine %3 43 43 %252 = OpIAdd %8 %251 %126 OpLine %3 43 39 -OpStore %214 %252 +OpStore %215 %252 OpBranch %229 %230 = OpLabel OpLine %3 1 1 -%253 = OpLoad %5 %211 +%253 = OpLoad %5 %212 OpReturnValue %253 OpFunctionEnd %257 = OpFunction %4 None %258 @@ -1193,8 +1193,8 @@ OpReturn OpFunctionEnd %465 = OpFunction %2 None %346 %453 = OpLabel -%468 = OpVariable %212 Function %74 -%469 = OpVariable %215 Function %135 +%468 = OpVariable %213 Function %74 +%469 = OpVariable %216 Function %135 %456 = OpLoad %8 %455 %459 = OpLoad %7 %457 %462 = OpLoad %6 %460 From 133b573133c4f851e3f47744edaf87662af972ce Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Thu, 14 Dec 2023 10:41:39 -0500 Subject: [PATCH 020/101] feat(const_eval): impl. `sinh` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 587c7c9e6b..914ed448d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ Bottom level categories: - `round` - `saturate` - `sin` + - `sinh` ## v0.19.0 (2024-01-17) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 33002d5c47..edff331e18 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -853,6 +853,9 @@ impl<'a> ConstantEvaluator<'a> { crate::MathFunction::Sin => { component_wise_float!(self, span, [arg], |e| { Ok([e.sin()]) }) } + crate::MathFunction::Sinh => { + component_wise_float!(self, span, [arg], |e| { Ok([e.sinh()]) }) + } fun => Err(ConstantEvaluatorError::NotImplemented(format!( "{fun:?} built-in function" ))), From f2dbdfcdc68f047e3f455bfcd8e555d4ba59dd01 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Thu, 14 Dec 2023 10:41:44 -0500 Subject: [PATCH 021/101] feat(const_eval): impl. `sqrt` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 914ed448d3..14776b65ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,7 @@ Bottom level categories: - `saturate` - `sin` - `sinh` + - `sqrt` ## v0.19.0 (2024-01-17) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index edff331e18..1a36a59c43 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -856,6 +856,9 @@ impl<'a> ConstantEvaluator<'a> { crate::MathFunction::Sinh => { component_wise_float!(self, span, [arg], |e| { Ok([e.sinh()]) }) } + crate::MathFunction::Sqrt => { + component_wise_float!(self, span, [arg], |e| { Ok([e.sqrt()]) }) + } fun => Err(ConstantEvaluatorError::NotImplemented(format!( "{fun:?} built-in function" ))), From 6f5b2a64e235dce09fd2e6a48e5eb6aedcf7a28e Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Thu, 14 Dec 2023 10:41:51 -0500 Subject: [PATCH 022/101] feat(const_eval): impl. `step` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14776b65ac..d6b1ccc534 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ Bottom level categories: - `sin` - `sinh` - `sqrt` + - `step` ## v0.19.0 (2024-01-17) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 1a36a59c43..eefb470b3a 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -859,6 +859,11 @@ impl<'a> ConstantEvaluator<'a> { crate::MathFunction::Sqrt => { component_wise_float!(self, span, [arg], |e| { Ok([e.sqrt()]) }) } + crate::MathFunction::Step => { + component_wise_float!(self, span, [arg, arg1.unwrap()], |edge, x| { + Ok([if edge <= x { 1.0 } else { 0.0 }]) + }) + } fun => Err(ConstantEvaluatorError::NotImplemented(format!( "{fun:?} built-in function" ))), From 29a46234f478e3c2f27c873fe110d345a7b3cea6 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Thu, 14 Dec 2023 11:20:45 -0500 Subject: [PATCH 023/101] feat(const_eval)!: reimpl. `clamp` --- naga/src/proc/constant_evaluator.rs | 123 ++++------------------------ 1 file changed, 14 insertions(+), 109 deletions(-) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index eefb470b3a..bb5a624109 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -820,7 +820,20 @@ impl<'a> ConstantEvaluator<'a> { }) } crate::MathFunction::Pow => self.math_pow(arg, arg1.unwrap(), span), - crate::MathFunction::Clamp => self.math_clamp(arg, arg1.unwrap(), arg2.unwrap(), span), + crate::MathFunction::Clamp => { + component_wise_scalar!( + self, + span, + [arg, arg1.unwrap(), arg2.unwrap()], + |e, low, high| { + if low > high { + Err(ConstantEvaluatorError::InvalidClamp) + } else { + Ok([e.clamp(low, high)]) + } + } + ) + } crate::MathFunction::Round => { // TODO: Use `f{32,64}.round_ties_even()` when available on stable. This polyfill // is shamelessly [~~stolen from~~ inspired by `ndarray-image`][polyfill source], @@ -879,114 +892,6 @@ impl<'a> ConstantEvaluator<'a> { component_wise_float!(self, span, [e1, e2], |e1, e2| { Ok([e1.powf(e2)]) }) } - fn math_clamp( - &mut self, - e: Handle, - low: Handle, - high: Handle, - span: Span, - ) -> Result, ConstantEvaluatorError> { - let e = self.eval_zero_value_and_splat(e, span)?; - let low = self.eval_zero_value_and_splat(low, span)?; - let high = self.eval_zero_value_and_splat(high, span)?; - - let expr = match ( - &self.expressions[e], - &self.expressions[low], - &self.expressions[high], - ) { - (&Expression::Literal(e), &Expression::Literal(low), &Expression::Literal(high)) => { - let literal = match (e, low, high) { - (Literal::I32(e), Literal::I32(low), Literal::I32(high)) => { - if low > high { - return Err(ConstantEvaluatorError::InvalidClamp); - } else { - Literal::I32(e.clamp(low, high)) - } - } - (Literal::U32(e), Literal::U32(low), Literal::U32(high)) => { - if low > high { - return Err(ConstantEvaluatorError::InvalidClamp); - } else { - Literal::U32(e.clamp(low, high)) - } - } - (Literal::F32(e), Literal::F32(low), Literal::F32(high)) => { - if low > high { - return Err(ConstantEvaluatorError::InvalidClamp); - } else { - Literal::F32(e.clamp(low, high)) - } - } - _ => return Err(ConstantEvaluatorError::InvalidMathArg), - }; - Expression::Literal(literal) - } - ( - &Expression::Compose { - components: ref src_components0, - ty: ty0, - }, - &Expression::Compose { - components: ref src_components1, - ty: ty1, - }, - &Expression::Compose { - components: ref src_components2, - ty: ty2, - }, - ) if ty0 == ty1 - && ty0 == ty2 - && matches!( - self.types[ty0].inner, - crate::TypeInner::Vector { - scalar: crate::Scalar { - kind: ScalarKind::Float, - .. - }, - .. - } - ) => - { - let mut components: Vec<_> = crate::proc::flatten_compose( - ty0, - src_components0, - self.expressions, - self.types, - ) - .chain(crate::proc::flatten_compose( - ty1, - src_components1, - self.expressions, - self.types, - )) - .chain(crate::proc::flatten_compose( - ty2, - src_components2, - self.expressions, - self.types, - )) - .collect(); - - let chunk_size = components.len() / 3; - let (es, rem) = components.split_at_mut(chunk_size); - let (lows, highs) = rem.split_at(chunk_size); - for ((e, low), high) in es.iter_mut().zip(lows).zip(highs) { - *e = self.math_clamp(*e, *low, *high, span)?; - } - components.truncate(chunk_size); - - Expression::Compose { - ty: ty0, - components, - } - } - _ => return Err(ConstantEvaluatorError::InvalidMathArg), - }; - - self.register_evaluated_expr(expr, span) - } - fn array_length( &mut self, array: Handle, From bdf1cb4ec317304c20d53d7726a4380fc70c98e6 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 5 Jan 2024 10:56:24 -0500 Subject: [PATCH 024/101] feat(const_eval): impl. `tan` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6b1ccc534..586c943f31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,7 @@ Bottom level categories: - `sinh` - `sqrt` - `step` + - `tan` ## v0.19.0 (2024-01-17) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index bb5a624109..bdf9eec202 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -869,6 +869,9 @@ impl<'a> ConstantEvaluator<'a> { crate::MathFunction::Sinh => { component_wise_float!(self, span, [arg], |e| { Ok([e.sinh()]) }) } + crate::MathFunction::Tan => { + component_wise_float!(self, span, [arg], |e| { Ok([e.tan()]) }) + } crate::MathFunction::Sqrt => { component_wise_float!(self, span, [arg], |e| { Ok([e.sqrt()]) }) } From 3ab9a8081583a352746326042054bf30cf5c47f2 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 5 Jan 2024 10:56:24 -0500 Subject: [PATCH 025/101] feat(const_eval): impl. `tanh` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 586c943f31..a06e271c5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ Bottom level categories: - `sqrt` - `step` - `tan` + - `tanh` ## v0.19.0 (2024-01-17) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index bdf9eec202..029671db8a 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -872,6 +872,9 @@ impl<'a> ConstantEvaluator<'a> { crate::MathFunction::Tan => { component_wise_float!(self, span, [arg], |e| { Ok([e.tan()]) }) } + crate::MathFunction::Tanh => { + component_wise_float!(self, span, [arg], |e| { Ok([e.tanh()]) }) + } crate::MathFunction::Sqrt => { component_wise_float!(self, span, [arg], |e| { Ok([e.sqrt()]) }) } From 7528b22e5702fe08584473444eaf0adca8732b30 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 22 Dec 2023 07:47:37 -0500 Subject: [PATCH 026/101] feat(const_eval): impl. `cos` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 3 + .../tests/out/spv/debug-symbol-terrain.spvasm | 73 +++++++++---------- 3 files changed, 40 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a06e271c5c..1b474ec20c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ Bottom level categories: - Many numeric built-ins have had a constant evaluation implementation added for them, which allows them to be used in a `const` context: - [#4879](https://github.com/gfx-rs/wgpu/pull/4879) by @ErichDonGubler: - `abs` + - `cos` - `round` - `saturate` - `sin` diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 029671db8a..cfd57a1767 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -834,6 +834,9 @@ impl<'a> ConstantEvaluator<'a> { } ) } + crate::MathFunction::Cos => { + component_wise_float!(self, span, [arg], |e| { Ok([e.cos()]) }) + } crate::MathFunction::Round => { // TODO: Use `f{32,64}.round_ties_even()` when available on stable. This polyfill // is shamelessly [~~stolen from~~ inspired by `ndarray-image`][polyfill source], diff --git a/naga/tests/out/spv/debug-symbol-terrain.spvasm b/naga/tests/out/spv/debug-symbol-terrain.spvasm index a818ee6fea..fd8e7f5df3 100644 --- a/naga/tests/out/spv/debug-symbol-terrain.spvasm +++ b/naga/tests/out/spv/debug-symbol-terrain.spvasm @@ -366,10 +366,10 @@ OpName %91 "x12" OpName %94 "m" OpName %203 "p" OpName %204 "fbm" -OpName %210 "x" -OpName %212 "v" -OpName %214 "a" -OpName %215 "i" +OpName %212 "x" +OpName %214 "v" +OpName %216 "a" +OpName %217 "i" OpName %255 "p" OpName %256 "min_max_height" OpName %257 "terrain_point" @@ -575,10 +575,12 @@ OpDecorate %582 Location 0 %206 = OpConstant %5 0.01 %207 = OpConstant %5 100.0 %208 = OpConstantComposite %6 %207 %207 -%209 = OpConstant %5 0.47942555 -%211 = OpConstantNull %6 -%213 = OpTypePointer Function %5 -%216 = OpTypePointer Function %8 +%209 = OpConstant %5 0.87758255 +%210 = OpConstant %5 0.47942555 +%211 = OpConstantComposite %6 %209 %210 +%213 = OpConstantNull %6 +%215 = OpTypePointer Function %5 +%218 = OpTypePointer Function %8 %258 = OpTypeFunction %4 %6 %6 %271 = OpTypeFunction %14 %6 %6 %272 = OpConstant %5 0.1 @@ -836,27 +838,24 @@ OpFunctionEnd %204 = OpFunction %5 None %68 %203 = OpFunctionParameter %6 %202 = OpLabel -%212 = OpVariable %213 Function %74 -%215 = OpVariable %216 Function %135 -%210 = OpVariable %87 Function %211 -%214 = OpVariable %213 Function %78 -OpBranch %217 -%217 = OpLabel +%214 = OpVariable %215 Function %74 +%217 = OpVariable %218 Function %135 +%212 = OpVariable %87 Function %213 +%216 = OpVariable %215 Function %78 +OpBranch %219 +%219 = OpLabel OpLine %3 36 13 -%218 = OpVectorTimesScalar %6 %203 %206 +%220 = OpVectorTimesScalar %6 %203 %206 OpLine %3 36 5 -OpStore %210 %218 +OpStore %212 %220 OpLine %3 39 17 -OpLine %3 40 24 -%219 = OpExtInst %5 %1 Cos %78 OpLine %3 40 14 -%220 = OpCompositeConstruct %6 %219 %209 OpLine %3 41 15 -%221 = OpCompositeExtract %5 %220 0 -%222 = OpCompositeExtract %5 %220 1 -%223 = OpCompositeExtract %5 %220 1 +%221 = OpCompositeExtract %5 %211 0 +%222 = OpCompositeExtract %5 %211 1 +%223 = OpCompositeExtract %5 %211 1 %224 = OpFNegate %5 %223 -%225 = OpCompositeExtract %5 %220 0 +%225 = OpCompositeExtract %5 %211 0 %226 = OpCompositeConstruct %6 %221 %222 %227 = OpCompositeConstruct %6 %224 %225 %228 = OpCompositeConstruct %9 %226 %227 @@ -867,7 +866,7 @@ OpLoopMerge %230 %232 None OpBranch %231 %231 = OpLabel OpLine %3 43 22 -%233 = OpLoad %8 %215 +%233 = OpLoad %8 %217 %234 = OpULessThan %112 %233 %205 OpLine %3 43 21 OpSelectionMerge %235 None @@ -878,44 +877,44 @@ OpBranch %230 OpBranch %237 %237 = OpLabel OpLine %3 1 1 -%239 = OpLoad %5 %212 -%240 = OpLoad %5 %214 -%241 = OpLoad %6 %210 +%239 = OpLoad %5 %214 +%240 = OpLoad %5 %216 +%241 = OpLoad %6 %212 OpLine %3 44 21 %242 = OpFunctionCall %5 %67 %241 OpLine %3 44 13 %243 = OpFMul %5 %240 %242 %244 = OpFAdd %5 %239 %243 OpLine %3 44 9 -OpStore %212 %244 +OpStore %214 %244 OpLine %3 45 13 -%245 = OpLoad %6 %210 +%245 = OpLoad %6 %212 %246 = OpMatrixTimesVector %6 %228 %245 OpLine %3 45 13 %247 = OpVectorTimesScalar %6 %246 %81 %248 = OpFAdd %6 %247 %208 OpLine %3 45 9 -OpStore %210 %248 +OpStore %212 %248 OpLine %3 1 1 -%249 = OpLoad %5 %214 +%249 = OpLoad %5 %216 OpLine %3 46 13 %250 = OpFMul %5 %249 %78 OpLine %3 46 9 -OpStore %214 %250 +OpStore %216 %250 OpBranch %238 %238 = OpLabel OpBranch %232 %232 = OpLabel OpLine %3 1 1 -%251 = OpLoad %8 %215 +%251 = OpLoad %8 %217 OpLine %3 43 43 %252 = OpIAdd %8 %251 %126 OpLine %3 43 39 -OpStore %215 %252 +OpStore %217 %252 OpBranch %229 %230 = OpLabel OpLine %3 1 1 -%253 = OpLoad %5 %212 +%253 = OpLoad %5 %214 OpReturnValue %253 OpFunctionEnd %257 = OpFunction %4 None %258 @@ -1193,8 +1192,8 @@ OpReturn OpFunctionEnd %465 = OpFunction %2 None %346 %453 = OpLabel -%468 = OpVariable %213 Function %74 -%469 = OpVariable %216 Function %135 +%468 = OpVariable %215 Function %74 +%469 = OpVariable %218 Function %135 %456 = OpLoad %8 %455 %459 = OpLoad %7 %457 %462 = OpLoad %6 %460 From 12b11f870be22ea2372f51e8df008324a475b2f9 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 22 Dec 2023 07:47:37 -0500 Subject: [PATCH 027/101] feat(const_eval): impl. `cosh` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b474ec20c..80704dc27f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ Bottom level categories: - [#4879](https://github.com/gfx-rs/wgpu/pull/4879) by @ErichDonGubler: - `abs` - `cos` + - `cosh` - `round` - `saturate` - `sin` diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index cfd57a1767..4692355a56 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -837,6 +837,9 @@ impl<'a> ConstantEvaluator<'a> { crate::MathFunction::Cos => { component_wise_float!(self, span, [arg], |e| { Ok([e.cos()]) }) } + crate::MathFunction::Cosh => { + component_wise_float!(self, span, [arg], |e| { Ok([e.cosh()]) }) + } crate::MathFunction::Round => { // TODO: Use `f{32,64}.round_ties_even()` when available on stable. This polyfill // is shamelessly [~~stolen from~~ inspired by `ndarray-image`][polyfill source], From 6654c6895033bede0f75bd09bfa2dbe1e6ca483a Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 22 Dec 2023 08:01:52 -0500 Subject: [PATCH 028/101] feat(const_eval): impl. `acos` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80704dc27f..ff937bbdd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ Bottom level categories: - Many numeric built-ins have had a constant evaluation implementation added for them, which allows them to be used in a `const` context: - [#4879](https://github.com/gfx-rs/wgpu/pull/4879) by @ErichDonGubler: - `abs` + - `acos` - `cos` - `cosh` - `round` diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 4692355a56..b56d4c6999 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -819,6 +819,9 @@ impl<'a> ConstantEvaluator<'a> { Scalar::U32([e]) => Ok(Scalar::U32([e])), // TODO: just re-use the expression, ezpz }) } + crate::MathFunction::Acos => { + component_wise_float!(self, span, [arg], |e| { Ok([e.acos()]) }) + } crate::MathFunction::Pow => self.math_pow(arg, arg1.unwrap(), span), crate::MathFunction::Clamp => { component_wise_scalar!( From afb54d58bac04df9e7b3ede37983558e559a3d2b Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 22 Dec 2023 08:01:52 -0500 Subject: [PATCH 029/101] feat(const_eval): impl. `acosh` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff937bbdd7..685b0755f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ Bottom level categories: - [#4879](https://github.com/gfx-rs/wgpu/pull/4879) by @ErichDonGubler: - `abs` - `acos` + - `acosh` - `cos` - `cosh` - `round` diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index b56d4c6999..598e0a92bd 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -822,6 +822,9 @@ impl<'a> ConstantEvaluator<'a> { crate::MathFunction::Acos => { component_wise_float!(self, span, [arg], |e| { Ok([e.acos()]) }) } + crate::MathFunction::Acosh => { + component_wise_float!(self, span, [arg], |e| { Ok([e.acosh()]) }) + } crate::MathFunction::Pow => self.math_pow(arg, arg1.unwrap(), span), crate::MathFunction::Clamp => { component_wise_scalar!( From e2783c7d4573d39bc3d0b53efeed9b9a3384e71b Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 22 Dec 2023 08:02:02 -0500 Subject: [PATCH 030/101] feat(const_eval): impl. `asin` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 685b0755f8..0a5a137283 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ Bottom level categories: - `abs` - `acos` - `acosh` + - `asin` - `cos` - `cosh` - `round` diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 598e0a92bd..ca0a596040 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -825,6 +825,9 @@ impl<'a> ConstantEvaluator<'a> { crate::MathFunction::Acosh => { component_wise_float!(self, span, [arg], |e| { Ok([e.acosh()]) }) } + crate::MathFunction::Asin => { + component_wise_float!(self, span, [arg], |e| { Ok([e.asin()]) }) + } crate::MathFunction::Pow => self.math_pow(arg, arg1.unwrap(), span), crate::MathFunction::Clamp => { component_wise_scalar!( From f8113c55b7eb9e01142b6108c2468663b1c83a45 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 22 Dec 2023 08:02:02 -0500 Subject: [PATCH 031/101] feat(const_eval): impl. `asinh` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a5a137283..5ef25b7e3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ Bottom level categories: - `acos` - `acosh` - `asin` + - `asinh` - `cos` - `cosh` - `round` diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index ca0a596040..c6f9922ddc 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -828,6 +828,9 @@ impl<'a> ConstantEvaluator<'a> { crate::MathFunction::Asin => { component_wise_float!(self, span, [arg], |e| { Ok([e.asin()]) }) } + crate::MathFunction::Asinh => { + component_wise_float!(self, span, [arg], |e| { Ok([e.asinh()]) }) + } crate::MathFunction::Pow => self.math_pow(arg, arg1.unwrap(), span), crate::MathFunction::Clamp => { component_wise_scalar!( From 262c07f40ca19428947e0ab61d78862690eb0962 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 22 Dec 2023 08:02:12 -0500 Subject: [PATCH 032/101] feat(const_eval): impl. `atan` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ef25b7e3a..a5540a0582 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,7 @@ Bottom level categories: - `acosh` - `asin` - `asinh` + - `atan` - `cos` - `cosh` - `round` diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index c6f9922ddc..4bfdb8112a 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -831,6 +831,9 @@ impl<'a> ConstantEvaluator<'a> { crate::MathFunction::Asinh => { component_wise_float!(self, span, [arg], |e| { Ok([e.asinh()]) }) } + crate::MathFunction::Atan => { + component_wise_float!(self, span, [arg], |e| { Ok([e.atan()]) }) + } crate::MathFunction::Pow => self.math_pow(arg, arg1.unwrap(), span), crate::MathFunction::Clamp => { component_wise_scalar!( From c2f110ed0c893df16ebc6a6fc19a977f84cd7896 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 22 Dec 2023 08:02:12 -0500 Subject: [PATCH 033/101] feat(const_eval): impl. `atanh` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5540a0582..9bfea9f358 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ Bottom level categories: - `asin` - `asinh` - `atan` + - `atanh` - `cos` - `cosh` - `round` diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 4bfdb8112a..3b3ba56209 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -834,6 +834,9 @@ impl<'a> ConstantEvaluator<'a> { crate::MathFunction::Atan => { component_wise_float!(self, span, [arg], |e| { Ok([e.atan()]) }) } + crate::MathFunction::Atanh => { + component_wise_float!(self, span, [arg], |e| { Ok([e.atanh()]) }) + } crate::MathFunction::Pow => self.math_pow(arg, arg1.unwrap(), span), crate::MathFunction::Clamp => { component_wise_scalar!( From 063e11027b21dc4d4e1db4c9f7ee7dbada586407 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 22 Dec 2023 08:05:15 -0500 Subject: [PATCH 034/101] refactor(const_eval): inline `math_pow` --- naga/src/proc/constant_evaluator.rs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 3b3ba56209..5cffdba86e 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -837,7 +837,11 @@ impl<'a> ConstantEvaluator<'a> { crate::MathFunction::Atanh => { component_wise_float!(self, span, [arg], |e| { Ok([e.atanh()]) }) } - crate::MathFunction::Pow => self.math_pow(arg, arg1.unwrap(), span), + crate::MathFunction::Pow => { + component_wise_float!(self, span, [arg, arg1.unwrap()], |e1, e2| { + Ok([e1.powf(e2)]) + }) + } crate::MathFunction::Clamp => { component_wise_scalar!( self, @@ -913,15 +917,6 @@ impl<'a> ConstantEvaluator<'a> { } } - fn math_pow( - &mut self, - e1: Handle, - e2: Handle, - span: Span, - ) -> Result, ConstantEvaluatorError> { - component_wise_float!(self, span, [e1, e2], |e1, e2| { Ok([e1.powf(e2)]) }) - } - fn array_length( &mut self, array: Handle, From d678c7a9cffcf759fdb7aaf85663e2c77e020c10 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Fri, 19 Jan 2024 18:28:03 +0100 Subject: [PATCH 035/101] d3d12: Null check the out ComPtr of a few creation functions (#5096) My understanding is that we shouldn't need to (The d3d12 docs aren't very specific about that), but we have evidence that these functions sometimes leave the resource pointer set to null without returning an error. --- wgpu-hal/src/dx12/descriptor.rs | 7 ++++ wgpu-hal/src/dx12/device.rs | 63 ++++++++++++++++++------------ wgpu-hal/src/dx12/mod.rs | 12 ++++++ wgpu-hal/src/dx12/suballocation.rs | 10 +++++ 4 files changed, 68 insertions(+), 24 deletions(-) diff --git a/wgpu-hal/src/dx12/descriptor.rs b/wgpu-hal/src/dx12/descriptor.rs index 8833c1adf4..2d4d2c1673 100644 --- a/wgpu-hal/src/dx12/descriptor.rs +++ b/wgpu-hal/src/dx12/descriptor.rs @@ -1,3 +1,4 @@ +use super::null_comptr_check; use crate::auxil::dxgi::result::HResult as _; use bit_set::BitSet; use parking_lot::Mutex; @@ -53,6 +54,8 @@ impl GeneralHeap { .into_device_result("Descriptor heap creation")? }; + null_comptr_check(&raw)?; + Ok(Self { raw: raw.clone(), ty, @@ -130,6 +133,8 @@ impl FixedSizeHeap { ) .into_device_result("Descriptor heap creation")?; + null_comptr_check(&heap)?; + Ok(Self { handle_size: device.get_descriptor_increment_size(ty) as _, availability: !0, // all free! @@ -254,6 +259,8 @@ impl CpuHeap { .create_descriptor_heap(total, ty, d3d12::DescriptorHeapFlags::empty(), 0) .into_device_result("CPU descriptor heap creation")?; + null_comptr_check(&raw)?; + Ok(Self { inner: Mutex::new(CpuHeapInner { _raw: raw.clone(), diff --git a/wgpu-hal/src/dx12/device.rs b/wgpu-hal/src/dx12/device.rs index 0c1977203f..bb128b2a6d 100644 --- a/wgpu-hal/src/dx12/device.rs +++ b/wgpu-hal/src/dx12/device.rs @@ -1,9 +1,11 @@ use crate::{ auxil::{self, dxgi::result::HResult as _}, dx12::shader_compilation, + DeviceError, }; +use d3d12::ComPtr; -use super::{conv, descriptor, view}; +use super::{conv, descriptor, null_comptr_check, view}; use parking_lot::Mutex; use std::{ ffi, mem, @@ -29,7 +31,7 @@ impl super::Device { private_caps: super::PrivateCapabilities, library: &Arc, dxc_container: Option>, - ) -> Result { + ) -> Result { let mem_allocator = if private_caps.suballocation_supported { super::suballocation::create_allocator_wrapper(&raw)? } else { @@ -48,6 +50,8 @@ impl super::Device { }; hr.into_device_result("Idle fence creation")?; + null_comptr_check(&idle_fence)?; + let mut zero_buffer = d3d12::Resource::null(); unsafe { let raw_desc = d3d12_ty::D3D12_RESOURCE_DESC { @@ -89,6 +93,8 @@ impl super::Device { ) .into_device_result("Zero buffer creation")?; + null_comptr_check(&zero_buffer)?; + // Note: without `D3D12_HEAP_FLAG_CREATE_NOT_ZEROED` // this resource is zeroed by default. }; @@ -142,7 +148,7 @@ impl super::Device { // A null pResource is used to initialize a null descriptor, // which guarantees D3D11-like null binding behavior (reading 0s, writes are discarded) raw.create_render_target_view( - d3d12::ComPtr::null(), + ComPtr::null(), &d3d12::RenderTargetViewDesc::texture_2d( winapi::shared::dxgiformat::DXGI_FORMAT_R8G8B8A8_UNORM, 0, @@ -185,10 +191,10 @@ impl super::Device { // Blocks until the dedicated present queue is finished with all of its work. // // Once this method completes, the surface is able to be resized or deleted. - pub(super) unsafe fn wait_for_present_queue_idle(&self) -> Result<(), crate::DeviceError> { + pub(super) unsafe fn wait_for_present_queue_idle(&self) -> Result<(), DeviceError> { let cur_value = self.idler.fence.get_value(); if cur_value == !0 { - return Err(crate::DeviceError::Lost); + return Err(DeviceError::Lost); } let value = cur_value + 1; @@ -326,7 +332,7 @@ impl crate::Device for super::Device { unsafe fn create_buffer( &self, desc: &crate::BufferDescriptor, - ) -> Result { + ) -> Result { let mut resource = d3d12::Resource::null(); let mut size = desc.size; if desc.usage.contains(crate::BufferUses::UNIFORM) { @@ -381,11 +387,12 @@ impl crate::Device for super::Device { &self, buffer: &super::Buffer, range: crate::MemoryRange, - ) -> Result { + ) -> Result { let mut ptr = ptr::null_mut(); // TODO: 0 for subresource should be fine here until map and unmap buffer is subresource aware? let hr = unsafe { (*buffer.resource).Map(0, ptr::null(), &mut ptr) }; hr.into_device_result("Map buffer")?; + Ok(crate::BufferMapping { ptr: ptr::NonNull::new(unsafe { ptr.offset(range.start as isize).cast::() }) .unwrap(), @@ -395,7 +402,7 @@ impl crate::Device for super::Device { }) } - unsafe fn unmap_buffer(&self, buffer: &super::Buffer) -> Result<(), crate::DeviceError> { + unsafe fn unmap_buffer(&self, buffer: &super::Buffer) -> Result<(), DeviceError> { unsafe { (*buffer.resource).Unmap(0, ptr::null()) }; Ok(()) } @@ -406,7 +413,7 @@ impl crate::Device for super::Device { unsafe fn create_texture( &self, desc: &crate::TextureDescriptor, - ) -> Result { + ) -> Result { use super::suballocation::create_texture_resource; let mut resource = d3d12::Resource::null(); @@ -465,7 +472,7 @@ impl crate::Device for super::Device { &self, texture: &super::Texture, desc: &crate::TextureViewDescriptor, - ) -> Result { + ) -> Result { let view_desc = desc.to_internal(texture); Ok(super::TextureView { @@ -591,7 +598,7 @@ impl crate::Device for super::Device { unsafe fn create_sampler( &self, desc: &crate::SamplerDescriptor, - ) -> Result { + ) -> Result { let handle = self.sampler_pool.lock().alloc_handle()?; let reduction = match desc.compare { @@ -633,7 +640,7 @@ impl crate::Device for super::Device { unsafe fn create_command_encoder( &self, desc: &crate::CommandEncoderDescriptor, - ) -> Result { + ) -> Result { let allocator = self .raw .create_command_allocator(d3d12::CmdListType::Direct) @@ -665,7 +672,7 @@ impl crate::Device for super::Device { unsafe fn create_bind_group_layout( &self, desc: &crate::BindGroupLayoutDescriptor, - ) -> Result { + ) -> Result { let (mut num_buffer_views, mut num_samplers, mut num_texture_views) = (0, 0, 0); for entry in desc.entries.iter() { let count = entry.count.map_or(1, NonZeroU32::get); @@ -714,7 +721,7 @@ impl crate::Device for super::Device { unsafe fn create_pipeline_layout( &self, desc: &crate::PipelineLayoutDescriptor, - ) -> Result { + ) -> Result { use naga::back::hlsl; // Pipeline layouts are implemented as RootSignature for D3D12. // @@ -1024,7 +1031,7 @@ impl crate::Device for super::Device { ) .map_err(|e| { log::error!("Unable to find serialization function: {:?}", e); - crate::DeviceError::Lost + DeviceError::Lost })? .into_device_result("Root signature serialization")?; @@ -1033,7 +1040,7 @@ impl crate::Device for super::Device { "Root signature serialization error: {:?}", unsafe { error.as_c_str() }.to_str().unwrap() ); - return Err(crate::DeviceError::Lost); + return Err(DeviceError::Lost); } let raw = self @@ -1076,7 +1083,7 @@ impl crate::Device for super::Device { unsafe fn create_bind_group( &self, desc: &crate::BindGroupDescriptor, - ) -> Result { + ) -> Result { let mut cpu_views = desc .layout .cpu_heap_views @@ -1437,6 +1444,8 @@ impl crate::Device for super::Device { hr.into_result() .map_err(|err| crate::PipelineError::Linkage(shader_stages, err.into_owned()))?; + null_comptr_check(&raw)?; + if let Some(name) = desc.label { let cwstr = conv::map_label(name); unsafe { raw.SetName(cwstr.as_ptr()) }; @@ -1474,6 +1483,8 @@ impl crate::Device for super::Device { crate::PipelineError::Linkage(wgt::ShaderStages::COMPUTE, err.into_owned()) })?; + null_comptr_check(&raw)?; + if let Some(name) = desc.label { let cwstr = conv::map_label(name); unsafe { raw.SetName(cwstr.as_ptr()) }; @@ -1489,7 +1500,7 @@ impl crate::Device for super::Device { unsafe fn create_query_set( &self, desc: &wgt::QuerySetDescriptor, - ) -> Result { + ) -> Result { let (heap_ty, raw_ty) = match desc.ty { wgt::QueryType::Occlusion => ( d3d12::QueryHeapType::Occlusion, @@ -1510,6 +1521,8 @@ impl crate::Device for super::Device { .create_query_heap(heap_ty, desc.count, 0) .into_device_result("Query heap creation")?; + null_comptr_check(&raw)?; + if let Some(label) = desc.label { let cwstr = conv::map_label(label); unsafe { raw.SetName(cwstr.as_ptr()) }; @@ -1519,7 +1532,7 @@ impl crate::Device for super::Device { } unsafe fn destroy_query_set(&self, _set: super::QuerySet) {} - unsafe fn create_fence(&self) -> Result { + unsafe fn create_fence(&self) -> Result { let mut raw = d3d12::Fence::null(); let hr = unsafe { self.raw.CreateFence( @@ -1530,13 +1543,15 @@ impl crate::Device for super::Device { ) }; hr.into_device_result("Fence creation")?; + null_comptr_check(&raw)?; + Ok(super::Fence { raw }) } unsafe fn destroy_fence(&self, _fence: super::Fence) {} unsafe fn get_fence_value( &self, fence: &super::Fence, - ) -> Result { + ) -> Result { Ok(unsafe { fence.raw.GetCompletedValue() }) } unsafe fn wait( @@ -1544,7 +1559,7 @@ impl crate::Device for super::Device { fence: &super::Fence, value: crate::FenceValue, timeout_ms: u32, - ) -> Result { + ) -> Result { let timeout_duration = Duration::from_millis(timeout_ms as u64); // We first check if the fence has already reached the value we're waiting for. @@ -1602,7 +1617,7 @@ impl crate::Device for super::Device { winbase::WAIT_OBJECT_0 => {} winbase::WAIT_ABANDONED | winbase::WAIT_FAILED => { log::error!("Wait failed!"); - break Err(crate::DeviceError::Lost); + break Err(DeviceError::Lost); } winerror::WAIT_TIMEOUT => { log::trace!("Wait timed out!"); @@ -1610,7 +1625,7 @@ impl crate::Device for super::Device { } other => { log::error!("Unexpected wait status: 0x{:x}", other); - break Err(crate::DeviceError::Lost); + break Err(DeviceError::Lost); } }; @@ -1664,7 +1679,7 @@ impl crate::Device for super::Device { unsafe fn create_acceleration_structure( &self, _desc: &crate::AccelerationStructureDescriptor, - ) -> Result { + ) -> Result { // Create a D3D12 resource as per-usual. todo!() } diff --git a/wgpu-hal/src/dx12/mod.rs b/wgpu-hal/src/dx12/mod.rs index af8d5a8c01..d56e5efa08 100644 --- a/wgpu-hal/src/dx12/mod.rs +++ b/wgpu-hal/src/dx12/mod.rs @@ -938,3 +938,15 @@ impl crate::Queue for Queue { (1_000_000_000.0 / frequency as f64) as f32 } } + +/// A shorthand for producing a `ResourceCreationFailed` error if a ComPtr is null. +#[inline] +pub fn null_comptr_check( + ptr: &d3d12::ComPtr, +) -> Result<(), crate::DeviceError> { + if d3d12::ComPtr::is_null(ptr) { + return Err(crate::DeviceError::ResourceCreationFailed); + } + + Ok(()) +} diff --git a/wgpu-hal/src/dx12/suballocation.rs b/wgpu-hal/src/dx12/suballocation.rs index 3b9696e455..47a398be53 100644 --- a/wgpu-hal/src/dx12/suballocation.rs +++ b/wgpu-hal/src/dx12/suballocation.rs @@ -16,6 +16,7 @@ use placed as allocation; // This is the fast path using gpu_allocator to suballocate buffers and textures. #[cfg(feature = "windows_rs")] mod placed { + use crate::dx12::null_comptr_check; use d3d12::ComPtr; use parking_lot::Mutex; use std::ptr; @@ -115,6 +116,8 @@ mod placed { ) }; + null_comptr_check(resource)?; + Ok((hr, Some(AllocationWrapper { allocation }))) } @@ -162,6 +165,8 @@ mod placed { ) }; + null_comptr_check(resource)?; + Ok((hr, Some(AllocationWrapper { allocation }))) } @@ -223,6 +228,7 @@ mod placed { // This is the older, slower path where it doesn't suballocate buffers. // Tracking issue for when it can be removed: https://github.com/gfx-rs/wgpu/issues/3207 mod committed { + use crate::dx12::null_comptr_check; use d3d12::ComPtr; use parking_lot::Mutex; use std::ptr; @@ -296,6 +302,8 @@ mod committed { ) }; + null_comptr_check(resource)?; + Ok((hr, None)) } @@ -332,6 +340,8 @@ mod committed { ) }; + null_comptr_check(resource)?; + Ok((hr, None)) } From 101e9a574d1f739176d3afbf1b96dbb259362004 Mon Sep 17 00:00:00 2001 From: Nick Date: Fri, 19 Jan 2024 12:32:10 -0500 Subject: [PATCH 036/101] Make sure to copy all of the buffers into the resource array for dx12. (#5091) * Make sure to copy all of the buffers into the resource array for dx12. Fixes #5088. Even though we're telling DX12 that the maximum frame latency should be our non-padded value, the swap chain may request any of the buffers allocated to it. * Up the maximum frame latency on the DX12 backend to allow a larger range. --- wgpu-hal/src/dx12/mod.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/wgpu-hal/src/dx12/mod.rs b/wgpu-hal/src/dx12/mod.rs index d56e5efa08..362097e749 100644 --- a/wgpu-hal/src/dx12/mod.rs +++ b/wgpu-hal/src/dx12/mod.rs @@ -660,10 +660,14 @@ impl crate::Surface for Surface { let non_srgb_format = auxil::dxgi::conv::map_texture_format_nosrgb(config.format); + // The range for `SetMaximumFrameLatency` is 1-16 so the maximum latency requested should be 15 because we add 1. + // https://learn.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgidevice1-setmaximumframelatency + debug_assert!(config.maximum_frame_latency <= 15); + // Nvidia recommends to use 1-2 more buffers than the maximum latency // https://developer.nvidia.com/blog/advanced-api-performance-swap-chains/ // For high latency extra buffers seems excessive, so go with a minimum of 3 and beyond that add 1. - let swap_chain_buffer = (config.maximum_frame_latency + 1).min(3); + let swap_chain_buffer = (config.maximum_frame_latency + 1).min(16); let swap_chain = match self.swap_chain.write().take() { //Note: this path doesn't properly re-initialize all of the things @@ -805,8 +809,8 @@ impl crate::Surface for Surface { unsafe { swap_chain.SetMaximumFrameLatency(config.maximum_frame_latency) }; let waitable = unsafe { swap_chain.GetFrameLatencyWaitableObject() }; - let mut resources = Vec::with_capacity(config.maximum_frame_latency as usize); - for i in 0..config.maximum_frame_latency { + let mut resources = Vec::with_capacity(swap_chain_buffer as usize); + for i in 0..swap_chain_buffer { let mut resource = d3d12::Resource::null(); unsafe { swap_chain.GetBuffer(i, &d3d12_ty::ID3D12Resource::uuidof(), resource.mut_void()) From f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e Mon Sep 17 00:00:00 2001 From: Teodor Tanasoaia <28601907+teoxoy@users.noreply.github.com> Date: Fri, 19 Jan 2024 22:42:19 +0100 Subject: [PATCH 037/101] [d3d12] use plane 1 for stencil only views (#5100) * [d3d12] use plane 1 for stencil only views * add test * skip stencil only view creation on WebGL --- tests/tests/root.rs | 1 + tests/tests/texture_view_creation.rs | 65 ++++++++++++++++++++++++++++ wgpu-hal/src/dx12/view.rs | 1 + 3 files changed, 67 insertions(+) create mode 100644 tests/tests/texture_view_creation.rs diff --git a/tests/tests/root.rs b/tests/tests/root.rs index e3f116b0c7..f886c0f9eb 100644 --- a/tests/tests/root.rs +++ b/tests/tests/root.rs @@ -34,6 +34,7 @@ mod shader; mod shader_primitive_index; mod shader_view_format; mod texture_bounds; +mod texture_view_creation; mod transfer; mod vertex_indices; mod write_texture; diff --git a/tests/tests/texture_view_creation.rs b/tests/tests/texture_view_creation.rs new file mode 100644 index 0000000000..eeede4c26f --- /dev/null +++ b/tests/tests/texture_view_creation.rs @@ -0,0 +1,65 @@ +use wgpu::*; +use wgpu_test::{gpu_test, FailureCase, GpuTestConfiguration, TestParameters}; + +#[gpu_test] +static STENCIL_ONLY_VIEW_CREATION: GpuTestConfiguration = GpuTestConfiguration::new() + .parameters( + TestParameters::default() + .skip(FailureCase::webgl2()) // WebGL doesn't have stencil only views + .limits(wgpu::Limits::downlevel_defaults()), + ) + .run_async(|ctx| async move { + for format in [TextureFormat::Stencil8, TextureFormat::Depth24PlusStencil8] { + let texture = ctx.device.create_texture(&TextureDescriptor { + label: None, + size: Extent3d { + width: 256, + height: 256, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: TextureDimension::D2, + format, + usage: TextureUsages::COPY_DST + | TextureUsages::COPY_SRC + | TextureUsages::TEXTURE_BINDING, + view_formats: &[], + }); + let _view = texture.create_view(&TextureViewDescriptor { + aspect: TextureAspect::StencilOnly, + ..Default::default() + }); + } + }); + +#[gpu_test] +static DEPTH_ONLY_VIEW_CREATION: GpuTestConfiguration = + GpuTestConfiguration::new().run_async(|ctx| async move { + for format in [ + TextureFormat::Depth16Unorm, + TextureFormat::Depth24Plus, + TextureFormat::Depth24PlusStencil8, + ] { + let texture = ctx.device.create_texture(&TextureDescriptor { + label: None, + size: Extent3d { + width: 256, + height: 256, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: TextureDimension::D2, + format, + usage: TextureUsages::COPY_DST + | TextureUsages::COPY_SRC + | TextureUsages::TEXTURE_BINDING, + view_formats: &[], + }); + let _view = texture.create_view(&TextureViewDescriptor { + aspect: TextureAspect::DepthOnly, + ..Default::default() + }); + } + }); diff --git a/wgpu-hal/src/dx12/view.rs b/wgpu-hal/src/dx12/view.rs index 6cbad7bd1d..ae8e5814a8 100644 --- a/wgpu-hal/src/dx12/view.rs +++ b/wgpu-hal/src/dx12/view.rs @@ -36,6 +36,7 @@ impl crate::TextureViewDescriptor<'_> { fn aspects_to_plane(aspects: crate::FormatAspects) -> u32 { match aspects { + crate::FormatAspects::STENCIL => 1, crate::FormatAspects::PLANE_1 => 1, crate::FormatAspects::PLANE_2 => 2, _ => 0, From 6c7c6fb99954210c3623b6062b5cfea1b5ba7cf0 Mon Sep 17 00:00:00 2001 From: Imbris <2002109+Imberflur@users.noreply.github.com> Date: Sat, 20 Jan 2024 22:26:54 -0500 Subject: [PATCH 038/101] Make sure to unset current context in wgl Surface::configure/present (#5087) --- CHANGELOG.md | 6 ++++++ wgpu-hal/src/gles/egl.rs | 1 + wgpu-hal/src/gles/wgl.rs | 41 +++++++++++++++++++++++----------------- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bfea9f358..18a9a81d22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,6 +61,12 @@ Bottom level categories: - `tan` - `tanh` +### Bug Fixes + +#### WGL + +- In Surface::configure and Surface::present, fix the current GL context not being unset when releasing the lock that guards access to making the context current. This was causing other threads to panic when trying to make the context current. By @Imberflur in [#5087](https://github.com/gfx-rs/wgpu/pull/5087). + ## v0.19.0 (2024-01-17) This release includes: diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs index ef0ff4b6f3..aa985d8121 100644 --- a/wgpu-hal/src/gles/egl.rs +++ b/wgpu-hal/src/gles/egl.rs @@ -1092,6 +1092,7 @@ impl Surface { .map_err(|e| { log::error!("swap_buffers failed: {}", e); crate::SurfaceError::Lost + // TODO: should we unset the current context here? })?; self.egl .instance diff --git a/wgpu-hal/src/gles/wgl.rs b/wgpu-hal/src/gles/wgl.rs index a09a50330d..dbe8218501 100644 --- a/wgpu-hal/src/gles/wgl.rs +++ b/wgpu-hal/src/gles/wgl.rs @@ -77,6 +77,24 @@ impl AdapterContext { AdapterContextLock { inner } } + + /// Obtain a lock to the WGL context and get handle to the [`glow::Context`] that can be used to + /// do rendering. + /// + /// Unlike [`lock`](Self::lock), this accepts a device to pass to `make_current` and exposes the error + /// when `make_current` fails. + #[track_caller] + fn lock_with_dc(&self, device: HDC) -> Result, Error> { + let inner = self + .inner + .try_lock_for(Duration::from_secs(CONTEXT_LOCK_TIMEOUT_SECS)) + .expect("Could not lock adapter context. This is most-likely a deadlock."); + + inner + .context + .make_current(device) + .map(|()| AdapterContextLock { inner }) + } } /// A guard containing a lock to an [`AdapterContext`] @@ -603,16 +621,10 @@ impl Surface { window: self.window, }; - let inner = context.inner.lock(); - - if let Err(e) = inner.context.make_current(dc.device) { + let gl = context.lock_with_dc(dc.device).map_err(|e| { log::error!("unable to make the OpenGL context current for surface: {e}",); - return Err(crate::SurfaceError::Other( - "unable to make the OpenGL context current for surface", - )); - } - - let gl = &inner.gl; + crate::SurfaceError::Other("unable to make the OpenGL context current for surface") + })?; unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None) }; unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(sc.framebuffer)) }; @@ -693,16 +705,11 @@ impl crate::Surface for Surface { } let format_desc = device.shared.describe_texture_format(config.format); - let inner = &device.shared.context.inner.lock(); - - if let Err(e) = inner.context.make_current(dc.device) { + let gl = &device.shared.context.lock_with_dc(dc.device).map_err(|e| { log::error!("unable to make the OpenGL context current for surface: {e}",); - return Err(crate::SurfaceError::Other( - "unable to make the OpenGL context current for surface", - )); - } + crate::SurfaceError::Other("unable to make the OpenGL context current for surface") + })?; - let gl = &inner.gl; let renderbuffer = unsafe { gl.create_renderbuffer() }.map_err(|error| { log::error!("Internal swapchain renderbuffer creation failed: {error}"); crate::DeviceError::OutOfMemory From e128d6c2613c7f8aecd25539c6fbc914bfda04f7 Mon Sep 17 00:00:00 2001 From: Lucas Kent Date: Sun, 21 Jan 2024 14:36:29 +1100 Subject: [PATCH 039/101] Error on missing web_sys_unstable_apis (#5104) --- .cargo/config.toml | 3 +++ .github/workflows/ci.yml | 2 +- wgpu/src/backend/mod.rs | 18 ++++++++++++++++-- wgpu/src/lib.rs | 4 ++-- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index b75130124b..8434ec2cc6 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -5,3 +5,6 @@ xtask = "run --manifest-path xtask/Cargo.toml" rustflags = [ "--cfg=web_sys_unstable_apis" ] +rustdocflags = [ +"--cfg=web_sys_unstable_apis" +] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 48a67b7926..6bb8d38245 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,7 +56,7 @@ env: RUST_BACKTRACE: full PKG_CONFIG_ALLOW_CROSS: 1 # allow android to work RUSTFLAGS: --cfg=web_sys_unstable_apis -D warnings - RUSTDOCFLAGS: -Dwarnings + RUSTDOCFLAGS: --cfg=web_sys_unstable_apis -D warnings WASM_BINDGEN_TEST_TIMEOUT: 300 # 5 minutes CACHE_SUFFIX: c # cache busting diff --git a/wgpu/src/backend/mod.rs b/wgpu/src/backend/mod.rs index 02d9632efb..9a0b7ef28a 100644 --- a/wgpu/src/backend/mod.rs +++ b/wgpu/src/backend/mod.rs @@ -1,9 +1,23 @@ -#[cfg(webgpu)] +#[cfg(all(webgpu, web_sys_unstable_apis))] mod webgpu; -#[cfg(webgpu)] +#[cfg(all(webgpu, web_sys_unstable_apis))] pub(crate) use webgpu::{get_browser_gpu_property, ContextWebGpu}; +#[cfg(all(webgpu, not(web_sys_unstable_apis)))] +compile_error!( + "webgpu feature used without web_sys_unstable_apis config: +Here are some ways to resolve this: +* If you wish to use webgpu backend, create a .cargo/config.toml in the root of the repo containing: + [build] + rustflags = [ \"--cfg=web_sys_unstable_apis\" ] + rustdocflags = [ \"--cfg=web_sys_unstable_apis\" ] +* If you wish to disable webgpu backend and instead use webgl backend, change your wgpu Cargo.toml entry to: + wgpu = { version = \"\", default-features = false, features = [\"webgl\"] } +" +); + #[cfg(wgpu_core)] mod wgpu_core; + #[cfg(wgpu_core)] pub(crate) use wgpu_core::ContextWgpuCore; diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index e94d45561f..a7dc98fff8 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -1812,7 +1812,7 @@ impl Instance { ); } - #[cfg(webgpu)] + #[cfg(all(webgpu, web_sys_unstable_apis))] { let is_only_available_backend = !cfg!(wgpu_core); let requested_webgpu = _instance_desc.backends.contains(Backends::BROWSER_WEBGPU); @@ -3086,7 +3086,7 @@ impl<'a> BufferSlice<'a> { /// this function directly hands you the ArrayBuffer that we mapped the data into in js. /// /// This is only available on WebGPU, on any other backends this will return `None`. - #[cfg(webgpu)] + #[cfg(all(webgpu, web_sys_unstable_apis))] pub fn get_mapped_range_as_array_buffer(&self) -> Option { self.buffer .context From 886dc94f57b08128a150e0baa004f3bb33998c85 Mon Sep 17 00:00:00 2001 From: i509VCB Date: Sun, 21 Jan 2024 17:10:56 -0600 Subject: [PATCH 040/101] Document Wayland specifics related to SurfaceTexture::present (#5093) Co-authored-by: Connor Fitzgerald --- CHANGELOG.md | 4 ++++ wgpu/src/lib.rs | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18a9a81d22..243f35b767 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,10 @@ Bottom level categories: ## Unreleased +### Documentation + +- Document Wayland specific behavior related to `SurfaceTexture::present`. By @i509VCB in [#5092](https://github.com/gfx-rs/wgpu/pull/5092). + ### New features - Many numeric built-ins have had a constant evaluation implementation added for them, which allows them to be used in a `const` context: diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index a7dc98fff8..9b4af33cd6 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -4738,6 +4738,12 @@ impl SurfaceTexture { /// Schedule this texture to be presented on the owning surface. /// /// Needs to be called after any work on the texture is scheduled via [`Queue::submit`]. + /// + /// # Platform dependent behavior + /// + /// On Wayland, `present` will attach a `wl_buffer` to the underlying `wl_surface` and commit the new surface + /// state. If it is desired to do things such as request a frame callback, scale the surface using the viewporter + /// or synchronize other double buffered state, then these operations should be done before the call to `present`. pub fn present(mut self) { self.presented = true; DynContext::surface_present( From e5c62fb5bd29c5bd99f2445e3b089689c0e145e2 Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Mon, 22 Jan 2024 00:14:17 +0100 Subject: [PATCH 041/101] vulkan: Replace fence with semaphore when acquiring surfaces (#4967) --- wgpu-core/src/device/queue.rs | 39 ++++++++- wgpu-hal/examples/halmark/main.rs | 8 +- wgpu-hal/examples/raw-gles.rs | 2 +- wgpu-hal/examples/ray-traced-triangle/main.rs | 8 +- wgpu-hal/src/dx12/mod.rs | 1 + wgpu-hal/src/empty.rs | 1 + wgpu-hal/src/gles/queue.rs | 1 + wgpu-hal/src/lib.rs | 3 + wgpu-hal/src/metal/mod.rs | 1 + wgpu-hal/src/vulkan/device.rs | 15 +++- wgpu-hal/src/vulkan/instance.rs | 24 ++++-- wgpu-hal/src/vulkan/mod.rs | 86 +++++++++++-------- 12 files changed, 133 insertions(+), 56 deletions(-) diff --git a/wgpu-core/src/device/queue.rs b/wgpu-core/src/device/queue.rs index be5c202ffb..43a2d1d982 100644 --- a/wgpu-core/src/device/queue.rs +++ b/wgpu-core/src/device/queue.rs @@ -24,6 +24,7 @@ use crate::{ use hal::{CommandEncoder as _, Device as _, Queue as _}; use parking_lot::Mutex; +use smallvec::SmallVec; use std::{ iter, mem, ptr, @@ -1115,10 +1116,13 @@ impl Global { .fetch_add(1, Ordering::Relaxed) + 1; let mut active_executions = Vec::new(); + let mut used_surface_textures = track::TextureUsageScope::new(); let snatch_guard = device.snatchable_lock.read(); + let mut submit_surface_textures_owned = SmallVec::<[_; 2]>::new(); + { let mut command_buffer_guard = hub.command_buffers.write(); @@ -1217,8 +1221,17 @@ impl Global { return Err(QueueSubmitError::DestroyedTexture(id)); } Some(TextureInner::Native { .. }) => false, - Some(TextureInner::Surface { ref has_work, .. }) => { + Some(TextureInner::Surface { + ref has_work, + ref raw, + .. + }) => { has_work.store(true, Ordering::Relaxed); + + if raw.is_some() { + submit_surface_textures_owned.push(texture.clone()); + } + true } }; @@ -1409,8 +1422,17 @@ impl Global { return Err(QueueSubmitError::DestroyedTexture(id)); } Some(TextureInner::Native { .. }) => {} - Some(TextureInner::Surface { ref has_work, .. }) => { + Some(TextureInner::Surface { + ref has_work, + ref raw, + .. + }) => { has_work.store(true, Ordering::Relaxed); + + if raw.is_some() { + submit_surface_textures_owned.push(texture.clone()); + } + unsafe { used_surface_textures .merge_single(texture, None, hal::TextureUses::PRESENT) @@ -1449,12 +1471,23 @@ impl Global { .flat_map(|pool_execution| pool_execution.cmd_buffers.iter()), ) .collect::>(); + + let mut submit_surface_textures = + SmallVec::<[_; 2]>::with_capacity(submit_surface_textures_owned.len()); + + for texture in &submit_surface_textures_owned { + submit_surface_textures.extend(match texture.inner.get(&snatch_guard) { + Some(TextureInner::Surface { raw, .. }) => raw.as_ref(), + _ => None, + }); + } + unsafe { queue .raw .as_ref() .unwrap() - .submit(&refs, Some((fence, submit_index))) + .submit(&refs, &submit_surface_textures, Some((fence, submit_index))) .map_err(DeviceError::from)?; } diff --git a/wgpu-hal/examples/halmark/main.rs b/wgpu-hal/examples/halmark/main.rs index 7bc8013415..c238f299e7 100644 --- a/wgpu-hal/examples/halmark/main.rs +++ b/wgpu-hal/examples/halmark/main.rs @@ -490,7 +490,7 @@ impl Example { let mut fence = device.create_fence().unwrap(); let init_cmd = cmd_encoder.end_encoding().unwrap(); queue - .submit(&[&init_cmd], Some((&mut fence, init_fence_value))) + .submit(&[&init_cmd], &[], Some((&mut fence, init_fence_value))) .unwrap(); device.wait(&fence, init_fence_value, !0).unwrap(); device.destroy_buffer(staging_buffer); @@ -542,7 +542,7 @@ impl Example { { let ctx = &mut self.contexts[self.context_index]; self.queue - .submit(&[], Some((&mut ctx.fence, ctx.fence_value))) + .submit(&[], &[], Some((&mut ctx.fence, ctx.fence_value))) .unwrap(); } @@ -729,7 +729,9 @@ impl Example { } else { None }; - self.queue.submit(&[&cmd_buf], fence_param).unwrap(); + self.queue + .submit(&[&cmd_buf], &[&surface_tex], fence_param) + .unwrap(); self.queue.present(&self.surface, surface_tex).unwrap(); ctx.used_cmd_bufs.push(cmd_buf); ctx.used_views.push(surface_tex_view); diff --git a/wgpu-hal/examples/raw-gles.rs b/wgpu-hal/examples/raw-gles.rs index 81ab4171e3..342100e1cb 100644 --- a/wgpu-hal/examples/raw-gles.rs +++ b/wgpu-hal/examples/raw-gles.rs @@ -183,6 +183,6 @@ fn fill_screen(exposed: &hal::ExposedAdapter, width: u32, height encoder.begin_render_pass(&rp_desc); encoder.end_render_pass(); let cmd_buf = encoder.end_encoding().unwrap(); - od.queue.submit(&[&cmd_buf], None).unwrap(); + od.queue.submit(&[&cmd_buf], &[], None).unwrap(); } } diff --git a/wgpu-hal/examples/ray-traced-triangle/main.rs b/wgpu-hal/examples/ray-traced-triangle/main.rs index 01a0968f3d..c05feae820 100644 --- a/wgpu-hal/examples/ray-traced-triangle/main.rs +++ b/wgpu-hal/examples/ray-traced-triangle/main.rs @@ -755,7 +755,7 @@ impl Example { let mut fence = device.create_fence().unwrap(); let init_cmd = cmd_encoder.end_encoding().unwrap(); queue - .submit(&[&init_cmd], Some((&mut fence, init_fence_value))) + .submit(&[&init_cmd], &[], Some((&mut fence, init_fence_value))) .unwrap(); device.wait(&fence, init_fence_value, !0).unwrap(); cmd_encoder.reset_all(iter::once(init_cmd)); @@ -960,7 +960,9 @@ impl Example { } else { None }; - self.queue.submit(&[&cmd_buf], fence_param).unwrap(); + self.queue + .submit(&[&cmd_buf], &[&surface_tex], fence_param) + .unwrap(); self.queue.present(&self.surface, surface_tex).unwrap(); ctx.used_cmd_bufs.push(cmd_buf); ctx.used_views.push(surface_tex_view); @@ -999,7 +1001,7 @@ impl Example { { let ctx = &mut self.contexts[self.context_index]; self.queue - .submit(&[], Some((&mut ctx.fence, ctx.fence_value))) + .submit(&[], &[], Some((&mut ctx.fence, ctx.fence_value))) .unwrap(); } diff --git a/wgpu-hal/src/dx12/mod.rs b/wgpu-hal/src/dx12/mod.rs index 362097e749..038bb8ca15 100644 --- a/wgpu-hal/src/dx12/mod.rs +++ b/wgpu-hal/src/dx12/mod.rs @@ -886,6 +886,7 @@ impl crate::Queue for Queue { unsafe fn submit( &self, command_buffers: &[&CommandBuffer], + _surface_textures: &[&Texture], signal_fence: Option<(&mut Fence, crate::FenceValue)>, ) -> Result<(), crate::DeviceError> { let mut temp_lists = self.temp_lists.lock(); diff --git a/wgpu-hal/src/empty.rs b/wgpu-hal/src/empty.rs index 12f86e6f31..d58e779b96 100644 --- a/wgpu-hal/src/empty.rs +++ b/wgpu-hal/src/empty.rs @@ -104,6 +104,7 @@ impl crate::Queue for Context { unsafe fn submit( &self, command_buffers: &[&Resource], + surface_textures: &[&Resource], signal_fence: Option<(&mut Resource, crate::FenceValue)>, ) -> DeviceResult<()> { Ok(()) diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 5a4deb8e1a..6ec553bd29 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -1748,6 +1748,7 @@ impl crate::Queue for super::Queue { unsafe fn submit( &self, command_buffers: &[&super::CommandBuffer], + _surface_textures: &[&super::Texture], signal_fence: Option<(&mut super::Fence, crate::FenceValue)>, ) -> Result<(), crate::DeviceError> { let shared = Arc::clone(&self.shared); diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 7961a4ed8e..561024dd98 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -413,9 +413,12 @@ pub trait Queue: WasmNotSendSync { /// - all of the command buffers were created from command pools /// that are associated with this queue. /// - all of the command buffers had `CommadBuffer::finish()` called. + /// - all surface textures that the command buffers write to must be + /// passed to the surface_textures argument. unsafe fn submit( &self, command_buffers: &[&A::CommandBuffer], + surface_textures: &[&A::SurfaceTexture], signal_fence: Option<(&mut A::Fence, FenceValue)>, ) -> Result<(), DeviceError>; unsafe fn present( diff --git a/wgpu-hal/src/metal/mod.rs b/wgpu-hal/src/metal/mod.rs index 39589115e7..298f60faac 100644 --- a/wgpu-hal/src/metal/mod.rs +++ b/wgpu-hal/src/metal/mod.rs @@ -368,6 +368,7 @@ impl crate::Queue for Queue { unsafe fn submit( &self, command_buffers: &[&CommandBuffer], + _surface_textures: &[&SurfaceTexture], signal_fence: Option<(&mut Fence, crate::FenceValue)>, ) -> Result<(), crate::DeviceError> { objc::rc::autoreleasepool(|| { diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index 23182b440c..fdfb6ee9ed 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -627,8 +627,16 @@ impl super::Device { let images = unsafe { functor.get_swapchain_images(raw) }.map_err(crate::DeviceError::from)?; - let vk_info = vk::FenceCreateInfo::builder().build(); - let fence = unsafe { self.shared.raw.create_fence(&vk_info, None) } + // NOTE: It's important that we define at least images.len() + 1 wait + // semaphores, since we prospectively need to provide the call to + // acquire the next image with an unsignaled semaphore. + let surface_semaphores = (0..images.len() + 1) + .map(|_| unsafe { + self.shared + .raw + .create_semaphore(&vk::SemaphoreCreateInfo::builder(), None) + }) + .collect::, _>>() .map_err(crate::DeviceError::from)?; Ok(super::Swapchain { @@ -636,10 +644,11 @@ impl super::Device { raw_flags, functor, device: Arc::clone(&self.shared), - fence, images, config: config.clone(), view_formats: wgt_view_formats, + surface_semaphores, + next_surface_index: 0, }) } diff --git a/wgpu-hal/src/vulkan/instance.rs b/wgpu-hal/src/vulkan/instance.rs index 179842c1e5..1f0159413f 100644 --- a/wgpu-hal/src/vulkan/instance.rs +++ b/wgpu-hal/src/vulkan/instance.rs @@ -169,7 +169,7 @@ impl super::Swapchain { /// # Safety /// /// - The device must have been made idle before calling this function. - unsafe fn release_resources(self, device: &ash::Device) -> Self { + unsafe fn release_resources(mut self, device: &ash::Device) -> Self { profiling::scope!("Swapchain::release_resources"); { profiling::scope!("vkDeviceWaitIdle"); @@ -177,7 +177,13 @@ impl super::Swapchain { // the presentation work is done, we are forced to wait until the device is idle. let _ = unsafe { device.device_wait_idle() }; }; - unsafe { device.destroy_fence(self.fence, None) }; + + for semaphore in self.surface_semaphores.drain(..) { + unsafe { + device.destroy_semaphore(semaphore, None); + } + } + self } } @@ -934,10 +940,12 @@ impl crate::Surface for super::Surface { timeout_ns = u64::MAX; } + let wait_semaphore = sc.surface_semaphores[sc.next_surface_index]; + // will block if no image is available let (index, suboptimal) = match unsafe { sc.functor - .acquire_next_image(sc.raw, timeout_ns, vk::Semaphore::null(), sc.fence) + .acquire_next_image(sc.raw, timeout_ns, wait_semaphore, vk::Fence::null()) } { // We treat `VK_SUBOPTIMAL_KHR` as `VK_SUCCESS` on Android. // See the comment in `Queue::present`. @@ -957,17 +965,14 @@ impl crate::Surface for super::Surface { } }; + sc.next_surface_index += 1; + sc.next_surface_index %= sc.surface_semaphores.len(); + // special case for Intel Vulkan returning bizzare values (ugh) if sc.device.vendor_id == crate::auxil::db::intel::VENDOR && index > 0x100 { return Err(crate::SurfaceError::Outdated); } - let fences = &[sc.fence]; - - unsafe { sc.device.raw.wait_for_fences(fences, true, !0) } - .map_err(crate::DeviceError::from)?; - unsafe { sc.device.raw.reset_fences(fences) }.map_err(crate::DeviceError::from)?; - // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkRenderPassBeginInfo.html#VUID-VkRenderPassBeginInfo-framebuffer-03209 let raw_flags = if sc .raw_flags @@ -994,6 +999,7 @@ impl crate::Surface for super::Surface { }, view_formats: sc.view_formats.clone(), }, + wait_semaphore, }; Ok(Some(crate::AcquiredSurfaceTexture { texture, diff --git a/wgpu-hal/src/vulkan/mod.rs b/wgpu-hal/src/vulkan/mod.rs index 45deda5d5b..787ebd7267 100644 --- a/wgpu-hal/src/vulkan/mod.rs +++ b/wgpu-hal/src/vulkan/mod.rs @@ -146,10 +146,14 @@ struct Swapchain { raw_flags: vk::SwapchainCreateFlagsKHR, functor: khr::Swapchain, device: Arc, - fence: vk::Fence, images: Vec, config: crate::SurfaceConfiguration, view_formats: Vec, + /// One wait semaphore per swapchain image. This will be associated with the + /// surface texture, and later collected during submission. + surface_semaphores: Vec, + /// Current semaphore index to use when acquiring a surface. + next_surface_index: usize, } pub struct Surface { @@ -163,6 +167,7 @@ pub struct Surface { pub struct SurfaceTexture { index: u32, texture: Texture, + wait_semaphore: vk::Semaphore, } impl Borrow for SurfaceTexture { @@ -585,29 +590,43 @@ impl crate::Queue for Queue { unsafe fn submit( &self, command_buffers: &[&CommandBuffer], + surface_textures: &[&SurfaceTexture], signal_fence: Option<(&mut Fence, crate::FenceValue)>, ) -> Result<(), crate::DeviceError> { - let vk_cmd_buffers = command_buffers - .iter() - .map(|cmd| cmd.raw) - .collect::>(); + let mut fence_raw = vk::Fence::null(); - let mut vk_info = vk::SubmitInfo::builder().command_buffers(&vk_cmd_buffers); + let mut wait_stage_masks = Vec::new(); + let mut wait_semaphores = Vec::new(); + let mut signal_semaphores = ArrayVec::<_, 2>::new(); + let mut signal_values = ArrayVec::<_, 2>::new(); - let mut fence_raw = vk::Fence::null(); - let mut vk_timeline_info; - let mut signal_semaphores = [vk::Semaphore::null(), vk::Semaphore::null()]; - let signal_values; + for &surface_texture in surface_textures { + wait_stage_masks.push(vk::PipelineStageFlags::TOP_OF_PIPE); + wait_semaphores.push(surface_texture.wait_semaphore); + } + + let old_index = self.relay_index.load(Ordering::Relaxed); + + let sem_index = if old_index >= 0 { + wait_stage_masks.push(vk::PipelineStageFlags::TOP_OF_PIPE); + wait_semaphores.push(self.relay_semaphores[old_index as usize]); + (old_index as usize + 1) % self.relay_semaphores.len() + } else { + 0 + }; + + signal_semaphores.push(self.relay_semaphores[sem_index]); + + self.relay_index + .store(sem_index as isize, Ordering::Relaxed); if let Some((fence, value)) = signal_fence { fence.maintain(&self.device.raw)?; match *fence { Fence::TimelineSemaphore(raw) => { - signal_values = [!0, value]; - signal_semaphores[1] = raw; - vk_timeline_info = vk::TimelineSemaphoreSubmitInfo::builder() - .signal_semaphore_values(&signal_values); - vk_info = vk_info.push_next(&mut vk_timeline_info); + signal_semaphores.push(raw); + signal_values.push(!0); + signal_values.push(value); } Fence::FencePool { ref mut active, @@ -627,26 +646,25 @@ impl crate::Queue for Queue { } } - let wait_stage_mask = [vk::PipelineStageFlags::TOP_OF_PIPE]; - let old_index = self.relay_index.load(Ordering::Relaxed); - let sem_index = if old_index >= 0 { - vk_info = vk_info - .wait_semaphores(&self.relay_semaphores[old_index as usize..old_index as usize + 1]) - .wait_dst_stage_mask(&wait_stage_mask); - (old_index as usize + 1) % self.relay_semaphores.len() - } else { - 0 - }; - self.relay_index - .store(sem_index as isize, Ordering::Relaxed); - signal_semaphores[0] = self.relay_semaphores[sem_index]; + let vk_cmd_buffers = command_buffers + .iter() + .map(|cmd| cmd.raw) + .collect::>(); - let signal_count = if signal_semaphores[1] == vk::Semaphore::null() { - 1 - } else { - 2 - }; - vk_info = vk_info.signal_semaphores(&signal_semaphores[..signal_count]); + let mut vk_info = vk::SubmitInfo::builder().command_buffers(&vk_cmd_buffers); + + vk_info = vk_info + .wait_semaphores(&wait_semaphores) + .wait_dst_stage_mask(&wait_stage_masks) + .signal_semaphores(&signal_semaphores); + + let mut vk_timeline_info; + + if !signal_values.is_empty() { + vk_timeline_info = + vk::TimelineSemaphoreSubmitInfo::builder().signal_semaphore_values(&signal_values); + vk_info = vk_info.push_next(&mut vk_timeline_info); + } profiling::scope!("vkQueueSubmit"); unsafe { From a0862aabb4f150261f7c21734dde9a22834f3796 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jan 2024 01:00:32 -0500 Subject: [PATCH 042/101] build(deps): bump the patch-updates group with 16 updates (#5115) Bumps the patch-updates group with 16 updates: | Package | From | To | | --- | --- | --- | | [bitflags](https://github.com/bitflags/bitflags) | `2.4.1` | `2.4.2` | | [env_logger](https://github.com/rust-cli/env_logger) | `0.10.1` | `0.10.2` | | [smallvec](https://github.com/servo/rust-smallvec) | `1.12.0` | `1.13.1` | | [winit](https://github.com/rust-windowing/winit) | `0.29.9` | `0.29.10` | | [anstream](https://github.com/rust-cli/anstyle) | `0.6.7` | `0.6.11` | | [clap](https://github.com/clap-rs/clap) | `4.4.16` | `4.4.18` | | [fdeflate](https://github.com/image-rs/fdeflate) | `0.3.3` | `0.3.4` | | [hermit-abi](https://github.com/hermitcore/hermit-rs) | `0.3.3` | `0.3.4` | | [linux-raw-sys](https://github.com/sunfishcode/linux-raw-sys) | `0.4.12` | `0.4.13` | | [pkg-config](https://github.com/rust-lang/pkg-config-rs) | `0.3.28` | `0.3.29` | | [proc-macro2](https://github.com/dtolnay/proc-macro2) | `1.0.76` | `1.0.78` | | [rayon](https://github.com/rayon-rs/rayon) | `1.8.0` | `1.8.1` | | [regex](https://github.com/rust-lang/regex) | `1.10.2` | `1.10.3` | | [smol_str](https://github.com/rust-analyzer/smol_str) | `0.2.0` | `0.2.1` | | [unicode-bidi](https://github.com/servo/unicode-bidi) | `0.3.14` | `0.3.15` | | [uuid](https://github.com/uuid-rs/uuid) | `1.6.1` | `1.7.0` | Updates `bitflags` from 2.4.1 to 2.4.2 - [Release notes](https://github.com/bitflags/bitflags/releases) - [Changelog](https://github.com/bitflags/bitflags/blob/main/CHANGELOG.md) - [Commits](https://github.com/bitflags/bitflags/compare/2.4.1...2.4.2) Updates `env_logger` from 0.10.1 to 0.10.2 - [Release notes](https://github.com/rust-cli/env_logger/releases) - [Changelog](https://github.com/rust-cli/env_logger/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-cli/env_logger/compare/v0.10.1...v0.10.2) Updates `smallvec` from 1.12.0 to 1.13.1 - [Release notes](https://github.com/servo/rust-smallvec/releases) - [Commits](https://github.com/servo/rust-smallvec/compare/v1.12.0...v1.13.1) Updates `winit` from 0.29.9 to 0.29.10 - [Release notes](https://github.com/rust-windowing/winit/releases) - [Changelog](https://github.com/rust-windowing/winit/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-windowing/winit/compare/v0.29.9...v0.29.10) Updates `anstream` from 0.6.7 to 0.6.11 - [Commits](https://github.com/rust-cli/anstyle/compare/anstream-v0.6.7...anstream-v0.6.11) Updates `clap` from 4.4.16 to 4.4.18 - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/v4.4.16...v4.4.18) Updates `fdeflate` from 0.3.3 to 0.3.4 - [Changelog](https://github.com/image-rs/fdeflate/blob/main/CHANGES.md) - [Commits](https://github.com/image-rs/fdeflate/compare/v0.3.3...v0.3.4) Updates `hermit-abi` from 0.3.3 to 0.3.4 - [Release notes](https://github.com/hermitcore/hermit-rs/releases) - [Commits](https://github.com/hermitcore/hermit-rs/compare/hermit-abi-0.3.3...hermit-abi-0.3.4) Updates `linux-raw-sys` from 0.4.12 to 0.4.13 - [Commits](https://github.com/sunfishcode/linux-raw-sys/compare/v0.4.12...v0.4.13) Updates `pkg-config` from 0.3.28 to 0.3.29 - [Changelog](https://github.com/rust-lang/pkg-config-rs/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/pkg-config-rs/compare/0.3.28...0.3.29) Updates `proc-macro2` from 1.0.76 to 1.0.78 - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.76...1.0.78) Updates `rayon` from 1.8.0 to 1.8.1 - [Changelog](https://github.com/rayon-rs/rayon/blob/master/RELEASES.md) - [Commits](https://github.com/rayon-rs/rayon/compare/rayon-core-v1.8.0...rayon-core-v1.8.1) Updates `regex` from 1.10.2 to 1.10.3 - [Release notes](https://github.com/rust-lang/regex/releases) - [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/regex/compare/1.10.2...1.10.3) Updates `smol_str` from 0.2.0 to 0.2.1 - [Commits](https://github.com/rust-analyzer/smol_str/commits) Updates `unicode-bidi` from 0.3.14 to 0.3.15 - [Release notes](https://github.com/servo/unicode-bidi/releases) - [Commits](https://github.com/servo/unicode-bidi/commits) Updates `uuid` from 1.6.1 to 1.7.0 - [Release notes](https://github.com/uuid-rs/uuid/releases) - [Commits](https://github.com/uuid-rs/uuid/compare/1.6.1...1.7.0) --- updated-dependencies: - dependency-name: bitflags dependency-type: direct:production update-type: version-update:semver-patch dependency-group: patch-updates - dependency-name: env_logger dependency-type: direct:production update-type: version-update:semver-patch dependency-group: patch-updates - dependency-name: smallvec dependency-type: direct:production update-type: version-update:semver-minor dependency-group: patch-updates - dependency-name: winit dependency-type: direct:production update-type: version-update:semver-patch dependency-group: patch-updates - dependency-name: anstream dependency-type: indirect update-type: version-update:semver-patch dependency-group: patch-updates - dependency-name: clap dependency-type: indirect update-type: version-update:semver-patch dependency-group: patch-updates - dependency-name: fdeflate dependency-type: indirect update-type: version-update:semver-patch dependency-group: patch-updates - dependency-name: hermit-abi dependency-type: indirect update-type: version-update:semver-patch dependency-group: patch-updates - dependency-name: linux-raw-sys dependency-type: indirect update-type: version-update:semver-patch dependency-group: patch-updates - dependency-name: pkg-config dependency-type: indirect update-type: version-update:semver-patch dependency-group: patch-updates - dependency-name: proc-macro2 dependency-type: indirect update-type: version-update:semver-patch dependency-group: patch-updates - dependency-name: rayon dependency-type: indirect update-type: version-update:semver-patch dependency-group: patch-updates - dependency-name: regex dependency-type: indirect update-type: version-update:semver-patch dependency-group: patch-updates - dependency-name: smol_str dependency-type: indirect update-type: version-update:semver-patch dependency-group: patch-updates - dependency-name: unicode-bidi dependency-type: indirect update-type: version-update:semver-patch dependency-group: patch-updates - dependency-name: uuid dependency-type: indirect update-type: version-update:semver-minor dependency-group: patch-updates ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 138 ++++++++++++++++++++++---------------------- naga/Cargo.toml | 2 +- wgpu-hal/Cargo.toml | 2 +- 3 files changed, 71 insertions(+), 71 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 240dec3584..c493eb6a88 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -68,7 +68,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39b801912a977c3fd52d80511fe1c0c8480c6f957f21ae2ce1b92ffe970cf4b9" dependencies = [ "android-properties", - "bitflags 2.4.1", + "bitflags 2.4.2", "cc", "cesu8", "jni", @@ -105,9 +105,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.7" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd2405b3ac1faab2990b74d728624cd9fd115651fcecc7c2d8daf01376275ba" +checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" dependencies = [ "anstyle", "anstyle-parse", @@ -319,9 +319,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" dependencies = [ "arbitrary", "serde", @@ -410,7 +410,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b50b5a44d59a98c55a9eeb518f39bf7499ba19fd98ee7d22618687f3f10adbf" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "log", "polling", "rustix", @@ -502,9 +502,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.16" +version = "4.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58e54881c004cec7895b0068a0a954cd5d62da01aef83fa35b1e594497bf5445" +checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" dependencies = [ "clap_builder", "clap_derive", @@ -512,9 +512,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.16" +version = "4.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59cb82d7f531603d2fd1f507441cdd35184fa81beff7bd489570de7f773460bb" +checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" dependencies = [ "anstream", "anstyle", @@ -897,7 +897,7 @@ checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" name = "d3d12" version = "0.19.0" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "libloading 0.8.1", "winapi", ] @@ -1177,9 +1177,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" dependencies = [ "humantime", "is-terminal", @@ -1222,9 +1222,9 @@ checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "fdeflate" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "209098dd6dfc4445aa6111f0e98653ac323eaa4dfd212c9ca3931bf9955c31bd" +checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" dependencies = [ "simd-adler32", ] @@ -1595,7 +1595,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "gpu-alloc-types", ] @@ -1605,7 +1605,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", ] [[package]] @@ -1627,7 +1627,7 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "gpu-descriptor-types", "hashbrown", ] @@ -1638,7 +1638,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bf0b36e6f090b7e1d8a4b49c0cb81c1f8376f72198c65dd3ad9ff3556b8b78c" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", ] [[package]] @@ -1663,7 +1663,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af2a7e73e1f34c48da31fb668a907f250794837e08faa144fd24f0b8b741e890" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "com", "libc", "libloading 0.8.1", @@ -1680,9 +1680,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" [[package]] name = "hexf-parse" @@ -1924,7 +1924,7 @@ version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "libc", "redox_syscall 0.4.1", ] @@ -1942,9 +1942,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "lock_api" @@ -2019,7 +2019,7 @@ version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c43f73953f8cbe511f021b58f18c3ce1c3d1ae13fe953293e13345bf83217f25" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "block", "core-graphics-types", "foreign-types 0.5.0", @@ -2058,7 +2058,7 @@ dependencies = [ "arrayvec 0.7.4", "bincode", "bit-set", - "bitflags 2.4.1", + "bitflags 2.4.2", "codespan-reporting", "criterion", "diff", @@ -2145,7 +2145,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "jni-sys", "log", "ndk-sys 0.5.0+25.2.9519653", @@ -2550,9 +2550,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" +checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" [[package]] name = "player" @@ -2565,7 +2565,7 @@ dependencies = [ "serde", "wgpu-core", "wgpu-types", - "winit 0.29.9", + "winit 0.29.10", ] [[package]] @@ -2689,9 +2689,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.76" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -2773,9 +2773,9 @@ checksum = "42a9830a0e1b9fb145ebb365b8bc4ccd75f290f98c0247deafbbe2c75cefb544" [[package]] name = "rayon" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" dependencies = [ "either", "rayon-core", @@ -2783,9 +2783,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -2811,9 +2811,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.2" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", @@ -2823,9 +2823,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a" dependencies = [ "aho-corasick", "memchr", @@ -2851,7 +2851,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ "base64", - "bitflags 2.4.1", + "bitflags 2.4.2", "serde", "serde_derive", ] @@ -2901,7 +2901,7 @@ version = "0.38.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "errno", "libc", "linux-raw-sys", @@ -3109,9 +3109,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.12.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2593d31f82ead8df961d8bd23a64c2ccf2eb5dd34b0a34bfb4dd54011c72009e" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "smithay-client-toolkit" @@ -3138,7 +3138,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60e3d9941fa3bacf7c2bf4b065304faa14164151254cd16ce1b1bc8fc381600f" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "calloop 0.12.3", "calloop-wayland-source", "cursor-icon", @@ -3159,9 +3159,9 @@ dependencies = [ [[package]] name = "smol_str" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c" +checksum = "e6845563ada680337a52d43bb0b29f396f2d911616f6573012645b9e3d048a49" dependencies = [ "serde", ] @@ -3215,7 +3215,7 @@ version = "0.3.0+sdk-1.3.268.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "serde", ] @@ -3527,9 +3527,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-id" @@ -3603,9 +3603,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" +checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" dependencies = [ "getrandom", "serde", @@ -3784,7 +3784,7 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ca7d52347346f5473bf2f56705f360e8440873052e575e55890c4fa57843ed3" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "nix 0.26.4", "wayland-backend", "wayland-scanner 0.31.0", @@ -3808,7 +3808,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "cursor-icon", "wayland-backend", ] @@ -3863,7 +3863,7 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e253d7107ba913923dc253967f35e8561a3c65f914543e46843c88ddd729e21c" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "wayland-backend", "wayland-client 0.31.1", "wayland-scanner 0.31.0", @@ -3875,7 +3875,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "wayland-backend", "wayland-client 0.31.1", "wayland-protocols 0.31.0", @@ -3888,7 +3888,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "wayland-backend", "wayland-client 0.31.1", "wayland-protocols 0.31.0", @@ -3990,7 +3990,7 @@ version = "0.19.0" dependencies = [ "arrayvec 0.7.4", "bit-vec", - "bitflags 2.4.1", + "bitflags 2.4.2", "cfg_aliases", "codespan-reporting", "indexmap", @@ -4040,7 +4040,7 @@ dependencies = [ "wgpu", "wgpu-hal", "wgpu-test", - "winit 0.29.9", + "winit 0.29.10", ] [[package]] @@ -4051,7 +4051,7 @@ dependencies = [ "arrayvec 0.7.4", "ash", "bit-set", - "bitflags 2.4.1", + "bitflags 2.4.2", "block", "cfg-if", "cfg_aliases", @@ -4087,7 +4087,7 @@ dependencies = [ "web-sys", "wgpu-types", "winapi", - "winit 0.29.9", + "winit 0.29.10", ] [[package]] @@ -4095,7 +4095,7 @@ name = "wgpu-info" version = "0.19.0" dependencies = [ "anyhow", - "bitflags 2.4.1", + "bitflags 2.4.2", "env_logger", "pico-args", "serde", @@ -4119,7 +4119,7 @@ version = "0.19.0" dependencies = [ "anyhow", "arrayvec 0.7.4", - "bitflags 2.4.1", + "bitflags 2.4.2", "bytemuck", "cfg-if", "console_log", @@ -4153,7 +4153,7 @@ dependencies = [ name = "wgpu-types" version = "0.19.0" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "js-sys", "serde", "serde_json", @@ -4504,14 +4504,14 @@ dependencies = [ [[package]] name = "winit" -version = "0.29.9" +version = "0.29.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2376dab13e09c01ad8b679f0dbc7038af4ec43d9a91344338e37bd686481550" +checksum = "4c824f11941eeae66ec71111cc2674373c772f482b58939bb4066b642aa2ffcf" dependencies = [ "ahash", "android-activity", "atomic-waker", - "bitflags 2.4.1", + "bitflags 2.4.2", "bytemuck", "calloop 0.12.3", "cfg_aliases", @@ -4612,7 +4612,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6924668544c48c0133152e7eec86d644a056ca3d09275eb8d5cdb9855f9d8699" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "dlib", "log", "once_cell", diff --git a/naga/Cargo.toml b/naga/Cargo.toml index 8e53d457f2..4435a6f211 100644 --- a/naga/Cargo.toml +++ b/naga/Cargo.toml @@ -42,7 +42,7 @@ harness = false [dependencies] arbitrary = { version = "1.3", features = ["derive"], optional = true } -bitflags = "2.2" +bitflags = "2.4" bit-set = "0.5" termcolor = { version = "1.4.1" } # remove termcolor dep when updating to the next version of codespan-reporting diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index 376ff8da27..9dd24ee2b1 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -173,7 +173,7 @@ features = ["wgsl-in"] cfg-if = "1" env_logger = "0.10" glam = "0.25.0" # for ray-traced-triangle example -winit = { version = "0.29.9", features = [ +winit = { version = "0.29.10", features = [ "android-native-activity", ] } # for "halmark" example From 2ee76043077aa0393472eb0cf3deb658c30da8f7 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 19 Jan 2024 12:06:12 -0500 Subject: [PATCH 043/101] fix(const_eval): use component count, not arg. count, for component-wise iter. --- naga/src/proc/constant_evaluator.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 5cffdba86e..a84863066e 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -97,7 +97,7 @@ macro_rules! gen_component_wise_extractor { .and_then(|comps| Ok(handler(comps)?.into())), )+ &Expression::Compose { ty, ref components } => match &eval.types[ty].inner { - &TypeInner::Vector { size: _, scalar } => match scalar.kind { + &TypeInner::Vector { size, scalar } => match scalar.kind { $(ScalarKind::$scalar_kind)|* => { let first_ty = ty; let mut component_groups = @@ -132,7 +132,7 @@ macro_rules! gen_component_wise_extractor { let component_groups = component_groups.into_inner().unwrap(); let mut new_components = ArrayVec::<_, { crate::VectorSize::MAX }>::new(); - for idx in 0..N { + for idx in 0..(size as u8).into() { let group = component_groups .iter() .map(|cs| cs[idx]) From 20f3a9fdf121baf31eab94c4024d83a990d3861a Mon Sep 17 00:00:00 2001 From: Alphyr <47725341+a1phyr@users.noreply.github.com> Date: Mon, 22 Jan 2024 16:27:03 +0100 Subject: [PATCH 044/101] Avoid a clone when creating a Glsl shader (#5118) --- wgpu/src/backend/wgpu_core.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/wgpu/src/backend/wgpu_core.rs b/wgpu/src/backend/wgpu_core.rs index 1d4139e73f..ddc133dd1e 100644 --- a/wgpu/src/backend/wgpu_core.rs +++ b/wgpu/src/backend/wgpu_core.rs @@ -852,13 +852,10 @@ impl crate::Context for ContextWgpuCore { ShaderSource::Glsl { ref shader, stage, - ref defines, + defines, } => { // Parse the given shader code and store its representation. - let options = naga::front::glsl::Options { - stage, - defines: defines.clone(), - }; + let options = naga::front::glsl::Options { stage, defines }; let mut parser = naga::front::glsl::Frontend::default(); let module = parser.parse(&options, shader).unwrap(); From ac8756c2d3618dddb64afadb5d397ece634691de Mon Sep 17 00:00:00 2001 From: Brad Werth Date: Mon, 22 Jan 2024 08:55:42 -0800 Subject: [PATCH 045/101] Release GPU resources from device.trackers, not from lifetime_tracker. (#5075) --- CHANGELOG.md | 4 +++ wgpu-core/src/device/life.rs | 43 -------------------------------- wgpu-core/src/device/resource.rs | 24 +++++++++++++++--- 3 files changed, 25 insertions(+), 46 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 243f35b767..485945fa39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,8 @@ Bottom level categories: ### New features +#### General + - Many numeric built-ins have had a constant evaluation implementation added for them, which allows them to be used in a `const` context: - [#4879](https://github.com/gfx-rs/wgpu/pull/4879) by @ErichDonGubler: - `abs` @@ -64,6 +66,8 @@ Bottom level categories: - `step` - `tan` - `tanh` +- Eager release of GPU resources comes from device.trackers. By @bradwerth in [#5075](https://github.com/gfx-rs/wgpu/pull/5075) + ### Bug Fixes diff --git a/wgpu-core/src/device/life.rs b/wgpu-core/src/device/life.rs index 22699d1068..b454fcaa8f 100644 --- a/wgpu-core/src/device/life.rs +++ b/wgpu-core/src/device/life.rs @@ -837,47 +837,4 @@ impl LifetimeTracker { } pending_callbacks } - - pub(crate) fn release_gpu_resources(&mut self) { - // This is called when the device is lost, which makes every associated - // resource invalid and unusable. This is an opportunity to release all of - // the underlying gpu resources, even though the objects remain visible to - // the user agent. We purge this memory naturally when resources have been - // moved into the appropriate buckets, so this function just needs to - // initiate movement into those buckets, and it can do that by calling - // "destroy" on all the resources we know about which aren't already marked - // for cleanup. - - // During these iterations, we discard all errors. We don't care! - - // Destroy all the mapped buffers. - for buffer in &self.mapped { - let _ = buffer.destroy(); - } - - // Destroy all the unmapped buffers. - for buffer in &self.ready_to_map { - let _ = buffer.destroy(); - } - - // Destroy all the future_suspected_buffers. - for buffer in &self.future_suspected_buffers { - let _ = buffer.destroy(); - } - - // Destroy the buffers in all active submissions. - for submission in &self.active { - for buffer in &submission.mapped { - let _ = buffer.destroy(); - } - } - - // Destroy all the future_suspected_textures. - // TODO: texture.destroy is not implemented - /* - for texture in &self.future_suspected_textures { - let _ = texture.destroy(); - } - */ - } } diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index 547774ec63..3523981562 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -380,7 +380,7 @@ impl Device { let mut device_lost_invocations = SmallVec::new(); if !self.is_valid() && life_tracker.queue_empty() { // We can release gpu resources associated with this device. - life_tracker.release_gpu_resources(); + self.release_gpu_resources(); // If we have a DeviceLostClosure, build an invocation with the // reason DeviceLostReason::Destroyed and no message. @@ -3331,7 +3331,6 @@ impl Device { // It's important to not hold the lock while calling the closure. drop(life_lock); device_lost_closure.call(DeviceLostReason::Unknown, message.to_string()); - life_lock = self.lock_life(); } // 2) Complete any outstanding mapAsync() steps. @@ -3343,7 +3342,26 @@ impl Device { // until they are cleared, and then drop the device. // Eagerly release GPU resources. - life_lock.release_gpu_resources(); + self.release_gpu_resources(); + } + + pub(crate) fn release_gpu_resources(&self) { + // This is called when the device is lost, which makes every associated + // resource invalid and unusable. This is an opportunity to release all of + // the underlying gpu resources, even though the objects remain visible to + // the user agent. We purge this memory naturally when resources have been + // moved into the appropriate buckets, so this function just needs to + // initiate movement into those buckets, and it can do that by calling + // "destroy" on all the resources we know about. + + // During these iterations, we discard all errors. We don't care! + let trackers = self.trackers.lock(); + for buffer in trackers.buffers.used_resources() { + let _ = buffer.destroy(); + } + for texture in trackers.textures.used_resources() { + let _ = texture.destroy(); + } } } From 60a5739df2806b6435ce6875354bf2ba9ba02709 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Tue, 23 Jan 2024 14:30:08 +0100 Subject: [PATCH 046/101] d3d12: Propagate errors when closing command lists (#5125) Before this commit, command lists that we failed to close were used anyway during submit, causing device loss. --- wgpu-core/src/device/queue.rs | 14 +++++++------- wgpu-hal/src/dx12/command.rs | 9 ++++----- wgpu-hal/src/dx12/mod.rs | 1 - 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/wgpu-core/src/device/queue.rs b/wgpu-core/src/device/queue.rs index 43a2d1d982..4e56350d81 100644 --- a/wgpu-core/src/device/queue.rs +++ b/wgpu-core/src/device/queue.rs @@ -228,18 +228,18 @@ impl PendingWrites { .push(TempResource::StagingBuffer(buffer)); } - #[must_use] - fn pre_submit(&mut self) -> Option<&A::CommandBuffer> { + fn pre_submit(&mut self) -> Result, DeviceError> { self.dst_buffers.clear(); self.dst_textures.clear(); if self.is_active { - let cmd_buf = unsafe { self.command_encoder.end_encoding().unwrap() }; + let cmd_buf = unsafe { self.command_encoder.end_encoding()? }; self.is_active = false; self.executing_command_buffers.push(cmd_buf); - self.executing_command_buffers.last() - } else { - None + + return Ok(self.executing_command_buffers.last()); } + + Ok(None) } #[must_use] @@ -1463,7 +1463,7 @@ impl Global { } let refs = pending_writes - .pre_submit() + .pre_submit()? .into_iter() .chain( active_executions diff --git a/wgpu-hal/src/dx12/command.rs b/wgpu-hal/src/dx12/command.rs index 3d05813ed7..f527898d90 100644 --- a/wgpu-hal/src/dx12/command.rs +++ b/wgpu-hal/src/dx12/command.rs @@ -289,14 +289,13 @@ impl crate::CommandEncoder for super::CommandEncoder { } unsafe fn end_encoding(&mut self) -> Result { let raw = self.list.take().unwrap(); - let closed = raw.close().into_result().is_ok(); - Ok(super::CommandBuffer { raw, closed }) + raw.close() + .into_device_result("GraphicsCommandList::close")?; + Ok(super::CommandBuffer { raw }) } unsafe fn reset_all>(&mut self, command_buffers: I) { for cmd_buf in command_buffers { - if cmd_buf.closed { - self.free_lists.push(cmd_buf.raw); - } + self.free_lists.push(cmd_buf.raw); } self.allocator.reset(); } diff --git a/wgpu-hal/src/dx12/mod.rs b/wgpu-hal/src/dx12/mod.rs index 038bb8ca15..3c786f9e4d 100644 --- a/wgpu-hal/src/dx12/mod.rs +++ b/wgpu-hal/src/dx12/mod.rs @@ -386,7 +386,6 @@ impl fmt::Debug for CommandEncoder { #[derive(Debug)] pub struct CommandBuffer { raw: d3d12::GraphicsCommandList, - closed: bool, } unsafe impl Send for CommandBuffer {} From c4b5cc94ad69e4fd5c489b539276370e049764fb Mon Sep 17 00:00:00 2001 From: wayne Date: Tue, 23 Jan 2024 15:25:25 +0000 Subject: [PATCH 047/101] don't panic if naga parsing of shader source fails (#5034) * naga: glsl parser should return singular ParseError similar to wgsl * wgpu: treat glsl the same as wgsl when creating ShaderModule * naga: update glsl parser tests to use new ParseError type * naga: glsl ParseError errors field should be public * wgpu-core: add 'glsl' feature * fix some minor bugs in glsl parse error refactor * naga/wgpu/wgpu-core: improve spirv parse error handling * wgpu-core: feature gate use of glsl and spv naga modules * wgpu: enable wgpu-core glsl and spirv features when appropriate * obey clippy * naga: derive Clone in Type * naga: don't feature gate Clone derivation for Type * obey cargo fmt * wgpu-core: use bytemuck instead of zerocopy * wgpu-core: apply suggested edit * wgpu-core: no need to borrow spirv code * Update wgpu/src/backend/wgpu_core.rs Co-authored-by: Alphyr <47725341+a1phyr@users.noreply.github.com> --------- Co-authored-by: Alphyr <47725341+a1phyr@users.noreply.github.com> --- Cargo.lock | 1 + naga-cli/src/bin/naga.rs | 23 ++------ naga/src/front/glsl/error.rs | 63 +++++++++++++++++++- naga/src/front/glsl/mod.rs | 8 +-- naga/src/front/glsl/parser_tests.rs | 90 +++++++++++++++++------------ naga/src/front/glsl/token.rs | 2 +- naga/src/front/spv/error.rs | 25 ++++++++ naga/src/lib.rs | 6 +- wgpu-core/Cargo.toml | 7 +++ wgpu-core/src/device/global.rs | 8 +++ wgpu-core/src/device/resource.rs | 28 ++++++++- wgpu-core/src/pipeline.rs | 26 +++++++++ wgpu/Cargo.toml | 4 +- wgpu/src/backend/wgpu_core.rs | 10 +--- 14 files changed, 221 insertions(+), 80 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c493eb6a88..0a05008384 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3991,6 +3991,7 @@ dependencies = [ "arrayvec 0.7.4", "bit-vec", "bitflags 2.4.2", + "bytemuck", "cfg_aliases", "codespan-reporting", "indexmap", diff --git a/naga-cli/src/bin/naga.rs b/naga-cli/src/bin/naga.rs index 8960866b34..7a3a0f260c 100644 --- a/naga-cli/src/bin/naga.rs +++ b/naga-cli/src/bin/naga.rs @@ -488,9 +488,10 @@ fn parse_input( }, &input, ) - .unwrap_or_else(|errors| { - let filename = input_path.file_name().and_then(std::ffi::OsStr::to_str); - emit_glsl_parser_error(errors, filename.unwrap_or("glsl"), &input); + .unwrap_or_else(|error| { + let filename = input_path.file_name().and_then(std::ffi::OsStr::to_str).unwrap_or("glsl"); + let mut writer = StandardStream::stderr(ColorChoice::Auto); + error.emit_to_writer_with_path(&mut writer, &input, filename); std::process::exit(1); }), Some(input), @@ -719,22 +720,6 @@ use codespan_reporting::{ }; use naga::WithSpan; -pub fn emit_glsl_parser_error(errors: Vec, filename: &str, source: &str) { - let files = SimpleFile::new(filename, source); - let config = codespan_reporting::term::Config::default(); - let writer = StandardStream::stderr(ColorChoice::Auto); - - for err in errors { - let mut diagnostic = Diagnostic::error().with_message(err.kind.to_string()); - - if let Some(range) = err.meta.to_range() { - diagnostic = diagnostic.with_labels(vec![Label::primary((), range)]); - } - - term::emit(&mut writer.lock(), &config, &files, &diagnostic).expect("cannot write error"); - } -} - pub fn emit_annotated_error(ann_err: &WithSpan, filename: &str, source: &str) { let files = SimpleFile::new(filename, source); let config = codespan_reporting::term::Config::default(); diff --git a/naga/src/front/glsl/error.rs b/naga/src/front/glsl/error.rs index d6e3586687..bd16ee30bc 100644 --- a/naga/src/front/glsl/error.rs +++ b/naga/src/front/glsl/error.rs @@ -1,7 +1,11 @@ use super::token::TokenValue; use crate::{proc::ConstantEvaluatorError, Span}; +use codespan_reporting::diagnostic::{Diagnostic, Label}; +use codespan_reporting::files::SimpleFile; +use codespan_reporting::term; use pp_rs::token::PreprocessorError; use std::borrow::Cow; +use termcolor::{NoColor, WriteColor}; use thiserror::Error; fn join_with_comma(list: &[ExpectedToken]) -> String { @@ -18,7 +22,7 @@ fn join_with_comma(list: &[ExpectedToken]) -> String { } /// One of the expected tokens returned in [`InvalidToken`](ErrorKind::InvalidToken). -#[derive(Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub enum ExpectedToken { /// A specific token was expected. Token(TokenValue), @@ -55,7 +59,7 @@ impl std::fmt::Display for ExpectedToken { } /// Information about the cause of an error. -#[derive(Debug, Error)] +#[derive(Clone, Debug, Error)] #[cfg_attr(test, derive(PartialEq))] pub enum ErrorKind { /// Whilst parsing as encountered an unexpected EOF. @@ -123,7 +127,7 @@ impl From for ErrorKind { } /// Error returned during shader parsing. -#[derive(Debug, Error)] +#[derive(Clone, Debug, Error)] #[error("{kind}")] #[cfg_attr(test, derive(PartialEq))] pub struct Error { @@ -132,3 +136,56 @@ pub struct Error { /// Holds information about the range of the source code where the error happened. pub meta: Span, } + +/// A collection of errors returned during shader parsing. +#[derive(Clone, Debug)] +#[cfg_attr(test, derive(PartialEq))] +pub struct ParseError { + pub errors: Vec, +} + +impl ParseError { + pub fn emit_to_writer(&self, writer: &mut impl WriteColor, source: &str) { + self.emit_to_writer_with_path(writer, source, "glsl"); + } + + pub fn emit_to_writer_with_path(&self, writer: &mut impl WriteColor, source: &str, path: &str) { + let path = path.to_string(); + let files = SimpleFile::new(path, source); + let config = codespan_reporting::term::Config::default(); + + for err in &self.errors { + let mut diagnostic = Diagnostic::error().with_message(err.kind.to_string()); + + if let Some(range) = err.meta.to_range() { + diagnostic = diagnostic.with_labels(vec![Label::primary((), range)]); + } + + term::emit(writer, &config, &files, &diagnostic).expect("cannot write error"); + } + } + + pub fn emit_to_string(&self, source: &str) -> String { + let mut writer = NoColor::new(Vec::new()); + self.emit_to_writer(&mut writer, source); + String::from_utf8(writer.into_inner()).unwrap() + } +} + +impl std::fmt::Display for ParseError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + self.errors.iter().try_for_each(|e| write!(f, "{e:?}")) + } +} + +impl std::error::Error for ParseError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + None + } +} + +impl From> for ParseError { + fn from(errors: Vec) -> Self { + Self { errors } + } +} diff --git a/naga/src/front/glsl/mod.rs b/naga/src/front/glsl/mod.rs index 49624a9433..395111d97b 100644 --- a/naga/src/front/glsl/mod.rs +++ b/naga/src/front/glsl/mod.rs @@ -13,7 +13,7 @@ To begin, take a look at the documentation for the [`Frontend`]. */ pub use ast::{Precision, Profile}; -pub use error::{Error, ErrorKind, ExpectedToken}; +pub use error::{Error, ErrorKind, ExpectedToken, ParseError}; pub use token::TokenValue; use crate::{proc::Layouter, FastHashMap, FastHashSet, Handle, Module, ShaderStage, Span, Type}; @@ -196,7 +196,7 @@ impl Frontend { &mut self, options: &Options, source: &str, - ) -> std::result::Result> { + ) -> std::result::Result { self.reset(options.stage); let lexer = lex::Lexer::new(source, &options.defines); @@ -207,12 +207,12 @@ impl Frontend { if self.errors.is_empty() { Ok(module) } else { - Err(std::mem::take(&mut self.errors)) + Err(std::mem::take(&mut self.errors).into()) } } Err(e) => { self.errors.push(e); - Err(std::mem::take(&mut self.errors)) + Err(std::mem::take(&mut self.errors).into()) } } } diff --git a/naga/src/front/glsl/parser_tests.rs b/naga/src/front/glsl/parser_tests.rs index 0f4fbab22f..259052cd27 100644 --- a/naga/src/front/glsl/parser_tests.rs +++ b/naga/src/front/glsl/parser_tests.rs @@ -1,7 +1,7 @@ use super::{ ast::Profile, error::ExpectedToken, - error::{Error, ErrorKind}, + error::{Error, ErrorKind, ParseError}, token::TokenValue, Frontend, Options, Span, }; @@ -21,10 +21,12 @@ fn version() { ) .err() .unwrap(), - vec![Error { - kind: ErrorKind::InvalidVersion(99000), - meta: Span::new(9, 14) - }], + ParseError { + errors: vec![Error { + kind: ErrorKind::InvalidVersion(99000), + meta: Span::new(9, 14) + }], + }, ); assert_eq!( @@ -35,10 +37,12 @@ fn version() { ) .err() .unwrap(), - vec![Error { - kind: ErrorKind::InvalidVersion(449), - meta: Span::new(9, 12) - }] + ParseError { + errors: vec![Error { + kind: ErrorKind::InvalidVersion(449), + meta: Span::new(9, 12) + }] + }, ); assert_eq!( @@ -49,10 +53,12 @@ fn version() { ) .err() .unwrap(), - vec![Error { - kind: ErrorKind::InvalidProfile("smart".into()), - meta: Span::new(13, 18), - }] + ParseError { + errors: vec![Error { + kind: ErrorKind::InvalidProfile("smart".into()), + meta: Span::new(13, 18), + }] + }, ); assert_eq!( @@ -63,19 +69,21 @@ fn version() { ) .err() .unwrap(), - vec![ - Error { - kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedHash,), - meta: Span::new(27, 28), - }, - Error { - kind: ErrorKind::InvalidToken( - TokenValue::Identifier("version".into()), - vec![ExpectedToken::Eof] - ), - meta: Span::new(28, 35) - } - ] + ParseError { + errors: vec![ + Error { + kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedHash,), + meta: Span::new(27, 28), + }, + Error { + kind: ErrorKind::InvalidToken( + TokenValue::Identifier("version".into()), + vec![ExpectedToken::Eof] + ), + meta: Span::new(28, 35) + } + ] + }, ); // valid versions @@ -447,10 +455,12 @@ fn functions() { ) .err() .unwrap(), - vec![Error { - kind: ErrorKind::SemanticError("Function already defined".into()), - meta: Span::new(134, 152), - }] + ParseError { + errors: vec![Error { + kind: ErrorKind::SemanticError("Function already defined".into()), + meta: Span::new(134, 152), + }] + }, ); println!(); @@ -626,10 +636,12 @@ fn implicit_conversions() { ) .err() .unwrap(), - vec![Error { - kind: ErrorKind::SemanticError("Unknown function \'test\'".into()), - meta: Span::new(156, 165), - }] + ParseError { + errors: vec![Error { + kind: ErrorKind::SemanticError("Unknown function \'test\'".into()), + meta: Span::new(156, 165), + }] + }, ); assert_eq!( @@ -648,10 +660,12 @@ fn implicit_conversions() { ) .err() .unwrap(), - vec![Error { - kind: ErrorKind::SemanticError("Ambiguous best function for \'test\'".into()), - meta: Span::new(158, 165), - }] + ParseError { + errors: vec![Error { + kind: ErrorKind::SemanticError("Ambiguous best function for \'test\'".into()), + meta: Span::new(158, 165), + }] + } ); } diff --git a/naga/src/front/glsl/token.rs b/naga/src/front/glsl/token.rs index 4c3b5d4a25..303723a27b 100644 --- a/naga/src/front/glsl/token.rs +++ b/naga/src/front/glsl/token.rs @@ -20,7 +20,7 @@ pub struct Token { /// /// This type is exported since it's returned in the /// [`InvalidToken`](super::ErrorKind::InvalidToken) error. -#[derive(Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub enum TokenValue { Identifier(String), diff --git a/naga/src/front/spv/error.rs b/naga/src/front/spv/error.rs index 2f9bf2d1bc..af025636c0 100644 --- a/naga/src/front/spv/error.rs +++ b/naga/src/front/spv/error.rs @@ -1,5 +1,9 @@ use super::ModuleState; use crate::arena::Handle; +use codespan_reporting::diagnostic::Diagnostic; +use codespan_reporting::files::SimpleFile; +use codespan_reporting::term; +use termcolor::{NoColor, WriteColor}; #[derive(Debug, thiserror::Error)] pub enum Error { @@ -127,3 +131,24 @@ pub enum Error { )] NonBindingArrayOfImageOrSamplers, } + +impl Error { + pub fn emit_to_writer(&self, writer: &mut impl WriteColor, source: &str) { + self.emit_to_writer_with_path(writer, source, "glsl"); + } + + pub fn emit_to_writer_with_path(&self, writer: &mut impl WriteColor, source: &str, path: &str) { + let path = path.to_string(); + let files = SimpleFile::new(path, source); + let config = codespan_reporting::term::Config::default(); + let diagnostic = Diagnostic::error().with_message(format!("{self:?}")); + + term::emit(writer, &config, &files, &diagnostic).expect("cannot write error"); + } + + pub fn emit_to_string(&self, source: &str) -> String { + let mut writer = NoColor::new(Vec::new()); + self.emit_to_writer(&mut writer, source); + String::from_utf8(writer.into_inner()).unwrap() + } +} diff --git a/naga/src/lib.rs b/naga/src/lib.rs index bfd8359d88..5c63e7db4a 100644 --- a/naga/src/lib.rs +++ b/naga/src/lib.rs @@ -687,8 +687,7 @@ pub enum ImageClass { } /// A data type declared in the module. -#[derive(Debug, Eq, Hash, PartialEq)] -#[cfg_attr(feature = "clone", derive(Clone))] +#[derive(Clone, Debug, Eq, Hash, PartialEq)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] @@ -700,8 +699,7 @@ pub struct Type { } /// Enum with additional information, depending on the kind of type. -#[derive(Debug, Eq, Hash, PartialEq)] -#[cfg_attr(feature = "clone", derive(Clone))] +#[derive(Clone, Debug, Eq, Hash, PartialEq)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] diff --git a/wgpu-core/Cargo.toml b/wgpu-core/Cargo.toml index 28edac35b5..95507bd7e2 100644 --- a/wgpu-core/Cargo.toml +++ b/wgpu-core/Cargo.toml @@ -59,6 +59,12 @@ serial-pass = ["serde", "wgt/serde", "arrayvec/serde"] ## Enable `ShaderModuleSource::Wgsl` wgsl = ["naga/wgsl-in"] +## Enable `ShaderModuleSource::Glsl` +glsl = ["naga/glsl-in"] + +## Enable `ShaderModuleSource::SpirV` +spirv = ["naga/spv-in", "dep:bytemuck"] + ## Implement `Send` and `Sync` on Wasm, but only if atomics are not enabled. ## ## WebGL/WebGPU objects can not be shared between threads. @@ -93,6 +99,7 @@ dx12 = ["hal/dx12"] arrayvec = "0.7" bit-vec = "0.6" bitflags = "2" +bytemuck = { version = "1.14", optional = true } codespan-reporting = "0.11" indexmap = "2" log = "0.4" diff --git a/wgpu-core/src/device/global.rs b/wgpu-core/src/device/global.rs index f7cfc1da15..54d8ed61df 100644 --- a/wgpu-core/src/device/global.rs +++ b/wgpu-core/src/device/global.rs @@ -1189,6 +1189,14 @@ impl Global { pipeline::ShaderModuleSource::Wgsl(ref code) => { trace.make_binary("wgsl", code.as_bytes()) } + #[cfg(feature = "glsl")] + pipeline::ShaderModuleSource::Glsl(ref code, _) => { + trace.make_binary("glsl", code.as_bytes()) + } + #[cfg(feature = "spirv")] + pipeline::ShaderModuleSource::SpirV(ref code, _) => { + trace.make_binary("spirv", bytemuck::cast_slice::(code)) + } pipeline::ShaderModuleSource::Naga(ref module) => { let string = ron::ser::to_string_pretty(module, ron::ser::PrettyConfig::default()) diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index 3523981562..b5de57f80f 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -1309,7 +1309,7 @@ impl Device { let (module, source) = match source { #[cfg(feature = "wgsl")] pipeline::ShaderModuleSource::Wgsl(code) => { - profiling::scope!("naga::wgsl::parse_str"); + profiling::scope!("naga::front::wgsl::parse_str"); let module = naga::front::wgsl::parse_str(&code).map_err(|inner| { pipeline::CreateShaderModuleError::Parsing(pipeline::ShaderError { source: code.to_string(), @@ -1319,6 +1319,32 @@ impl Device { })?; (Cow::Owned(module), code.into_owned()) } + #[cfg(feature = "spirv")] + pipeline::ShaderModuleSource::SpirV(spv, options) => { + let parser = naga::front::spv::Frontend::new(spv.iter().cloned(), &options); + profiling::scope!("naga::front::spv::Frontend"); + let module = parser.parse().map_err(|inner| { + pipeline::CreateShaderModuleError::ParsingSpirV(pipeline::ShaderError { + source: String::new(), + label: desc.label.as_ref().map(|l| l.to_string()), + inner: Box::new(inner), + }) + })?; + (Cow::Owned(module), String::new()) + } + #[cfg(feature = "glsl")] + pipeline::ShaderModuleSource::Glsl(code, options) => { + let mut parser = naga::front::glsl::Frontend::default(); + profiling::scope!("naga::front::glsl::Frontend.parse"); + let module = parser.parse(&options, &code).map_err(|inner| { + pipeline::CreateShaderModuleError::ParsingGlsl(pipeline::ShaderError { + source: code.to_string(), + label: desc.label.as_ref().map(|l| l.to_string()), + inner: Box::new(inner), + }) + })?; + (Cow::Owned(module), code.into_owned()) + } pipeline::ShaderModuleSource::Naga(module) => (module, String::new()), pipeline::ShaderModuleSource::Dummy(_) => panic!("found `ShaderModuleSource::Dummy`"), }; diff --git a/wgpu-core/src/pipeline.rs b/wgpu-core/src/pipeline.rs index 6e2998235d..1dc2d1eff1 100644 --- a/wgpu-core/src/pipeline.rs +++ b/wgpu-core/src/pipeline.rs @@ -26,6 +26,10 @@ pub(crate) struct LateSizedBufferGroup { pub enum ShaderModuleSource<'a> { #[cfg(feature = "wgsl")] Wgsl(Cow<'a, str>), + #[cfg(feature = "glsl")] + Glsl(Cow<'a, str>, naga::front::glsl::Options), + #[cfg(feature = "spirv")] + SpirV(Cow<'a, [u32]>, naga::front::spv::Options), Naga(Cow<'static, naga::Module>), /// Dummy variant because `Naga` doesn't have a lifetime and without enough active features it /// could be the last one active. @@ -103,6 +107,22 @@ impl fmt::Display for ShaderError { write!(f, "\nShader '{label}' parsing {string}") } } +#[cfg(feature = "glsl")] +impl fmt::Display for ShaderError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let label = self.label.as_deref().unwrap_or_default(); + let string = self.inner.emit_to_string(&self.source); + write!(f, "\nShader '{label}' parsing {string}") + } +} +#[cfg(feature = "spirv")] +impl fmt::Display for ShaderError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let label = self.label.as_deref().unwrap_or_default(); + let string = self.inner.emit_to_string(&self.source); + write!(f, "\nShader '{label}' parsing {string}") + } +} impl fmt::Display for ShaderError> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use codespan_reporting::{ @@ -151,6 +171,12 @@ pub enum CreateShaderModuleError { #[cfg(feature = "wgsl")] #[error(transparent)] Parsing(#[from] ShaderError), + #[cfg(feature = "glsl")] + #[error(transparent)] + ParsingGlsl(#[from] ShaderError), + #[cfg(feature = "spirv")] + #[error(transparent)] + ParsingSpirV(#[from] ShaderError), #[error("Failed to generate the backend-specific code")] Generation, #[error(transparent)] diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index 813bc71f57..cc97e4d249 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -56,10 +56,10 @@ webgl = ["hal", "wgc/gles"] # -------------------------------------------------------------------- ## Enable accepting SPIR-V shaders as input. -spirv = ["naga/spv-in"] +spirv = ["naga/spv-in", "wgc/spirv"] ## Enable accepting GLSL shaders as input. -glsl = ["naga/glsl-in"] +glsl = ["naga/glsl-in", "wgc/glsl"] ## Enable accepting WGSL shaders as input. wgsl = ["wgc?/wgsl"] diff --git a/wgpu/src/backend/wgpu_core.rs b/wgpu/src/backend/wgpu_core.rs index ddc133dd1e..62f619d64c 100644 --- a/wgpu/src/backend/wgpu_core.rs +++ b/wgpu/src/backend/wgpu_core.rs @@ -844,9 +844,7 @@ impl crate::Context for ContextWgpuCore { strict_capabilities: true, block_ctx_dump_prefix: None, }; - let parser = naga::front::spv::Frontend::new(spv.iter().cloned(), &options); - let module = parser.parse().unwrap(); - wgc::pipeline::ShaderModuleSource::Naga(Owned(module)) + wgc::pipeline::ShaderModuleSource::SpirV(Borrowed(spv), options) } #[cfg(feature = "glsl")] ShaderSource::Glsl { @@ -854,12 +852,8 @@ impl crate::Context for ContextWgpuCore { stage, defines, } => { - // Parse the given shader code and store its representation. let options = naga::front::glsl::Options { stage, defines }; - let mut parser = naga::front::glsl::Frontend::default(); - let module = parser.parse(&options, shader).unwrap(); - - wgc::pipeline::ShaderModuleSource::Naga(Owned(module)) + wgc::pipeline::ShaderModuleSource::Glsl(Borrowed(shader), options) } #[cfg(feature = "wgsl")] ShaderSource::Wgsl(ref code) => wgc::pipeline::ShaderModuleSource::Wgsl(Borrowed(code)), From 8d64915b3c8da527a3a4f085db9124fe0f50fb53 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Tue, 23 Jan 2024 16:31:13 +0100 Subject: [PATCH 048/101] Remove the lock around TextureView::parent (#5126) --- wgpu-core/src/command/render.rs | 16 ++++++++-------- wgpu-core/src/device/life.rs | 10 +--------- wgpu-core/src/device/resource.rs | 12 ++++-------- wgpu-core/src/resource.rs | 2 +- 4 files changed, 14 insertions(+), 26 deletions(-) diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index d4a5770fa8..e172511e21 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -714,7 +714,7 @@ struct RenderAttachment<'a, A: HalApi> { impl TextureView { fn to_render_attachment(&self, usage: hal::TextureUses) -> RenderAttachment { RenderAttachment { - texture: self.parent.read().as_ref().unwrap().clone(), + texture: self.parent.clone(), selector: &self.selector, usage, } @@ -749,7 +749,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { if channel.load_op == LoadOp::Load { pending_discard_init_fixups.extend(texture_memory_actions.register_init_action( &TextureInitTrackerAction { - texture: view.parent.read().as_ref().unwrap().clone(), + texture: view.parent.clone(), range: TextureInitRange::from(view.selector.clone()), // Note that this is needed even if the target is discarded, kind: MemoryInitKind::NeedsInitializedMemory, @@ -758,7 +758,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { } else if channel.store_op == StoreOp::Store { // Clear + Store texture_memory_actions.register_implicit_init( - view.parent.read().as_ref().unwrap(), + &view.parent, TextureInitRange::from(view.selector.clone()), ); } @@ -767,7 +767,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { // discard right away be alright since the texture can't be used // during the pass anyways texture_memory_actions.discard(TextureSurfaceDiscard { - texture: view.parent.read().as_ref().unwrap().clone(), + texture: view.parent.clone(), mip_level: view.selector.mips.start, layer: view.selector.layers.start, }); @@ -936,7 +936,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { if need_init_beforehand { pending_discard_init_fixups.extend( texture_memory_actions.register_init_action(&TextureInitTrackerAction { - texture: view.parent.read().as_ref().unwrap().clone(), + texture: view.parent.clone(), range: TextureInitRange::from(view.selector.clone()), kind: MemoryInitKind::NeedsInitializedMemory, }), @@ -954,7 +954,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { if at.depth.store_op != at.stencil.store_op { if !need_init_beforehand { texture_memory_actions.register_implicit_init( - view.parent.read().as_ref().unwrap(), + &view.parent, TextureInitRange::from(view.selector.clone()), ); } @@ -969,7 +969,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { } else if at.depth.store_op == StoreOp::Discard { // Both are discarded using the regular path. discarded_surfaces.push(TextureSurfaceDiscard { - texture: view.parent.read().as_ref().unwrap().clone(), + texture: view.parent.clone(), mip_level: view.selector.mips.start, layer: view.selector.layers.start, }); @@ -1095,7 +1095,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { } texture_memory_actions.register_implicit_init( - resolve_view.parent.read().as_ref().unwrap(), + &resolve_view.parent, TextureInitRange::from(resolve_view.selector.clone()), ); render_attachments diff --git a/wgpu-core/src/device/life.rs b/wgpu-core/src/device/life.rs index b454fcaa8f..eeae617747 100644 --- a/wgpu-core/src/device/life.rs +++ b/wgpu-core/src/device/life.rs @@ -525,20 +525,12 @@ impl LifetimeTracker { fn triage_suspected_texture_views(&mut self, trackers: &Mutex>) -> &mut Self { let mut trackers = trackers.lock(); let resource_map = &mut self.suspected_resources.texture_views; - let mut removed_resources = Self::triage_resources( + Self::triage_resources( resource_map, self.active.as_mut_slice(), &mut trackers.views, |maps| &mut maps.texture_views, ); - removed_resources.drain(..).for_each(|texture_view| { - let mut lock = texture_view.parent.write(); - if let Some(parent_texture) = lock.take() { - self.suspected_resources - .textures - .insert(parent_texture.as_info().id(), parent_texture); - } - }); self } diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index b5de57f80f..2600051b39 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -1178,7 +1178,7 @@ impl Device { Ok(TextureView { raw: Some(raw), - parent: RwLock::new(Some(texture.clone())), + parent: texture.clone(), device: self.clone(), desc: resource::HalTextureViewDescriptor { texture_format: texture.desc.format, @@ -1918,17 +1918,13 @@ impl Device { used: &mut BindGroupStates, used_texture_ranges: &mut Vec>, ) -> Result<(), binding_model::CreateBindGroupError> { - let texture = view.parent.read(); - let texture_id = texture.as_ref().unwrap().as_info().id(); + let texture = &view.parent; + let texture_id = texture.as_info().id(); // Careful here: the texture may no longer have its own ref count, // if it was deleted by the user. let texture = used .textures - .add_single( - texture.as_ref().unwrap(), - Some(view.selector.clone()), - internal_use, - ) + .add_single(texture, Some(view.selector.clone()), internal_use) .ok_or(binding_model::CreateBindGroupError::InvalidTexture( texture_id, ))?; diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index 0d337d12c0..39b026feb3 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -1172,7 +1172,7 @@ pub enum TextureViewNotRenderableReason { pub struct TextureView { pub(crate) raw: Option, // if it's a surface texture - it's none - pub(crate) parent: RwLock>>>, + pub(crate) parent: Arc>, pub(crate) device: Arc>, //TODO: store device_id for quick access? pub(crate) desc: HalTextureViewDescriptor, From 6440af03a6a7b64d225d52c85118343a87c45656 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Tue, 23 Jan 2024 19:18:21 -0800 Subject: [PATCH 049/101] Join threads in MULTITHREADED_COMPUTE example. (#5129) Join all threads before returning from the test case, to ensure that we don't return from `main` until all open `Device`s have been dropped. This avoids a race condition in glibc in which a thread calling `dlclose` can unmap a shared library's code even while the main thread is still running its finalization functions. (See #5084 for details.) Joining all threads before returning from the test ensures that the Vulkan loader has finished `dlclose`-ing the Vulkan validation layer shared library before `main` returns. Remove `skip` for this test on GL/llvmpipe. With this change, that has not been observed to crash. Without it, the test crashes within ten runs or so. Fixes #5084. Fixed #4285. --- CHANGELOG.md | 4 +++ examples/src/hello_compute/tests.rs | 38 ++++++++++++++++------------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 485945fa39..cbdac26b4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,6 +75,10 @@ Bottom level categories: - In Surface::configure and Surface::present, fix the current GL context not being unset when releasing the lock that guards access to making the context current. This was causing other threads to panic when trying to make the context current. By @Imberflur in [#5087](https://github.com/gfx-rs/wgpu/pull/5087). +#### Tests + +- Fix intermittent crashes on Linux in the `multithreaded_compute` test. By @jimblandy in [#5129](https://github.com/gfx-rs/wgpu/pull/5129). + ## v0.19.0 (2024-01-17) This release includes: diff --git a/examples/src/hello_compute/tests.rs b/examples/src/hello_compute/tests.rs index 8021e191ed..f4554d7de5 100644 --- a/examples/src/hello_compute/tests.rs +++ b/examples/src/hello_compute/tests.rs @@ -57,9 +57,7 @@ static MULTITHREADED_COMPUTE: GpuTestConfiguration = GpuTestConfiguration::new() TestParameters::default() .downlevel_flags(wgpu::DownlevelFlags::COMPUTE_SHADERS) .limits(wgpu::Limits::downlevel_defaults()) - .skip(FailureCase::adapter("V3D")) - // Segfaults on linux CI only https://github.com/gfx-rs/wgpu/issues/4285 - .skip(FailureCase::backend_adapter(wgpu::Backends::GL, "llvmpipe")), + .skip(FailureCase::adapter("V3D")), ) .run_sync(|ctx| { use std::{sync::mpsc, sync::Arc, thread, time::Duration}; @@ -69,25 +67,31 @@ static MULTITHREADED_COMPUTE: GpuTestConfiguration = GpuTestConfiguration::new() let thread_count = 8; let (tx, rx) = mpsc::channel(); - for _ in 0..thread_count { - let tx = tx.clone(); - let ctx = Arc::clone(&ctx); - thread::spawn(move || { - let input = &[100, 100, 100]; - pollster::block_on(assert_execute_gpu( - &ctx.device, - &ctx.queue, - input, - &[25, 25, 25], - )); - tx.send(true).unwrap(); - }); - } + let workers: Vec<_> = (0..thread_count) + .map(move |_| { + let tx = tx.clone(); + let ctx = Arc::clone(&ctx); + thread::spawn(move || { + let input = &[100, 100, 100]; + pollster::block_on(assert_execute_gpu( + &ctx.device, + &ctx.queue, + input, + &[25, 25, 25], + )); + tx.send(true).unwrap(); + }) + }) + .collect(); for _ in 0..thread_count { rx.recv_timeout(Duration::from_secs(10)) .expect("A thread never completed."); } + + for worker in workers { + worker.join().unwrap(); + } }); async fn assert_execute_gpu( From b3490de69d4c0107605e7ff2b28cafd2b2ccaa5a Mon Sep 17 00:00:00 2001 From: Okko Hakola Date: Wed, 24 Jan 2024 13:49:18 +0200 Subject: [PATCH 050/101] [d3d12] Avoid panic on instance drop (#5134) --- CHANGELOG.md | 3 +++ wgpu-hal/src/dx12/instance.rs | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cbdac26b4c..53a43857bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -71,6 +71,9 @@ Bottom level categories: ### Bug Fixes +#### General +- Fix `panic!` when dropping `Instance` without `InstanceFlags::VALIDATION`. By @hakolao in [#5134](https://github.com/gfx-rs/wgpu/pull/5134) + #### WGL - In Surface::configure and Surface::present, fix the current GL context not being unset when releasing the lock that guards access to making the context current. This was causing other threads to panic when trying to make the context current. By @Imberflur in [#5087](https://github.com/gfx-rs/wgpu/pull/5087). diff --git a/wgpu-hal/src/dx12/instance.rs b/wgpu-hal/src/dx12/instance.rs index 7bf5f3ef75..47e4463d2b 100644 --- a/wgpu-hal/src/dx12/instance.rs +++ b/wgpu-hal/src/dx12/instance.rs @@ -7,7 +7,9 @@ use std::{mem, sync::Arc}; impl Drop for super::Instance { fn drop(&mut self) { - crate::auxil::dxgi::exception::unregister_exception_handler(); + if self.flags.contains(wgt::InstanceFlags::VALIDATION) { + crate::auxil::dxgi::exception::unregister_exception_handler(); + } } } From 96b1e162c5a421615143b0c156fe23b56988cad3 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Wed, 24 Jan 2024 12:36:23 +0100 Subject: [PATCH 051/101] Request INDIRECT_FIRST_INSTANCE feature in vertex_indices test --- tests/tests/vertex_indices/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/tests/vertex_indices/mod.rs b/tests/tests/vertex_indices/mod.rs index 156df2d06f..745eeff8c3 100644 --- a/tests/tests/vertex_indices/mod.rs +++ b/tests/tests/vertex_indices/mod.rs @@ -465,6 +465,7 @@ static VERTEX_INDICES: GpuTestConfiguration = GpuTestConfiguration::new() .parameters( TestParameters::default() .test_features_limits() - .features(wgpu::Features::VERTEX_WRITABLE_STORAGE), + .features(wgpu::Features::VERTEX_WRITABLE_STORAGE) + .features(wgpu::Features::INDIRECT_FIRST_INSTANCE), ) .run_async(vertex_index_common); From b0e4734a7ee88863ae746cbcc7257cbf6dbe31f9 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Wed, 24 Jan 2024 10:40:16 +0100 Subject: [PATCH 052/101] Differentiate between device loss caused by an error and caused by dropping the device --- tests/tests/device.rs | 4 ++-- wgpu-core/src/device/global.rs | 2 +- wgpu-types/src/lib.rs | 7 +++++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/tests/device.rs b/tests/tests/device.rs index 5ab54927f8..56f5251b92 100644 --- a/tests/tests/device.rs +++ b/tests/tests/device.rs @@ -531,8 +531,8 @@ static DEVICE_DROP_THEN_LOST: GpuTestConfiguration = GpuTestConfiguration::new() let callback = Box::new(move |reason, message| { was_called_clone.store(true, std::sync::atomic::Ordering::SeqCst); assert!( - matches!(reason, wgt::DeviceLostReason::Unknown), - "Device lost info reason should match DeviceLostReason::Unknown." + matches!(reason, wgt::DeviceLostReason::Dropped), + "Device lost info reason should match DeviceLostReason::Dropped." ); assert!( message == "Device dropped.", diff --git a/wgpu-core/src/device/global.rs b/wgpu-core/src/device/global.rs index 54d8ed61df..c3b3706108 100644 --- a/wgpu-core/src/device/global.rs +++ b/wgpu-core/src/device/global.rs @@ -2237,7 +2237,7 @@ impl Global { if let Some(device) = hub.devices.unregister(device_id) { let device_lost_closure = device.lock_life().device_lost_closure.take(); if let Some(closure) = device_lost_closure { - closure.call(DeviceLostReason::Unknown, String::from("Device dropped.")); + closure.call(DeviceLostReason::Dropped, String::from("Device dropped.")); } // The things `Device::prepare_to_die` takes care are mostly diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index cfc2af253e..fa2a8df5f8 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -7099,4 +7099,11 @@ pub enum DeviceLostReason { Unknown = 0, /// After Device::destroy Destroyed = 1, + /// After Device::drop + /// + /// WebGPU does not invoke the device lost callback when the device is + /// dropped to prevent garbage collection from being observable. In wgpu, + /// we invoke the callback on drop to help with managing memory owned by + /// the callback. + Dropped = 2, } From 7d0f656dd9295365029ab2b2bf02a22e6a0c8f9b Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Wed, 24 Jan 2024 20:55:20 +0100 Subject: [PATCH 053/101] Snatch texture views of destroyed textures (#5131) --- wgpu-core/src/command/render.rs | 24 +++++++++++++++++----- wgpu-core/src/device/global.rs | 6 ++++++ wgpu-core/src/device/resource.rs | 11 ++++++++--- wgpu-core/src/present.rs | 3 ++- wgpu-core/src/resource.rs | 34 ++++++++++++++++++++++++++++---- 5 files changed, 65 insertions(+), 13 deletions(-) diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index e172511e21..bf5bf9ad58 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -1,4 +1,5 @@ use crate::resource::Resource; +use crate::snatch::SnatchGuard; use crate::{ api_log, binding_model::BindError, @@ -533,6 +534,8 @@ pub enum RenderPassErrorInner { Encoder(#[from] CommandEncoderError), #[error("Attachment texture view {0:?} is invalid")] InvalidAttachment(id::TextureViewId), + #[error("Attachment texture view {0:?} is invalid")] + InvalidResolveTarget(id::TextureViewId), #[error("The format of the depth-stencil attachment ({0:?}) is not a depth-stencil format")] InvalidDepthStencilAttachmentFormat(wgt::TextureFormat), #[error("The format of the {location} ({format:?}) is not resolvable")] @@ -789,6 +792,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { buffer_guard: &'a Storage, id::BufferId>, texture_guard: &'a Storage, id::TextureId>, query_set_guard: &'a Storage, id::QuerySetId>, + snatch_guard: &SnatchGuard<'a>, ) -> Result { profiling::scope!("RenderPassInfo::start"); @@ -993,7 +997,9 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { depth_stencil = Some(hal::DepthStencilAttachment { target: hal::Attachment { - view: view.raw(), + view: view + .raw(snatch_guard) + .ok_or_else(|| RenderPassErrorInner::InvalidAttachment(view.info.id()))?, usage, }, depth_ops: at.depth.hal_ops(), @@ -1102,14 +1108,18 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { .push(resolve_view.to_render_attachment(hal::TextureUses::COLOR_TARGET)); hal_resolve_target = Some(hal::Attachment { - view: resolve_view.raw(), + view: resolve_view.raw(snatch_guard).ok_or_else(|| { + RenderPassErrorInner::InvalidResolveTarget(resolve_view.info.id()) + })?, usage: hal::TextureUses::COLOR_TARGET, }); } colors.push(Some(hal::ColorAttachment { target: hal::Attachment { - view: color_view.raw(), + view: color_view.raw(snatch_guard).ok_or_else(|| { + RenderPassErrorInner::InvalidAttachment(color_view.info.id()) + })?, usage: hal::TextureUses::COLOR_TARGET, }, resolve_target: hal_resolve_target, @@ -1209,6 +1219,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { fn finish( mut self, raw: &mut A::CommandEncoder, + snatch_guard: &SnatchGuard, ) -> Result<(UsageScope, SurfacesInDiscardState), RenderPassErrorInner> { profiling::scope!("RenderPassInfo::finish"); unsafe { @@ -1256,7 +1267,9 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { color_attachments: &[], depth_stencil_attachment: Some(hal::DepthStencilAttachment { target: hal::Attachment { - view: view.raw(), + view: view.raw(snatch_guard).ok_or_else(|| { + RenderPassErrorInner::InvalidAttachment(view.info.id()) + })?, usage: hal::TextureUses::DEPTH_STENCIL_WRITE, }, depth_ops, @@ -1386,6 +1399,7 @@ impl Global { &*buffer_guard, &*texture_guard, &*query_set_guard, + &snatch_guard, ) .map_pass_err(pass_scope)?; @@ -2366,7 +2380,7 @@ impl Global { log::trace!("Merging renderpass into cmd_buf {:?}", encoder_id); let (trackers, pending_discard_init_fixups) = - info.finish(raw).map_pass_err(pass_scope)?; + info.finish(raw, &snatch_guard).map_pass_err(pass_scope)?; encoder.close().map_pass_err(pass_scope)?; (trackers, pending_discard_init_fixups) diff --git a/wgpu-core/src/device/global.rs b/wgpu-core/src/device/global.rs index c3b3706108..9435993eab 100644 --- a/wgpu-core/src/device/global.rs +++ b/wgpu-core/src/device/global.rs @@ -818,6 +818,12 @@ impl Global { }; let (id, resource) = fid.assign(view); + + { + let mut views = texture.views.lock(); + views.push(Arc::downgrade(&resource)); + } + api_log!("Texture::create_view({texture_id:?}) -> {id:?}"); device.trackers.lock().views.insert_single(id, resource); return (id, None); diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index 2600051b39..68f5b6d0c4 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -595,6 +595,7 @@ impl Device { }, info: ResourceInfo::new(desc.label.borrow_or_default()), clear_mode: RwLock::new(clear_mode), + views: Mutex::new(Vec::new()), } } @@ -1177,7 +1178,7 @@ impl Device { }; Ok(TextureView { - raw: Some(raw), + raw: Snatchable::new(raw), parent: texture.clone(), device: self.clone(), desc: resource::HalTextureViewDescriptor { @@ -2126,7 +2127,9 @@ impl Device { )?; let res_index = hal_textures.len(); hal_textures.push(hal::TextureBinding { - view: view.raw(), + view: view + .raw(&snatch_guard) + .ok_or(Error::InvalidTextureView(id))?, usage: internal_use, }); (res_index, 1) @@ -2152,7 +2155,9 @@ impl Device { &mut used_texture_ranges, )?; hal_textures.push(hal::TextureBinding { - view: view.raw(), + view: view + .raw(&snatch_guard) + .ok_or(Error::InvalidTextureView(id))?, usage: internal_use, }); } diff --git a/wgpu-core/src/present.rs b/wgpu-core/src/present.rs index d7b34497a2..44b741b8c4 100644 --- a/wgpu-core/src/present.rs +++ b/wgpu-core/src/present.rs @@ -32,7 +32,7 @@ use crate::{ }; use hal::{Queue as _, Surface as _}; -use parking_lot::RwLock; +use parking_lot::{Mutex, RwLock}; use thiserror::Error; use wgt::SurfaceStatus as Status; @@ -231,6 +231,7 @@ impl Global { clear_mode: RwLock::new(resource::TextureClearMode::Surface { clear_view: Some(clear_view), }), + views: Mutex::new(Vec::new()), }; let (id, resource) = fid.assign(texture); diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index 39b026feb3..ceab4b2326 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -34,7 +34,7 @@ use std::{ ptr::NonNull, sync::{ atomic::{AtomicBool, AtomicUsize, Ordering}, - Arc, + Arc, Weak, }, }; @@ -741,6 +741,7 @@ pub struct Texture { pub(crate) full_range: TextureSelector, pub(crate) info: ResourceInfo, pub(crate) clear_mode: RwLock>, + pub(crate) views: Mutex>>>, } impl Drop for Texture { @@ -852,8 +853,14 @@ impl Texture { } }; + let views = { + let mut guard = self.views.lock(); + std::mem::take(&mut *guard) + }; + queue::TempResource::DestroyedTexture(Arc::new(DestroyedTexture { raw: Some(raw), + views, device: Arc::clone(&self.device), submission_index: self.info.submission_index(), id: self.info.id.unwrap(), @@ -970,6 +977,7 @@ impl Global { #[derive(Debug)] pub struct DestroyedTexture { raw: Option, + views: Vec>>, device: Arc>, label: String, pub(crate) id: TextureId, @@ -988,6 +996,24 @@ impl DestroyedTexture { impl Drop for DestroyedTexture { fn drop(&mut self) { + let device = &self.device; + for view in self.views.drain(..) { + if let Some(view) = view.upgrade() { + if let Some(raw_view) = view.raw.snatch(device.snatchable_lock.write()) { + resource_log!("Destroy raw TextureView (destroyed) {:?}", view.label()); + + #[cfg(feature = "trace")] + if let Some(t) = self.device.trace.lock().as_mut() { + t.add(trace::Action::DestroyTextureView(view.info.id())); + } + + unsafe { + use hal::Device; + self.device.raw().destroy_texture_view(raw_view); + } + } + } + } if let Some(raw) = self.raw.take() { resource_log!("Destroy raw Texture (destroyed) {:?}", self.label()); @@ -1170,7 +1196,7 @@ pub enum TextureViewNotRenderableReason { #[derive(Debug)] pub struct TextureView { - pub(crate) raw: Option, + pub(crate) raw: Snatchable, // if it's a surface texture - it's none pub(crate) parent: Arc>, pub(crate) device: Arc>, @@ -1203,8 +1229,8 @@ impl Drop for TextureView { } impl TextureView { - pub(crate) fn raw(&self) -> &A::TextureView { - self.raw.as_ref().unwrap() + pub(crate) fn raw<'a>(&'a self, snatch_guard: &'a SnatchGuard) -> Option<&'a A::TextureView> { + self.raw.get(snatch_guard) } } From efb35d4fa1059a514942d375fa5239c6d27cf35a Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Thu, 25 Jan 2024 06:11:43 +0100 Subject: [PATCH 054/101] Snatch bind groups associated with destroyed textures and buffers (#5136) * Make bind groups snatchable * Snatch bindgroups when destroying associated textures and buffers. --- .github/workflows/ci.yml | 4 ++- wgpu-core/src/binding_model.rs | 6 ++--- wgpu-core/src/device/global.rs | 9 +++++++ wgpu-core/src/device/resource.rs | 5 +++- wgpu-core/src/present.rs | 1 + wgpu-core/src/resource.rs | 44 ++++++++++++++++++++++++++++++++ 6 files changed, 64 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6bb8d38245..df275a43ab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -76,7 +76,9 @@ env: jobs: check: # runtime is normally 2-8 minutes - timeout-minutes: 15 + # + # currently high due to documentation time problems on mac. + timeout-minutes: 30 strategy: fail-fast: false diff --git a/wgpu-core/src/binding_model.rs b/wgpu-core/src/binding_model.rs index 39a21f7a13..833920ea35 100644 --- a/wgpu-core/src/binding_model.rs +++ b/wgpu-core/src/binding_model.rs @@ -13,7 +13,7 @@ use crate::{ init_tracker::{BufferInitTrackerAction, TextureInitTrackerAction}, resource::{Resource, ResourceInfo, ResourceType}, resource_log, - snatch::SnatchGuard, + snatch::{SnatchGuard, Snatchable}, track::{BindGroupStates, UsageConflict}, validation::{MissingBufferUsageError, MissingTextureUsageError}, Label, @@ -833,7 +833,7 @@ pub(crate) fn buffer_binding_type_alignment( #[derive(Debug)] pub struct BindGroup { - pub(crate) raw: Option, + pub(crate) raw: Snatchable, pub(crate) device: Arc>, pub(crate) layout: Arc>, pub(crate) info: ResourceInfo, @@ -874,7 +874,7 @@ impl BindGroup { for texture in &self.used_texture_ranges { let _ = texture.texture.raw(guard)?; } - self.raw.as_ref() + self.raw.get(guard) } pub(crate) fn validate_dynamic_bindings( &self, diff --git a/wgpu-core/src/device/global.rs b/wgpu-core/src/device/global.rs index 9435993eab..1872159fcc 100644 --- a/wgpu-core/src/device/global.rs +++ b/wgpu-core/src/device/global.rs @@ -1130,6 +1130,15 @@ impl Global { }; let (id, resource) = fid.assign(bind_group); + + let weak_ref = Arc::downgrade(&resource); + for range in &resource.used_texture_ranges { + range.texture.bind_groups.lock().push(weak_ref.clone()); + } + for range in &resource.used_buffer_ranges { + range.buffer.bind_groups.lock().push(weak_ref.clone()); + } + api_log!("Device::create_bind_group -> {id:?}"); device diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index 68f5b6d0c4..06aedc00f6 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -566,6 +566,7 @@ impl Device { sync_mapped_writes: Mutex::new(None), map_state: Mutex::new(resource::BufferMapState::Idle), info: ResourceInfo::new(desc.label.borrow_or_default()), + bind_groups: Mutex::new(Vec::new()), }) } @@ -596,6 +597,7 @@ impl Device { info: ResourceInfo::new(desc.label.borrow_or_default()), clear_mode: RwLock::new(clear_mode), views: Mutex::new(Vec::new()), + bind_groups: Mutex::new(Vec::new()), } } @@ -615,6 +617,7 @@ impl Device { sync_mapped_writes: Mutex::new(None), map_state: Mutex::new(resource::BufferMapState::Idle), info: ResourceInfo::new(desc.label.borrow_or_default()), + bind_groups: Mutex::new(Vec::new()), } } @@ -2199,7 +2202,7 @@ impl Device { }; Ok(binding_model::BindGroup { - raw: Some(raw), + raw: Snatchable::new(raw), device: self.clone(), layout: layout.clone(), info: ResourceInfo::new(desc.label.borrow_or_default()), diff --git a/wgpu-core/src/present.rs b/wgpu-core/src/present.rs index 44b741b8c4..00a2953ea5 100644 --- a/wgpu-core/src/present.rs +++ b/wgpu-core/src/present.rs @@ -232,6 +232,7 @@ impl Global { clear_view: Some(clear_view), }), views: Mutex::new(Vec::new()), + bind_groups: Mutex::new(Vec::new()), }; let (id, resource) = fid.assign(texture); diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index ceab4b2326..b08216eeeb 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -1,6 +1,7 @@ #[cfg(feature = "trace")] use crate::device::trace; use crate::{ + binding_model::BindGroup, device::{ queue, BufferMapPendingClosure, Device, DeviceError, HostMap, MissingDownlevelFlags, MissingFeatures, @@ -378,6 +379,7 @@ pub struct Buffer { pub(crate) sync_mapped_writes: Mutex>, pub(crate) info: ResourceInfo, pub(crate) map_state: Mutex>, + pub(crate) bind_groups: Mutex>>>, } impl Drop for Buffer { @@ -541,12 +543,18 @@ impl Buffer { } }; + let bind_groups = { + let mut guard = self.bind_groups.lock(); + std::mem::take(&mut *guard) + }; + queue::TempResource::DestroyedBuffer(Arc::new(DestroyedBuffer { raw: Some(raw), device: Arc::clone(&self.device), submission_index: self.info.submission_index(), id: self.info.id.unwrap(), label: self.info.label.clone(), + bind_groups, })) }; @@ -596,6 +604,29 @@ impl Resource for Buffer { } } +fn snatch_and_destroy_bind_groups( + device: &Device, + bind_groups: &[Weak>], +) { + for bind_group in bind_groups { + if let Some(bind_group) = bind_group.upgrade() { + if let Some(raw_bind_group) = bind_group.raw.snatch(device.snatchable_lock.write()) { + resource_log!("Destroy raw BindGroup (destroyed) {:?}", bind_group.label()); + + #[cfg(feature = "trace")] + if let Some(t) = device.trace.lock().as_mut() { + t.add(trace::Action::DestroyBindGroup(bind_group.info.id())); + } + + unsafe { + use hal::Device; + device.raw().destroy_bind_group(raw_bind_group); + } + } + } + } +} + /// A buffer that has been marked as destroyed and is staged for actual deletion soon. #[derive(Debug)] pub struct DestroyedBuffer { @@ -604,6 +635,7 @@ pub struct DestroyedBuffer { label: String, pub(crate) id: BufferId, pub(crate) submission_index: u64, + bind_groups: Vec>>, } impl DestroyedBuffer { @@ -618,6 +650,8 @@ impl DestroyedBuffer { impl Drop for DestroyedBuffer { fn drop(&mut self) { + snatch_and_destroy_bind_groups(&self.device, &self.bind_groups); + if let Some(raw) = self.raw.take() { resource_log!("Destroy raw Buffer (destroyed) {:?}", self.label()); @@ -742,6 +776,7 @@ pub struct Texture { pub(crate) info: ResourceInfo, pub(crate) clear_mode: RwLock>, pub(crate) views: Mutex>>>, + pub(crate) bind_groups: Mutex>>>, } impl Drop for Texture { @@ -858,9 +893,15 @@ impl Texture { std::mem::take(&mut *guard) }; + let bind_groups = { + let mut guard = self.bind_groups.lock(); + std::mem::take(&mut *guard) + }; + queue::TempResource::DestroyedTexture(Arc::new(DestroyedTexture { raw: Some(raw), views, + bind_groups, device: Arc::clone(&self.device), submission_index: self.info.submission_index(), id: self.info.id.unwrap(), @@ -978,6 +1019,7 @@ impl Global { pub struct DestroyedTexture { raw: Option, views: Vec>>, + bind_groups: Vec>>, device: Arc>, label: String, pub(crate) id: TextureId, @@ -997,6 +1039,8 @@ impl DestroyedTexture { impl Drop for DestroyedTexture { fn drop(&mut self) { let device = &self.device; + snatch_and_destroy_bind_groups(device, &self.bind_groups); + for view in self.views.drain(..) { if let Some(view) = view.upgrade() { if let Some(raw_view) = view.raw.snatch(device.snatchable_lock.write()) { From d47534ed9a46956cc8a192b878b7204fedfaafbd Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Thu, 25 Jan 2024 09:06:29 +0100 Subject: [PATCH 055/101] Discard draws when the instance/vertex/index count is zero (#5137) --- wgpu-core/src/command/bundle.rs | 20 +++++++++++++------- wgpu-core/src/command/render.rs | 25 +++++++++++++++++-------- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/wgpu-core/src/command/bundle.rs b/wgpu-core/src/command/bundle.rs index 40e652fef4..aec42a4935 100644 --- a/wgpu-core/src/command/bundle.rs +++ b/wgpu-core/src/command/bundle.rs @@ -514,9 +514,12 @@ impl RenderBundleEncoder { }) .map_pass_err(scope); } - commands.extend(state.flush_vertices()); - commands.extend(state.flush_binds(used_bind_groups, base.dynamic_offsets)); - commands.push(command); + + if instance_count > 0 && vertex_count > 0 { + commands.extend(state.flush_vertices()); + commands.extend(state.flush_binds(used_bind_groups, base.dynamic_offsets)); + commands.push(command); + } } RenderCommand::DrawIndexed { index_count, @@ -556,10 +559,13 @@ impl RenderBundleEncoder { }) .map_pass_err(scope); } - commands.extend(state.flush_index()); - commands.extend(state.flush_vertices()); - commands.extend(state.flush_binds(used_bind_groups, base.dynamic_offsets)); - commands.push(command); + + if instance_count > 0 && index_count > 0 { + commands.extend(state.flush_index()); + commands.extend(state.flush_vertices()); + commands.extend(state.flush_binds(used_bind_groups, base.dynamic_offsets)); + commands.push(command); + } } RenderCommand::MultiDrawIndirect { buffer_id, diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index bf5bf9ad58..f4933d898b 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -1931,7 +1931,14 @@ impl Global { } unsafe { - raw.draw(first_vertex, vertex_count, first_instance, instance_count); + if instance_count > 0 && vertex_count > 0 { + raw.draw( + first_vertex, + vertex_count, + first_instance, + instance_count, + ); + } } } RenderCommand::DrawIndexed { @@ -1972,13 +1979,15 @@ impl Global { } unsafe { - raw.draw_indexed( - first_index, - index_count, - base_vertex, - first_instance, - instance_count, - ); + if instance_count > 0 && index_count > 0 { + raw.draw_indexed( + first_index, + index_count, + base_vertex, + first_instance, + instance_count, + ); + } } } RenderCommand::MultiDrawIndirect { From e2e9ef55474f32742bfdff3ccbac3b2cda4ebf85 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Fri, 26 Jan 2024 09:08:03 +0100 Subject: [PATCH 056/101] Fix the validation of vertex/index/instance ranges in render bundles --- wgpu-core/src/command/bundle.rs | 188 +++++++++++++++++-------------- wgpu-core/src/command/draw.rs | 9 +- wgpu-core/src/command/render.rs | 13 ++- wgpu-core/src/device/resource.rs | 5 + wgpu-core/src/pipeline.rs | 4 + 5 files changed, 131 insertions(+), 88 deletions(-) diff --git a/wgpu-core/src/command/bundle.rs b/wgpu-core/src/command/bundle.rs index aec42a4935..5d474f6a3a 100644 --- a/wgpu-core/src/command/bundle.rs +++ b/wgpu-core/src/command/bundle.rs @@ -96,7 +96,7 @@ use crate::{ hub::Hub, id::{self, RenderBundleId}, init_tracker::{BufferInitTrackerAction, MemoryInitKind, TextureInitTrackerAction}, - pipeline::{self, PipelineFlags, RenderPipeline}, + pipeline::{PipelineFlags, RenderPipeline, VertexStep}, resource::{Resource, ResourceInfo, ResourceType}, resource_log, track::RenderBundleScope, @@ -110,6 +110,91 @@ use thiserror::Error; use hal::CommandEncoder as _; +/// https://gpuweb.github.io/gpuweb/#dom-gpurendercommandsmixin-draw +fn validate_draw( + vertex: &[Option], + step: &[VertexStep], + first_vertex: u32, + vertex_count: u32, + first_instance: u32, + instance_count: u32, +) -> Result<(), DrawError> { + let vertices_end = first_vertex as u64 + vertex_count as u64; + let instances_end = first_instance as u64 + instance_count as u64; + + for (idx, (vbs, step)) in vertex.iter().zip(step).enumerate() { + let Some(vbs) = vbs else { + continue; + }; + + let stride_count = match step.mode { + wgt::VertexStepMode::Vertex => vertices_end, + wgt::VertexStepMode::Instance => instances_end, + }; + + if stride_count == 0 { + continue; + } + + let offset = (stride_count - 1) * step.stride + step.last_stride; + let limit = vbs.range.end - vbs.range.start; + if offset > limit { + return Err(DrawError::VertexOutOfBounds { + step_mode: step.mode, + offset, + limit, + slot: idx as u32, + }); + } + } + + Ok(()) +} + +// See https://gpuweb.github.io/gpuweb/#dom-gpurendercommandsmixin-drawindexed +fn validate_indexed_draw( + vertex: &[Option], + step: &[VertexStep], + index_state: &IndexState, + first_index: u32, + index_count: u32, + first_instance: u32, + instance_count: u32, +) -> Result<(), DrawError> { + let last_index = first_index as u64 + index_count as u64; + let index_limit = index_state.limit(); + if last_index <= index_limit { + return Err(DrawError::IndexBeyondLimit { + last_index, + index_limit, + }); + } + + let stride_count = first_instance as u64 + instance_count as u64; + for (idx, (vbs, step)) in vertex.iter().zip(step).enumerate() { + let Some(vbs) = vbs else { + continue; + }; + + if stride_count == 0 || step.mode != wgt::VertexStepMode::Instance { + continue; + } + + let offset = (stride_count - 1) * step.stride + step.last_stride; + let limit = vbs.range.end - vbs.range.start; + if offset > limit { + return Err(DrawError::VertexOutOfBounds { + step_mode: step.mode, + offset, + limit, + slot: idx as u32, + }); + } + } + + Ok(()) +} + /// Describes a [`RenderBundleEncoder`]. #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] #[cfg_attr(feature = "trace", derive(serde::Serialize))] @@ -495,25 +580,15 @@ impl RenderBundleEncoder { }; let pipeline = state.pipeline(scope)?; let used_bind_groups = pipeline.used_bind_groups; - let vertex_limits = state.vertex_limits(pipeline); - let last_vertex = first_vertex as u64 + vertex_count as u64; - if last_vertex > vertex_limits.vertex_limit { - return Err(DrawError::VertexBeyondLimit { - last_vertex, - vertex_limit: vertex_limits.vertex_limit, - slot: vertex_limits.vertex_limit_slot, - }) - .map_pass_err(scope); - } - let last_instance = first_instance as u64 + instance_count as u64; - if last_instance > vertex_limits.instance_limit { - return Err(DrawError::InstanceBeyondLimit { - last_instance, - instance_limit: vertex_limits.instance_limit, - slot: vertex_limits.instance_limit_slot, - }) - .map_pass_err(scope); - } + + validate_draw( + &state.vertex[..], + &pipeline.steps, + first_vertex, + vertex_count, + first_instance, + instance_count, + ).map_pass_err(scope)?; if instance_count > 0 && vertex_count > 0 { commands.extend(state.flush_vertices()); @@ -539,26 +614,16 @@ impl RenderBundleEncoder { Some(ref index) => index, None => return Err(DrawError::MissingIndexBuffer).map_pass_err(scope), }; - //TODO: validate that base_vertex + max_index() is within the provided range - let vertex_limits = state.vertex_limits(pipeline); - let index_limit = index.limit(); - let last_index = first_index as u64 + index_count as u64; - if last_index > index_limit { - return Err(DrawError::IndexBeyondLimit { - last_index, - index_limit, - }) - .map_pass_err(scope); - } - let last_instance = first_instance as u64 + instance_count as u64; - if last_instance > vertex_limits.instance_limit { - return Err(DrawError::InstanceBeyondLimit { - last_instance, - instance_limit: vertex_limits.instance_limit, - slot: vertex_limits.instance_limit_slot, - }) - .map_pass_err(scope); - } + + validate_indexed_draw( + &state.vertex[..], + &pipeline.steps, + index, + first_index, + index_count, + first_instance, + instance_count, + ).map_pass_err(scope)?; if instance_count > 0 && index_count > 0 { commands.extend(state.flush_index()); @@ -1119,18 +1184,6 @@ struct BindState { is_dirty: bool, } -#[derive(Debug)] -struct VertexLimitState { - /// Length of the shortest vertex rate vertex buffer - vertex_limit: u64, - /// Buffer slot which the shortest vertex rate vertex buffer is bound to - vertex_limit_slot: u32, - /// Length of the shortest instance rate vertex buffer - instance_limit: u64, - /// Buffer slot which the shortest instance rate vertex buffer is bound to - instance_limit_slot: u32, -} - /// The bundle's current pipeline, and some cached information needed for validation. struct PipelineState { /// The pipeline @@ -1138,7 +1191,7 @@ struct PipelineState { /// How this pipeline's vertex shader traverses each vertex buffer, indexed /// by vertex buffer slot number. - steps: Vec, + steps: Vec, /// Ranges of push constants this pipeline uses, copied from the pipeline /// layout. @@ -1223,35 +1276,6 @@ struct State { } impl State { - fn vertex_limits(&self, pipeline: &PipelineState) -> VertexLimitState { - let mut vert_state = VertexLimitState { - vertex_limit: u32::MAX as u64, - vertex_limit_slot: 0, - instance_limit: u32::MAX as u64, - instance_limit_slot: 0, - }; - for (idx, (vbs, step)) in self.vertex.iter().zip(&pipeline.steps).enumerate() { - if let Some(ref vbs) = *vbs { - let limit = (vbs.range.end - vbs.range.start) / step.stride; - match step.mode { - wgt::VertexStepMode::Vertex => { - if limit < vert_state.vertex_limit { - vert_state.vertex_limit = limit; - vert_state.vertex_limit_slot = idx as _; - } - } - wgt::VertexStepMode::Instance => { - if limit < vert_state.instance_limit { - vert_state.instance_limit = limit; - vert_state.instance_limit_slot = idx as _; - } - } - } - } - } - vert_state - } - /// Return the id of the current pipeline, if any. fn pipeline_id(&self) -> Option { self.pipeline.as_ref().map(|p| p.pipeline.as_info().id()) diff --git a/wgpu-core/src/command/draw.rs b/wgpu-core/src/command/draw.rs index 6dc8b4fbb9..058ba81f95 100644 --- a/wgpu-core/src/command/draw.rs +++ b/wgpu-core/src/command/draw.rs @@ -8,7 +8,7 @@ use crate::{ track::UsageConflict, validation::{MissingBufferUsageError, MissingTextureUsageError}, }; -use wgt::{BufferAddress, BufferSize, Color}; +use wgt::{BufferAddress, BufferSize, Color, VertexStepMode}; use std::num::NonZeroU32; use thiserror::Error; @@ -33,6 +33,13 @@ pub enum DrawError { vertex_limit: u64, slot: u32, }, + #[error("{step_mode:?} buffer out of bounds at slot {slot}. Offset {offset} beyond limit {limit}. Did you bind the correct `Vertex` step-rate vertex buffer?")] + VertexOutOfBounds { + step_mode: VertexStepMode, + offset: u64, + limit: u64, + slot: u32, + }, #[error("Instance {last_instance} extends beyond limit {instance_limit} imposed by the buffer in slot {slot}. Did you bind the correct `Instance` step-rate vertex buffer?")] InstanceBeyondLimit { last_instance: u64, diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index f4933d898b..9f31d3c6d0 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -361,6 +361,7 @@ impl VertexBufferState { total_size: 0, step: pipeline::VertexStep { stride: 0, + last_stride: 0, mode: VertexStepMode::Vertex, }, bound: false, @@ -384,11 +385,13 @@ struct VertexState { impl VertexState { fn update_limits(&mut self) { - // Ensure that the limits are always smaller than u32::MAX so that - // interger overlows can be prevented via saturating additions. - let max = u32::MAX as u64; - self.vertex_limit = max; - self.instance_limit = max; + // TODO: This isn't entirely spec-compliant. + // We currently require that the buffer range can fit `stride` * count bytes. + // The spec, however, lets a buffer be a bit smaller as long as the size of the + // last element fits in it (the last element can be smaller than the stride between + // elements). + self.vertex_limit = u32::MAX as u64; + self.instance_limit = u32::MAX as u64; for (idx, vbs) in self.inputs.iter().enumerate() { if vbs.step.stride == 0 || !vbs.bound { continue; diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index 06aedc00f6..b46bfde691 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -2717,8 +2717,13 @@ impl Device { let mut shader_expects_dual_source_blending = false; let mut pipeline_expects_dual_source_blending = false; for (i, vb_state) in desc.vertex.buffers.iter().enumerate() { + let mut last_stride = 0; + for attribute in vb_state.attributes.iter() { + last_stride = last_stride.max(attribute.offset + attribute.format.size()); + } vertex_steps.push(pipeline::VertexStep { stride: vb_state.array_stride, + last_stride, mode: vb_state.step_mode, }); if vb_state.attributes.is_empty() { diff --git a/wgpu-core/src/pipeline.rs b/wgpu-core/src/pipeline.rs index 1dc2d1eff1..7fb45321f0 100644 --- a/wgpu-core/src/pipeline.rs +++ b/wgpu-core/src/pipeline.rs @@ -493,6 +493,9 @@ pub struct VertexStep { /// The byte stride in the buffer between one attribute value and the next. pub stride: wgt::BufferAddress, + /// The byte size required to fit the last vertex in the stream. + pub last_stride: wgt::BufferAddress, + /// Whether the buffer is indexed by vertex number or instance number. pub mode: wgt::VertexStepMode, } @@ -501,6 +504,7 @@ impl Default for VertexStep { fn default() -> Self { Self { stride: 0, + last_stride: 0, mode: wgt::VertexStepMode::Vertex, } } From 0003db18c4e97bcf9635e1e827f38155e6b6b4eb Mon Sep 17 00:00:00 2001 From: vero Date: Sat, 27 Jan 2024 17:42:02 -0800 Subject: [PATCH 057/101] Refactor tests to be feature flag bit-width agnostic (#5155) --- CHANGELOG.md | 3 ++- player/tests/data/bind-group.ron | 2 +- player/tests/data/buffer-copy.ron | 2 +- player/tests/data/clear-buffer-texture.ron | 2 +- .../tests/data/pipeline-statistics-query.ron | 2 +- player/tests/data/quad.ron | 2 +- player/tests/data/zero-init-buffer.ron | 2 +- .../tests/data/zero-init-texture-binding.ron | 4 +-- .../data/zero-init-texture-copytobuffer.ron | 2 +- .../data/zero-init-texture-rendertarget.ron | 2 +- player/tests/test.rs | 26 +++++++++++++++++-- 11 files changed, 36 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53a43857bc..8abab11a6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -81,6 +81,7 @@ Bottom level categories: #### Tests - Fix intermittent crashes on Linux in the `multithreaded_compute` test. By @jimblandy in [#5129](https://github.com/gfx-rs/wgpu/pull/5129). +- Refactor tests to read feature flags by name instead of a hardcoded hexadecimal u64. By @rodolphito in [#5155](https://github.com/gfx-rs/wgpu/pull/5155). ## v0.19.0 (2024-01-17) @@ -193,7 +194,7 @@ let surface = instance.create_surface(my_window.clone())?; ``` All platform specific surface creation using points have moved into `SurfaceTargetUnsafe` as well. -For example: +For example: Safety by @daxpedda in [#4597](https://github.com/gfx-rs/wgpu/pull/4597) Unification by @wumpf in [#4984](https://github.com/gfx-rs/wgpu/pull/4984) diff --git a/player/tests/data/bind-group.ron b/player/tests/data/bind-group.ron index 7b89d456bc..eacc36eb66 100644 --- a/player/tests/data/bind-group.ron +++ b/player/tests/data/bind-group.ron @@ -1,5 +1,5 @@ ( - features: 0x0, + features: [], expectations: [], //not crash! actions: [ CreateBuffer(Id(0, 1, Empty), ( diff --git a/player/tests/data/buffer-copy.ron b/player/tests/data/buffer-copy.ron index 05c3a94334..5c66f2c019 100644 --- a/player/tests/data/buffer-copy.ron +++ b/player/tests/data/buffer-copy.ron @@ -1,5 +1,5 @@ ( - features: 0x0000_0004_0000_0000, // MAPPABLE_PRIMARY_BUFFERS + features: ["MAPPABLE_PRIMARY_BUFFERS"], expectations: [ ( name: "basic", diff --git a/player/tests/data/clear-buffer-texture.ron b/player/tests/data/clear-buffer-texture.ron index 592e141c9f..7b25fa42c5 100644 --- a/player/tests/data/clear-buffer-texture.ron +++ b/player/tests/data/clear-buffer-texture.ron @@ -1,5 +1,5 @@ ( - features: 0x0004_0004_0000_0000, // MAPPABLE_PRIMARY_BUFFERS | CLEAR_TEXTURE + features: ["MAPPABLE_PRIMARY_BUFFERS", "CLEAR_TEXTURE"], expectations: [ ( name: "Quad", diff --git a/player/tests/data/pipeline-statistics-query.ron b/player/tests/data/pipeline-statistics-query.ron index 999c333a30..2565ee7376 100644 --- a/player/tests/data/pipeline-statistics-query.ron +++ b/player/tests/data/pipeline-statistics-query.ron @@ -1,5 +1,5 @@ ( - features: 0x0000_0005_0000_0000, // MAPPABLE_PRIMARY_BUFFERS | PIPELINE_STATISTICS_QUERY + features: ["MAPPABLE_PRIMARY_BUFFERS", "PIPELINE_STATISTICS_QUERY"], expectations: [ ( name: "Queried number of compute invocations is correct", diff --git a/player/tests/data/quad.ron b/player/tests/data/quad.ron index 563ba24b84..68bf8ee97e 100644 --- a/player/tests/data/quad.ron +++ b/player/tests/data/quad.ron @@ -1,5 +1,5 @@ ( - features: 0x0, + features: [], expectations: [ ( name: "Quad", diff --git a/player/tests/data/zero-init-buffer.ron b/player/tests/data/zero-init-buffer.ron index b93f65c736..73692d10ee 100644 --- a/player/tests/data/zero-init-buffer.ron +++ b/player/tests/data/zero-init-buffer.ron @@ -1,5 +1,5 @@ ( - features: 0x0000_0004_0000_0000, // MAPPABLE_PRIMARY_BUFFERS + features: ["MAPPABLE_PRIMARY_BUFFERS"], expectations: [ // Ensuring that mapping zero-inits buffers. ( diff --git a/player/tests/data/zero-init-texture-binding.ron b/player/tests/data/zero-init-texture-binding.ron index 17aa3b4279..7dcfa4e2e6 100644 --- a/player/tests/data/zero-init-texture-binding.ron +++ b/player/tests/data/zero-init-texture-binding.ron @@ -1,5 +1,5 @@ ( - features: 0x0, + features: [], expectations: [ ( name: "Sampled Texture", @@ -56,7 +56,7 @@ format: "rgba8unorm", usage: 9, // STORAGE + COPY_SRC view_formats: [], - )), + )), CreateTextureView( id: Id(1, 1, Empty), parent_id: Id(1, 1, Empty), diff --git a/player/tests/data/zero-init-texture-copytobuffer.ron b/player/tests/data/zero-init-texture-copytobuffer.ron index 0bb16ccebb..599ddbd67d 100644 --- a/player/tests/data/zero-init-texture-copytobuffer.ron +++ b/player/tests/data/zero-init-texture-copytobuffer.ron @@ -1,5 +1,5 @@ ( - features: 0x0, + features: [], expectations: [ ( name: "Copy to Buffer", diff --git a/player/tests/data/zero-init-texture-rendertarget.ron b/player/tests/data/zero-init-texture-rendertarget.ron index 831af942a2..ec844fe073 100644 --- a/player/tests/data/zero-init-texture-rendertarget.ron +++ b/player/tests/data/zero-init-texture-rendertarget.ron @@ -1,5 +1,5 @@ ( - features: 0x0, + features: [], expectations: [ ( name: "Render Target", diff --git a/player/tests/test.rs b/player/tests/test.rs index 196777d0b2..cb09aecebc 100644 --- a/player/tests/test.rs +++ b/player/tests/test.rs @@ -49,7 +49,6 @@ struct Expectation { data: ExpectedData, } -#[derive(serde::Deserialize)] struct Test<'a> { features: wgt::Features, expectations: Vec, @@ -72,7 +71,30 @@ impl Test<'_> { _ => unreachable!(), }; let string = read_to_string(path).unwrap().replace("Empty", backend_name); - ron::de::from_str(&string).unwrap() + + #[derive(serde::Deserialize)] + struct SerializedTest<'a> { + features: Vec, + expectations: Vec, + actions: Vec>, + } + let SerializedTest { + features, + expectations, + actions, + } = ron::de::from_str(&string).unwrap(); + let features = features + .iter() + .map(|feature| { + wgt::Features::from_name(feature) + .unwrap_or_else(|| panic!("Invalid feature flag {}", feature)) + }) + .fold(wgt::Features::empty(), |a, b| a | b); + Test { + features, + expectations, + actions, + } } fn run( From 4face1c2ba88cfa505ba93cf24ea9a4275d4b772 Mon Sep 17 00:00:00 2001 From: Bude Date: Sun, 28 Jan 2024 21:13:04 +0100 Subject: [PATCH 058/101] Feature/serde feature (#5149) * Add serde, serialize, deserialize features to wgpu and wgpu-core Remove trace, replay features from wgpu-types * Do not use trace, replay in wgpu-types anymore * Make use of deserialize, serialize features in wgpu-core * Make use of serialize, deserialize features in wgpu * Run cargo fmt * Use serde(default) for deserialize only * Fix serial-pass feature * Add a comment for new features * Add CHANGELOG entry * Run cargo fmt * serial-pass also needs serde features for Id * Add feature documentation to lib.rs docs * wgpu-types implicit serde feature * wgpu-core explicit serde feature * wgpu explicit serde feature * Update CHANGELOG.md * Fix compilation with default features * Address review comments --- CHANGELOG.md | 3 + deno_webgpu/Cargo.toml | 2 +- player/Cargo.toml | 2 +- tests/Cargo.toml | 2 +- wgpu-core/Cargo.toml | 10 +- wgpu-core/src/binding_model.rs | 22 ++-- wgpu-core/src/command/bundle.rs | 9 +- wgpu-core/src/command/compute.rs | 22 ++-- wgpu-core/src/command/draw.rs | 18 +-- wgpu-core/src/command/mod.rs | 9 +- wgpu-core/src/command/render.rs | 31 ++--- wgpu-core/src/device/mod.rs | 10 +- wgpu-core/src/device/trace.rs | 6 +- wgpu-core/src/id.rs | 3 +- wgpu-core/src/lib.rs | 2 +- wgpu-core/src/pipeline.rs | 27 ++--- wgpu-core/src/resource.rs | 7 +- wgpu-info/Cargo.toml | 2 +- wgpu-types/Cargo.toml | 2 - wgpu-types/src/lib.rs | 199 +++++++++++-------------------- wgpu/Cargo.toml | 3 + wgpu/src/lib.rs | 10 +- 22 files changed, 146 insertions(+), 255 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8abab11a6e..5074fb597f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,12 +67,15 @@ Bottom level categories: - `tan` - `tanh` - Eager release of GPU resources comes from device.trackers. By @bradwerth in [#5075](https://github.com/gfx-rs/wgpu/pull/5075) +- `wgpu-types`'s `trace` and `replay` features have been replaced by the `serde` feature. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) +- `wgpu-core`'s `serial-pass` feature has been removed. Use `serde` instead. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) ### Bug Fixes #### General - Fix `panic!` when dropping `Instance` without `InstanceFlags::VALIDATION`. By @hakolao in [#5134](https://github.com/gfx-rs/wgpu/pull/5134) +- Fix `serde` feature not compiling for `wgpu-types`. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) #### WGL diff --git a/deno_webgpu/Cargo.toml b/deno_webgpu/Cargo.toml index d1097c658d..9f6d96a95b 100644 --- a/deno_webgpu/Cargo.toml +++ b/deno_webgpu/Cargo.toml @@ -22,7 +22,7 @@ surface = ["wgpu-core/raw-window-handle", "dep:raw-window-handle"] deno_core.workspace = true serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["full"] } -wgpu-types = { workspace = true, features = ["trace", "replay", "serde"] } +wgpu-types = { workspace = true, features = ["serde"] } raw-window-handle = { workspace = true, optional = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies.wgpu-core] diff --git a/player/Cargo.toml b/player/Cargo.toml index 63493a4ee2..6c391cb4d6 100644 --- a/player/Cargo.toml +++ b/player/Cargo.toml @@ -29,7 +29,7 @@ winit = { workspace = true, optional = true } [dependencies.wgt] workspace = true -features = ["replay"] +features = ["serde"] [target.'cfg(not(target_arch = "wasm32"))'.dependencies.wgc] workspace = true diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 7c0288388d..c4cbaa9e3e 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -38,7 +38,7 @@ serde_json.workspace = true serde.workspace = true wgpu-macros.workspace = true wgpu.workspace = true -wgt = { workspace = true, features = ["replay"] } +wgt = { workspace = true, features = ["serde"] } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] env_logger.workspace = true diff --git a/wgpu-core/Cargo.toml b/wgpu-core/Cargo.toml index 95507bd7e2..d66f7b7d3a 100644 --- a/wgpu-core/Cargo.toml +++ b/wgpu-core/Cargo.toml @@ -47,14 +47,14 @@ renderdoc = ["hal/renderdoc"] ## to the validation carried out at public APIs in all builds. strict_asserts = ["wgt/strict_asserts"] +## Enables serialization via `serde` on common wgpu types. +serde = ["dep:serde", "wgt/serde", "arrayvec/serde"] + ## Enable API tracing. -trace = ["ron", "serde", "wgt/trace", "arrayvec/serde", "naga/serialize"] +trace = ["ron", "serde", "naga/serialize"] ## Enable API replaying -replay = ["serde", "wgt/replay", "arrayvec/serde", "naga/deserialize"] - -## Enable serializable compute/render passes, and bundle encoders. -serial-pass = ["serde", "wgt/serde", "arrayvec/serde"] +replay = ["serde", "naga/deserialize"] ## Enable `ShaderModuleSource::Wgsl` wgsl = ["naga/wgsl-in"] diff --git a/wgpu-core/src/binding_model.rs b/wgpu-core/src/binding_model.rs index 833920ea35..fe4f977d03 100644 --- a/wgpu-core/src/binding_model.rs +++ b/wgpu-core/src/binding_model.rs @@ -21,9 +21,9 @@ use crate::{ use arrayvec::ArrayVec; -#[cfg(feature = "replay")] +#[cfg(feature = "serde")] use serde::Deserialize; -#[cfg(feature = "trace")] +#[cfg(feature = "serde")] use serde::Serialize; use std::{borrow::Cow, ops::Range, sync::Arc}; @@ -406,8 +406,7 @@ impl BindingTypeMaxCountValidator { /// Bindable resource and the slot to bind it to. #[derive(Clone, Debug)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct BindGroupEntry<'a> { /// Slot for which binding provides resource. Corresponds to an entry of the same /// binding index in the [`BindGroupLayoutDescriptor`]. @@ -418,8 +417,7 @@ pub struct BindGroupEntry<'a> { /// Describes a group of bindings and the resources to be bound. #[derive(Clone, Debug)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct BindGroupDescriptor<'a> { /// Debug label of the bind group. /// @@ -433,8 +431,7 @@ pub struct BindGroupDescriptor<'a> { /// Describes a [`BindGroupLayout`]. #[derive(Clone, Debug)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct BindGroupLayoutDescriptor<'a> { /// Debug label of the bind group layout. /// @@ -582,8 +579,7 @@ pub enum PushConstantUploadError { /// /// A `PipelineLayoutDescriptor` can be used to create a pipeline layout. #[derive(Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct PipelineLayoutDescriptor<'a> { /// Debug label of the pipeine layout. /// @@ -734,8 +730,7 @@ impl Resource for PipelineLayout { #[repr(C)] #[derive(Clone, Debug, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct BufferBinding { pub buffer_id: BufferId, pub offset: wgt::BufferAddress, @@ -745,8 +740,7 @@ pub struct BufferBinding { // Note: Duplicated in `wgpu-rs` as `BindingResource` // They're different enough that it doesn't make sense to share a common type #[derive(Debug, Clone)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum BindingResource<'a> { Buffer(BufferBinding), BufferArray(Cow<'a, [BufferBinding]>), diff --git a/wgpu-core/src/command/bundle.rs b/wgpu-core/src/command/bundle.rs index 5d474f6a3a..49def22d45 100644 --- a/wgpu-core/src/command/bundle.rs +++ b/wgpu-core/src/command/bundle.rs @@ -197,8 +197,7 @@ fn validate_indexed_draw( /// Describes a [`RenderBundleEncoder`]. #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct RenderBundleEncoderDescriptor<'a> { /// Debug label of the render bundle encoder. /// @@ -226,7 +225,7 @@ pub struct RenderBundleEncoderDescriptor<'a> { } #[derive(Debug)] -#[cfg_attr(feature = "serial-pass", derive(serde::Deserialize, serde::Serialize))] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct RenderBundleEncoder { base: BasePass, parent_id: id::DeviceId, @@ -235,9 +234,9 @@ pub struct RenderBundleEncoder { pub(crate) is_stencil_read_only: bool, // Resource binding dedupe state. - #[cfg_attr(feature = "serial-pass", serde(skip))] + #[cfg_attr(feature = "serde", serde(skip))] current_bind_groups: BindGroupStateChange, - #[cfg_attr(feature = "serial-pass", serde(skip))] + #[cfg_attr(feature = "serde", serde(skip))] current_pipeline: StateChange, } diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index ef56f54985..cd7949b3da 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -29,9 +29,9 @@ use crate::{ }; use hal::CommandEncoder as _; -#[cfg(any(feature = "serial-pass", feature = "replay"))] +#[cfg(feature = "serde")] use serde::Deserialize; -#[cfg(any(feature = "serial-pass", feature = "trace"))] +#[cfg(feature = "serde")] use serde::Serialize; use thiserror::Error; @@ -40,14 +40,7 @@ use std::{fmt, mem, str}; #[doc(hidden)] #[derive(Clone, Copy, Debug)] -#[cfg_attr( - any(feature = "serial-pass", feature = "trace"), - derive(serde::Serialize) -)] -#[cfg_attr( - any(feature = "serial-pass", feature = "replay"), - derive(serde::Deserialize) -)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum ComputeCommand { SetBindGroup { index: u32, @@ -98,16 +91,16 @@ pub enum ComputeCommand { EndPipelineStatisticsQuery, } -#[cfg_attr(feature = "serial-pass", derive(serde::Deserialize, serde::Serialize))] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct ComputePass { base: BasePass, parent_id: id::CommandEncoderId, timestamp_writes: Option, // Resource binding dedupe state. - #[cfg_attr(feature = "serial-pass", serde(skip))] + #[cfg_attr(feature = "serde", serde(skip))] current_bind_groups: BindGroupStateChange, - #[cfg_attr(feature = "serial-pass", serde(skip))] + #[cfg_attr(feature = "serde", serde(skip))] current_pipeline: StateChange, } @@ -151,8 +144,7 @@ impl fmt::Debug for ComputePass { /// Describes the writing of timestamp values in a compute pass. #[repr(C)] #[derive(Clone, Debug, PartialEq, Eq)] -#[cfg_attr(any(feature = "serial-pass", feature = "trace"), derive(Serialize))] -#[cfg_attr(any(feature = "serial-pass", feature = "replay"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct ComputePassTimestampWrites { /// The query set to write the timestamps to. pub query_set: id::QuerySetId, diff --git a/wgpu-core/src/command/draw.rs b/wgpu-core/src/command/draw.rs index 058ba81f95..e03a78ee93 100644 --- a/wgpu-core/src/command/draw.rs +++ b/wgpu-core/src/command/draw.rs @@ -126,14 +126,7 @@ impl crate::error::PrettyError for RenderCommandError { } #[derive(Clone, Copy, Debug, Default)] -#[cfg_attr( - any(feature = "serial-pass", feature = "trace"), - derive(serde::Serialize) -)] -#[cfg_attr( - any(feature = "serial-pass", feature = "replay"), - derive(serde::Deserialize) -)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Rect { pub x: T, pub y: T, @@ -143,14 +136,7 @@ pub struct Rect { #[doc(hidden)] #[derive(Clone, Copy, Debug)] -#[cfg_attr( - any(feature = "serial-pass", feature = "trace"), - derive(serde::Serialize) -)] -#[cfg_attr( - any(feature = "serial-pass", feature = "replay"), - derive(serde::Deserialize) -)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum RenderCommand { SetBindGroup { index: u32, diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index 784d158bce..40ac0628f0 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -338,14 +338,7 @@ pub struct BasePassRef<'a, C> { /// [`InsertDebugMarker`]: RenderCommand::InsertDebugMarker #[doc(hidden)] #[derive(Debug)] -#[cfg_attr( - any(feature = "serial-pass", feature = "trace"), - derive(serde::Serialize) -)] -#[cfg_attr( - any(feature = "serial-pass", feature = "replay"), - derive(serde::Deserialize) -)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct BasePass { pub label: Option, diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index 9f31d3c6d0..fedc6f7c89 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -40,9 +40,9 @@ use wgt::{ TextureViewDimension, VertexStepMode, }; -#[cfg(any(feature = "serial-pass", feature = "replay"))] +#[cfg(feature = "serde")] use serde::Deserialize; -#[cfg(any(feature = "serial-pass", feature = "trace"))] +#[cfg(feature = "serde")] use serde::Serialize; use std::sync::Arc; @@ -56,8 +56,7 @@ use super::{ /// Operation to perform to the output attachment at the start of a renderpass. #[repr(C)] #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] -#[cfg_attr(any(feature = "serial-pass", feature = "trace"), derive(Serialize))] -#[cfg_attr(any(feature = "serial-pass", feature = "replay"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum LoadOp { /// Clear the output attachment with the clear color. Clearing is faster than loading. @@ -69,8 +68,7 @@ pub enum LoadOp { /// Operation to perform to the output attachment at the end of a renderpass. #[repr(C)] #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] -#[cfg_attr(any(feature = "serial-pass", feature = "trace"), derive(Serialize))] -#[cfg_attr(any(feature = "serial-pass", feature = "replay"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum StoreOp { /// Discards the content of the render target. @@ -84,8 +82,7 @@ pub enum StoreOp { /// Describes an individual channel within a render pass, such as color, depth, or stencil. #[repr(C)] #[derive(Clone, Debug, Eq, PartialEq)] -#[cfg_attr(any(feature = "serial-pass", feature = "trace"), derive(Serialize))] -#[cfg_attr(any(feature = "serial-pass", feature = "replay"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct PassChannel { /// Operation to perform to the output attachment at the start of a /// renderpass. @@ -122,8 +119,7 @@ impl PassChannel { /// Describes a color attachment to a render pass. #[repr(C)] #[derive(Clone, Debug, PartialEq)] -#[cfg_attr(any(feature = "serial-pass", feature = "trace"), derive(Serialize))] -#[cfg_attr(any(feature = "serial-pass", feature = "replay"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct RenderPassColorAttachment { /// The view to use as an attachment. pub view: id::TextureViewId, @@ -136,8 +132,7 @@ pub struct RenderPassColorAttachment { /// Describes a depth/stencil attachment to a render pass. #[repr(C)] #[derive(Clone, Debug, PartialEq)] -#[cfg_attr(any(feature = "serial-pass", feature = "trace"), derive(Serialize))] -#[cfg_attr(any(feature = "serial-pass", feature = "replay"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct RenderPassDepthStencilAttachment { /// The view to use as an attachment. pub view: id::TextureViewId, @@ -188,8 +183,7 @@ impl RenderPassDepthStencilAttachment { /// Location to write a timestamp to (beginning or end of the pass). #[repr(C)] #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] -#[cfg_attr(any(feature = "serial-pass", feature = "trace"), derive(Serialize))] -#[cfg_attr(any(feature = "serial-pass", feature = "replay"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum RenderPassTimestampLocation { Beginning = 0, @@ -199,8 +193,7 @@ pub enum RenderPassTimestampLocation { /// Describes the writing of timestamp values in a render pass. #[repr(C)] #[derive(Clone, Debug, PartialEq, Eq)] -#[cfg_attr(any(feature = "serial-pass", feature = "trace"), derive(Serialize))] -#[cfg_attr(any(feature = "serial-pass", feature = "replay"), derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct RenderPassTimestampWrites { /// The query set to write the timestamp to. pub query_set: id::QuerySetId, @@ -224,7 +217,7 @@ pub struct RenderPassDescriptor<'a> { pub occlusion_query_set: Option, } -#[cfg_attr(feature = "serial-pass", derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct RenderPass { base: BasePass, parent_id: id::CommandEncoderId, @@ -234,9 +227,9 @@ pub struct RenderPass { occlusion_query_set_id: Option, // Resource binding dedupe state. - #[cfg_attr(feature = "serial-pass", serde(skip))] + #[cfg_attr(feature = "serde", serde(skip))] current_bind_groups: BindGroupStateChange, - #[cfg_attr(feature = "serial-pass", serde(skip))] + #[cfg_attr(feature = "serde", serde(skip))] current_pipeline: StateChange, } diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index c417952c40..2d53026162 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -42,15 +42,14 @@ pub type DeviceDescriptor<'a> = wgt::DeviceDescriptor>; #[repr(C)] #[derive(Clone, Copy, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum HostMap { Read, Write, } #[derive(Clone, Debug, Hash, PartialEq)] -#[cfg_attr(feature = "serial-pass", derive(serde::Deserialize, serde::Serialize))] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub(crate) struct AttachmentData { pub colors: ArrayVec, { hal::MAX_COLOR_ATTACHMENTS }>, pub resolves: ArrayVec, @@ -74,7 +73,7 @@ pub enum RenderPassCompatibilityCheckType { } #[derive(Clone, Debug, Hash, PartialEq)] -#[cfg_attr(feature = "serial-pass", derive(serde::Deserialize, serde::Serialize))] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub(crate) struct RenderPassContext { pub attachments: AttachmentData, pub sample_count: u32, @@ -457,8 +456,7 @@ pub struct MissingFeatures(pub wgt::Features); pub struct MissingDownlevelFlags(pub wgt::DownlevelFlags); #[derive(Clone, Debug)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ImplicitPipelineContext { pub root_id: id::PipelineLayoutId, pub group_ids: ArrayVec, diff --git a/wgpu-core/src/device/trace.rs b/wgpu-core/src/device/trace.rs index 315b7e8e84..0802b610d8 100644 --- a/wgpu-core/src/device/trace.rs +++ b/wgpu-core/src/device/trace.rs @@ -33,8 +33,7 @@ pub(crate) fn new_render_bundle_encoder_descriptor<'a>( #[allow(clippy::large_enum_variant)] #[derive(Debug)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum Action<'a> { Init { desc: crate::device::DeviceDescriptor<'a>, @@ -126,8 +125,7 @@ pub enum Action<'a> { } #[derive(Debug)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum Command { CopyBufferToBuffer { src: id::BufferId, diff --git a/wgpu-core/src/id.rs b/wgpu-core/src/id.rs index 739beb7180..f55a077f6a 100644 --- a/wgpu-core/src/id.rs +++ b/wgpu-core/src/id.rs @@ -67,8 +67,7 @@ pub struct Id(NonZeroId, PhantomData); // This type represents Id in a more readable (and editable) way. #[allow(dead_code)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] enum SerialId { // The only variant forces RON to not ignore "Id" Id(Index, Epoch, Backend), diff --git a/wgpu-core/src/lib.rs b/wgpu-core/src/lib.rs index 74c27bd960..5413be6b63 100644 --- a/wgpu-core/src/lib.rs +++ b/wgpu-core/src/lib.rs @@ -13,9 +13,9 @@ //! [https://renderdoc.org/](https://renderdoc.org/) //! - **`strict_asserts`** --- Apply run-time checks, even in release builds. These are in addition //! to the validation carried out at public APIs in all builds. +//! - **`serde`** --- Enables serialization via `serde` on common wgpu types. //! - **`trace`** --- Enable API tracing. //! - **`replay`** --- Enable API replaying -//! - **`serial-pass`** --- Enable serializable compute/render passes, and bundle encoders. //! - **`wgsl`** --- Enable `ShaderModuleSource::Wgsl` //! - **`fragile-send-sync-non-atomic-wasm`** --- Implement `Send` and `Sync` on Wasm, but only if //! atomics are not enabled. diff --git a/wgpu-core/src/pipeline.rs b/wgpu-core/src/pipeline.rs index 7fb45321f0..b6c3bf5bfe 100644 --- a/wgpu-core/src/pipeline.rs +++ b/wgpu-core/src/pipeline.rs @@ -38,8 +38,7 @@ pub enum ShaderModuleSource<'a> { } #[derive(Clone, Debug)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ShaderModuleDescriptor<'a> { pub label: Label<'a>, #[cfg_attr(feature = "serde", serde(default))] @@ -208,8 +207,7 @@ impl CreateShaderModuleError { /// Describes a programmable pipeline stage. #[derive(Clone, Debug)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ProgrammableStageDescriptor<'a> { /// The compiled shader module for this stage. pub module: ShaderModuleId, @@ -236,8 +234,7 @@ pub enum ImplicitLayoutError { /// Describes a compute pipeline. #[derive(Clone, Debug)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ComputePipelineDescriptor<'a> { pub label: Label<'a>, /// The layout of bind groups for this pipeline. @@ -311,8 +308,7 @@ impl ComputePipeline { /// Describes how the vertex buffer is interpreted. #[derive(Clone, Debug)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] pub struct VertexBufferLayout<'a> { /// The stride, in bytes, between elements of this buffer. @@ -325,8 +321,7 @@ pub struct VertexBufferLayout<'a> { /// Describes the vertex process in a render pipeline. #[derive(Clone, Debug)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct VertexState<'a> { /// The compiled vertex stage and its entry point. pub stage: ProgrammableStageDescriptor<'a>, @@ -336,8 +331,7 @@ pub struct VertexState<'a> { /// Describes fragment processing in a render pipeline. #[derive(Clone, Debug)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct FragmentState<'a> { /// The compiled fragment stage and its entry point. pub stage: ProgrammableStageDescriptor<'a>, @@ -347,8 +341,7 @@ pub struct FragmentState<'a> { /// Describes a render (graphics) pipeline. #[derive(Clone, Debug)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct RenderPipelineDescriptor<'a> { pub label: Label<'a>, /// The layout of bind groups for this pipeline. @@ -356,13 +349,13 @@ pub struct RenderPipelineDescriptor<'a> { /// The vertex processing state for this pipeline. pub vertex: VertexState<'a>, /// The properties of the pipeline at the primitive assembly and rasterization level. - #[cfg_attr(any(feature = "replay", feature = "trace"), serde(default))] + #[cfg_attr(feature = "serde", serde(default))] pub primitive: wgt::PrimitiveState, /// The effect of draw calls on the depth and stencil aspects of the output target, if any. - #[cfg_attr(any(feature = "replay", feature = "trace"), serde(default))] + #[cfg_attr(feature = "serde", serde(default))] pub depth_stencil: Option, /// The multi-sampling properties of the pipeline. - #[cfg_attr(any(feature = "replay", feature = "trace"), serde(default))] + #[cfg_attr(feature = "serde", serde(default))] pub multisample: wgt::MultisampleState, /// The fragment processing state for this pipeline. pub fragment: Option>, diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index b08216eeeb..85384939f6 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -1186,8 +1186,8 @@ impl Borrow for Texture { /// Describes a [`TextureView`]. #[derive(Clone, Debug, Default, Eq, PartialEq)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize), serde(default))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(default))] pub struct TextureViewDescriptor<'a> { /// Debug label of the texture view. /// @@ -1343,8 +1343,7 @@ impl Resource for TextureView { /// Describes a [`Sampler`] #[derive(Clone, Debug, PartialEq)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct SamplerDescriptor<'a> { /// Debug label of the sampler. /// diff --git a/wgpu-info/Cargo.toml b/wgpu-info/Cargo.toml index a729bbc885..59fc074fa8 100644 --- a/wgpu-info/Cargo.toml +++ b/wgpu-info/Cargo.toml @@ -17,4 +17,4 @@ pico-args.workspace = true serde.workspace = true serde_json.workspace = true wgpu.workspace = true -wgpu-types = { workspace = true, features = ["trace", "replay"] } +wgpu-types = { workspace = true, features = ["serde"] } diff --git a/wgpu-types/Cargo.toml b/wgpu-types/Cargo.toml index 7528b18c0a..ff3649f24b 100644 --- a/wgpu-types/Cargo.toml +++ b/wgpu-types/Cargo.toml @@ -28,8 +28,6 @@ targets = [ [lib] [features] -trace = ["serde"] -replay = ["serde"] strict_asserts = [] fragile-send-sync-non-atomic-wasm = [] diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index fa2a8df5f8..7c39c32e03 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -10,7 +10,9 @@ #![warn(missing_docs, unsafe_op_in_unsafe_fn)] #[cfg(any(feature = "serde", test))] -use serde::{Deserialize, Serialize}; +use serde::Deserialize; +#[cfg(any(feature = "serde", test))] +use serde::Serialize; use std::hash::{Hash, Hasher}; use std::path::PathBuf; use std::{num::NonZeroU32, ops::Range}; @@ -128,8 +130,7 @@ impl Backend { /// https://gpuweb.github.io/gpuweb/#enumdef-gpupowerpreference). #[repr(C)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Default)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum PowerPreference { #[default] @@ -197,8 +198,7 @@ impl From for Backends { /// https://gpuweb.github.io/gpuweb/#dictdef-gpurequestadapteroptions). #[repr(C)] #[derive(Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct RequestAdapterOptions { /// Power preference for the adapter. pub power_preference: PowerPreference, @@ -989,7 +989,7 @@ impl InstanceFlags { /// [`downlevel_defaults()`]: Limits::downlevel_defaults #[repr(C)] #[derive(Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "camelCase", default))] pub struct Limits { /// Maximum allowed value for the `size.width` of a texture created with `TextureDimension::D1`. @@ -1664,8 +1664,7 @@ pub struct AdapterInfo { /// https://gpuweb.github.io/gpuweb/#gpudevicedescriptor). #[repr(C)] #[derive(Clone, Debug, Default)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct DeviceDescriptor { /// Debug label for the device. pub label: L, @@ -1727,8 +1726,7 @@ impl_bitflags!(ShaderStages); /// https://gpuweb.github.io/gpuweb/#enumdef-gputextureviewdimension). #[repr(C)] #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum TextureViewDimension { /// A one dimensional texture. `texture_1d` in WGSL and `texture1D` in GLSL. #[cfg_attr(feature = "serde", serde(rename = "1d"))] @@ -1772,8 +1770,7 @@ impl TextureViewDimension { /// used with the first render target. #[repr(C)] #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum BlendFactor { /// 0.0 @@ -1835,8 +1832,7 @@ impl BlendFactor { /// https://gpuweb.github.io/gpuweb/#enumdef-gpublendoperation). #[repr(C)] #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum BlendOperation { /// Src + Dst @@ -1858,8 +1854,7 @@ pub enum BlendOperation { /// https://gpuweb.github.io/gpuweb/#dictdef-gpublendcomponent). #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] pub struct BlendComponent { /// Multiplier for the source, which is produced by the fragment shader. @@ -1914,8 +1909,7 @@ impl Default for BlendComponent { /// https://gpuweb.github.io/gpuweb/#dictdef-gpublendstate). #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] pub struct BlendState { /// Color equation. @@ -1954,8 +1948,7 @@ impl BlendState { /// https://gpuweb.github.io/gpuweb/#dictdef-gpucolortargetstate). #[repr(C)] #[derive(Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] pub struct ColorTargetState { /// The [`TextureFormat`] of the image that this pipeline will render to. Must match the format @@ -1987,8 +1980,7 @@ impl From for ColorTargetState { /// https://gpuweb.github.io/gpuweb/#enumdef-gpuprimitivetopology). #[repr(C)] #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum PrimitiveTopology { /// Vertex data is a list of points. Each vertex is a new point. @@ -2028,8 +2020,7 @@ impl PrimitiveTopology { /// https://gpuweb.github.io/gpuweb/#enumdef-gpufrontface). #[repr(C)] #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum FrontFace { /// Triangles with vertices in counter clockwise order are considered the front face. @@ -2050,8 +2041,7 @@ pub enum FrontFace { /// except that the `"none"` value is represented using `Option` instead. #[repr(C)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum Face { /// Front face @@ -2063,8 +2053,7 @@ pub enum Face { /// Type of drawing mode for polygons #[repr(C)] #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum PolygonMode { /// Polygons are filled @@ -2082,8 +2071,7 @@ pub enum PolygonMode { /// https://gpuweb.github.io/gpuweb/#dictdef-gpuprimitivestate). #[repr(C)] #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] pub struct PrimitiveState { /// The primitive topology used to interpret vertices. @@ -2123,8 +2111,7 @@ pub struct PrimitiveState { /// https://gpuweb.github.io/gpuweb/#dictdef-gpumultisamplestate). #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] pub struct MultisampleState { /// The number of samples calculated per pixel (for MSAA). For non-multisampled textures, @@ -2223,7 +2210,7 @@ pub struct TextureFormatFeatures { /// ASTC block dimensions #[repr(C)] #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum AstcBlock { /// 4x4 block compressed texture. 16 bytes per block (8 bit/px). B4x4, @@ -2258,7 +2245,7 @@ pub enum AstcBlock { /// ASTC RGBA channel #[repr(C)] #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum AstcChannel { /// 8 bit integer RGBA, [0, 255] converted to/from linear-color float [0, 1] in shader. /// @@ -4366,8 +4353,7 @@ impl MaintainResult { /// https://gpuweb.github.io/gpuweb/#dictdef-gpudepthstencilstate). #[repr(C)] #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct StencilState { /// Front face mode. pub front: StencilFaceState, @@ -4414,8 +4400,7 @@ impl StencilState { /// https://gpuweb.github.io/gpuweb/#dictdef-gpudepthstencilstate). #[repr(C)] #[derive(Clone, Copy, Debug, Default)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct DepthBiasState { /// Constant depth biasing factor, in basic units of the depth format. pub constant: i32, @@ -4456,8 +4441,7 @@ impl Eq for DepthBiasState {} /// https://gpuweb.github.io/gpuweb/#dictdef-gpudepthstencilstate). #[repr(C)] #[derive(Clone, Debug, Hash, PartialEq, Eq)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct DepthStencilState { /// Format of the depth/stencil buffer, must be special depth format. Must match the format /// of the depth/stencil attachment in [`CommandEncoder::begin_render_pass`][CEbrp]. @@ -4469,10 +4453,10 @@ pub struct DepthStencilState { /// Comparison function used to compare depth values in the depth test. pub depth_compare: CompareFunction, /// Stencil state. - #[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))] + #[cfg_attr(feature = "serde", serde(default))] pub stencil: StencilState, /// Depth bias state. - #[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))] + #[cfg_attr(feature = "serde", serde(default))] pub bias: DepthBiasState, } @@ -4504,7 +4488,7 @@ impl DepthStencilState { /// https://gpuweb.github.io/gpuweb/#enumdef-gpuindexformat). #[repr(C)] #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum IndexFormat { /// Indices are 16 bit unsigned integers. @@ -4520,8 +4504,7 @@ pub enum IndexFormat { /// https://gpuweb.github.io/gpuweb/#enumdef-gpustenciloperation). #[repr(C)] #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum StencilOperation { /// Keep stencil value unchanged. @@ -4554,8 +4537,7 @@ pub enum StencilOperation { /// https://gpuweb.github.io/gpuweb/#dictdef-gpustencilfacestate). #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] pub struct StencilFaceState { /// Comparison function that determines if the fail_op or pass_op is used on the stencil buffer. @@ -4605,8 +4587,7 @@ impl Default for StencilFaceState { /// https://gpuweb.github.io/gpuweb/#enumdef-gpucomparefunction). #[repr(C)] #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum CompareFunction { /// Function never passes @@ -4700,8 +4681,7 @@ impl CompareFunction { /// [`Instance`]: VertexStepMode::Instance #[repr(C)] #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum VertexStepMode { /// Vertex data is advanced every vertex. @@ -4722,8 +4702,7 @@ pub enum VertexStepMode { /// [`vertex_attr_array`]: ../wgpu/macro.vertex_attr_array.html #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] pub struct VertexAttribute { /// Format of the input @@ -4740,8 +4719,7 @@ pub struct VertexAttribute { /// https://gpuweb.github.io/gpuweb/#enumdef-gpuvertexformat). #[repr(C)] #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))] pub enum VertexFormat { /// Two unsigned bytes (u8). `vec2` in shaders. @@ -4900,8 +4878,7 @@ impl_bitflags!(BufferUsages); /// https://gpuweb.github.io/gpuweb/#dictdef-gpubufferdescriptor). #[repr(C)] #[derive(Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct BufferDescriptor { /// Debug label of a buffer. This will show up in graphics debuggers for easy identification. pub label: L, @@ -4935,8 +4912,7 @@ impl BufferDescriptor { /// Corresponds to [WebGPU `GPUCommandEncoderDescriptor`]( /// https://gpuweb.github.io/gpuweb/#dictdef-gpucommandencoderdescriptor). #[repr(C)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct CommandEncoderDescriptor { /// Debug label for the command encoder. This will show up in graphics debuggers for easy identification. @@ -4961,8 +4937,7 @@ impl Default for CommandEncoderDescriptor> { /// Behavior of the presentation engine based on frame rate. #[repr(C)] #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum PresentMode { /// Chooses FifoRelaxed -> Fifo based on availability. /// @@ -5034,8 +5009,7 @@ pub enum PresentMode { /// compositing. #[repr(C)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))] pub enum CompositeAlphaMode { /// Chooses either `Opaque` or `Inherit` automatically,depending on the @@ -5134,8 +5108,7 @@ impl Default for SurfaceCapabilities { /// [`Surface`]: ../wgpu/struct.Surface.html #[repr(C)] #[derive(Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct SurfaceConfiguration { /// The usage of the swap chain. The only supported usage is `RENDER_ATTACHMENT`. pub usage: TextureUsages, @@ -5261,7 +5234,7 @@ impl PresentationTimestamp { /// This is not to be used as a generic color type, only for specific wgpu interfaces. #[repr(C)] #[derive(Clone, Copy, Debug, Default, PartialEq)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] pub struct Color { /// Red component of the color @@ -5320,8 +5293,7 @@ impl Color { /// https://gpuweb.github.io/gpuweb/#enumdef-gputexturedimension). #[repr(C)] #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum TextureDimension { /// 1D texture #[cfg_attr(feature = "serde", serde(rename = "1d"))] @@ -5340,8 +5312,7 @@ pub enum TextureDimension { /// https://gpuweb.github.io/gpuweb/#dictdef-gpuorigin2ddict). #[repr(C)] #[derive(Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] pub struct Origin2d { /// @@ -5376,8 +5347,7 @@ impl std::fmt::Debug for Origin2d { /// https://gpuweb.github.io/gpuweb/#dictdef-gpuorigin3ddict). #[repr(C)] #[derive(Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] pub struct Origin3d { /// X position of the origin @@ -5419,8 +5389,7 @@ impl std::fmt::Debug for Origin3d { /// https://gpuweb.github.io/gpuweb/#dictdef-gpuextent3ddict). #[repr(C)] #[derive(Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] pub struct Extent3d { /// Width of the extent @@ -5619,8 +5588,7 @@ fn test_max_mips() { /// https://gpuweb.github.io/gpuweb/#dictdef-gputexturedescriptor). #[repr(C)] #[derive(Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct TextureDescriptor { /// Debug label of the texture. This will show up in graphics debuggers for easy identification. pub label: L, @@ -5751,8 +5719,7 @@ impl TextureDescriptor { /// https://gpuweb.github.io/gpuweb/#enumdef-gputextureaspect). #[repr(C)] #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum TextureAspect { /// Depth, Stencil, and Color. @@ -5776,8 +5743,7 @@ pub enum TextureAspect { /// https://gpuweb.github.io/gpuweb/#enumdef-gpuaddressmode). #[repr(C)] #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum AddressMode { /// Clamp the value to the edge of the texture @@ -5810,8 +5776,7 @@ pub enum AddressMode { /// https://gpuweb.github.io/gpuweb/#enumdef-gpufiltermode). #[repr(C)] #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum FilterMode { /// Nearest neighbor sampling. @@ -5827,8 +5792,7 @@ pub enum FilterMode { /// A range of push constant memory to pass to a shader stage. #[derive(Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct PushConstantRange { /// Stage push constant range is visible from. Each stage can only be served by at most one range. /// One range can serve multiple stages however. @@ -5844,8 +5808,7 @@ pub struct PushConstantRange { /// https://gpuweb.github.io/gpuweb/#dictdef-gpucommandbufferdescriptor). #[repr(C)] #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct CommandBufferDescriptor { /// Debug label of this command buffer. pub label: L, @@ -5866,8 +5829,7 @@ impl CommandBufferDescriptor { /// https://gpuweb.github.io/gpuweb/#dictdef-gpurenderbundleencoderdescriptor). #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct RenderBundleDepthStencil { /// Format of the attachment. pub format: TextureFormat, @@ -5894,8 +5856,7 @@ pub struct RenderBundleDepthStencil { /// https://gpuweb.github.io/gpuweb/#dictdef-gpurenderbundledescriptor). #[repr(C)] #[derive(Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct RenderBundleDescriptor { /// Debug label of the render bundle encoder. This will show up in graphics debuggers for easy identification. pub label: L, @@ -5931,8 +5892,7 @@ impl Default for RenderBundleDescriptor> { /// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagedatalayout). #[repr(C)] #[derive(Clone, Copy, Debug, Default)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ImageDataLayout { /// Offset into the buffer that is the start of the texture. Must be a multiple of texture block size. /// For non-compressed textures, this is 1. @@ -5972,8 +5932,7 @@ pub struct ImageDataLayout { /// Corresponds to [WebGPU `GPUBufferBindingType`]( /// https://gpuweb.github.io/gpuweb/#enumdef-gpubufferbindingtype). #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum BufferBindingType { /// A buffer for uniform values. /// @@ -6038,8 +5997,7 @@ pub enum BufferBindingType { /// Corresponds to [WebGPU `GPUTextureSampleType`]( /// https://gpuweb.github.io/gpuweb/#enumdef-gputexturesampletype). #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum TextureSampleType { /// Sampling returns floats. /// @@ -6121,8 +6079,7 @@ impl Default for TextureSampleType { /// Corresponds to [WebGPU `GPUStorageTextureAccess`]( /// https://gpuweb.github.io/gpuweb/#enumdef-gpustoragetextureaccess). #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum StorageTextureAccess { /// The texture can only be written in the shader and it: @@ -6184,8 +6141,7 @@ pub enum StorageTextureAccess { /// https://gpuweb.github.io/gpuweb/#enumdef-gpusamplerbindingtype). #[repr(C)] #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum SamplerBindingType { /// The sampling result is produced based on more than a single color sample from a texture, @@ -6205,8 +6161,7 @@ pub enum SamplerBindingType { /// Corresponds to WebGPU's mutually exclusive fields within [`GPUBindGroupLayoutEntry`]( /// https://gpuweb.github.io/gpuweb/#dictdef-gpubindgrouplayoutentry). #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum BindingType { /// A buffer binding. /// @@ -6222,7 +6177,7 @@ pub enum BindingType { /// for each dynamic binding in increasing order of binding number. /// /// [RPsbg]: ../wgpu/struct.RenderPass.html#method.set_bind_group - #[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))] + #[cfg_attr(feature = "serde", serde(default))] has_dynamic_offset: bool, /// The minimum size for a [`BufferBinding`] matching this entry, in bytes. @@ -6250,7 +6205,7 @@ pub enum BindingType { /// [minimum buffer binding size]: https://www.w3.org/TR/webgpu/#minimum-buffer-binding-size /// [`create_render_pipeline`]: ../wgpu/struct.Device.html#method.create_render_pipeline /// [`create_compute_pipeline`]: ../wgpu/struct.Device.html#method.create_compute_pipeline - #[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))] + #[cfg_attr(feature = "serde", serde(default))] min_binding_size: Option, }, /// A sampler that can be used to sample a texture. @@ -6355,8 +6310,7 @@ impl BindingType { /// Corresponds to [WebGPU `GPUBindGroupLayoutEntry`]( /// https://gpuweb.github.io/gpuweb/#dictdef-gpubindgrouplayoutentry). #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct BindGroupLayoutEntry { /// Binding index. Must match shader index and be unique inside a BindGroupLayout. A binding /// of index 1, would be described as `layout(set = 0, binding = 1) uniform` in shaders. @@ -6370,7 +6324,7 @@ pub struct BindGroupLayoutEntry { /// If this value is Some and `ty` is `BindingType::Texture`, [`Features::TEXTURE_BINDING_ARRAY`] must be supported. /// /// If this value is Some and `ty` is any other variant, bind group creation will fail. - #[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))] + #[cfg_attr(feature = "serde", serde(default))] pub count: Option, } @@ -6380,8 +6334,7 @@ pub struct BindGroupLayoutEntry { /// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopybuffer). #[repr(C)] #[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ImageCopyBuffer { /// The buffer to be copied to/from. pub buffer: B, @@ -6395,8 +6348,7 @@ pub struct ImageCopyBuffer { /// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopytexture). #[repr(C)] #[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ImageCopyTexture { /// The texture to be copied to/from. pub texture: T, @@ -6405,10 +6357,10 @@ pub struct ImageCopyTexture { /// The base texel of the texture in the selected `mip_level`. Together /// with the `copy_size` argument to copy functions, defines the /// sub-region of the texture to copy. - #[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))] + #[cfg_attr(feature = "serde", serde(default))] pub origin: Origin3d, /// The copy aspect. - #[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))] + #[cfg_attr(feature = "serde", serde(default))] pub aspect: TextureAspect, } @@ -6528,8 +6480,7 @@ unsafe impl Sync for ExternalImageSource {} /// Corresponds to [HTML Canvas `PredefinedColorSpace`]( /// https://html.spec.whatwg.org/multipage/canvas.html#predefinedcolorspace). #[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum PredefinedColorSpace { /// sRGB color space @@ -6544,8 +6495,7 @@ pub enum PredefinedColorSpace { /// Corresponds to [WebGPU `GPUImageCopyTextureTagged`]( /// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopytexturetagged). #[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ImageCopyTextureTagged { /// The texture to be copied to/from. pub texture: T, @@ -6576,8 +6526,7 @@ impl ImageCopyTextureTagged { /// Subresource range within an image #[repr(C)] #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] pub struct ImageSubresourceRange { /// Aspect of the texture. Color textures must be [`TextureAspect::All`][TAA]. @@ -6678,8 +6627,7 @@ impl ImageSubresourceRange { /// Color variation to use when sampler addressing mode is [`AddressMode::ClampToBorder`] #[repr(C)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum SamplerBorderColor { /// [0, 0, 0, 0] TransparentBlack, @@ -6701,8 +6649,7 @@ pub enum SamplerBorderColor { /// Corresponds to [WebGPU `GPUQuerySetDescriptor`]( /// https://gpuweb.github.io/gpuweb/#dictdef-gpuquerysetdescriptor). #[derive(Clone, Debug)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct QuerySetDescriptor { /// Debug label for the query set. pub label: L, @@ -6729,8 +6676,7 @@ impl QuerySetDescriptor { /// Corresponds to [WebGPU `GPUQueryType`]( /// https://gpuweb.github.io/gpuweb/#enumdef-gpuquerytype). #[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum QueryType { /// Query returns a single 64-bit number, serving as an occlusion boolean. Occlusion, @@ -6876,8 +6822,7 @@ impl DispatchIndirectArgs { /// Describes how shader bound checks should be performed. #[derive(Clone, Debug)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ShaderBoundChecks { runtime_checks: bool, } diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index cc97e4d249..a0c1926713 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -78,6 +78,9 @@ strict_asserts = ["wgc?/strict_asserts", "wgt/strict_asserts"] ## Log all API entry points at info instead of trace level. api_log_info = ["wgc/api_log_info"] +## Enables serialization via `serde` on common wgpu types. +serde = ["dep:serde", "wgc/serde"] + ## Allow writing of trace capture files. ## See [`Adapter::request_device`]. trace = ["serde", "wgc/trace"] diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 9b4af33cd6..b963fa695b 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -37,6 +37,7 @@ //! - **`strict_asserts`** --- Apply run-time checks, even in release builds. These are in addition //! to the validation carried out at public APIs in all builds. //! - **`api_log_info`** --- Log all API entry points at info instead of trace level. +//! - **`serde`** --- Enables serialization via `serde` on common wgpu types. //! - **`trace`** --- Allow writing of trace capture files. See [`Adapter::request_device`]. //! - **`replay`** --- Allow deserializing of trace capture files that were written with the `trace` //! feature. To replay a trace file use the [wgpu @@ -1115,8 +1116,7 @@ static_assertions::assert_impl_all!(BufferBinding<'_>: Send, Sync); /// Corresponds to [WebGPU `GPULoadOp`](https://gpuweb.github.io/gpuweb/#enumdef-gpuloadop), /// plus the corresponding clearValue. #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum LoadOp { /// Loads the specified value for this attachment into the render pass. /// @@ -1143,8 +1143,7 @@ impl Default for LoadOp { /// /// Corresponds to [WebGPU `GPUStoreOp`](https://gpuweb.github.io/gpuweb/#enumdef-gpustoreop). #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Default)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum StoreOp { /// Stores the resulting value of the render pass for this attachment. #[default] @@ -1166,8 +1165,7 @@ pub enum StoreOp { /// This type is unique to the Rust API of `wgpu`. In the WebGPU specification, /// separate `loadOp` and `storeOp` fields are used instead. #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Operations { /// How data should be read through this attachment. pub load: LoadOp, From dec6ea5ea494c77d8233185738ec669ccdfd49be Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Mon, 29 Jan 2024 10:56:04 +0100 Subject: [PATCH 059/101] Improve the consistency of identifiers (#5108) --- deno_webgpu/queue.rs | 6 +- player/src/bin/play.rs | 13 +- player/src/lib.rs | 21 +-- player/tests/test.rs | 15 +- wgpu-core/src/binding_model.rs | 37 ++-- wgpu-core/src/command/bundle.rs | 12 +- wgpu-core/src/command/compute.rs | 2 +- wgpu-core/src/command/mod.rs | 18 +- wgpu-core/src/command/query.rs | 8 +- wgpu-core/src/command/render.rs | 10 +- wgpu-core/src/device/global.rs | 108 ++++++------ wgpu-core/src/device/life.rs | 13 +- wgpu-core/src/device/mod.rs | 11 +- wgpu-core/src/device/queue.rs | 19 +- wgpu-core/src/device/resource.rs | 20 ++- wgpu-core/src/global.rs | 3 +- wgpu-core/src/hub.rs | 50 +++--- wgpu-core/src/id.rs | 286 ++++++++++++++++++++----------- wgpu-core/src/identity.rs | 75 ++++---- wgpu-core/src/instance.rs | 99 ++++++----- wgpu-core/src/pipeline.rs | 32 ++-- wgpu-core/src/present.rs | 5 +- wgpu-core/src/registry.rs | 65 +++---- wgpu-core/src/resource.rs | 88 +++++----- wgpu-core/src/storage.rs | 55 +++--- wgpu-core/src/track/buffer.rs | 27 ++- wgpu-core/src/track/metadata.rs | 14 +- wgpu-core/src/track/mod.rs | 68 ++++---- wgpu-core/src/track/stateless.rs | 39 +++-- wgpu-core/src/track/texture.rs | 23 ++- wgpu/src/backend/wgpu_core.rs | 17 +- 31 files changed, 687 insertions(+), 572 deletions(-) diff --git a/deno_webgpu/queue.rs b/deno_webgpu/queue.rs index 1f6258935f..61b56c7586 100644 --- a/deno_webgpu/queue.rs +++ b/deno_webgpu/queue.rs @@ -32,7 +32,7 @@ pub fn op_webgpu_queue_submit( }) .collect::, AnyError>>()?; - let maybe_err = gfx_select!(queue => instance.queue_submit(queue, &ids)).err(); + let maybe_err = gfx_select!(queue => instance.queue_submit(queue.transmute(), &ids)).err(); for rid in command_buffers { let resource = state.resource_table.take::(rid)?; @@ -84,7 +84,7 @@ pub fn op_webgpu_write_buffer( None => &buf[data_offset..], }; let maybe_err = gfx_select!(queue => instance.queue_write_buffer( - queue, + queue.transmute(), buffer, buffer_offset, data @@ -120,7 +120,7 @@ pub fn op_webgpu_write_texture( let data_layout = data_layout.into(); gfx_ok!(queue => instance.queue_write_texture( - queue, + queue.transmute(), &destination, buf, &data_layout, diff --git a/player/src/bin/play.rs b/player/src/bin/play.rs index f91b1b6615..5e87232d8c 100644 --- a/player/src/bin/play.rs +++ b/player/src/bin/play.rs @@ -61,7 +61,7 @@ fn main() { global.instance_create_surface( window.display_handle().unwrap().into(), window.window_handle().unwrap().into(), - wgc::id::TypedId::zip(0, 1, wgt::Backend::Empty), + wgc::id::Id::zip(0, 1, wgt::Backend::Empty), ) } .unwrap(); @@ -79,22 +79,21 @@ fn main() { #[cfg(not(feature = "winit"))] compatible_surface: None, }, - wgc::instance::AdapterInputs::IdSet( - &[wgc::id::TypedId::zip(0, 0, backend)], - |id| id.backend(), - ), + wgc::instance::AdapterInputs::IdSet(&[wgc::id::Id::zip(0, 0, backend)], |id| { + id.backend() + }), ) .expect("Unable to find an adapter for selected backend"); let info = gfx_select!(adapter => global.adapter_get_info(adapter)).unwrap(); log::info!("Picked '{}'", info.name); - let id = wgc::id::TypedId::zip(1, 0, backend); + let id = wgc::id::Id::zip(1, 0, backend); let (_, _, error) = gfx_select!(adapter => global.adapter_request_device( adapter, &desc, None, id, - id + id.transmute() )); if let Some(e) = error { panic!("{:?}", e); diff --git a/player/src/lib.rs b/player/src/lib.rs index ec8b91371a..3062d6a851 100644 --- a/player/src/lib.rs +++ b/player/src/lib.rs @@ -14,10 +14,10 @@ use std::{borrow::Cow, fs, path::Path}; pub struct IdentityPassThroughFactory; -impl wgc::identity::IdentityHandlerFactory for IdentityPassThroughFactory { - type Input = I; +impl wgc::identity::IdentityHandlerFactory for IdentityPassThroughFactory { + type Input = wgc::id::Id; - fn input_to_id(id_in: Self::Input) -> I { + fn input_to_id(id_in: Self::Input) -> wgc::id::Id { id_in } @@ -38,7 +38,7 @@ pub trait GlobalPlay { device: wgc::id::DeviceId, action: trace::Action, dir: &Path, - comb_manager: &mut wgc::identity::IdentityManager, + comb_manager: &mut wgc::identity::IdentityManager, ); } @@ -153,7 +153,7 @@ impl GlobalPlay for wgc::global::Global { device: wgc::id::DeviceId, action: trace::Action, dir: &Path, - comb_manager: &mut wgc::identity::IdentityManager, + comb_manager: &mut wgc::identity::IdentityManager, ) { use wgc::device::trace::Action; log::debug!("action {:?}", action); @@ -350,7 +350,7 @@ impl GlobalPlay for wgc::global::Global { let bin = std::fs::read(dir.join(data)).unwrap(); let size = (range.end - range.start) as usize; if queued { - self.queue_write_buffer::(device, id, range.start, &bin) + self.queue_write_buffer::(device.transmute(), id, range.start, &bin) .unwrap(); } else { self.device_wait_for_buffer::(device, id).unwrap(); @@ -365,23 +365,24 @@ impl GlobalPlay for wgc::global::Global { size, } => { let bin = std::fs::read(dir.join(data)).unwrap(); - self.queue_write_texture::(device, &to, &bin, &layout, &size) + self.queue_write_texture::(device.transmute(), &to, &bin, &layout, &size) .unwrap(); } Action::Submit(_index, ref commands) if commands.is_empty() => { - self.queue_submit::(device, &[]).unwrap(); + self.queue_submit::(device.transmute(), &[]).unwrap(); } Action::Submit(_index, commands) => { let (encoder, error) = self.device_create_command_encoder::( device, &wgt::CommandEncoderDescriptor { label: None }, - comb_manager.process(device.backend()), + comb_manager.process(device.backend()).transmute(), ); if let Some(e) = error { panic!("{e}"); } let cmdbuf = self.encode_commands::(encoder, commands); - self.queue_submit::(device, &[cmdbuf]).unwrap(); + self.queue_submit::(device.transmute(), &[cmdbuf]) + .unwrap(); } } } diff --git a/player/tests/test.rs b/player/tests/test.rs index cb09aecebc..bf6e0b315c 100644 --- a/player/tests/test.rs +++ b/player/tests/test.rs @@ -105,7 +105,7 @@ impl Test<'_> { test_num: u32, ) { let backend = adapter.backend(); - let device_id = wgc::id::TypedId::zip(test_num, 0, backend); + let device_id = wgc::id::Id::zip(test_num, 0, backend); let (_, _, error) = wgc::gfx_select!(adapter => global.adapter_request_device( adapter, &wgt::DeviceDescriptor { @@ -115,7 +115,7 @@ impl Test<'_> { }, None, device_id, - device_id + device_id.transmute() )); if let Some(e) = error { panic!("{:?}", e); @@ -128,7 +128,7 @@ impl Test<'_> { } println!("\t\t\tMapping..."); for expect in &self.expectations { - let buffer = wgc::id::TypedId::zip(expect.buffer.index, expect.buffer.epoch, backend); + let buffer = wgc::id::Id::zip(expect.buffer.index, expect.buffer.epoch, backend); wgc::gfx_select!(device_id => global.buffer_map_async( buffer, expect.offset .. expect.offset+expect.data.len() as wgt::BufferAddress, @@ -148,7 +148,7 @@ impl Test<'_> { for expect in self.expectations { println!("\t\t\tChecking {}", expect.name); - let buffer = wgc::id::TypedId::zip(expect.buffer.index, expect.buffer.epoch, backend); + let buffer = wgc::id::Id::zip(expect.buffer.index, expect.buffer.epoch, backend); let (ptr, size) = wgc::gfx_select!(device_id => global.buffer_get_mapped_range(buffer, expect.offset, Some(expect.data.len() as wgt::BufferAddress))) .unwrap(); @@ -221,10 +221,9 @@ impl Corpus { force_fallback_adapter: false, compatible_surface: None, }, - wgc::instance::AdapterInputs::IdSet( - &[wgc::id::TypedId::zip(0, 0, backend)], - |id| id.backend(), - ), + wgc::instance::AdapterInputs::IdSet(&[wgc::id::Id::zip(0, 0, backend)], |id| { + id.backend() + }), ) { Ok(adapter) => adapter, Err(_) => continue, diff --git a/wgpu-core/src/binding_model.rs b/wgpu-core/src/binding_model.rs index fe4f977d03..9520c50cd8 100644 --- a/wgpu-core/src/binding_model.rs +++ b/wgpu-core/src/binding_model.rs @@ -6,10 +6,7 @@ use crate::{ }, error::{ErrorFormatter, PrettyError}, hal_api::HalApi, - id::{ - BindGroupId, BindGroupLayoutId, BufferId, PipelineLayoutId, SamplerId, TextureId, - TextureViewId, - }, + id::{BindGroupLayoutId, BufferId, SamplerId, TextureId, TextureViewId}, init_tracker::{BufferInitTrackerAction, TextureInitTrackerAction}, resource::{Resource, ResourceInfo, ResourceType}, resource_log, @@ -441,7 +438,7 @@ pub struct BindGroupLayoutDescriptor<'a> { pub entries: Cow<'a, [wgt::BindGroupLayoutEntry]>, } -pub type BindGroupLayouts = crate::storage::Storage, BindGroupLayoutId>; +pub type BindGroupLayouts = crate::storage::Storage>; /// Bind group layout. #[derive(Debug)] @@ -458,7 +455,7 @@ pub struct BindGroupLayout { pub(crate) origin: bgl::Origin, #[allow(unused)] pub(crate) binding_count_validator: BindingTypeMaxCountValidator, - pub(crate) info: ResourceInfo, + pub(crate) info: ResourceInfo>, pub(crate) label: String, } @@ -482,14 +479,16 @@ impl Drop for BindGroupLayout { } } -impl Resource for BindGroupLayout { +impl Resource for BindGroupLayout { const TYPE: ResourceType = "BindGroupLayout"; - fn as_info(&self) -> &ResourceInfo { + type Marker = crate::id::markers::BindGroupLayout; + + fn as_info(&self) -> &ResourceInfo { &self.info } - fn as_info_mut(&mut self) -> &mut ResourceInfo { + fn as_info_mut(&mut self) -> &mut ResourceInfo { &mut self.info } @@ -602,7 +601,7 @@ pub struct PipelineLayoutDescriptor<'a> { pub struct PipelineLayout { pub(crate) raw: Option, pub(crate) device: Arc>, - pub(crate) info: ResourceInfo, + pub(crate) info: ResourceInfo>, pub(crate) bind_group_layouts: ArrayVec>, { hal::MAX_BIND_GROUPS }>, pub(crate) push_constant_ranges: ArrayVec, } @@ -716,14 +715,16 @@ impl PipelineLayout { } } -impl Resource for PipelineLayout { +impl Resource for PipelineLayout { const TYPE: ResourceType = "PipelineLayout"; - fn as_info(&self) -> &ResourceInfo { + type Marker = crate::id::markers::PipelineLayout; + + fn as_info(&self) -> &ResourceInfo { &self.info } - fn as_info_mut(&mut self) -> &mut ResourceInfo { + fn as_info_mut(&mut self) -> &mut ResourceInfo { &mut self.info } } @@ -830,7 +831,7 @@ pub struct BindGroup { pub(crate) raw: Snatchable, pub(crate) device: Arc>, pub(crate) layout: Arc>, - pub(crate) info: ResourceInfo, + pub(crate) info: ResourceInfo>, pub(crate) used: BindGroupStates, pub(crate) used_buffer_ranges: Vec>, pub(crate) used_texture_ranges: Vec>, @@ -919,14 +920,16 @@ impl BindGroup { } } -impl Resource for BindGroup { +impl Resource for BindGroup { const TYPE: ResourceType = "BindGroup"; - fn as_info(&self) -> &ResourceInfo { + type Marker = crate::id::markers::BindGroup; + + fn as_info(&self) -> &ResourceInfo { &self.info } - fn as_info_mut(&mut self) -> &mut ResourceInfo { + fn as_info_mut(&mut self) -> &mut ResourceInfo { &mut self.info } } diff --git a/wgpu-core/src/command/bundle.rs b/wgpu-core/src/command/bundle.rs index 49def22d45..9d80c62f85 100644 --- a/wgpu-core/src/command/bundle.rs +++ b/wgpu-core/src/command/bundle.rs @@ -94,7 +94,7 @@ use crate::{ error::{ErrorFormatter, PrettyError}, hal_api::HalApi, hub::Hub, - id::{self, RenderBundleId}, + id, init_tracker::{BufferInitTrackerAction, MemoryInitKind, TextureInitTrackerAction}, pipeline::{PipelineFlags, RenderPipeline, VertexStep}, resource::{Resource, ResourceInfo, ResourceType}, @@ -832,7 +832,7 @@ pub struct RenderBundle { pub(super) buffer_memory_init_actions: Vec>, pub(super) texture_memory_init_actions: Vec>, pub(super) context: RenderPassContext, - pub(crate) info: ResourceInfo, + pub(crate) info: ResourceInfo>, discard_hal_labels: bool, } @@ -1067,14 +1067,16 @@ impl RenderBundle { } } -impl Resource for RenderBundle { +impl Resource for RenderBundle { const TYPE: ResourceType = "RenderBundle"; - fn as_info(&self) -> &ResourceInfo { + type Marker = crate::id::markers::RenderBundle; + + fn as_info(&self) -> &ResourceInfo { &self.info } - fn as_info_mut(&mut self) -> &mut ResourceInfo { + fn as_info_mut(&mut self) -> &mut ResourceInfo { &mut self.info } } diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index cd7949b3da..afd9c5204f 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -305,7 +305,7 @@ impl State { &mut self, raw_encoder: &mut A::CommandEncoder, base_trackers: &mut Tracker, - bind_group_guard: &Storage, id::BindGroupId>, + bind_group_guard: &Storage>, indirect_buffer: Option, snatch_guard: &SnatchGuard, ) -> Result<(), UsageConflict> { diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index 40ac0628f0..1201e30f0e 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -140,7 +140,7 @@ pub struct CommandBuffer { pub(crate) device: Arc>, limits: wgt::Limits, support_clear_texture: bool, - pub(crate) info: ResourceInfo, + pub(crate) info: ResourceInfo>, pub(crate) data: Mutex>>, } @@ -255,7 +255,7 @@ impl CommandBuffer { id: id::CommandEncoderId, ) -> Result, CommandEncoderError> { let storage = hub.command_buffers.read(); - match storage.get(id) { + match storage.get(id.transmute()) { Ok(cmd_buf) => match cmd_buf.data.lock().as_ref().unwrap().status { CommandEncoderStatus::Recording => Ok(cmd_buf.clone()), CommandEncoderStatus::Finished => Err(CommandEncoderError::NotRecording), @@ -296,14 +296,16 @@ impl CommandBuffer { } } -impl Resource for CommandBuffer { +impl Resource for CommandBuffer { const TYPE: ResourceType = "CommandBuffer"; - fn as_info(&self) -> &ResourceInfo { + type Marker = crate::id::markers::CommandBuffer; + + fn as_info(&self) -> &ResourceInfo { &self.info } - fn as_info_mut(&mut self) -> &mut ResourceInfo { + fn as_info_mut(&mut self) -> &mut ResourceInfo { &mut self.info } @@ -418,7 +420,7 @@ impl Global { let hub = A::hub(self); - let error = match hub.command_buffers.get(encoder_id) { + let error = match hub.command_buffers.get(encoder_id.transmute()) { Ok(cmd_buf) => { let mut cmd_buf_data = cmd_buf.data.lock(); let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); @@ -444,7 +446,7 @@ impl Global { Err(_) => Some(CommandEncoderError::Invalid), }; - (encoder_id, error) + (encoder_id.transmute(), error) } pub fn command_encoder_push_debug_group( @@ -700,7 +702,7 @@ impl PrettyError for PassErrorScope { // This error is not in the error chain, only notes are needed match *self { Self::Pass(id) => { - fmt.command_buffer_label(&id); + fmt.command_buffer_label(&id.transmute()); } Self::SetBindGroup(id) => { fmt.bind_group_label(&id); diff --git a/wgpu-core/src/command/query.rs b/wgpu-core/src/command/query.rs index 8c1f4b8f12..ab97cfc37a 100644 --- a/wgpu-core/src/command/query.rs +++ b/wgpu-core/src/command/query.rs @@ -7,7 +7,7 @@ use crate::{ device::DeviceError, global::Global, hal_api::HalApi, - id::{self, Id, TypedId}, + id::{self, Id}, identity::GlobalIdentityHandlerFactory, init_tracker::MemoryInitKind, resource::QuerySet, @@ -49,7 +49,7 @@ impl QueryResetMap { pub fn reset_queries( &mut self, raw_encoder: &mut A::CommandEncoder, - query_set_storage: &Storage, id::QuerySetId>, + query_set_storage: &Storage>, backend: wgt::Backend, ) -> Result<(), id::QuerySetId> { for (query_set_id, (state, epoch)) in self.map.drain() { @@ -314,7 +314,7 @@ impl QuerySet { pub(super) fn end_occlusion_query( raw_encoder: &mut A::CommandEncoder, - storage: &Storage, id::QuerySetId>, + storage: &Storage>, active_query: &mut Option<(id::QuerySetId, u32)>, ) -> Result<(), QueryUseError> { if let Some((query_set_id, query_index)) = active_query.take() { @@ -331,7 +331,7 @@ pub(super) fn end_occlusion_query( pub(super) fn end_pipeline_statistics_query( raw_encoder: &mut A::CommandEncoder, - storage: &Storage, id::QuerySetId>, + storage: &Storage>, active_query: &mut Option<(id::QuerySetId, u32)>, ) -> Result<(), QueryUseError> { if let Some((query_set_id, query_index)) = active_query.take() { diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index fedc6f7c89..933e00824b 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -784,10 +784,10 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { trackers: &mut Tracker, texture_memory_actions: &mut CommandBufferTextureMemoryActions, pending_query_resets: &mut QueryResetMap, - view_guard: &'a Storage, id::TextureViewId>, - buffer_guard: &'a Storage, id::BufferId>, - texture_guard: &'a Storage, id::TextureId>, - query_set_guard: &'a Storage, id::QuerySetId>, + view_guard: &'a Storage>, + buffer_guard: &'a Storage>, + texture_guard: &'a Storage>, + query_set_guard: &'a Storage>, snatch_guard: &SnatchGuard<'a>, ) -> Result { profiling::scope!("RenderPassInfo::start"); @@ -2391,7 +2391,7 @@ impl Global { (trackers, pending_discard_init_fixups) }; - let cmd_buf = hub.command_buffers.get(encoder_id).unwrap(); + let cmd_buf = hub.command_buffers.get(encoder_id.transmute()).unwrap(); let mut cmd_buf_data = cmd_buf.data.lock(); let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); diff --git a/wgpu-core/src/device/global.rs b/wgpu-core/src/device/global.rs index 1872159fcc..8db2db913f 100644 --- a/wgpu-core/src/device/global.rs +++ b/wgpu-core/src/device/global.rs @@ -8,6 +8,7 @@ use crate::{ }, global::Global, hal_api::HalApi, + id::markers, id::{self, AdapterId, DeviceId, QueueId, SurfaceId}, identity::{GlobalIdentityHandlerFactory, Input}, init_tracker::TextureInitTracker, @@ -146,12 +147,12 @@ impl Global { &self, device_id: DeviceId, desc: &resource::BufferDescriptor, - id_in: Input, + id_in: Input, ) -> (id::BufferId, Option) { profiling::scope!("Device::create_buffer"); let hub = A::hub(self); - let fid = hub.buffers.prepare::(id_in); + let fid = hub.buffers.prepare::(id_in); let mut to_destroy: ArrayVec, 2> = ArrayVec::new(); let error = loop { @@ -309,20 +310,20 @@ impl Global { /// [`device_create_buffer`]: Global::device_create_buffer /// [`usage`]: https://www.w3.org/TR/webgpu/#dom-gputexturedescriptor-usage /// [`wgpu_types::BufferUsages`]: wgt::BufferUsages - pub fn create_buffer_error(&self, id_in: Input, label: Label) { + pub fn create_buffer_error(&self, id_in: Input, label: Label) { let hub = A::hub(self); - let fid = hub.buffers.prepare::(id_in); + let fid = hub.buffers.prepare::(id_in); fid.assign_error(label.borrow_or_default()); } pub fn create_render_bundle_error( &self, - id_in: Input, + id_in: Input, label: Label, ) { let hub = A::hub(self); - let fid = hub.render_bundles.prepare::(id_in); + let fid = hub.render_bundles.prepare::(id_in); fid.assign_error(label.borrow_or_default()); } @@ -330,9 +331,9 @@ impl Global { /// Assign `id_in` an error with the given `label`. /// /// See `create_buffer_error` for more context and explaination. - pub fn create_texture_error(&self, id_in: Input, label: Label) { + pub fn create_texture_error(&self, id_in: Input, label: Label) { let hub = A::hub(self); - let fid = hub.textures.prepare::(id_in); + let fid = hub.textures.prepare::(id_in); fid.assign_error(label.borrow_or_default()); } @@ -545,13 +546,13 @@ impl Global { &self, device_id: DeviceId, desc: &resource::TextureDescriptor, - id_in: Input, + id_in: Input, ) -> (id::TextureId, Option) { profiling::scope!("Device::create_texture"); let hub = A::hub(self); - let fid = hub.textures.prepare::(id_in); + let fid = hub.textures.prepare::(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -599,13 +600,13 @@ impl Global { hal_texture: A::Texture, device_id: DeviceId, desc: &resource::TextureDescriptor, - id_in: Input, + id_in: Input, ) -> (id::TextureId, Option) { profiling::scope!("Device::create_texture_from_hal"); let hub = A::hub(self); - let fid = hub.textures.prepare::(id_in); + let fid = hub.textures.prepare::(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -673,12 +674,12 @@ impl Global { hal_buffer: A::Buffer, device_id: DeviceId, desc: &resource::BufferDescriptor, - id_in: Input, + id_in: Input, ) -> (id::BufferId, Option) { profiling::scope!("Device::create_buffer"); let hub = A::hub(self); - let fid = hub.buffers.prepare::(id_in); + let fid = hub.buffers.prepare::(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -783,13 +784,13 @@ impl Global { &self, texture_id: id::TextureId, desc: &resource::TextureViewDescriptor, - id_in: Input, + id_in: Input, ) -> (id::TextureViewId, Option) { profiling::scope!("Texture::create_view"); let hub = A::hub(self); - let fid = hub.texture_views.prepare::(id_in); + let fid = hub.texture_views.prepare::(id_in); let error = loop { let texture = match hub.textures.get(texture_id) { @@ -873,12 +874,12 @@ impl Global { &self, device_id: DeviceId, desc: &resource::SamplerDescriptor, - id_in: Input, + id_in: Input, ) -> (id::SamplerId, Option) { profiling::scope!("Device::create_sampler"); let hub = A::hub(self); - let fid = hub.samplers.prepare::(id_in); + let fid = hub.samplers.prepare::(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -934,7 +935,7 @@ impl Global { &self, device_id: DeviceId, desc: &binding_model::BindGroupLayoutDescriptor, - id_in: Input, + id_in: Input, ) -> ( id::BindGroupLayoutId, Option, @@ -942,7 +943,7 @@ impl Global { profiling::scope!("Device::create_bind_group_layout"); let hub = A::hub(self); - let fid = hub.bind_group_layouts.prepare::(id_in); + let fid = hub.bind_group_layouts.prepare::(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -1004,7 +1005,7 @@ impl Global { return (id.unwrap(), None); }; - let fid = hub.bind_group_layouts.prepare::(id_in); + let fid = hub.bind_group_layouts.prepare::(id_in); let id = fid.assign_error(desc.label.borrow_or_default()); (id, Some(error)) } @@ -1033,7 +1034,7 @@ impl Global { &self, device_id: DeviceId, desc: &binding_model::PipelineLayoutDescriptor, - id_in: Input, + id_in: Input, ) -> ( id::PipelineLayoutId, Option, @@ -1041,7 +1042,7 @@ impl Global { profiling::scope!("Device::create_pipeline_layout"); let hub = A::hub(self); - let fid = hub.pipeline_layouts.prepare::(id_in); + let fid = hub.pipeline_layouts.prepare::(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -1094,12 +1095,12 @@ impl Global { &self, device_id: DeviceId, desc: &binding_model::BindGroupDescriptor, - id_in: Input, + id_in: Input, ) -> (id::BindGroupId, Option) { profiling::scope!("Device::create_bind_group"); let hub = A::hub(self); - let fid = hub.bind_groups.prepare::(id_in); + let fid = hub.bind_groups.prepare::(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -1178,7 +1179,7 @@ impl Global { device_id: DeviceId, desc: &pipeline::ShaderModuleDescriptor, source: pipeline::ShaderModuleSource, - id_in: Input, + id_in: Input, ) -> ( id::ShaderModuleId, Option, @@ -1186,7 +1187,7 @@ impl Global { profiling::scope!("Device::create_shader_module"); let hub = A::hub(self); - let fid = hub.shader_modules.prepare::(id_in); + let fid = hub.shader_modules.prepare::(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -1256,7 +1257,7 @@ impl Global { device_id: DeviceId, desc: &pipeline::ShaderModuleDescriptor, source: Cow<[u32]>, - id_in: Input, + id_in: Input, ) -> ( id::ShaderModuleId, Option, @@ -1264,7 +1265,7 @@ impl Global { profiling::scope!("Device::create_shader_module"); let hub = A::hub(self); - let fid = hub.shader_modules.prepare::(id_in); + let fid = hub.shader_modules.prepare::(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -1318,12 +1319,14 @@ impl Global { &self, device_id: DeviceId, desc: &wgt::CommandEncoderDescriptor(command_buffer_id) + self.command_encoder_drop::(command_buffer_id.transmute()) } pub fn device_create_render_bundle_encoder( @@ -1394,7 +1400,7 @@ impl Global { device_id: DeviceId, desc: &command::RenderBundleEncoderDescriptor, ) -> ( - id::RenderBundleEncoderId, + *mut command::RenderBundleEncoder, Option, ) { profiling::scope!("Device::create_render_bundle_encoder"); @@ -1410,13 +1416,13 @@ impl Global { &self, bundle_encoder: command::RenderBundleEncoder, desc: &command::RenderBundleDescriptor, - id_in: Input, + id_in: Input, ) -> (id::RenderBundleId, Option) { profiling::scope!("RenderBundleEncoder::finish"); let hub = A::hub(self); - let fid = hub.render_bundles.prepare::(id_in); + let fid = hub.render_bundles.prepare::(id_in); let error = loop { let device = match hub.devices.get(bundle_encoder.parent()) { @@ -1480,12 +1486,12 @@ impl Global { &self, device_id: DeviceId, desc: &resource::QuerySetDescriptor, - id_in: Input, + id_in: Input, ) -> (id::QuerySetId, Option) { profiling::scope!("Device::create_query_set"); let hub = A::hub(self); - let fid = hub.query_sets.prepare::(id_in); + let fid = hub.query_sets.prepare::(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -1554,7 +1560,7 @@ impl Global { &self, device_id: DeviceId, desc: &pipeline::RenderPipelineDescriptor, - id_in: Input, + id_in: Input, implicit_pipeline_ids: Option>, ) -> ( id::RenderPipelineId, @@ -1564,7 +1570,7 @@ impl Global { let hub = A::hub(self); - let fid = hub.render_pipelines.prepare::(id_in); + let fid = hub.render_pipelines.prepare::(id_in); let implicit_context = implicit_pipeline_ids.map(|ipi| ipi.prepare(hub)); let implicit_error_context = implicit_context.clone(); @@ -1633,7 +1639,7 @@ impl Global { &self, pipeline_id: id::RenderPipelineId, index: u32, - id_in: Input, + id_in: Input, ) -> ( id::BindGroupLayoutId, Option, @@ -1648,7 +1654,7 @@ impl Global { let id = match pipeline.layout.bind_group_layouts.get(index as usize) { Some(bg) => hub .bind_group_layouts - .prepare::(id_in) + .prepare::(id_in) .assign_existing(bg), None => break binding_model::GetBindGroupLayoutError::InvalidGroupIndex(index), }; @@ -1657,7 +1663,7 @@ impl Global { let id = hub .bind_group_layouts - .prepare::(id_in) + .prepare::(id_in) .assign_error(""); (id, Some(error)) } @@ -1692,7 +1698,7 @@ impl Global { &self, device_id: DeviceId, desc: &pipeline::ComputePipelineDescriptor, - id_in: Input, + id_in: Input, implicit_pipeline_ids: Option>, ) -> ( id::ComputePipelineId, @@ -1702,7 +1708,7 @@ impl Global { let hub = A::hub(self); - let fid = hub.compute_pipelines.prepare::(id_in); + let fid = hub.compute_pipelines.prepare::(id_in); let implicit_context = implicit_pipeline_ids.map(|ipi| ipi.prepare(hub)); let implicit_error_context = implicit_context.clone(); @@ -1766,7 +1772,7 @@ impl Global { &self, pipeline_id: id::ComputePipelineId, index: u32, - id_in: Input, + id_in: Input, ) -> ( id::BindGroupLayoutId, Option, @@ -1782,7 +1788,7 @@ impl Global { let id = match pipeline.layout.bind_group_layouts.get(index as usize) { Some(bg) => hub .bind_group_layouts - .prepare::(id_in) + .prepare::(id_in) .assign_existing(bg), None => break binding_model::GetBindGroupLayoutError::InvalidGroupIndex(index), }; @@ -1792,7 +1798,7 @@ impl Global { let id = hub .bind_group_layouts - .prepare::(id_in) + .prepare::(id_in) .assign_error(""); (id, Some(error)) } @@ -2118,7 +2124,7 @@ impl Global { let (closures, queue_empty) = { if let wgt::Maintain::WaitForSubmissionIndex(submission_index) = maintain { - if submission_index.queue_id != device_id { + if submission_index.queue_id != device_id.transmute() { return Err(WaitIdleError::WrongSubmissionIndex( submission_index.queue_id, device_id, diff --git a/wgpu-core/src/device/life.rs b/wgpu-core/src/device/life.rs index eeae617747..ced9877251 100644 --- a/wgpu-core/src/device/life.rs +++ b/wgpu-core/src/device/life.rs @@ -7,7 +7,7 @@ use crate::{ }, hal_api::HalApi, id::{ - self, BindGroupId, BindGroupLayoutId, BufferId, ComputePipelineId, PipelineLayoutId, + self, BindGroupId, BindGroupLayoutId, BufferId, ComputePipelineId, Id, PipelineLayoutId, QuerySetId, RenderBundleId, RenderPipelineId, SamplerId, StagingBufferId, TextureId, TextureViewId, }, @@ -419,15 +419,14 @@ impl LifetimeTracker { } impl LifetimeTracker { - fn triage_resources( - resources_map: &mut FastHashMap>, + fn triage_resources( + resources_map: &mut FastHashMap, Arc>, active: &mut [ActiveSubmission], - trackers: &mut impl ResourceTracker, - get_resource_map: impl Fn(&mut ResourceMaps) -> &mut FastHashMap>, + trackers: &mut impl ResourceTracker, + get_resource_map: impl Fn(&mut ResourceMaps) -> &mut FastHashMap, Arc>, ) -> Vec> where - Id: id::TypedId, - R: Resource, + R: Resource, { let mut removed_resources = Vec::new(); resources_map.retain(|&id, resource| { diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 2d53026162..703b21ae94 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -2,7 +2,8 @@ use crate::{ binding_model, hal_api::HalApi, hub::Hub, - id::{self}, + id, + id::markers, identity::{GlobalIdentityHandlerFactory, Input}, resource::{Buffer, BufferAccessResult}, resource::{BufferAccessError, BufferMapOperation}, @@ -463,18 +464,18 @@ pub struct ImplicitPipelineContext { } pub struct ImplicitPipelineIds<'a, G: GlobalIdentityHandlerFactory> { - pub root_id: Input, - pub group_ids: &'a [Input], + pub root_id: Input, + pub group_ids: &'a [Input], } impl ImplicitPipelineIds<'_, G> { fn prepare(self, hub: &Hub) -> ImplicitPipelineContext { ImplicitPipelineContext { - root_id: hub.pipeline_layouts.prepare::(self.root_id).into_id(), + root_id: hub.pipeline_layouts.prepare::(self.root_id).into_id(), group_ids: self .group_ids .iter() - .map(|id_in| hub.bind_group_layouts.prepare::(*id_in).into_id()) + .map(|id_in| hub.bind_group_layouts.prepare::(*id_in).into_id()) .collect(), } } diff --git a/wgpu-core/src/device/queue.rs b/wgpu-core/src/device/queue.rs index 4e56350d81..4bd0046227 100644 --- a/wgpu-core/src/device/queue.rs +++ b/wgpu-core/src/device/queue.rs @@ -12,6 +12,7 @@ use crate::{ global::Global, hal_api::HalApi, hal_label, + id::markers, id::{self, QueueId}, identity::{GlobalIdentityHandlerFactory, Input}, init_tracker::{has_copy_partial_init_tracker_coverage, TextureInitRange}, @@ -37,17 +38,19 @@ use super::Device; pub struct Queue { pub device: Option>>, pub raw: Option, - pub info: ResourceInfo, + pub info: ResourceInfo>, } -impl Resource for Queue { +impl Resource for Queue { const TYPE: ResourceType = "Queue"; - fn as_info(&self) -> &ResourceInfo { + type Marker = crate::id::markers::Queue; + + fn as_info(&self) -> &ResourceInfo { &self.info } - fn as_info_mut(&mut self) -> &mut ResourceInfo { + fn as_info_mut(&mut self) -> &mut ResourceInfo { &mut self.info } } @@ -436,7 +439,7 @@ impl Global { &self, queue_id: QueueId, buffer_size: wgt::BufferSize, - id_in: Input, + id_in: Input, ) -> Result<(id::StagingBufferId, *mut u8), QueueWriteError> { profiling::scope!("Queue::create_staging_buffer"); let hub = A::hub(self); @@ -451,7 +454,7 @@ impl Global { let (staging_buffer, staging_buffer_ptr) = prepare_staging_buffer(device, buffer_size.get(), device.instance_flags)?; - let fid = hub.staging_buffers.prepare::(id_in); + let fid = hub.staging_buffers.prepare::(id_in); let (id, _) = fid.assign(staging_buffer); resource_log!("Queue::create_staging_buffer {id:?}"); @@ -669,7 +672,7 @@ impl Global { .get(destination.texture) .map_err(|_| TransferError::InvalidTexture(destination.texture))?; - if dst.device.as_info().id() != queue_id { + if dst.device.as_info().id() != queue_id.transmute() { return Err(DeviceError::WrongDevice.into()); } @@ -1150,7 +1153,7 @@ impl Global { Err(_) => continue, }; - if cmdbuf.device.as_info().id() != queue_id { + if cmdbuf.device.as_info().id() != queue_id.transmute() { return Err(DeviceError::WrongDevice.into()); } diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index b46bfde691..b9b942449e 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -12,7 +12,7 @@ use crate::{ hal_api::HalApi, hal_label, hub::Hub, - id::{self, DeviceId, QueueId}, + id::QueueId, init_tracker::{ BufferInitTracker, BufferInitTrackerAction, MemoryInitKind, TextureInitRange, TextureInitTracker, TextureInitTrackerAction, @@ -90,7 +90,7 @@ pub struct Device { pub(crate) queue_id: RwLock>, queue_to_drop: RwLock>, pub(crate) zero_buffer: Option, - pub(crate) info: ResourceInfo, + pub(crate) info: ResourceInfo>, pub(crate) command_allocator: Mutex>>, //Note: The submission index here corresponds to the last submission that is done. @@ -1785,7 +1785,7 @@ impl Device { dynamic_binding_info: &mut Vec, late_buffer_binding_sizes: &mut FastHashMap, used: &mut BindGroupStates, - storage: &'a Storage, id::BufferId>, + storage: &'a Storage>, limits: &wgt::Limits, snatch_guard: &'a SnatchGuard<'a>, ) -> Result, binding_model::CreateBindGroupError> { @@ -2386,7 +2386,7 @@ impl Device { pub(crate) fn create_pipeline_layout( self: &Arc, desc: &binding_model::PipelineLayoutDescriptor, - bgl_registry: &Registry>, + bgl_registry: &Registry>, ) -> Result, binding_model::CreatePipelineLayoutError> { use crate::binding_model::CreatePipelineLayoutError as Error; @@ -2499,8 +2499,8 @@ impl Device { self: &Arc, implicit_context: Option, mut derived_group_layouts: ArrayVec, - bgl_registry: &Registry>, - pipeline_layout_registry: &Registry>, + bgl_registry: &Registry>, + pipeline_layout_registry: &Registry>, ) -> Result>, pipeline::ImplicitLayoutError> { while derived_group_layouts .last() @@ -3440,14 +3440,16 @@ impl Device { } } -impl Resource for Device { +impl Resource for Device { const TYPE: ResourceType = "Device"; - fn as_info(&self) -> &ResourceInfo { + type Marker = crate::id::markers::Device; + + fn as_info(&self) -> &ResourceInfo { &self.info } - fn as_info_mut(&mut self) -> &mut ResourceInfo { + fn as_info_mut(&mut self) -> &mut ResourceInfo { &mut self.info } } diff --git a/wgpu-core/src/global.rs b/wgpu-core/src/global.rs index 87271917c2..950fabe2db 100644 --- a/wgpu-core/src/global.rs +++ b/wgpu-core/src/global.rs @@ -5,7 +5,6 @@ use wgt::Backend; use crate::{ hal_api::HalApi, hub::{HubReport, Hubs}, - id::SurfaceId, identity::GlobalIdentityHandlerFactory, instance::{Instance, Surface}, registry::{Registry, RegistryReport}, @@ -47,7 +46,7 @@ impl GlobalReport { pub struct Global { pub instance: Instance, - pub surfaces: Registry, + pub surfaces: Registry, pub(crate) hubs: Hubs, _phantom: PhantomData, } diff --git a/wgpu-core/src/hub.rs b/wgpu-core/src/hub.rs index 22208fdf5f..8494bef2b4 100644 --- a/wgpu-core/src/hub.rs +++ b/wgpu-core/src/hub.rs @@ -2,10 +2,13 @@ The `wgpu_core` API uses identifiers of type [`Id`] to refer to resources of type `R`. For example, [`id::DeviceId`] is an alias for -`Id>`, and [`id::BufferId`] is an alias for -`Id>`. `Id` implements `Copy`, `Hash`, `Eq`, `Ord`, and +`Id`, and [`id::BufferId`] is an alias for +`Id`. `Id` implements `Copy`, `Hash`, `Eq`, `Ord`, and of course `Debug`. +[`id::DeviceId`]: crate::id::DeviceId +[`id::BufferId`]: crate::id::BufferId + Each `Id` contains not only an index for the resource it denotes but also a Backend indicating which `wgpu` backend it belongs to. You can use the [`gfx_select`] macro to dynamically dispatch on an id's @@ -43,7 +46,7 @@ impl Global { &self, device_id: id::DeviceId, desc: &resource::BufferDescriptor, - id_in: Input, + id_in: Input, ) -> (id::BufferId, Option) { /* ... */ } @@ -115,7 +118,6 @@ use crate::{ command::{CommandBuffer, RenderBundle}, device::{queue::Queue, Device}, hal_api::HalApi, - id, identity::GlobalIdentityHandlerFactory, instance::{Adapter, HalSurface, Surface}, pipeline::{ComputePipeline, RenderPipeline, ShaderModule}, @@ -177,23 +179,23 @@ impl HubReport { /// /// [`A::hub(global)`]: HalApi::hub pub struct Hub { - pub adapters: Registry>, - pub devices: Registry>, - pub queues: Registry>, - pub pipeline_layouts: Registry>, - pub shader_modules: Registry>, - pub bind_group_layouts: Registry>, - pub bind_groups: Registry>, - pub command_buffers: Registry>, - pub render_bundles: Registry>, - pub render_pipelines: Registry>, - pub compute_pipelines: Registry>, - pub query_sets: Registry>, - pub buffers: Registry>, - pub staging_buffers: Registry>, - pub textures: Registry>, - pub texture_views: Registry>, - pub samplers: Registry>, + pub adapters: Registry>, + pub devices: Registry>, + pub queues: Registry>, + pub pipeline_layouts: Registry>, + pub shader_modules: Registry>, + pub bind_group_layouts: Registry>, + pub bind_groups: Registry>, + pub command_buffers: Registry>, + pub render_bundles: Registry>, + pub render_pipelines: Registry>, + pub compute_pipelines: Registry>, + pub query_sets: Registry>, + pub buffers: Registry>, + pub staging_buffers: Registry>, + pub textures: Registry>, + pub texture_views: Registry>, + pub samplers: Registry>, } impl Hub { @@ -222,11 +224,7 @@ impl Hub { //TODO: instead of having a hacky `with_adapters` parameter, // we should have `clear_device(device_id)` that specifically destroys // everything related to a logical device. - pub(crate) fn clear( - &self, - surface_guard: &Storage, - with_adapters: bool, - ) { + pub(crate) fn clear(&self, surface_guard: &Storage, with_adapters: bool) { use hal::Surface; let mut devices = self.devices.write(); diff --git a/wgpu-core/src/id.rs b/wgpu-core/src/id.rs index f55a077f6a..56eaf61058 100644 --- a/wgpu-core/src/id.rs +++ b/wgpu-core/src/id.rs @@ -1,6 +1,5 @@ use crate::{Epoch, Index}; use std::{ - any::Any, cmp::Ordering, fmt::{self, Debug}, hash::Hash, @@ -9,15 +8,74 @@ use std::{ use wgt::{Backend, WasmNotSendSync}; type IdType = u64; -type NonZeroId = std::num::NonZeroU64; type ZippedIndex = Index; +type NonZeroId = std::num::NonZeroU64; const INDEX_BITS: usize = std::mem::size_of::() * 8; const EPOCH_BITS: usize = INDEX_BITS - BACKEND_BITS; const BACKEND_BITS: usize = 3; const BACKEND_SHIFT: usize = INDEX_BITS * 2 - BACKEND_BITS; pub const EPOCH_MASK: u32 = (1 << (EPOCH_BITS)) - 1; -type Dummy = hal::api::Empty; + +/// The raw underlying representation of an identifier. +#[repr(transparent)] +#[cfg_attr(any(feature = "serde", feature = "trace"), derive(serde::Serialize))] +#[cfg_attr(any(feature = "serde", feature = "replay"), derive(serde::Deserialize))] +#[cfg_attr(feature = "trace", serde(into = "SerialId"))] +#[cfg_attr(feature = "replay", serde(from = "SerialId"))] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct RawId(NonZeroId); + +impl RawId { + #[doc(hidden)] + #[inline] + pub fn from_non_zero(non_zero: NonZeroId) -> Self { + Self(non_zero) + } + + #[doc(hidden)] + #[inline] + pub fn into_non_zero(self) -> NonZeroId { + self.0 + } + + /// Zip together an identifier and return its raw underlying representation. + pub fn zip(index: Index, epoch: Epoch, backend: Backend) -> RawId { + assert_eq!(0, epoch >> EPOCH_BITS); + assert_eq!(0, (index as IdType) >> INDEX_BITS); + let v = index as IdType + | ((epoch as IdType) << INDEX_BITS) + | ((backend as IdType) << BACKEND_SHIFT); + Self(NonZeroId::new(v).unwrap()) + } + + /// Unzip a raw identifier into its components. + #[allow(trivial_numeric_casts)] + pub fn unzip(self) -> (Index, Epoch, Backend) { + ( + (self.0.get() as ZippedIndex) as Index, + (((self.0.get() >> INDEX_BITS) as ZippedIndex) & (EPOCH_MASK as ZippedIndex)) as Index, + self.backend(), + ) + } + + pub fn backend(self) -> Backend { + match self.0.get() >> (BACKEND_SHIFT) as u8 { + 0 => Backend::Empty, + 1 => Backend::Vulkan, + 2 => Backend::Metal, + 3 => Backend::Dx12, + 4 => Backend::Gl, + _ => unreachable!(), + } + } +} + +/// Coerce a slice of identifiers into a slice of raw identifiers. +pub fn into_raw_slice(ids: &[Id]) -> &[RawId] { + // SAFETY: Any Id is repr(transparent) over `RawId`. + unsafe { std::slice::from_raw_parts(ids.as_ptr().cast(), ids.len()) } +} /// An identifier for a wgpu object. /// @@ -49,21 +107,13 @@ type Dummy = hal::api::Empty; /// [`Registry`]: crate::hub::Registry /// [`Empty`]: hal::api::Empty #[repr(transparent)] -#[cfg_attr(feature = "trace", derive(serde::Serialize), serde(into = "SerialId"))] -#[cfg_attr( - feature = "replay", - derive(serde::Deserialize), - serde(from = "SerialId") -)] +#[cfg_attr(any(feature = "serde", feature = "trace"), derive(serde::Serialize))] +#[cfg_attr(any(feature = "serde", feature = "replay"), derive(serde::Deserialize))] #[cfg_attr( - all(feature = "serde", not(feature = "trace")), - derive(serde::Serialize) + any(feature = "serde", feature = "trace", feature = "replay"), + serde(transparent) )] -#[cfg_attr( - all(feature = "serde", not(feature = "replay")), - derive(serde::Deserialize) -)] -pub struct Id(NonZeroId, PhantomData); +pub struct Id(RawId, PhantomData); // This type represents Id in a more readable (and editable) way. #[allow(dead_code)] @@ -72,39 +122,40 @@ enum SerialId { // The only variant forces RON to not ignore "Id" Id(Index, Epoch, Backend), } + #[cfg(feature = "trace")] -impl From> for SerialId -where - T: 'static + WasmNotSendSync, -{ - fn from(id: Id) -> Self { +impl From for SerialId { + fn from(id: RawId) -> Self { let (index, epoch, backend) = id.unzip(); Self::Id(index, epoch, backend) } } + #[cfg(feature = "replay")] -impl From for Id -where - T: 'static + WasmNotSendSync, -{ +impl From for RawId { fn from(id: SerialId) -> Self { match id { - SerialId::Id(index, epoch, backend) => TypedId::zip(index, epoch, backend), + SerialId::Id(index, epoch, backend) => RawId::zip(index, epoch, backend), } } } impl Id where - T: 'static + WasmNotSendSync, + T: Marker, { /// # Safety /// /// The raw id must be valid for the type. - pub unsafe fn from_raw(raw: NonZeroId) -> Self { + pub unsafe fn from_raw(raw: RawId) -> Self { Self(raw, PhantomData) } + /// Coerce the identifiers into its raw underlying representation. + pub fn into_raw(self) -> RawId { + self.0 + } + #[allow(dead_code)] pub(crate) fn dummy(index: u32) -> Self { Id::zip(index, 1, Backend::Empty) @@ -115,24 +166,53 @@ where self.backend() != Backend::Empty } + /// Get the backend this identifier corresponds to. + #[inline] pub fn backend(self) -> Backend { - match self.0.get() >> (BACKEND_SHIFT) as u8 { - 0 => Backend::Empty, - 1 => Backend::Vulkan, - 2 => Backend::Metal, - 3 => Backend::Dx12, - 4 => Backend::Gl, - _ => unreachable!(), - } + self.0.backend() + } + + /// Transmute this identifier to one with a different marker trait. + /// + /// Legal use is governed through a sealed trait, however it's correctness + /// depends on the current implementation of `wgpu-core`. + #[inline] + pub const fn transmute>(self) -> Id { + Id(self.0, PhantomData) + } + + #[inline] + pub fn zip(index: Index, epoch: Epoch, backend: Backend) -> Self { + Id(RawId::zip(index, epoch, backend), PhantomData) + } + + #[inline] + pub fn unzip(self) -> (Index, Epoch, Backend) { + self.0.unzip() } } -impl Copy for Id where T: 'static + WasmNotSendSync {} +pub(crate) mod transmute { + // This trait is effectively sealed to prevent illegal transmutes. + pub trait Transmute: super::Marker {} + + // Self-transmute is always legal. + impl Transmute for T where T: super::Marker {} + + // TODO: Remove these once queues have their own identifiers. + impl Transmute for super::markers::Device {} + impl Transmute for super::markers::Queue {} + impl Transmute for super::markers::CommandEncoder {} + impl Transmute for super::markers::CommandBuffer {} +} + +impl Copy for Id where T: Marker {} impl Clone for Id where - T: 'static + WasmNotSendSync, + T: Marker, { + #[inline] fn clone(&self) -> Self { *self } @@ -140,7 +220,7 @@ where impl Debug for Id where - T: 'static + WasmNotSendSync, + T: Marker, { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { let (index, epoch, backend) = self.unzip(); @@ -159,8 +239,9 @@ where impl Hash for Id where - T: 'static + WasmNotSendSync, + T: Marker, { + #[inline] fn hash(&self, state: &mut H) { self.0.hash(state); } @@ -168,19 +249,21 @@ where impl PartialEq for Id where - T: 'static + WasmNotSendSync, + T: Marker, { + #[inline] fn eq(&self, other: &Self) -> bool { self.0 == other.0 } } -impl Eq for Id where T: 'static + WasmNotSendSync {} +impl Eq for Id where T: Marker {} impl PartialOrd for Id where - T: 'static + WasmNotSendSync, + T: Marker, { + #[inline] fn partial_cmp(&self, other: &Self) -> Option { self.0.partial_cmp(&other.0) } @@ -188,78 +271,73 @@ where impl Ord for Id where - T: 'static + WasmNotSendSync, + T: Marker, { + #[inline] fn cmp(&self, other: &Self) -> Ordering { self.0.cmp(&other.0) } } -/// Trait carrying methods for direct `Id` access. +/// Marker trait used to determine which types uniquely identify a resource. /// -/// Most `wgpu-core` clients should not use this trait. Unusual clients that -/// need to construct `Id` values directly, or access their components, like the -/// WGPU recording player, may use this trait to do so. -pub trait TypedId: Copy + Debug + Any + 'static + WasmNotSendSync + Eq + Hash { - fn zip(index: Index, epoch: Epoch, backend: Backend) -> Self; - fn unzip(self) -> (Index, Epoch, Backend); - fn into_raw(self) -> NonZeroId; -} +/// For example, `Device` will have the same type of identifier as +/// `Device` because `Device` for any `T` defines the same maker type. +pub trait Marker: 'static + WasmNotSendSync {} -#[allow(trivial_numeric_casts)] -impl TypedId for Id -where - T: 'static + WasmNotSendSync, -{ - fn zip(index: Index, epoch: Epoch, backend: Backend) -> Self { - assert_eq!(0, epoch >> EPOCH_BITS); - assert_eq!(0, (index as IdType) >> INDEX_BITS); - let v = index as IdType - | ((epoch as IdType) << INDEX_BITS) - | ((backend as IdType) << BACKEND_SHIFT); - Id(NonZeroId::new(v).unwrap(), PhantomData) - } +// This allows `()` to be used as a marker type for tests. +// +// We don't want these in production code, since they essentially remove type +// safety, like how identifiers across different types can be compared. +#[cfg(test)] +impl Marker for () {} - fn unzip(self) -> (Index, Epoch, Backend) { - ( - (self.0.get() as ZippedIndex) as Index, - (((self.0.get() >> INDEX_BITS) as ZippedIndex) & (EPOCH_MASK as ZippedIndex)) as Index, - self.backend(), - ) - } +/// Define identifiers for each resource. +macro_rules! ids { + ($( + $(#[$($meta:meta)*])* + pub type $name:ident $marker:ident; + )*) => { + /// Marker types for each resource. + pub mod markers { + $( + #[derive(Debug)] + pub enum $marker {} + impl super::Marker for $marker {} + )* + } - fn into_raw(self) -> NonZeroId { - self.0 + $( + $(#[$($meta)*])* + pub type $name = Id; + )* } } -pub type AdapterId = Id>; -pub type SurfaceId = Id; -// Device -pub type DeviceId = Id>; -pub type QueueId = DeviceId; -// Resource -pub type BufferId = Id>; -pub type StagingBufferId = Id>; -pub type TextureViewId = Id>; -pub type TextureId = Id>; -pub type SamplerId = Id>; -// Binding model -pub type BindGroupLayoutId = Id>; -pub type PipelineLayoutId = Id>; -pub type BindGroupId = Id>; -// Pipeline -pub type ShaderModuleId = Id>; -pub type RenderPipelineId = Id>; -pub type ComputePipelineId = Id>; -// Command -pub type CommandEncoderId = CommandBufferId; -pub type CommandBufferId = Id>; -pub type RenderPassEncoderId = *mut crate::command::RenderPass; -pub type ComputePassEncoderId = *mut crate::command::ComputePass; -pub type RenderBundleEncoderId = *mut crate::command::RenderBundleEncoder; -pub type RenderBundleId = Id>; -pub type QuerySetId = Id>; +ids! { + pub type AdapterId Adapter; + pub type SurfaceId Surface; + pub type DeviceId Device; + pub type QueueId Queue; + pub type BufferId Buffer; + pub type StagingBufferId StagingBuffer; + pub type TextureViewId TextureView; + pub type TextureId Texture; + pub type SamplerId Sampler; + pub type BindGroupLayoutId BindGroupLayout; + pub type PipelineLayoutId PipelineLayout; + pub type BindGroupId BindGroup; + pub type ShaderModuleId ShaderModule; + pub type RenderPipelineId RenderPipeline; + pub type ComputePipelineId ComputePipeline; + pub type CommandEncoderId CommandEncoder; + pub type CommandBufferId CommandBuffer; + pub type RenderPassEncoderId RenderPassEncoder; + pub type ComputePassEncoderId ComputePassEncoder; + pub type RenderBundleEncoderId RenderBundleEncoder; + pub type RenderBundleId RenderBundle; + pub type QuerySetId QuerySet; +} #[test] fn test_id_backend() { @@ -270,7 +348,7 @@ fn test_id_backend() { Backend::Dx12, Backend::Gl, ] { - let id: Id<()> = Id::zip(1, 0, b); + let id = crate::id::Id::<()>::zip(1, 0, b); let (_id, _epoch, backend) = id.unzip(); assert_eq!(id.backend(), b); assert_eq!(backend, b); @@ -292,7 +370,7 @@ fn test_id() { for &i in &indexes { for &e in &epochs { for &b in &backends { - let id: Id<()> = Id::zip(i, e, b); + let id = crate::id::Id::<()>::zip(i, e, b); let (index, epoch, backend) = id.unzip(); assert_eq!(index, i); assert_eq!(epoch, e); diff --git a/wgpu-core/src/identity.rs b/wgpu-core/src/identity.rs index 3f421dd697..44989a6d40 100644 --- a/wgpu-core/src/identity.rs +++ b/wgpu-core/src/identity.rs @@ -2,7 +2,7 @@ use parking_lot::Mutex; use wgt::Backend; use crate::{ - id::{self}, + id::{self, Id, Marker}, Epoch, FastHashMap, Index, }; use std::{fmt::Debug, marker::PhantomData, sync::Arc}; @@ -47,10 +47,10 @@ impl IdentityValues { /// /// The backend is incorporated into the id, so that ids allocated with /// different `backend` values are always distinct. - pub fn alloc(&mut self, backend: Backend) -> I { + pub fn alloc(&mut self, backend: Backend) -> Id { self.count += 1; match self.free.pop() { - Some((index, epoch)) => I::zip(index, epoch + 1, backend), + Some((index, epoch)) => Id::zip(index, epoch + 1, backend), None => { let epoch = 1; let used = self.used.entry(epoch).or_insert_with(Default::default); @@ -60,12 +60,12 @@ impl IdentityValues { 0 }; used.push(index); - I::zip(index, epoch, backend) + Id::zip(index, epoch, backend) } } } - pub fn mark_as_used(&mut self, id: I) -> I { + pub fn mark_as_used(&mut self, id: Id) -> Id { self.count += 1; let (index, epoch, _backend) = id.unzip(); let used = self.used.entry(epoch).or_insert_with(Default::default); @@ -74,7 +74,7 @@ impl IdentityValues { } /// Free `id`. It will never be returned from `alloc` again. - pub fn release(&mut self, id: I) { + pub fn release(&mut self, id: Id) { let (index, epoch, _backend) = id.unzip(); self.free.push((index, epoch)); self.count -= 1; @@ -86,24 +86,24 @@ impl IdentityValues { } #[derive(Debug)] -pub struct IdentityManager { +pub struct IdentityManager { pub(super) values: Mutex, - _phantom: PhantomData, + _phantom: PhantomData, } -impl IdentityManager { - pub fn process(&self, backend: Backend) -> I { +impl IdentityManager { + pub fn process(&self, backend: Backend) -> Id { self.values.lock().alloc(backend) } - pub fn mark_as_used(&self, id: I) -> I { + pub fn mark_as_used(&self, id: Id) -> Id { self.values.lock().mark_as_used(id) } - pub fn free(&self, id: I) { + pub fn free(&self, id: Id) { self.values.lock().release(id) } } -impl IdentityManager { +impl IdentityManager { pub fn new() -> Self { Self { values: Mutex::new(IdentityValues::default()), @@ -115,7 +115,7 @@ impl IdentityManager { /// A type that can produce [`IdentityManager`] filters for ids of type `I`. /// /// See the module-level documentation for details. -pub trait IdentityHandlerFactory { +pub trait IdentityHandlerFactory { type Input: Copy; /// Create an [`IdentityManager`] implementation that can /// transform proto-ids into ids of type `I`. @@ -123,11 +123,11 @@ pub trait IdentityHandlerFactory { /// and are not generated by wgpu /// /// [`IdentityManager`]: IdentityManager - fn spawn(&self) -> Arc> { + fn spawn(&self) -> Arc> { Arc::new(IdentityManager::new()) } fn autogenerate_ids() -> bool; - fn input_to_id(id_in: Self::Input) -> I; + fn input_to_id(id_in: Self::Input) -> Id; } /// A global identity handler factory based on [`IdentityManager`]. @@ -138,13 +138,13 @@ pub trait IdentityHandlerFactory { #[derive(Debug)] pub struct IdentityManagerFactory; -impl IdentityHandlerFactory for IdentityManagerFactory { +impl IdentityHandlerFactory for IdentityManagerFactory { type Input = (); fn autogenerate_ids() -> bool { true } - fn input_to_id(_id_in: Self::Input) -> I { + fn input_to_id(_id_in: Self::Input) -> Id { unreachable!("It should not be called") } } @@ -152,23 +152,25 @@ impl IdentityHandlerFactory for IdentityManagerFactory { /// A factory that can build [`IdentityManager`]s for all resource /// types. pub trait GlobalIdentityHandlerFactory: - IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory { } @@ -178,8 +180,7 @@ pub type Input = >::Input; #[test] fn test_epoch_end_of_life() { - use id::TypedId as _; - let man = IdentityManager::::new(); + let man = IdentityManager::::new(); let forced_id = man.mark_as_used(id::BufferId::zip(0, 1, Backend::Empty)); assert_eq!(forced_id.unzip().0, 0); let id1 = man.process(Backend::Empty); diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 158a305772..cb5871d6b8 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -6,6 +6,7 @@ use crate::{ device::{queue::Queue, resource::Device, DeviceDescriptor}, global::Global, hal_api::HalApi, + id::markers, id::{AdapterId, DeviceId, QueueId, SurfaceId}, identity::{GlobalIdentityHandlerFactory, Input}, present::Presentation, @@ -149,18 +150,20 @@ impl Instance { pub struct Surface { pub(crate) presentation: Mutex>, - pub(crate) info: ResourceInfo, + pub(crate) info: ResourceInfo, pub(crate) raw: AnySurface, } -impl Resource for Surface { +impl Resource for Surface { const TYPE: ResourceType = "Surface"; - fn as_info(&self) -> &ResourceInfo { + type Marker = crate::id::markers::Surface; + + fn as_info(&self) -> &ResourceInfo { &self.info } - fn as_info_mut(&mut self) -> &mut ResourceInfo { + fn as_info_mut(&mut self) -> &mut ResourceInfo { &mut self.info } @@ -190,7 +193,7 @@ impl Surface { pub struct Adapter { pub(crate) raw: hal::ExposedAdapter, - pub(crate) info: ResourceInfo, + pub(crate) info: ResourceInfo>, } impl Adapter { @@ -382,14 +385,16 @@ impl Adapter { } } -impl Resource for Adapter { +impl Resource for Adapter { const TYPE: ResourceType = "Adapter"; - fn as_info(&self) -> &ResourceInfo { + type Marker = crate::id::markers::Adapter; + + fn as_info(&self) -> &ResourceInfo { &self.info } - fn as_info_mut(&mut self) -> &mut ResourceInfo { + fn as_info_mut(&mut self) -> &mut ResourceInfo { &mut self.info } } @@ -478,7 +483,7 @@ impl Global { &self, display_handle: raw_window_handle::RawDisplayHandle, window_handle: raw_window_handle::RawWindowHandle, - id_in: Input, + id_in: Input, ) -> Result { profiling::scope!("Instance::create_surface"); @@ -526,7 +531,7 @@ impl Global { raw: hal_surface, }; - let (id, _) = self.surfaces.prepare::(id_in).assign(surface); + let (id, _) = self.surfaces.prepare::(id_in).assign(surface); Ok(id) } @@ -537,7 +542,7 @@ impl Global { pub unsafe fn instance_create_surface_metal( &self, layer: *mut std::ffi::c_void, - id_in: Input, + id_in: Input, ) -> SurfaceId { profiling::scope!("Instance::create_surface_metal"); @@ -561,7 +566,7 @@ impl Global { }, }; - let (id, _) = self.surfaces.prepare::(id_in).assign(surface); + let (id, _) = self.surfaces.prepare::(id_in).assign(surface); id } @@ -572,7 +577,7 @@ impl Global { pub unsafe fn instance_create_surface_from_visual( &self, visual: *mut std::ffi::c_void, - id_in: Input, + id_in: Input, ) -> SurfaceId { profiling::scope!("Instance::instance_create_surface_from_visual"); @@ -592,7 +597,7 @@ impl Global { }, }; - let (id, _) = self.surfaces.prepare::(id_in).assign(surface); + let (id, _) = self.surfaces.prepare::(id_in).assign(surface); id } @@ -603,7 +608,7 @@ impl Global { pub unsafe fn instance_create_surface_from_surface_handle( &self, surface_handle: *mut std::ffi::c_void, - id_in: Input, + id_in: Input, ) -> SurfaceId { profiling::scope!("Instance::instance_create_surface_from_surface_handle"); @@ -625,7 +630,7 @@ impl Global { }, }; - let (id, _) = self.surfaces.prepare::(id_in).assign(surface); + let (id, _) = self.surfaces.prepare::(id_in).assign(surface); id } @@ -636,7 +641,7 @@ impl Global { pub unsafe fn instance_create_surface_from_swap_chain_panel( &self, swap_chain_panel: *mut std::ffi::c_void, - id_in: Input, + id_in: Input, ) -> SurfaceId { profiling::scope!("Instance::instance_create_surface_from_swap_chain_panel"); @@ -658,7 +663,7 @@ impl Global { }, }; - let (id, _) = self.surfaces.prepare::(id_in).assign(surface); + let (id, _) = self.surfaces.prepare::(id_in).assign(surface); id } @@ -703,7 +708,7 @@ impl Global { &self, _: A, instance: &Option, - inputs: &AdapterInputs>, + inputs: &AdapterInputs>, list: &mut Vec, ) { let inst = match *instance { @@ -722,12 +727,15 @@ impl Global { for raw in hal_adapters { let adapter = Adapter::new(raw); log::info!("Adapter {:?} {:?}", A::VARIANT, adapter.raw.info); - let (id, _) = hub.adapters.prepare::(id_backend).assign(adapter); + let (id, _) = hub.adapters.prepare::(id_backend).assign(adapter); list.push(id); } } - pub fn enumerate_adapters(&self, inputs: AdapterInputs>) -> Vec { + pub fn enumerate_adapters( + &self, + inputs: AdapterInputs>, + ) -> Vec { profiling::scope!("Instance::enumerate_adapters"); api_log!("Instance::enumerate_adapters"); @@ -758,7 +766,7 @@ impl Global { fn select( &self, selected: &mut usize, - new_id: Option>, + new_id: Option>, mut list: Vec>, ) -> Option { match selected.checked_sub(list.len()) { @@ -771,7 +779,7 @@ impl Global { log::info!("Adapter {:?} {:?}", A::VARIANT, adapter.raw.info); let (id, _) = HalApi::hub(self) .adapters - .prepare::(new_id.unwrap()) + .prepare::(new_id.unwrap()) .assign(adapter); Some(id) } @@ -781,7 +789,7 @@ impl Global { pub fn request_adapter( &self, desc: &RequestAdapterOptions, - inputs: AdapterInputs>, + inputs: AdapterInputs>, ) -> Result { profiling::scope!("Instance::request_adapter"); api_log!("Instance::request_adapter"); @@ -947,24 +955,23 @@ impl Global { pub unsafe fn create_adapter_from_hal( &self, hal_adapter: hal::ExposedAdapter, - input: Input, + input: Input, ) -> AdapterId { profiling::scope!("Instance::create_adapter_from_hal"); - let fid = A::hub(self).adapters.prepare::(input); + let fid = A::hub(self).adapters.prepare::(input); - let (id, _adapter): (crate::id::Id>, Arc>) = - match A::VARIANT { - #[cfg(vulkan)] - Backend::Vulkan => fid.assign(Adapter::new(hal_adapter)), - #[cfg(metal)] - Backend::Metal => fid.assign(Adapter::new(hal_adapter)), - #[cfg(dx12)] - Backend::Dx12 => fid.assign(Adapter::new(hal_adapter)), - #[cfg(gles)] - Backend::Gl => fid.assign(Adapter::new(hal_adapter)), - _ => unreachable!(), - }; + let (id, _adapter): (_, Arc>) = match A::VARIANT { + #[cfg(vulkan)] + Backend::Vulkan => fid.assign(Adapter::new(hal_adapter)), + #[cfg(metal)] + Backend::Metal => fid.assign(Adapter::new(hal_adapter)), + #[cfg(dx12)] + Backend::Dx12 => fid.assign(Adapter::new(hal_adapter)), + #[cfg(gles)] + Backend::Gl => fid.assign(Adapter::new(hal_adapter)), + _ => unreachable!(), + }; resource_log!("Created Adapter {:?}", id); id } @@ -1065,15 +1072,15 @@ impl Global { adapter_id: AdapterId, desc: &DeviceDescriptor, trace_path: Option<&std::path::Path>, - device_id_in: Input, - queue_id_in: Input, + device_id_in: Input, + queue_id_in: Input, ) -> (DeviceId, QueueId, Option) { profiling::scope!("Adapter::request_device"); api_log!("Adapter::request_device"); let hub = A::hub(self); - let device_fid = hub.devices.prepare::(device_id_in); - let queue_fid = hub.queues.prepare::(queue_id_in); + let device_fid = hub.devices.prepare::(device_id_in); + let queue_fid = hub.queues.prepare::(queue_id_in); let error = loop { let adapter = match hub.adapters.get(adapter_id) { @@ -1114,14 +1121,14 @@ impl Global { hal_device: OpenDevice, desc: &DeviceDescriptor, trace_path: Option<&std::path::Path>, - device_id_in: Input, - queue_id_in: Input, + device_id_in: Input, + queue_id_in: Input, ) -> (DeviceId, QueueId, Option) { profiling::scope!("Global::create_device_from_hal"); let hub = A::hub(self); - let devices_fid = hub.devices.prepare::(device_id_in); - let queues_fid = hub.queues.prepare::(queue_id_in); + let devices_fid = hub.devices.prepare::(device_id_in); + let queues_fid = hub.queues.prepare::(queue_id_in); let error = loop { let adapter = match hub.adapters.get(adapter_id) { diff --git a/wgpu-core/src/pipeline.rs b/wgpu-core/src/pipeline.rs index b6c3bf5bfe..c40eb1d821 100644 --- a/wgpu-core/src/pipeline.rs +++ b/wgpu-core/src/pipeline.rs @@ -5,7 +5,7 @@ use crate::{ command::ColorAttachmentError, device::{Device, DeviceError, MissingDownlevelFlags, MissingFeatures, RenderPassContext}, hal_api::HalApi, - id::{ComputePipelineId, PipelineLayoutId, RenderPipelineId, ShaderModuleId}, + id::{PipelineLayoutId, ShaderModuleId}, resource::{Resource, ResourceInfo, ResourceType}, resource_log, validation, Label, }; @@ -50,7 +50,7 @@ pub struct ShaderModule { pub(crate) raw: Option, pub(crate) device: Arc>, pub(crate) interface: Option, - pub(crate) info: ResourceInfo, + pub(crate) info: ResourceInfo>, pub(crate) label: String, } @@ -70,14 +70,16 @@ impl Drop for ShaderModule { } } -impl Resource for ShaderModule { +impl Resource for ShaderModule { const TYPE: ResourceType = "ShaderModule"; - fn as_info(&self) -> &ResourceInfo { + type Marker = crate::id::markers::ShaderModule; + + fn as_info(&self) -> &ResourceInfo { &self.info } - fn as_info_mut(&mut self) -> &mut ResourceInfo { + fn as_info_mut(&mut self) -> &mut ResourceInfo { &mut self.info } @@ -267,7 +269,7 @@ pub struct ComputePipeline { pub(crate) device: Arc>, pub(crate) _shader_module: Arc>, pub(crate) late_sized_buffer_groups: ArrayVec, - pub(crate) info: ResourceInfo, + pub(crate) info: ResourceInfo>, } impl Drop for ComputePipeline { @@ -288,14 +290,16 @@ impl Drop for ComputePipeline { } } -impl Resource for ComputePipeline { +impl Resource for ComputePipeline { const TYPE: ResourceType = "ComputePipeline"; - fn as_info(&self) -> &ResourceInfo { + type Marker = crate::id::markers::ComputePipeline; + + fn as_info(&self) -> &ResourceInfo { &self.info } - fn as_info_mut(&mut self) -> &mut ResourceInfo { + fn as_info_mut(&mut self) -> &mut ResourceInfo { &mut self.info } } @@ -515,7 +519,7 @@ pub struct RenderPipeline { pub(crate) strip_index_format: Option, pub(crate) vertex_steps: Vec, pub(crate) late_sized_buffer_groups: ArrayVec, - pub(crate) info: ResourceInfo, + pub(crate) info: ResourceInfo>, } impl Drop for RenderPipeline { @@ -536,14 +540,16 @@ impl Drop for RenderPipeline { } } -impl Resource for RenderPipeline { +impl Resource for RenderPipeline { const TYPE: ResourceType = "RenderPipeline"; - fn as_info(&self) -> &ResourceInfo { + type Marker = crate::id::markers::RenderPipeline; + + fn as_info(&self) -> &ResourceInfo { &self.info } - fn as_info_mut(&mut self) -> &mut ResourceInfo { + fn as_info_mut(&mut self) -> &mut ResourceInfo { &mut self.info } } diff --git a/wgpu-core/src/present.rs b/wgpu-core/src/present.rs index 00a2953ea5..081ab736de 100644 --- a/wgpu-core/src/present.rs +++ b/wgpu-core/src/present.rs @@ -23,6 +23,7 @@ use crate::{ global::Global, hal_api::HalApi, hal_label, + id::markers, id::{SurfaceId, TextureId}, identity::{GlobalIdentityHandlerFactory, Input}, init_tracker::TextureInitTracker, @@ -125,13 +126,13 @@ impl Global { pub fn surface_get_current_texture( &self, surface_id: SurfaceId, - texture_id_in: Input, + texture_id_in: Input, ) -> Result { profiling::scope!("SwapChain::get_next_texture"); let hub = A::hub(self); - let fid = hub.textures.prepare::(texture_id_in); + let fid = hub.textures.prepare::(texture_id_in); let surface = self .surfaces diff --git a/wgpu-core/src/registry.rs b/wgpu-core/src/registry.rs index feb32903af..c2b8c38d9a 100644 --- a/wgpu-core/src/registry.rs +++ b/wgpu-core/src/registry.rs @@ -4,7 +4,7 @@ use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use wgt::Backend; use crate::{ - id, + id::{self, Id, Marker}, identity::{IdentityHandlerFactory, IdentityManager}, resource::Resource, storage::{Element, InvalidId, Storage}, @@ -37,14 +37,14 @@ impl RegistryReport { /// any other dependent resource /// #[derive(Debug)] -pub struct Registry> { - identity: Arc>, - storage: RwLock>, +pub struct Registry { + identity: Arc>, + storage: RwLock>, backend: Backend, } -impl> Registry { - pub(crate) fn new>(backend: Backend, factory: &F) -> Self { +impl Registry { + pub(crate) fn new>(backend: Backend, factory: &F) -> Self { Self { identity: factory.spawn(), storage: RwLock::new(Storage::new()), @@ -52,25 +52,25 @@ impl> Registry { } } - pub(crate) fn without_backend>(factory: &F) -> Self { + pub(crate) fn without_backend>(factory: &F) -> Self { Self::new(Backend::Empty, factory) } } #[must_use] -pub(crate) struct FutureId<'a, I: id::TypedId, T: Resource> { - id: I, - identity: Arc>, - data: &'a RwLock>, +pub(crate) struct FutureId<'a, T: Resource> { + id: Id, + identity: Arc>, + data: &'a RwLock>, } -impl> FutureId<'_, I, T> { +impl FutureId<'_, T> { #[allow(dead_code)] - pub fn id(&self) -> I { + pub fn id(&self) -> Id { self.id } - pub fn into_id(self) -> I { + pub fn into_id(self) -> Id { self.id } @@ -82,7 +82,7 @@ impl> FutureId<'_, I, T> { /// Assign a new resource to this ID. /// /// Registers it with the registry, and fills out the resource info. - pub fn assign(self, value: T) -> (I, Arc) { + pub fn assign(self, value: T) -> (Id, Arc) { let mut data = self.data.write(); data.insert(self.id, self.init(value)); (self.id, data.get(self.id).unwrap().clone()) @@ -94,73 +94,76 @@ impl> FutureId<'_, I, T> { /// /// This _will_ leak the ID, and it will not be recycled again. /// See https://github.com/gfx-rs/wgpu/issues/4912. - pub fn assign_existing(self, value: &Arc) -> I { + pub fn assign_existing(self, value: &Arc) -> Id { let mut data = self.data.write(); debug_assert!(!data.contains(self.id)); data.insert(self.id, value.clone()); self.id } - pub fn assign_error(self, label: &str) -> I { + pub fn assign_error(self, label: &str) -> Id { self.data.write().insert_error(self.id, label); self.id } } -impl> Registry { - pub(crate) fn prepare(&self, id_in: F::Input) -> FutureId +impl Registry { + pub(crate) fn prepare(&self, id_in: F::Input) -> FutureId where - F: IdentityHandlerFactory, + F: IdentityHandlerFactory, + T::Marker: id::transmute::Transmute, { FutureId { id: if F::autogenerate_ids() { self.identity.process(self.backend) } else { - self.identity.mark_as_used(F::input_to_id(id_in)) + self.identity + .mark_as_used(F::input_to_id(id_in).transmute()) }, identity: self.identity.clone(), data: &self.storage, } } - pub(crate) fn request(&self) -> FutureId { + + pub(crate) fn request(&self) -> FutureId { FutureId { id: self.identity.process(self.backend), identity: self.identity.clone(), data: &self.storage, } } - pub(crate) fn try_get(&self, id: I) -> Result>, InvalidId> { + pub(crate) fn try_get(&self, id: Id) -> Result>, InvalidId> { self.read().try_get(id).map(|o| o.cloned()) } - pub(crate) fn get(&self, id: I) -> Result, InvalidId> { + pub(crate) fn get(&self, id: Id) -> Result, InvalidId> { self.read().get_owned(id) } - pub(crate) fn read<'a>(&'a self) -> RwLockReadGuard<'a, Storage> { + pub(crate) fn read<'a>(&'a self) -> RwLockReadGuard<'a, Storage> { self.storage.read() } - pub(crate) fn write<'a>(&'a self) -> RwLockWriteGuard<'a, Storage> { + pub(crate) fn write<'a>(&'a self) -> RwLockWriteGuard<'a, Storage> { self.storage.write() } - pub fn unregister_locked(&self, id: I, storage: &mut Storage) -> Option> { + pub fn unregister_locked(&self, id: Id, storage: &mut Storage) -> Option> { storage.remove(id) } - pub fn force_replace(&self, id: I, mut value: T) { + pub fn force_replace(&self, id: Id, mut value: T) { let mut storage = self.storage.write(); value.as_info_mut().set_id(id, &self.identity); storage.force_replace(id, value) } - pub fn force_replace_with_error(&self, id: I, label: &str) { + pub fn force_replace_with_error(&self, id: Id, label: &str) { let mut storage = self.storage.write(); storage.remove(id); storage.insert_error(id, label); } - pub(crate) fn unregister(&self, id: I) -> Option> { + pub(crate) fn unregister(&self, id: Id) -> Option> { let value = self.storage.write().remove(id); //Returning None is legal if it's an error ID value } - pub fn label_for_resource(&self, id: I) -> String { + pub fn label_for_resource(&self, id: Id) -> String { let guard = self.storage.read(); let type_name = guard.kind(); diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index 85384939f6..fad1aa610c 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -8,10 +8,7 @@ use crate::{ }, global::Global, hal_api::HalApi, - id::{ - AdapterId, BufferId, DeviceId, QuerySetId, SamplerId, StagingBufferId, SurfaceId, - TextureId, TextureViewId, TypedId, - }, + id::{AdapterId, BufferId, DeviceId, Id, Marker, SurfaceId, TextureId}, identity::{GlobalIdentityHandlerFactory, IdentityManager}, init_tracker::{BufferInitTracker, TextureInitTracker}, resource, resource_log, @@ -59,9 +56,9 @@ use std::{ /// [`Device`]: crate::device::resource::Device /// [`Buffer`]: crate::resource::Buffer #[derive(Debug)] -pub struct ResourceInfo { - id: Option, - identity: Option>>, +pub struct ResourceInfo { + id: Option>, + identity: Option>>, /// The index of the last queue submission in which the resource /// was used. /// @@ -75,7 +72,7 @@ pub struct ResourceInfo { pub(crate) label: String, } -impl Drop for ResourceInfo { +impl Drop for ResourceInfo { fn drop(&mut self) { if let Some(identity) = self.identity.as_ref() { let id = self.id.as_ref().unwrap(); @@ -84,7 +81,7 @@ impl Drop for ResourceInfo { } } -impl ResourceInfo { +impl ResourceInfo { #[allow(unused_variables)] pub(crate) fn new(label: &str) -> Self { Self { @@ -97,7 +94,7 @@ impl ResourceInfo { pub(crate) fn label(&self) -> &dyn Debug where - Id: Debug, + Id: Debug, { if !self.label.is_empty() { return &self.label; @@ -110,11 +107,11 @@ impl ResourceInfo { &"" } - pub(crate) fn id(&self) -> Id { + pub(crate) fn id(&self) -> Id { self.id.unwrap() } - pub(crate) fn set_id(&mut self, id: Id, identity: &Arc>) { + pub(crate) fn set_id(&mut self, id: Id, identity: &Arc>) { self.id = Some(id); self.identity = Some(identity.clone()); } @@ -133,10 +130,11 @@ impl ResourceInfo { pub(crate) type ResourceType = &'static str; -pub trait Resource: 'static + WasmNotSendSync { +pub trait Resource: 'static + Sized + WasmNotSendSync { + type Marker: Marker; const TYPE: ResourceType; - fn as_info(&self) -> &ResourceInfo; - fn as_info_mut(&mut self) -> &mut ResourceInfo; + fn as_info(&self) -> &ResourceInfo; + fn as_info_mut(&mut self) -> &mut ResourceInfo; fn label(&self) -> String { self.as_info().label.clone() } @@ -377,7 +375,7 @@ pub struct Buffer { pub(crate) size: wgt::BufferAddress, pub(crate) initialization_status: RwLock, pub(crate) sync_mapped_writes: Mutex>, - pub(crate) info: ResourceInfo, + pub(crate) info: ResourceInfo>, pub(crate) map_state: Mutex>, pub(crate) bind_groups: Mutex>>>, } @@ -592,14 +590,16 @@ pub enum CreateBufferError { MissingDownlevelFlags(#[from] MissingDownlevelFlags), } -impl Resource for Buffer { +impl Resource for Buffer { const TYPE: ResourceType = "Buffer"; - fn as_info(&self) -> &ResourceInfo { + type Marker = crate::id::markers::Buffer; + + fn as_info(&self) -> &ResourceInfo { &self.info } - fn as_info_mut(&mut self) -> &mut ResourceInfo { + fn as_info_mut(&mut self) -> &mut ResourceInfo { &mut self.info } } @@ -693,7 +693,7 @@ pub struct StagingBuffer { pub(crate) device: Arc>, pub(crate) size: wgt::BufferAddress, pub(crate) is_coherent: bool, - pub(crate) info: ResourceInfo, + pub(crate) info: ResourceInfo>, } impl Drop for StagingBuffer { @@ -708,14 +708,16 @@ impl Drop for StagingBuffer { } } -impl Resource for StagingBuffer { +impl Resource for StagingBuffer { const TYPE: ResourceType = "StagingBuffer"; - fn as_info(&self) -> &ResourceInfo { + type Marker = crate::id::markers::StagingBuffer; + + fn as_info(&self) -> &ResourceInfo { &self.info } - fn as_info_mut(&mut self) -> &mut ResourceInfo { + fn as_info_mut(&mut self) -> &mut ResourceInfo { &mut self.info } @@ -773,7 +775,7 @@ pub struct Texture { pub(crate) format_features: wgt::TextureFormatFeatures, pub(crate) initialization_status: RwLock, pub(crate) full_range: TextureSelector, - pub(crate) info: ResourceInfo, + pub(crate) info: ResourceInfo>, pub(crate) clear_mode: RwLock>, pub(crate) views: Mutex>>>, pub(crate) bind_groups: Mutex>>>, @@ -1166,14 +1168,16 @@ pub enum CreateTextureError { MissingDownlevelFlags(#[from] MissingDownlevelFlags), } -impl Resource for Texture { +impl Resource for Texture { const TYPE: ResourceType = "Texture"; - fn as_info(&self) -> &ResourceInfo { + type Marker = crate::id::markers::Texture; + + fn as_info(&self) -> &ResourceInfo { &self.info } - fn as_info_mut(&mut self) -> &mut ResourceInfo { + fn as_info_mut(&mut self) -> &mut ResourceInfo { &mut self.info } } @@ -1251,7 +1255,7 @@ pub struct TextureView { pub(crate) render_extent: Result, pub(crate) samples: u32, pub(crate) selector: TextureSelector, - pub(crate) info: ResourceInfo, + pub(crate) info: ResourceInfo>, } impl Drop for TextureView { @@ -1329,14 +1333,16 @@ pub enum CreateTextureViewError { #[non_exhaustive] pub enum TextureViewDestroyError {} -impl Resource for TextureView { +impl Resource for TextureView { const TYPE: ResourceType = "TextureView"; - fn as_info(&self) -> &ResourceInfo { + type Marker = crate::id::markers::TextureView; + + fn as_info(&self) -> &ResourceInfo { &self.info } - fn as_info_mut(&mut self) -> &mut ResourceInfo { + fn as_info_mut(&mut self) -> &mut ResourceInfo { &mut self.info } } @@ -1374,7 +1380,7 @@ pub struct SamplerDescriptor<'a> { pub struct Sampler { pub(crate) raw: Option, pub(crate) device: Arc>, - pub(crate) info: ResourceInfo, + pub(crate) info: ResourceInfo, /// `true` if this is a comparison sampler pub(crate) comparison: bool, /// `true` if this is a filtering sampler @@ -1448,14 +1454,16 @@ pub enum CreateSamplerError { MissingFeatures(#[from] MissingFeatures), } -impl Resource for Sampler { +impl Resource for Sampler { const TYPE: ResourceType = "Sampler"; - fn as_info(&self) -> &ResourceInfo { + type Marker = crate::id::markers::Sampler; + + fn as_info(&self) -> &ResourceInfo { &self.info } - fn as_info_mut(&mut self) -> &mut ResourceInfo { + fn as_info_mut(&mut self) -> &mut ResourceInfo { &mut self.info } } @@ -1479,7 +1487,7 @@ pub type QuerySetDescriptor<'a> = wgt::QuerySetDescriptor>; pub struct QuerySet { pub(crate) raw: Option, pub(crate) device: Arc>, - pub(crate) info: ResourceInfo, + pub(crate) info: ResourceInfo, pub(crate) desc: wgt::QuerySetDescriptor<()>, } @@ -1500,14 +1508,16 @@ impl Drop for QuerySet { } } -impl Resource for QuerySet { +impl Resource for QuerySet { const TYPE: ResourceType = "QuerySet"; - fn as_info(&self) -> &ResourceInfo { + type Marker = crate::id::markers::QuerySet; + + fn as_info(&self) -> &ResourceInfo { &self.info } - fn as_info_mut(&mut self) -> &mut ResourceInfo { + fn as_info_mut(&mut self) -> &mut ResourceInfo { &mut self.info } } diff --git a/wgpu-core/src/storage.rs b/wgpu-core/src/storage.rs index 3e7a8f44fc..62e7af7c82 100644 --- a/wgpu-core/src/storage.rs +++ b/wgpu-core/src/storage.rs @@ -1,8 +1,11 @@ -use std::{marker::PhantomData, ops, sync::Arc}; +use std::ops; +use std::sync::Arc; use wgt::Backend; -use crate::{id, resource::Resource, Epoch, Index}; +use crate::id::Id; +use crate::resource::Resource; +use crate::{Epoch, Index}; /// An entry in a `Storage::map` table. #[derive(Debug)] @@ -30,47 +33,41 @@ pub(crate) struct InvalidId; /// values, so you should use an id allocator like `IdentityManager` /// that keeps the index values dense and close to zero. #[derive(Debug)] -pub struct Storage +pub struct Storage where - T: Resource, - I: id::TypedId, + T: Resource, { pub(crate) map: Vec>, kind: &'static str, - _phantom: PhantomData, } -impl ops::Index for Storage +impl ops::Index> for Storage where - T: Resource, - I: id::TypedId, + T: Resource, { type Output = Arc; - fn index(&self, id: I) -> &Arc { + fn index(&self, id: Id) -> &Arc { self.get(id).unwrap() } } -impl Storage +impl Storage where - T: Resource, - I: id::TypedId, + T: Resource, { pub(crate) fn new() -> Self { Self { map: Vec::new(), kind: T::TYPE, - _phantom: PhantomData, } } } -impl Storage +impl Storage where - T: Resource, - I: id::TypedId, + T: Resource, { #[allow(dead_code)] - pub(crate) fn contains(&self, id: I) -> bool { + pub(crate) fn contains(&self, id: Id) -> bool { let (index, epoch, _) = id.unzip(); match self.map.get(index as usize) { Some(&Element::Vacant) => false, @@ -88,7 +85,7 @@ where /// This function is primarily intended for the `as_hal` family of functions /// where you may need to fallibly get a object backed by an id that could /// be in a different hub. - pub(crate) fn try_get(&self, id: I) -> Result>, InvalidId> { + pub(crate) fn try_get(&self, id: Id) -> Result>, InvalidId> { let (index, epoch, _) = id.unzip(); let (result, storage_epoch) = match self.map.get(index as usize) { Some(&Element::Occupied(ref v, epoch)) => (Ok(Some(v)), epoch), @@ -106,7 +103,7 @@ where /// Get a reference to an item behind a potentially invalid ID. /// Panics if there is an epoch mismatch, or the entry is empty. - pub(crate) fn get(&self, id: I) -> Result<&Arc, InvalidId> { + pub(crate) fn get(&self, id: Id) -> Result<&Arc, InvalidId> { let (index, epoch, _) = id.unzip(); let (result, storage_epoch) = match self.map.get(index as usize) { Some(&Element::Occupied(ref v, epoch)) => (Ok(v), epoch), @@ -124,11 +121,11 @@ where /// Get an owned reference to an item behind a potentially invalid ID. /// Panics if there is an epoch mismatch, or the entry is empty. - pub(crate) fn get_owned(&self, id: I) -> Result, InvalidId> { + pub(crate) fn get_owned(&self, id: Id) -> Result, InvalidId> { Ok(Arc::clone(self.get(id)?)) } - pub(crate) fn label_for_invalid_id(&self, id: I) -> &str { + pub(crate) fn label_for_invalid_id(&self, id: Id) -> &str { let (index, _, _) = id.unzip(); match self.map.get(index as usize) { Some(Element::Error(_, label)) => label, @@ -161,13 +158,13 @@ where } } - pub(crate) fn insert(&mut self, id: I, value: Arc) { + pub(crate) fn insert(&mut self, id: Id, value: Arc) { log::trace!("User is inserting {}{:?}", T::TYPE, id); let (index, epoch, _backend) = id.unzip(); self.insert_impl(index as usize, epoch, Element::Occupied(value, epoch)) } - pub(crate) fn insert_error(&mut self, id: I, label: &str) { + pub(crate) fn insert_error(&mut self, id: Id, label: &str) { log::trace!("User is insering as error {}{:?}", T::TYPE, id); let (index, epoch, _) = id.unzip(); self.insert_impl( @@ -177,7 +174,7 @@ where ) } - pub(crate) fn replace_with_error(&mut self, id: I) -> Result, InvalidId> { + pub(crate) fn replace_with_error(&mut self, id: Id) -> Result, InvalidId> { let (index, epoch, _) = id.unzip(); match std::mem::replace( &mut self.map[index as usize], @@ -192,13 +189,13 @@ where } } - pub(crate) fn force_replace(&mut self, id: I, value: T) { + pub(crate) fn force_replace(&mut self, id: Id, value: T) { log::trace!("User is replacing {}{:?}", T::TYPE, id); let (index, epoch, _) = id.unzip(); self.map[index as usize] = Element::Occupied(Arc::new(value), epoch); } - pub(crate) fn remove(&mut self, id: I) -> Option> { + pub(crate) fn remove(&mut self, id: Id) -> Option> { log::trace!("User is removing {}{:?}", T::TYPE, id); let (index, epoch, _) = id.unzip(); match std::mem::replace(&mut self.map[index as usize], Element::Vacant) { @@ -211,13 +208,13 @@ where } } - pub(crate) fn iter(&self, backend: Backend) -> impl Iterator)> { + pub(crate) fn iter(&self, backend: Backend) -> impl Iterator, &Arc)> { self.map .iter() .enumerate() .filter_map(move |(index, x)| match *x { Element::Occupied(ref value, storage_epoch) => { - Some((I::zip(index as Index, storage_epoch, backend), value)) + Some((Id::zip(index as Index, storage_epoch, backend), value)) } _ => None, }) diff --git a/wgpu-core/src/track/buffer.rs b/wgpu-core/src/track/buffer.rs index 2c2a6937f9..a9d61f9e00 100644 --- a/wgpu-core/src/track/buffer.rs +++ b/wgpu-core/src/track/buffer.rs @@ -10,7 +10,7 @@ use std::{borrow::Cow, marker::PhantomData, sync::Arc}; use super::{PendingTransition, ResourceTracker}; use crate::{ hal_api::HalApi, - id::{BufferId, TypedId}, + id::BufferId, resource::{Buffer, Resource}, snatch::SnatchGuard, storage::Storage, @@ -26,7 +26,6 @@ use wgt::{strict_assert, strict_assert_eq}; impl ResourceUses for BufferUses { const EXCLUSIVE: Self = Self::EXCLUSIVE; - type Id = BufferId; type Selector = (); fn bits(self) -> u16 { @@ -92,7 +91,7 @@ impl BufferBindGroupState { /// Adds the given resource with the given state. pub fn add_single<'a>( &self, - storage: &'a Storage, BufferId>, + storage: &'a Storage>, id: BufferId, state: BufferUses, ) -> Option<&'a Arc>> { @@ -110,7 +109,7 @@ impl BufferBindGroupState { pub(crate) struct BufferUsageScope { state: Vec, - metadata: ResourceMetadata>, + metadata: ResourceMetadata>, } impl BufferUsageScope { @@ -248,7 +247,7 @@ impl BufferUsageScope { /// the vectors will be extended. A call to set_size is not needed. pub fn merge_single<'a>( &mut self, - storage: &'a Storage, BufferId>, + storage: &'a Storage>, id: BufferId, new_state: BufferUses, ) -> Result<&'a Arc>, UsageConflict> { @@ -288,12 +287,12 @@ pub(crate) struct BufferTracker { start: Vec, end: Vec, - metadata: ResourceMetadata>, + metadata: ResourceMetadata>, temp: Vec>, } -impl ResourceTracker> for BufferTracker { +impl ResourceTracker> for BufferTracker { /// Try to remove the buffer `id` from this tracker if it is otherwise unused. /// /// A buffer is 'otherwise unused' when the only references to it are: @@ -654,11 +653,11 @@ impl BufferStateProvider<'_> { unsafe fn insert_or_merge( start_states: Option<&mut [BufferUses]>, current_states: &mut [BufferUses], - resource_metadata: &mut ResourceMetadata>, + resource_metadata: &mut ResourceMetadata>, index32: u32, index: usize, state_provider: BufferStateProvider<'_>, - metadata_provider: ResourceMetadataProvider<'_, A, BufferId, Buffer>, + metadata_provider: ResourceMetadataProvider<'_, A, Buffer>, ) -> Result<(), UsageConflict> { let currently_owned = unsafe { resource_metadata.contains_unchecked(index) }; @@ -709,11 +708,11 @@ unsafe fn insert_or_merge( unsafe fn insert_or_barrier_update( start_states: Option<&mut [BufferUses]>, current_states: &mut [BufferUses], - resource_metadata: &mut ResourceMetadata>, + resource_metadata: &mut ResourceMetadata>, index: usize, start_state_provider: BufferStateProvider<'_>, end_state_provider: Option>, - metadata_provider: ResourceMetadataProvider<'_, A, BufferId, Buffer>, + metadata_provider: ResourceMetadataProvider<'_, A, Buffer>, barriers: &mut Vec>, ) { let currently_owned = unsafe { resource_metadata.contains_unchecked(index) }; @@ -743,11 +742,11 @@ unsafe fn insert_or_barrier_update( unsafe fn insert( start_states: Option<&mut [BufferUses]>, current_states: &mut [BufferUses], - resource_metadata: &mut ResourceMetadata>, + resource_metadata: &mut ResourceMetadata>, index: usize, start_state_provider: BufferStateProvider<'_>, end_state_provider: Option>, - metadata_provider: ResourceMetadataProvider<'_, A, BufferId, Buffer>, + metadata_provider: ResourceMetadataProvider<'_, A, Buffer>, ) { let new_start_state = unsafe { start_state_provider.get_state(index) }; let new_end_state = @@ -777,7 +776,7 @@ unsafe fn merge( index32: u32, index: usize, state_provider: BufferStateProvider<'_>, - metadata_provider: ResourceMetadataProvider<'_, A, BufferId, Buffer>, + metadata_provider: ResourceMetadataProvider<'_, A, Buffer>, ) -> Result<(), UsageConflict> { let current_state = unsafe { current_states.get_unchecked_mut(index) }; let new_state = unsafe { state_provider.get_state(index) }; diff --git a/wgpu-core/src/track/metadata.rs b/wgpu-core/src/track/metadata.rs index 3464170ebf..76f6582061 100644 --- a/wgpu-core/src/track/metadata.rs +++ b/wgpu-core/src/track/metadata.rs @@ -1,6 +1,6 @@ //! The `ResourceMetadata` type. -use crate::{hal_api::HalApi, id::TypedId, resource::Resource, Epoch}; +use crate::{hal_api::HalApi, resource::Resource, Epoch}; use bit_vec::BitVec; use std::{borrow::Cow, marker::PhantomData, mem, sync::Arc}; use wgt::strict_assert; @@ -13,7 +13,7 @@ use wgt::strict_assert; /// members, but a bit vector tracks occupancy, so iteration touches /// only occupied elements. #[derive(Debug)] -pub(super) struct ResourceMetadata> { +pub(super) struct ResourceMetadata { /// If the resource with index `i` is a member, `owned[i]` is `true`. owned: BitVec, @@ -21,10 +21,10 @@ pub(super) struct ResourceMetadata> { resources: Vec>>, /// This tells Rust that this type should be covariant with `A`. - _phantom: PhantomData<(A, I)>, + _phantom: PhantomData, } -impl> ResourceMetadata { +impl ResourceMetadata { pub(super) fn new() -> Self { Self { owned: BitVec::default(), @@ -172,15 +172,15 @@ impl> ResourceMetadata { /// /// This is used to abstract over the various places /// trackers can get new resource metadata from. -pub(super) enum ResourceMetadataProvider<'a, A: HalApi, I: TypedId, T: Resource> { +pub(super) enum ResourceMetadataProvider<'a, A: HalApi, T: Resource> { /// Comes directly from explicit values. Direct { resource: Cow<'a, Arc> }, /// Comes from another metadata tracker. Indirect { - metadata: &'a ResourceMetadata, + metadata: &'a ResourceMetadata, }, } -impl> ResourceMetadataProvider<'_, A, I, T> { +impl ResourceMetadataProvider<'_, A, T> { /// Get the epoch and an owned refcount from this. /// /// # Safety diff --git a/wgpu-core/src/track/mod.rs b/wgpu-core/src/track/mod.rs index c13e815cb6..68975c931e 100644 --- a/wgpu-core/src/track/mod.rs +++ b/wgpu-core/src/track/mod.rs @@ -104,7 +104,7 @@ mod texture; use crate::{ binding_model, command, conv, hal_api::HalApi, - id::{self, TypedId}, + id::{self, Id}, pipeline, resource, snatch::SnatchGuard, storage::Storage, @@ -182,8 +182,6 @@ pub(crate) trait ResourceUses: /// All flags that are exclusive. const EXCLUSIVE: Self; - /// The relevant resource ID type. - type Id: Copy + fmt::Debug + TypedId; /// The selector used by this resource. type Selector: fmt::Debug; @@ -320,8 +318,8 @@ impl fmt::Display for InvalidUse { pub(crate) struct BindGroupStates { pub buffers: BufferBindGroupState, pub textures: TextureBindGroupState, - pub views: StatelessBindGroupSate>, - pub samplers: StatelessBindGroupSate>, + pub views: StatelessBindGroupSate>, + pub samplers: StatelessBindGroupSate>, } impl BindGroupStates { @@ -354,20 +352,19 @@ pub(crate) struct RenderBundleScope { pub buffers: RwLock>, pub textures: RwLock>, // Don't need to track views and samplers, they are never used directly, only by bind groups. - pub bind_groups: RwLock>>, - pub render_pipelines: - RwLock>>, - pub query_sets: RwLock>>, + pub bind_groups: RwLock>>, + pub render_pipelines: RwLock>>, + pub query_sets: RwLock>>, } impl RenderBundleScope { /// Create the render bundle scope and pull the maximum IDs from the hubs. pub fn new( - buffers: &Storage, id::BufferId>, - textures: &Storage, id::TextureId>, - bind_groups: &Storage, id::BindGroupId>, - render_pipelines: &Storage, id::RenderPipelineId>, - query_sets: &Storage, id::QuerySetId>, + buffers: &Storage>, + textures: &Storage>, + bind_groups: &Storage>, + render_pipelines: &Storage>, + query_sets: &Storage>, ) -> Self { let value = Self { buffers: RwLock::new(BufferUsageScope::new()), @@ -424,8 +421,8 @@ pub(crate) struct UsageScope { impl UsageScope { /// Create the render bundle scope and pull the maximum IDs from the hubs. pub fn new( - buffers: &Storage, id::BufferId>, - textures: &Storage, id::TextureId>, + buffers: &Storage>, + textures: &Storage>, ) -> Self { let mut value = Self { buffers: BufferUsageScope::new(), @@ -481,25 +478,24 @@ impl UsageScope { } } -pub(crate) trait ResourceTracker +pub(crate) trait ResourceTracker where - Id: TypedId, - R: resource::Resource, + R: resource::Resource, { - fn remove_abandoned(&mut self, id: Id) -> bool; + fn remove_abandoned(&mut self, id: Id) -> bool; } /// A full double sided tracker used by CommandBuffers and the Device. pub(crate) struct Tracker { pub buffers: BufferTracker, pub textures: TextureTracker, - pub views: StatelessTracker>, - pub samplers: StatelessTracker>, - pub bind_groups: StatelessTracker>, - pub compute_pipelines: StatelessTracker>, - pub render_pipelines: StatelessTracker>, - pub bundles: StatelessTracker>, - pub query_sets: StatelessTracker>, + pub views: StatelessTracker>, + pub samplers: StatelessTracker>, + pub bind_groups: StatelessTracker>, + pub compute_pipelines: StatelessTracker>, + pub render_pipelines: StatelessTracker>, + pub bundles: StatelessTracker>, + pub query_sets: StatelessTracker>, } impl Tracker { @@ -520,15 +516,15 @@ impl Tracker { /// Pull the maximum IDs from the hubs. pub fn set_size( &mut self, - buffers: Option<&Storage, id::BufferId>>, - textures: Option<&Storage, id::TextureId>>, - views: Option<&Storage, id::TextureViewId>>, - samplers: Option<&Storage, id::SamplerId>>, - bind_groups: Option<&Storage, id::BindGroupId>>, - compute_pipelines: Option<&Storage, id::ComputePipelineId>>, - render_pipelines: Option<&Storage, id::RenderPipelineId>>, - bundles: Option<&Storage, id::RenderBundleId>>, - query_sets: Option<&Storage, id::QuerySetId>>, + buffers: Option<&Storage>>, + textures: Option<&Storage>>, + views: Option<&Storage>>, + samplers: Option<&Storage>>, + bind_groups: Option<&Storage>>, + compute_pipelines: Option<&Storage>>, + render_pipelines: Option<&Storage>>, + bundles: Option<&Storage>>, + query_sets: Option<&Storage>>, ) { if let Some(buffers) = buffers { self.buffers.set_size(buffers.len()); diff --git a/wgpu-core/src/track/stateless.rs b/wgpu-core/src/track/stateless.rs index 6795890cc6..c1380e1248 100644 --- a/wgpu-core/src/track/stateless.rs +++ b/wgpu-core/src/track/stateless.rs @@ -4,24 +4,27 @@ * distinction between a usage scope and a full tracker. !*/ -use std::{marker::PhantomData, sync::Arc}; +use std::sync::Arc; use parking_lot::Mutex; use crate::{ - hal_api::HalApi, id::TypedId, resource::Resource, resource_log, storage::Storage, + hal_api::HalApi, id::Id, resource::Resource, resource_log, storage::Storage, track::ResourceMetadata, }; use super::ResourceTracker; +/// Satisfy clippy. +type Pair = (Id<::Marker>, Arc); + /// Stores all the resources that a bind group stores. #[derive(Debug)] -pub(crate) struct StatelessBindGroupSate> { - resources: Mutex)>>, +pub(crate) struct StatelessBindGroupSate { + resources: Mutex>>, } -impl> StatelessBindGroupSate { +impl StatelessBindGroupSate { pub fn new() -> Self { Self { resources: Mutex::new(Vec::new()), @@ -58,7 +61,7 @@ impl> StatelessBindGroupSate { } /// Adds the given resource. - pub fn add_single<'a>(&self, storage: &'a Storage, id: Id) -> Option<&'a T> { + pub fn add_single<'a>(&self, storage: &'a Storage, id: Id) -> Option<&'a T> { let resource = storage.get(id).ok()?; let mut resources = self.resources.lock(); @@ -70,14 +73,11 @@ impl> StatelessBindGroupSate { /// Stores all resource state within a command buffer or device. #[derive(Debug)] -pub(crate) struct StatelessTracker> { - metadata: ResourceMetadata, - _phantom: PhantomData, +pub(crate) struct StatelessTracker { + metadata: ResourceMetadata, } -impl> ResourceTracker - for StatelessTracker -{ +impl ResourceTracker for StatelessTracker { /// Try to remove the given resource from the tracker iff we have the last reference to the /// resource and the epoch matches. /// @@ -85,7 +85,7 @@ impl> ResourceTracker /// /// If the ID is higher than the length of internal vectors, /// false will be returned. - fn remove_abandoned(&mut self, id: Id) -> bool { + fn remove_abandoned(&mut self, id: Id) -> bool { let index = id.unzip().0 as usize; if index >= self.metadata.size() { @@ -120,11 +120,10 @@ impl> ResourceTracker } } -impl> StatelessTracker { +impl StatelessTracker { pub fn new() -> Self { Self { metadata: ResourceMetadata::new(), - _phantom: PhantomData, } } @@ -164,7 +163,7 @@ impl> StatelessTracker { /// /// If the ID is higher than the length of internal vectors, /// the vectors will be extended. A call to set_size is not needed. - pub fn insert_single(&mut self, id: Id, resource: Arc) { + pub fn insert_single(&mut self, id: Id, resource: Arc) { let (index32, _epoch, _) = id.unzip(); let index = index32 as usize; @@ -181,7 +180,11 @@ impl> StatelessTracker { /// /// If the ID is higher than the length of internal vectors, /// the vectors will be extended. A call to set_size is not needed. - pub fn add_single<'a>(&mut self, storage: &'a Storage, id: Id) -> Option<&'a Arc> { + pub fn add_single<'a>( + &mut self, + storage: &'a Storage, + id: Id, + ) -> Option<&'a Arc> { let resource = storage.get(id).ok()?; let (index32, _epoch, _) = id.unzip(); @@ -222,7 +225,7 @@ impl> StatelessTracker { } } - pub fn get(&self, id: Id) -> Option<&Arc> { + pub fn get(&self, id: Id) -> Option<&Arc> { let index = id.unzip().0 as usize; if index > self.metadata.size() { return None; diff --git a/wgpu-core/src/track/texture.rs b/wgpu-core/src/track/texture.rs index 94574596a9..f42740bf46 100644 --- a/wgpu-core/src/track/texture.rs +++ b/wgpu-core/src/track/texture.rs @@ -22,7 +22,7 @@ use super::{range::RangedStates, PendingTransition, PendingTransitionList, ResourceTracker}; use crate::{ hal_api::HalApi, - id::{TextureId, TypedId}, + id::TextureId, resource::{Resource, Texture, TextureInner}, snatch::SnatchGuard, track::{ @@ -50,7 +50,6 @@ pub struct TextureSelector { impl ResourceUses for TextureUses { const EXCLUSIVE: Self = Self::EXCLUSIVE; - type Id = TextureId; type Selector = TextureSelector; fn bits(self) -> u16 { @@ -232,7 +231,7 @@ impl TextureStateSet { #[derive(Debug)] pub(crate) struct TextureUsageScope { set: TextureStateSet, - metadata: ResourceMetadata>, + metadata: ResourceMetadata>, } impl TextureUsageScope { @@ -387,14 +386,14 @@ pub(crate) struct TextureTracker { start_set: TextureStateSet, end_set: TextureStateSet, - metadata: ResourceMetadata>, + metadata: ResourceMetadata>, temp: Vec>, _phantom: PhantomData, } -impl ResourceTracker> for TextureTracker { +impl ResourceTracker> for TextureTracker { /// Try to remove the given resource from the tracker iff we have the last reference to the /// resource and the epoch matches. /// @@ -864,10 +863,10 @@ impl<'a> TextureStateProvider<'a> { unsafe fn insert_or_merge( texture_selector: &TextureSelector, current_state_set: &mut TextureStateSet, - resource_metadata: &mut ResourceMetadata>, + resource_metadata: &mut ResourceMetadata>, index: usize, state_provider: TextureStateProvider<'_>, - metadata_provider: ResourceMetadataProvider<'_, A, TextureId, Texture>, + metadata_provider: ResourceMetadataProvider<'_, A, Texture>, ) -> Result<(), UsageConflict> { let currently_owned = unsafe { resource_metadata.contains_unchecked(index) }; @@ -920,11 +919,11 @@ unsafe fn insert_or_barrier_update( texture_selector: &TextureSelector, start_state: Option<&mut TextureStateSet>, current_state_set: &mut TextureStateSet, - resource_metadata: &mut ResourceMetadata>, + resource_metadata: &mut ResourceMetadata>, index: usize, start_state_provider: TextureStateProvider<'_>, end_state_provider: Option>, - metadata_provider: ResourceMetadataProvider<'_, A, TextureId, Texture>, + metadata_provider: ResourceMetadataProvider<'_, A, Texture>, barriers: &mut Vec>, ) { let currently_owned = unsafe { resource_metadata.contains_unchecked(index) }; @@ -973,11 +972,11 @@ unsafe fn insert( texture_selector: Option<&TextureSelector>, start_state: Option<&mut TextureStateSet>, end_state: &mut TextureStateSet, - resource_metadata: &mut ResourceMetadata>, + resource_metadata: &mut ResourceMetadata>, index: usize, start_state_provider: TextureStateProvider<'_>, end_state_provider: Option>, - metadata_provider: ResourceMetadataProvider<'_, A, TextureId, Texture>, + metadata_provider: ResourceMetadataProvider<'_, A, Texture>, ) { let start_layers = unsafe { start_state_provider.get_state(texture_selector, index) }; match start_layers { @@ -1060,7 +1059,7 @@ unsafe fn merge( current_state_set: &mut TextureStateSet, index: usize, state_provider: TextureStateProvider<'_>, - metadata_provider: ResourceMetadataProvider<'_, A, TextureId, Texture>, + metadata_provider: ResourceMetadataProvider<'_, A, Texture>, ) -> Result<(), UsageConflict> { let current_simple = unsafe { current_state_set.simple.get_unchecked_mut(index) }; let current_state = if *current_simple == TextureUses::COMPLEX { diff --git a/wgpu/src/backend/wgpu_core.rs b/wgpu/src/backend/wgpu_core.rs index 62f619d64c..3aec48fb69 100644 --- a/wgpu/src/backend/wgpu_core.rs +++ b/wgpu/src/backend/wgpu_core.rs @@ -24,7 +24,6 @@ use std::{ }; use wgc::command::{bundle_ffi::*, compute_ffi::*, render_ffi::*}; use wgc::device::DeviceLostClosure; -use wgc::id::TypedId; use wgt::WasmNotSendSync; const LABEL: &str = "label"; @@ -604,7 +603,7 @@ impl crate::Context for ContextWgpuCore { id: queue_id, error_sink, }; - ready(Ok((device_id, device, device_id, queue))) + ready(Ok((device_id, device, device_id.transmute(), queue))) } fn instance_poll_all_devices(&self, force_wait: bool) -> bool { @@ -1805,7 +1804,8 @@ impl crate::Context for ContextWgpuCore { if let Err(cause) = wgc::gfx_select!( encoder => self.0.command_encoder_run_compute_pass(*encoder, pass_data) ) { - let name = wgc::gfx_select!(encoder => self.0.command_buffer_label(*encoder)); + let name = + wgc::gfx_select!(encoder => self.0.command_buffer_label(encoder.transmute())); self.handle_error( &encoder_data.error_sink, cause, @@ -1888,7 +1888,8 @@ impl crate::Context for ContextWgpuCore { if let Err(cause) = wgc::gfx_select!(encoder => self.0.command_encoder_run_render_pass(*encoder, pass_data)) { - let name = wgc::gfx_select!(encoder => self.0.command_buffer_label(*encoder)); + let name = + wgc::gfx_select!(encoder => self.0.command_buffer_label(encoder.transmute())); self.handle_error( &encoder_data.error_sink, cause, @@ -2922,10 +2923,10 @@ impl crate::Context for ContextWgpuCore { impl From for wgc::id::Id where - T: 'static + WasmNotSendSync, + T: wgc::id::Marker, { fn from(id: ObjectId) -> Self { - let id = id.id(); + let id = wgc::id::RawId::from_non_zero(id.id()); // SAFETY: The id was created via the impl below unsafe { Self::from_raw(id) } } @@ -2933,10 +2934,10 @@ where impl From> for ObjectId where - T: 'static + WasmNotSendSync, + T: wgc::id::Marker, { fn from(id: wgc::id::Id) -> Self { - let id = id.into_raw(); + let id = id.into_raw().into_non_zero(); Self::from_global_id(id) } } From 6e020a079e9a512a7465252c238c5a85b1177fc5 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Mon, 29 Jan 2024 14:01:03 +0100 Subject: [PATCH 060/101] Fix the validation for vertex limits for regular render passes (#5156) --- CHANGELOG.md | 1 + wgpu-core/src/command/render.rs | 29 ++++++++++++++++++++++------- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5074fb597f..902a1bd1b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,6 +76,7 @@ Bottom level categories: #### General - Fix `panic!` when dropping `Instance` without `InstanceFlags::VALIDATION`. By @hakolao in [#5134](https://github.com/gfx-rs/wgpu/pull/5134) - Fix `serde` feature not compiling for `wgpu-types`. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) +- Fix the validation of vertex and index ranges. By @nical in [#5144](https://github.com/gfx-rs/wgpu/pull/5144) and [#5156](https://github.com/gfx-rs/wgpu/pull/5156) #### WGL diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index 933e00824b..786342a901 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -378,18 +378,33 @@ struct VertexState { impl VertexState { fn update_limits(&mut self) { - // TODO: This isn't entirely spec-compliant. - // We currently require that the buffer range can fit `stride` * count bytes. - // The spec, however, lets a buffer be a bit smaller as long as the size of the - // last element fits in it (the last element can be smaller than the stride between - // elements). + // Implements the validation from https://gpuweb.github.io/gpuweb/#dom-gpurendercommandsmixin-draw + // Except that the formula is shuffled to extract the number of vertices in order + // to carry the bulk of the computation when changing states intead of when producing + // draws. Draw calls tend to happen at a higher frequency. Here we determine vertex + // limits that can be cheaply checked for each draw call. self.vertex_limit = u32::MAX as u64; self.instance_limit = u32::MAX as u64; for (idx, vbs) in self.inputs.iter().enumerate() { - if vbs.step.stride == 0 || !vbs.bound { + if !vbs.bound { continue; } - let limit = vbs.total_size / vbs.step.stride; + + let limit = if vbs.total_size < vbs.step.last_stride { + // The buffer cannot fit the last vertex. + 0 + } else { + if vbs.step.stride == 0 { + // We already checked that the last stride fits, the same + // vertex will be repeated so this slot can accomodate any number of + // vertices. + continue; + } + + // The general case. + (vbs.total_size - vbs.step.last_stride) / vbs.step.stride + 1 + }; + match vbs.step.mode { VertexStepMode::Vertex => { if limit < self.vertex_limit { From 950d765a4d18c79e5fde3655ef507f04bae58101 Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Mon, 29 Jan 2024 15:37:57 +0100 Subject: [PATCH 061/101] Remove G parameter in Global and generic IdentityHandlerFactory (#5159) --- deno_webgpu/binding.rs | 6 +- deno_webgpu/buffer.rs | 2 +- deno_webgpu/bundle.rs | 2 +- deno_webgpu/command_encoder.rs | 2 +- deno_webgpu/lib.rs | 12 ++-- deno_webgpu/pipeline.rs | 16 ++--- deno_webgpu/sampler.rs | 2 +- deno_webgpu/shader.rs | 2 +- deno_webgpu/surface.rs | 3 +- deno_webgpu/texture.rs | 4 +- player/src/bin/play.rs | 18 ++--- player/src/lib.rs | 54 ++++++--------- player/tests/test.rs | 13 ++-- wgpu-core/src/command/clear.rs | 3 +- wgpu-core/src/command/compute.rs | 3 +- wgpu-core/src/command/mod.rs | 7 +- wgpu-core/src/command/query.rs | 3 +- wgpu-core/src/command/render.rs | 3 +- wgpu-core/src/command/transfer.rs | 3 +- wgpu-core/src/device/global.rs | 106 ++++++++++++++--------------- wgpu-core/src/device/mod.rs | 20 +++--- wgpu-core/src/device/queue.rs | 8 +-- wgpu-core/src/error.rs | 6 +- wgpu-core/src/global.rs | 37 ++++------- wgpu-core/src/hal_api.rs | 13 ++-- wgpu-core/src/hub.rs | 62 ++++++++--------- wgpu-core/src/id.rs | 12 +++- wgpu-core/src/identity.rs | 72 ++------------------ wgpu-core/src/instance.rs | 107 ++++++++++++++---------------- wgpu-core/src/lib.rs | 2 +- wgpu-core/src/present.rs | 21 +++--- wgpu-core/src/registry.rs | 29 ++++---- wgpu-core/src/resource.rs | 4 +- wgpu/src/backend/wgpu_core.rs | 94 ++++++++++++-------------- 34 files changed, 299 insertions(+), 452 deletions(-) diff --git a/deno_webgpu/binding.rs b/deno_webgpu/binding.rs index 5f1abde2b8..c0b9b5836d 100644 --- a/deno_webgpu/binding.rs +++ b/deno_webgpu/binding.rs @@ -208,7 +208,7 @@ pub fn op_webgpu_create_bind_group_layout( gfx_put!(device => instance.device_create_bind_group_layout( device, &descriptor, - () + None ) => state, WebGpuBindGroupLayout) } @@ -243,7 +243,7 @@ pub fn op_webgpu_create_pipeline_layout( gfx_put!(device => instance.device_create_pipeline_layout( device, &descriptor, - () + None ) => state, super::pipeline::WebGpuPipelineLayout) } @@ -322,6 +322,6 @@ pub fn op_webgpu_create_bind_group( gfx_put!(device => instance.device_create_bind_group( device, &descriptor, - () + None ) => state, WebGpuBindGroup) } diff --git a/deno_webgpu/buffer.rs b/deno_webgpu/buffer.rs index b46ceb1973..3cb9fdf830 100644 --- a/deno_webgpu/buffer.rs +++ b/deno_webgpu/buffer.rs @@ -64,7 +64,7 @@ pub fn op_webgpu_create_buffer( gfx_put!(device => instance.device_create_buffer( device, &descriptor, - () + None ) => state, WebGpuBuffer) } diff --git a/deno_webgpu/bundle.rs b/deno_webgpu/bundle.rs index 7e37bc649e..d503599313 100644 --- a/deno_webgpu/bundle.rs +++ b/deno_webgpu/bundle.rs @@ -113,7 +113,7 @@ pub fn op_webgpu_render_bundle_encoder_finish( &wgpu_core::command::RenderBundleDescriptor { label: Some(label), }, - () + None ) => state, WebGpuRenderBundle) } diff --git a/deno_webgpu/command_encoder.rs b/deno_webgpu/command_encoder.rs index 33f271ce97..679ac3cabf 100644 --- a/deno_webgpu/command_encoder.rs +++ b/deno_webgpu/command_encoder.rs @@ -61,7 +61,7 @@ pub fn op_webgpu_create_command_encoder( gfx_put!(device => instance.device_create_command_encoder( device, &descriptor, - () + None ) => state, WebGpuCommandEncoder) } diff --git a/deno_webgpu/lib.rs b/deno_webgpu/lib.rs index bc6d7a2ae5..40e76e0fa5 100644 --- a/deno_webgpu/lib.rs +++ b/deno_webgpu/lib.rs @@ -96,8 +96,7 @@ fn check_unstable(state: &OpState, api_name: &str) { } } -pub type Instance = - std::sync::Arc>; +pub type Instance = std::sync::Arc; struct WebGpuAdapter(Instance, wgpu_core::id::AdapterId); impl Resource for WebGpuAdapter { @@ -410,7 +409,6 @@ pub async fn op_webgpu_request_adapter( } else { state.put(std::sync::Arc::new(wgpu_core::global::Global::new( "webgpu", - wgpu_core::identity::IdentityManagerFactory, wgpu_types::InstanceDescriptor { backends, flags: wgpu_types::InstanceFlags::from_build_config(), @@ -428,7 +426,7 @@ pub async fn op_webgpu_request_adapter( }; let res = instance.request_adapter( &descriptor, - wgpu_core::instance::AdapterInputs::Mask(backends, |_| ()), + wgpu_core::instance::AdapterInputs::Mask(backends, |_| None), ); let adapter = match res { @@ -675,8 +673,8 @@ pub async fn op_webgpu_request_device( adapter, &descriptor, std::env::var("DENO_WEBGPU_TRACE").ok().as_ref().map(std::path::Path::new), - (), - () + None, + None )); if let Some(err) = maybe_err { return Err(DomExceptionOperationError::new(&err.to_string()).into()); @@ -773,6 +771,6 @@ pub fn op_webgpu_create_query_set( gfx_put!(device => instance.device_create_query_set( device, &descriptor, - () + None ) => state, WebGpuQuerySet) } diff --git a/deno_webgpu/pipeline.rs b/deno_webgpu/pipeline.rs index bf98b690b7..9175fe2075 100644 --- a/deno_webgpu/pipeline.rs +++ b/deno_webgpu/pipeline.rs @@ -118,8 +118,8 @@ pub fn op_webgpu_create_compute_pipeline( GPUPipelineLayoutOrGPUAutoLayoutMode::Layout(_) => None, GPUPipelineLayoutOrGPUAutoLayoutMode::Auto(GPUAutoLayoutMode::Auto) => { Some(wgpu_core::device::ImplicitPipelineIds { - root_id: (), - group_ids: &[(); MAX_BIND_GROUPS], + root_id: None, + group_ids: &[None; MAX_BIND_GROUPS], }) } }; @@ -127,7 +127,7 @@ pub fn op_webgpu_create_compute_pipeline( let (compute_pipeline, maybe_err) = gfx_select!(device => instance.device_create_compute_pipeline( device, &descriptor, - (), + None, implicit_pipelines )); @@ -159,7 +159,7 @@ pub fn op_webgpu_compute_pipeline_get_bind_group_layout( .get::(compute_pipeline_rid)?; let compute_pipeline = compute_pipeline_resource.1; - let (bind_group_layout, maybe_err) = gfx_select!(compute_pipeline => instance.compute_pipeline_get_bind_group_layout(compute_pipeline, index, ())); + let (bind_group_layout, maybe_err) = gfx_select!(compute_pipeline => instance.compute_pipeline_get_bind_group_layout(compute_pipeline, index, None)); let label = gfx_select!(bind_group_layout => instance.bind_group_layout_label(bind_group_layout)); @@ -392,8 +392,8 @@ pub fn op_webgpu_create_render_pipeline( GPUPipelineLayoutOrGPUAutoLayoutMode::Layout(_) => None, GPUPipelineLayoutOrGPUAutoLayoutMode::Auto(GPUAutoLayoutMode::Auto) => { Some(wgpu_core::device::ImplicitPipelineIds { - root_id: (), - group_ids: &[(); MAX_BIND_GROUPS], + root_id: None, + group_ids: &[None; MAX_BIND_GROUPS], }) } }; @@ -401,7 +401,7 @@ pub fn op_webgpu_create_render_pipeline( let (render_pipeline, maybe_err) = gfx_select!(device => instance.device_create_render_pipeline( device, &descriptor, - (), + None, implicit_pipelines )); @@ -425,7 +425,7 @@ pub fn op_webgpu_render_pipeline_get_bind_group_layout( .get::(render_pipeline_rid)?; let render_pipeline = render_pipeline_resource.1; - let (bind_group_layout, maybe_err) = gfx_select!(render_pipeline => instance.render_pipeline_get_bind_group_layout(render_pipeline, index, ())); + let (bind_group_layout, maybe_err) = gfx_select!(render_pipeline => instance.render_pipeline_get_bind_group_layout(render_pipeline, index, None)); let label = gfx_select!(bind_group_layout => instance.bind_group_layout_label(bind_group_layout)); diff --git a/deno_webgpu/sampler.rs b/deno_webgpu/sampler.rs index 5876498b29..0d65d727a1 100644 --- a/deno_webgpu/sampler.rs +++ b/deno_webgpu/sampler.rs @@ -74,6 +74,6 @@ pub fn op_webgpu_create_sampler( gfx_put!(device => instance.device_create_sampler( device, &descriptor, - () + None ) => state, WebGpuSampler) } diff --git a/deno_webgpu/shader.rs b/deno_webgpu/shader.rs index f091b15f8f..f4604a04a5 100644 --- a/deno_webgpu/shader.rs +++ b/deno_webgpu/shader.rs @@ -49,6 +49,6 @@ pub fn op_webgpu_create_shader_module( device, &descriptor, source, - () + None ) => state, WebGpuShaderModule) } diff --git a/deno_webgpu/surface.rs b/deno_webgpu/surface.rs index 1ac9d8704d..4d8412999c 100644 --- a/deno_webgpu/surface.rs +++ b/deno_webgpu/surface.rs @@ -75,6 +75,7 @@ pub fn op_webgpu_surface_configure( present_mode: args.present_mode.unwrap_or_default(), alpha_mode: args.alpha_mode, view_formats: args.view_formats, + desired_maximum_frame_latency: 2, }; let err = gfx_select!(device => instance.surface_configure(surface, device, &conf)); @@ -97,7 +98,7 @@ pub fn op_webgpu_surface_get_current_texture( let surface_resource = state.resource_table.get::(surface_rid)?; let surface = surface_resource.1; - let output = gfx_select!(device => instance.surface_get_current_texture(surface, ()))?; + let output = gfx_select!(device => instance.surface_get_current_texture(surface, None))?; match output.status { SurfaceStatus::Good | SurfaceStatus::Suboptimal => { diff --git a/deno_webgpu/texture.rs b/deno_webgpu/texture.rs index 8e1afa492f..a9be7b9914 100644 --- a/deno_webgpu/texture.rs +++ b/deno_webgpu/texture.rs @@ -83,7 +83,7 @@ pub fn op_webgpu_create_texture( let (val, maybe_err) = gfx_select!(device => instance.device_create_texture( device, &descriptor, - () + None )); let rid = state.resource_table.add(WebGpuTexture { @@ -128,6 +128,6 @@ pub fn op_webgpu_create_texture_view( gfx_put!(texture => instance.texture_create_view( texture, &descriptor, - () + None ) => state, WebGpuTextureView) } diff --git a/player/src/bin/play.rs b/player/src/bin/play.rs index 5e87232d8c..7e3cbad11b 100644 --- a/player/src/bin/play.rs +++ b/player/src/bin/play.rs @@ -3,7 +3,7 @@ #[cfg(not(target_arch = "wasm32"))] fn main() { - use player::{GlobalPlay as _, IdentityPassThroughFactory}; + use player::GlobalPlay as _; use wgc::{device::trace, gfx_select}; use std::{ @@ -49,11 +49,7 @@ fn main() { .build(&event_loop) .unwrap(); - let global = wgc::global::Global::new( - "player", - IdentityPassThroughFactory, - wgt::InstanceDescriptor::default(), - ); + let global = wgc::global::Global::new("player", wgt::InstanceDescriptor::default()); let mut command_buffer_id_manager = wgc::identity::IdentityManager::new(); #[cfg(feature = "winit")] @@ -61,7 +57,7 @@ fn main() { global.instance_create_surface( window.display_handle().unwrap().into(), window.window_handle().unwrap().into(), - wgc::id::Id::zip(0, 1, wgt::Backend::Empty), + Some(wgc::id::Id::zip(0, 1, wgt::Backend::Empty)), ) } .unwrap(); @@ -79,9 +75,7 @@ fn main() { #[cfg(not(feature = "winit"))] compatible_surface: None, }, - wgc::instance::AdapterInputs::IdSet(&[wgc::id::Id::zip(0, 0, backend)], |id| { - id.backend() - }), + wgc::instance::AdapterInputs::IdSet(&[wgc::id::AdapterId::zip(0, 0, backend)]), ) .expect("Unable to find an adapter for selected backend"); @@ -92,8 +86,8 @@ fn main() { adapter, &desc, None, - id, - id.transmute() + Some(id), + Some(id.transmute()) )); if let Some(e) = error { panic!("{:?}", e); diff --git a/player/src/lib.rs b/player/src/lib.rs index 3062d6a851..eb89e43f73 100644 --- a/player/src/lib.rs +++ b/player/src/lib.rs @@ -12,21 +12,6 @@ use wgc::device::trace; use std::{borrow::Cow, fs, path::Path}; -pub struct IdentityPassThroughFactory; - -impl wgc::identity::IdentityHandlerFactory for IdentityPassThroughFactory { - type Input = wgc::id::Id; - - fn input_to_id(id_in: Self::Input) -> wgc::id::Id { - id_in - } - - fn autogenerate_ids() -> bool { - false - } -} -impl wgc::identity::GlobalIdentityHandlerFactory for IdentityPassThroughFactory {} - pub trait GlobalPlay { fn encode_commands( &self, @@ -42,7 +27,7 @@ pub trait GlobalPlay { ); } -impl GlobalPlay for wgc::global::Global { +impl GlobalPlay for wgc::global::Global { fn encode_commands( &self, encoder: wgc::id::CommandEncoderId, @@ -169,7 +154,7 @@ impl GlobalPlay for wgc::global::Global { } Action::CreateBuffer(id, desc) => { self.device_maintain_ids::(device).unwrap(); - let (_, error) = self.device_create_buffer::(device, &desc, id); + let (_, error) = self.device_create_buffer::(device, &desc, Some(id)); if let Some(e) = error { panic!("{e}"); } @@ -182,7 +167,7 @@ impl GlobalPlay for wgc::global::Global { } Action::CreateTexture(id, desc) => { self.device_maintain_ids::(device).unwrap(); - let (_, error) = self.device_create_texture::(device, &desc, id); + let (_, error) = self.device_create_texture::(device, &desc, Some(id)); if let Some(e) = error { panic!("{e}"); } @@ -199,7 +184,7 @@ impl GlobalPlay for wgc::global::Global { desc, } => { self.device_maintain_ids::(device).unwrap(); - let (_, error) = self.texture_create_view::(parent_id, &desc, id); + let (_, error) = self.texture_create_view::(parent_id, &desc, Some(id)); if let Some(e) = error { panic!("{e}"); } @@ -209,7 +194,7 @@ impl GlobalPlay for wgc::global::Global { } Action::CreateSampler(id, desc) => { self.device_maintain_ids::(device).unwrap(); - let (_, error) = self.device_create_sampler::(device, &desc, id); + let (_, error) = self.device_create_sampler::(device, &desc, Some(id)); if let Some(e) = error { panic!("{e}"); } @@ -219,13 +204,13 @@ impl GlobalPlay for wgc::global::Global { } Action::GetSurfaceTexture { id, parent_id } => { self.device_maintain_ids::(device).unwrap(); - self.surface_get_current_texture::(parent_id, id) + self.surface_get_current_texture::(parent_id, Some(id)) .unwrap() .texture_id .unwrap(); } Action::CreateBindGroupLayout(id, desc) => { - let (_, error) = self.device_create_bind_group_layout::(device, &desc, id); + let (_, error) = self.device_create_bind_group_layout::(device, &desc, Some(id)); if let Some(e) = error { panic!("{e}"); } @@ -235,7 +220,7 @@ impl GlobalPlay for wgc::global::Global { } Action::CreatePipelineLayout(id, desc) => { self.device_maintain_ids::(device).unwrap(); - let (_, error) = self.device_create_pipeline_layout::(device, &desc, id); + let (_, error) = self.device_create_pipeline_layout::(device, &desc, Some(id)); if let Some(e) = error { panic!("{e}"); } @@ -245,7 +230,7 @@ impl GlobalPlay for wgc::global::Global { } Action::CreateBindGroup(id, desc) => { self.device_maintain_ids::(device).unwrap(); - let (_, error) = self.device_create_bind_group::(device, &desc, id); + let (_, error) = self.device_create_bind_group::(device, &desc, Some(id)); if let Some(e) = error { panic!("{e}"); } @@ -264,7 +249,8 @@ impl GlobalPlay for wgc::global::Global { } else { panic!("Unknown shader {}", data); }; - let (_, error) = self.device_create_shader_module::(device, &desc, source, id); + let (_, error) = + self.device_create_shader_module::(device, &desc, source, Some(id)); if let Some(e) = error { println!("shader compilation error:\n---{code}\n---\n{e}"); } @@ -282,11 +268,11 @@ impl GlobalPlay for wgc::global::Global { implicit_context .as_ref() .map(|ic| wgc::device::ImplicitPipelineIds { - root_id: ic.root_id, - group_ids: &ic.group_ids, + root_id: Some(ic.root_id), + group_ids: wgc::id::as_option_slice(&ic.group_ids), }); let (_, error) = - self.device_create_compute_pipeline::(device, &desc, id, implicit_ids); + self.device_create_compute_pipeline::(device, &desc, Some(id), implicit_ids); if let Some(e) = error { panic!("{e}"); } @@ -304,11 +290,11 @@ impl GlobalPlay for wgc::global::Global { implicit_context .as_ref() .map(|ic| wgc::device::ImplicitPipelineIds { - root_id: ic.root_id, - group_ids: &ic.group_ids, + root_id: Some(ic.root_id), + group_ids: wgc::id::as_option_slice(&ic.group_ids), }); let (_, error) = - self.device_create_render_pipeline::(device, &desc, id, implicit_ids); + self.device_create_render_pipeline::(device, &desc, Some(id), implicit_ids); if let Some(e) = error { panic!("{e}"); } @@ -322,7 +308,7 @@ impl GlobalPlay for wgc::global::Global { let (_, error) = self.render_bundle_encoder_finish::( bundle, &wgt::RenderBundleDescriptor { label: desc.label }, - id, + Some(id), ); if let Some(e) = error { panic!("{e}"); @@ -333,7 +319,7 @@ impl GlobalPlay for wgc::global::Global { } Action::CreateQuerySet { id, desc } => { self.device_maintain_ids::(device).unwrap(); - let (_, error) = self.device_create_query_set::(device, &desc, id); + let (_, error) = self.device_create_query_set::(device, &desc, Some(id)); if let Some(e) = error { panic!("{e}"); } @@ -375,7 +361,7 @@ impl GlobalPlay for wgc::global::Global { let (encoder, error) = self.device_create_command_encoder::( device, &wgt::CommandEncoderDescriptor { label: None }, - comb_manager.process(device.backend()).transmute(), + Some(comb_manager.process(device.backend()).transmute()), ); if let Some(e) = error { panic!("{e}"); diff --git a/player/tests/test.rs b/player/tests/test.rs index bf6e0b315c..e38de1ceaf 100644 --- a/player/tests/test.rs +++ b/player/tests/test.rs @@ -10,7 +10,7 @@ !*/ #![cfg(not(target_arch = "wasm32"))] -use player::{GlobalPlay, IdentityPassThroughFactory}; +use player::GlobalPlay; use std::{ fs::{read_to_string, File}, io::{Read, Seek, SeekFrom}, @@ -100,7 +100,7 @@ impl Test<'_> { fn run( self, dir: &Path, - global: &wgc::global::Global, + global: &wgc::global::Global, adapter: wgc::id::AdapterId, test_num: u32, ) { @@ -114,8 +114,8 @@ impl Test<'_> { required_limits: wgt::Limits::default(), }, None, - device_id, - device_id.transmute() + Some(device_id), + Some(device_id.transmute()) )); if let Some(e) = error { panic!("{:?}", e); @@ -203,7 +203,6 @@ impl Corpus { let global = wgc::global::Global::new( "test", - IdentityPassThroughFactory, wgt::InstanceDescriptor { backends: corpus.backends, flags: wgt::InstanceFlags::debugging(), @@ -221,9 +220,7 @@ impl Corpus { force_fallback_adapter: false, compatible_surface: None, }, - wgc::instance::AdapterInputs::IdSet(&[wgc::id::Id::zip(0, 0, backend)], |id| { - id.backend() - }), + wgc::instance::AdapterInputs::IdSet(&[wgc::id::Id::zip(0, 0, backend)]), ) { Ok(adapter) => adapter, Err(_) => continue, diff --git a/wgpu-core/src/command/clear.rs b/wgpu-core/src/command/clear.rs index 1a4b4cdeb1..2569fea1a4 100644 --- a/wgpu-core/src/command/clear.rs +++ b/wgpu-core/src/command/clear.rs @@ -10,7 +10,6 @@ use crate::{ global::Global, hal_api::HalApi, id::{BufferId, CommandEncoderId, DeviceId, TextureId}, - identity::GlobalIdentityHandlerFactory, init_tracker::{MemoryInitKind, TextureInitRange}, resource::{Resource, Texture, TextureClearMode}, track::{TextureSelector, TextureTracker}, @@ -71,7 +70,7 @@ whereas subesource range specified start {subresource_base_array_layer} and coun Device(#[from] DeviceError), } -impl Global { +impl Global { pub fn command_encoder_clear_buffer( &self, command_encoder_id: CommandEncoderId, diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index afd9c5204f..c2d75f3b50 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -18,7 +18,6 @@ use crate::{ hal_api::HalApi, hal_label, id, id::DeviceId, - identity::GlobalIdentityHandlerFactory, init_tracker::MemoryInitKind, pipeline, resource::{self}, @@ -340,7 +339,7 @@ impl State { // Common routines between render/compute -impl Global { +impl Global { pub fn command_encoder_run_compute_pass( &self, encoder_id: id::CommandEncoderId, diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index 1201e30f0e..2d5fca200a 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -27,10 +27,7 @@ use crate::snatch::SnatchGuard; use crate::init_tracker::BufferInitTrackerAction; use crate::resource::{Resource, ResourceInfo, ResourceType}; use crate::track::{Tracker, UsageScope}; -use crate::{ - api_log, global::Global, hal_api::HalApi, id, identity::GlobalIdentityHandlerFactory, - resource_log, Label, -}; +use crate::{api_log, global::Global, hal_api::HalApi, id, resource_log, Label}; use hal::CommandEncoder as _; use parking_lot::Mutex; @@ -410,7 +407,7 @@ pub enum CommandEncoderError { Device(#[from] DeviceError), } -impl Global { +impl Global { pub fn command_encoder_finish( &self, encoder_id: id::CommandEncoderId, diff --git a/wgpu-core/src/command/query.rs b/wgpu-core/src/command/query.rs index ab97cfc37a..39d7a9cc93 100644 --- a/wgpu-core/src/command/query.rs +++ b/wgpu-core/src/command/query.rs @@ -8,7 +8,6 @@ use crate::{ global::Global, hal_api::HalApi, id::{self, Id}, - identity::GlobalIdentityHandlerFactory, init_tracker::MemoryInitKind, resource::QuerySet, storage::Storage, @@ -346,7 +345,7 @@ pub(super) fn end_pipeline_statistics_query( } } -impl Global { +impl Global { pub fn command_encoder_write_timestamp( &self, command_encoder_id: id::CommandEncoderId, diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index 786342a901..ec550caf17 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -20,7 +20,6 @@ use crate::{ global::Global, hal_api::HalApi, hal_label, id, - identity::GlobalIdentityHandlerFactory, init_tracker::{MemoryInitKind, TextureInitRange, TextureInitTrackerAction}, pipeline::{self, PipelineFlags}, resource::{Buffer, QuerySet, Texture, TextureView, TextureViewNotRenderableReason}, @@ -1303,7 +1302,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { // Common routines between render/compute -impl Global { +impl Global { pub fn command_encoder_run_render_pass( &self, encoder_id: id::CommandEncoderId, diff --git a/wgpu-core/src/command/transfer.rs b/wgpu-core/src/command/transfer.rs index 6bde17c646..e52a6882eb 100644 --- a/wgpu-core/src/command/transfer.rs +++ b/wgpu-core/src/command/transfer.rs @@ -9,7 +9,6 @@ use crate::{ global::Global, hal_api::HalApi, id::{BufferId, CommandEncoderId, DeviceId, TextureId}, - identity::GlobalIdentityHandlerFactory, init_tracker::{ has_copy_partial_init_tracker_coverage, MemoryInitKind, TextureInitRange, TextureInitTrackerAction, @@ -554,7 +553,7 @@ fn handle_dst_texture_init( Ok(()) } -impl Global { +impl Global { pub fn command_encoder_copy_buffer_to_buffer( &self, command_encoder_id: CommandEncoderId, diff --git a/wgpu-core/src/device/global.rs b/wgpu-core/src/device/global.rs index 8db2db913f..daa42fddef 100644 --- a/wgpu-core/src/device/global.rs +++ b/wgpu-core/src/device/global.rs @@ -8,9 +8,7 @@ use crate::{ }, global::Global, hal_api::HalApi, - id::markers, id::{self, AdapterId, DeviceId, QueueId, SurfaceId}, - identity::{GlobalIdentityHandlerFactory, Input}, init_tracker::TextureInitTracker, instance::{self, Adapter, Surface}, pipeline, present, @@ -36,7 +34,7 @@ use std::{ use super::{ImplicitPipelineIds, InvalidDevice, UserClosures}; -impl Global { +impl Global { pub fn adapter_is_surface_supported( &self, adapter_id: AdapterId, @@ -147,12 +145,12 @@ impl Global { &self, device_id: DeviceId, desc: &resource::BufferDescriptor, - id_in: Input, + id_in: Option, ) -> (id::BufferId, Option) { profiling::scope!("Device::create_buffer"); let hub = A::hub(self); - let fid = hub.buffers.prepare::(id_in); + let fid = hub.buffers.prepare(id_in); let mut to_destroy: ArrayVec, 2> = ArrayVec::new(); let error = loop { @@ -310,20 +308,20 @@ impl Global { /// [`device_create_buffer`]: Global::device_create_buffer /// [`usage`]: https://www.w3.org/TR/webgpu/#dom-gputexturedescriptor-usage /// [`wgpu_types::BufferUsages`]: wgt::BufferUsages - pub fn create_buffer_error(&self, id_in: Input, label: Label) { + pub fn create_buffer_error(&self, id_in: Option, label: Label) { let hub = A::hub(self); - let fid = hub.buffers.prepare::(id_in); + let fid = hub.buffers.prepare(id_in); fid.assign_error(label.borrow_or_default()); } pub fn create_render_bundle_error( &self, - id_in: Input, + id_in: Option, label: Label, ) { let hub = A::hub(self); - let fid = hub.render_bundles.prepare::(id_in); + let fid = hub.render_bundles.prepare(id_in); fid.assign_error(label.borrow_or_default()); } @@ -331,9 +329,9 @@ impl Global { /// Assign `id_in` an error with the given `label`. /// /// See `create_buffer_error` for more context and explaination. - pub fn create_texture_error(&self, id_in: Input, label: Label) { + pub fn create_texture_error(&self, id_in: Option, label: Label) { let hub = A::hub(self); - let fid = hub.textures.prepare::(id_in); + let fid = hub.textures.prepare(id_in); fid.assign_error(label.borrow_or_default()); } @@ -546,13 +544,13 @@ impl Global { &self, device_id: DeviceId, desc: &resource::TextureDescriptor, - id_in: Input, + id_in: Option, ) -> (id::TextureId, Option) { profiling::scope!("Device::create_texture"); let hub = A::hub(self); - let fid = hub.textures.prepare::(id_in); + let fid = hub.textures.prepare(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -600,13 +598,13 @@ impl Global { hal_texture: A::Texture, device_id: DeviceId, desc: &resource::TextureDescriptor, - id_in: Input, + id_in: Option, ) -> (id::TextureId, Option) { profiling::scope!("Device::create_texture_from_hal"); let hub = A::hub(self); - let fid = hub.textures.prepare::(id_in); + let fid = hub.textures.prepare(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -674,12 +672,12 @@ impl Global { hal_buffer: A::Buffer, device_id: DeviceId, desc: &resource::BufferDescriptor, - id_in: Input, + id_in: Option, ) -> (id::BufferId, Option) { profiling::scope!("Device::create_buffer"); let hub = A::hub(self); - let fid = hub.buffers.prepare::(id_in); + let fid = hub.buffers.prepare(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -784,13 +782,13 @@ impl Global { &self, texture_id: id::TextureId, desc: &resource::TextureViewDescriptor, - id_in: Input, + id_in: Option, ) -> (id::TextureViewId, Option) { profiling::scope!("Texture::create_view"); let hub = A::hub(self); - let fid = hub.texture_views.prepare::(id_in); + let fid = hub.texture_views.prepare(id_in); let error = loop { let texture = match hub.textures.get(texture_id) { @@ -874,12 +872,12 @@ impl Global { &self, device_id: DeviceId, desc: &resource::SamplerDescriptor, - id_in: Input, + id_in: Option, ) -> (id::SamplerId, Option) { profiling::scope!("Device::create_sampler"); let hub = A::hub(self); - let fid = hub.samplers.prepare::(id_in); + let fid = hub.samplers.prepare(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -935,7 +933,7 @@ impl Global { &self, device_id: DeviceId, desc: &binding_model::BindGroupLayoutDescriptor, - id_in: Input, + id_in: Option, ) -> ( id::BindGroupLayoutId, Option, @@ -943,7 +941,7 @@ impl Global { profiling::scope!("Device::create_bind_group_layout"); let hub = A::hub(self); - let fid = hub.bind_group_layouts.prepare::(id_in); + let fid = hub.bind_group_layouts.prepare(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -1005,7 +1003,7 @@ impl Global { return (id.unwrap(), None); }; - let fid = hub.bind_group_layouts.prepare::(id_in); + let fid = hub.bind_group_layouts.prepare(id_in); let id = fid.assign_error(desc.label.borrow_or_default()); (id, Some(error)) } @@ -1034,7 +1032,7 @@ impl Global { &self, device_id: DeviceId, desc: &binding_model::PipelineLayoutDescriptor, - id_in: Input, + id_in: Option, ) -> ( id::PipelineLayoutId, Option, @@ -1042,7 +1040,7 @@ impl Global { profiling::scope!("Device::create_pipeline_layout"); let hub = A::hub(self); - let fid = hub.pipeline_layouts.prepare::(id_in); + let fid = hub.pipeline_layouts.prepare(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -1095,12 +1093,12 @@ impl Global { &self, device_id: DeviceId, desc: &binding_model::BindGroupDescriptor, - id_in: Input, + id_in: Option, ) -> (id::BindGroupId, Option) { profiling::scope!("Device::create_bind_group"); let hub = A::hub(self); - let fid = hub.bind_groups.prepare::(id_in); + let fid = hub.bind_groups.prepare(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -1179,7 +1177,7 @@ impl Global { device_id: DeviceId, desc: &pipeline::ShaderModuleDescriptor, source: pipeline::ShaderModuleSource, - id_in: Input, + id_in: Option, ) -> ( id::ShaderModuleId, Option, @@ -1187,7 +1185,7 @@ impl Global { profiling::scope!("Device::create_shader_module"); let hub = A::hub(self); - let fid = hub.shader_modules.prepare::(id_in); + let fid = hub.shader_modules.prepare(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -1257,7 +1255,7 @@ impl Global { device_id: DeviceId, desc: &pipeline::ShaderModuleDescriptor, source: Cow<[u32]>, - id_in: Input, + id_in: Option, ) -> ( id::ShaderModuleId, Option, @@ -1265,7 +1263,7 @@ impl Global { profiling::scope!("Device::create_shader_module"); let hub = A::hub(self); - let fid = hub.shader_modules.prepare::(id_in); + let fid = hub.shader_modules.prepare(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -1319,14 +1317,12 @@ impl Global { &self, device_id: DeviceId, desc: &wgt::CommandEncoderDescriptor) -> ImplicitPipelineContext { ImplicitPipelineContext { - root_id: hub.pipeline_layouts.prepare::(self.root_id).into_id(), + root_id: hub.pipeline_layouts.prepare(self.root_id).into_id(), group_ids: self .group_ids .iter() - .map(|id_in| hub.bind_group_layouts.prepare::(*id_in).into_id()) + .map(|id_in| hub.bind_group_layouts.prepare(*id_in).into_id()) .collect(), } } diff --git a/wgpu-core/src/device/queue.rs b/wgpu-core/src/device/queue.rs index 4bd0046227..08c5b767b6 100644 --- a/wgpu-core/src/device/queue.rs +++ b/wgpu-core/src/device/queue.rs @@ -12,9 +12,7 @@ use crate::{ global::Global, hal_api::HalApi, hal_label, - id::markers, id::{self, QueueId}, - identity::{GlobalIdentityHandlerFactory, Input}, init_tracker::{has_copy_partial_init_tracker_coverage, TextureInitRange}, resource::{ Buffer, BufferAccessError, BufferMapState, DestroyedBuffer, DestroyedTexture, Resource, @@ -365,7 +363,7 @@ pub enum QueueSubmitError { //TODO: move out common parts of write_xxx. -impl Global { +impl Global { pub fn queue_write_buffer( &self, queue_id: QueueId, @@ -439,7 +437,7 @@ impl Global { &self, queue_id: QueueId, buffer_size: wgt::BufferSize, - id_in: Input, + id_in: Option, ) -> Result<(id::StagingBufferId, *mut u8), QueueWriteError> { profiling::scope!("Queue::create_staging_buffer"); let hub = A::hub(self); @@ -454,7 +452,7 @@ impl Global { let (staging_buffer, staging_buffer_ptr) = prepare_staging_buffer(device, buffer_size.get(), device.instance_flags)?; - let fid = hub.staging_buffers.prepare::(id_in); + let fid = hub.staging_buffers.prepare(id_in); let (id, _) = fid.assign(staging_buffer); resource_log!("Queue::create_staging_buffer {id:?}"); diff --git a/wgpu-core/src/error.rs b/wgpu-core/src/error.rs index 4a33207ca8..91b46261ae 100644 --- a/wgpu-core/src/error.rs +++ b/wgpu-core/src/error.rs @@ -1,11 +1,11 @@ use core::fmt; use std::error::Error; -use crate::{gfx_select, global::Global, identity::IdentityManagerFactory}; +use crate::{gfx_select, global::Global}; pub struct ErrorFormatter<'a> { writer: &'a mut dyn fmt::Write, - global: &'a Global, + global: &'a Global, } impl<'a> ErrorFormatter<'a> { @@ -94,7 +94,7 @@ pub trait PrettyError: Error + Sized { pub fn format_pretty_any( writer: &mut dyn fmt::Write, - global: &Global, + global: &Global, error: &(dyn Error + 'static), ) { let mut fmt = ErrorFormatter { writer, global }; diff --git a/wgpu-core/src/global.rs b/wgpu-core/src/global.rs index 950fabe2db..9a8c43bf33 100644 --- a/wgpu-core/src/global.rs +++ b/wgpu-core/src/global.rs @@ -1,11 +1,10 @@ -use std::{marker::PhantomData, sync::Arc}; +use std::sync::Arc; use wgt::Backend; use crate::{ hal_api::HalApi, hub::{HubReport, Hubs}, - identity::GlobalIdentityHandlerFactory, instance::{Instance, Surface}, registry::{Registry, RegistryReport}, resource_log, @@ -44,38 +43,31 @@ impl GlobalReport { } } -pub struct Global { +pub struct Global { pub instance: Instance, pub surfaces: Registry, pub(crate) hubs: Hubs, - _phantom: PhantomData, } -impl Global { - pub fn new(name: &str, factory: G, instance_desc: wgt::InstanceDescriptor) -> Self { +impl Global { + pub fn new(name: &str, instance_desc: wgt::InstanceDescriptor) -> Self { profiling::scope!("Global::new"); Self { instance: Instance::new(name, instance_desc), - surfaces: Registry::without_backend(&factory), - hubs: Hubs::new(&factory), - _phantom: PhantomData, + surfaces: Registry::without_backend(), + hubs: Hubs::new(), } } /// # Safety /// /// Refer to the creation of wgpu-hal Instance for every backend. - pub unsafe fn from_hal_instance( - name: &str, - factory: G, - hal_instance: A::Instance, - ) -> Self { + pub unsafe fn from_hal_instance(name: &str, hal_instance: A::Instance) -> Self { profiling::scope!("Global::new"); Self { instance: A::create_instance_from_hal(name, hal_instance), - surfaces: Registry::without_backend(&factory), - hubs: Hubs::new(&factory), - _phantom: PhantomData, + surfaces: Registry::without_backend(), + hubs: Hubs::new(), } } @@ -89,13 +81,12 @@ impl Global { /// # Safety /// /// - The raw handles obtained from the Instance must not be manually destroyed - pub unsafe fn from_instance(factory: G, instance: Instance) -> Self { + pub unsafe fn from_instance(instance: Instance) -> Self { profiling::scope!("Global::new"); Self { instance, - surfaces: Registry::without_backend(&factory), - hubs: Hubs::new(&factory), - _phantom: PhantomData, + surfaces: Registry::without_backend(), + hubs: Hubs::new(), } } @@ -137,7 +128,7 @@ impl Global { } } -impl Drop for Global { +impl Drop for Global { fn drop(&mut self) { profiling::scope!("Global::drop"); resource_log!("Global::drop"); @@ -175,7 +166,7 @@ impl Drop for Global { } #[cfg(send_sync)] -fn _test_send_sync(global: &Global) { +fn _test_send_sync(global: &Global) { fn test_internal(_: T) {} test_internal(global) } diff --git a/wgpu-core/src/hal_api.rs b/wgpu-core/src/hal_api.rs index d1dee98ed1..7de5073791 100644 --- a/wgpu-core/src/hal_api.rs +++ b/wgpu-core/src/hal_api.rs @@ -3,7 +3,6 @@ use wgt::{Backend, WasmNotSendSync}; use crate::{ global::Global, hub::Hub, - identity::GlobalIdentityHandlerFactory, instance::{HalSurface, Instance, Surface}, }; @@ -11,7 +10,7 @@ pub trait HalApi: hal::Api + 'static + WasmNotSendSync { const VARIANT: Backend; fn create_instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance; fn instance_as_hal(instance: &Instance) -> Option<&Self::Instance>; - fn hub(global: &Global) -> &Hub; + fn hub(global: &Global) -> &Hub; fn get_surface(surface: &Surface) -> Option<&HalSurface>; } @@ -23,7 +22,7 @@ impl HalApi for hal::api::Empty { fn instance_as_hal(_: &Instance) -> Option<&Self::Instance> { unimplemented!("called empty api") } - fn hub(_: &Global) -> &Hub { + fn hub(_: &Global) -> &Hub { unimplemented!("called empty api") } fn get_surface(_: &Surface) -> Option<&HalSurface> { @@ -44,7 +43,7 @@ impl HalApi for hal::api::Vulkan { fn instance_as_hal(instance: &Instance) -> Option<&Self::Instance> { instance.vulkan.as_ref() } - fn hub(global: &Global) -> &Hub { + fn hub(global: &Global) -> &Hub { &global.hubs.vulkan } fn get_surface(surface: &Surface) -> Option<&HalSurface> { @@ -65,7 +64,7 @@ impl HalApi for hal::api::Metal { fn instance_as_hal(instance: &Instance) -> Option<&Self::Instance> { instance.metal.as_ref() } - fn hub(global: &Global) -> &Hub { + fn hub(global: &Global) -> &Hub { &global.hubs.metal } fn get_surface(surface: &Surface) -> Option<&HalSurface> { @@ -86,7 +85,7 @@ impl HalApi for hal::api::Dx12 { fn instance_as_hal(instance: &Instance) -> Option<&Self::Instance> { instance.dx12.as_ref() } - fn hub(global: &Global) -> &Hub { + fn hub(global: &Global) -> &Hub { &global.hubs.dx12 } fn get_surface(surface: &Surface) -> Option<&HalSurface> { @@ -108,7 +107,7 @@ impl HalApi for hal::api::Gles { fn instance_as_hal(instance: &Instance) -> Option<&Self::Instance> { instance.gl.as_ref() } - fn hub(global: &Global) -> &Hub { + fn hub(global: &Global) -> &Hub { &global.hubs.gl } fn get_surface(surface: &Surface) -> Option<&HalSurface> { diff --git a/wgpu-core/src/hub.rs b/wgpu-core/src/hub.rs index 8494bef2b4..7829484aa8 100644 --- a/wgpu-core/src/hub.rs +++ b/wgpu-core/src/hub.rs @@ -40,7 +40,7 @@ specify the id, and they all return the id used. For example, the declaration of `Global::device_create_buffer` looks like this: ```ignore -impl Global { +impl Global { /* ... */ pub fn device_create_buffer( &self, @@ -60,15 +60,7 @@ itself to choose ids always pass `()`. In either case, the id ultimately assigned is returned as the first element of the tuple. Producing true identifiers from `id_in` values is the job of an -[`crate::identity::IdentityManager`], but only if the `IdentityHandlerFactory` -create it and then generated by it, otherwise ids will be received from outside. - -`Global::new` expects a `factory` argument that -implements the [`GlobalIdentityHandlerFactory`] trait, which extends -[`crate::identity::IdentityHandlerFactory`] for each resource id type `I`. This -trait, in turn, has a `spawn` method that constructs an -`crate::identity::IdentityManager` for the `Global` to use, -if ids should be generated by wgpu or will return None otherwise. +[`crate::identity::IdentityManager`] or ids will be received from outside through `Option` arguments. ## Id allocation and streaming @@ -105,7 +97,6 @@ as much, allowing subsequent operations using that id to be properly flagged as errors as well. [`gfx_select`]: crate::gfx_select -[`Input`]: crate::identity::IdentityHandlerFactory::Input [`process`]: crate::identity::IdentityManager::process [`Id`]: crate::id::Id [wrapped in a mutex]: trait.IdentityHandler.html#impl-IdentityHandler%3CI%3E-for-Mutex%3CIdentityManager%3E @@ -118,7 +109,6 @@ use crate::{ command::{CommandBuffer, RenderBundle}, device::{queue::Queue, Device}, hal_api::HalApi, - identity::GlobalIdentityHandlerFactory, instance::{Adapter, HalSurface, Surface}, pipeline::{ComputePipeline, RenderPipeline, ShaderModule}, registry::{Registry, RegistryReport}, @@ -199,25 +189,25 @@ pub struct Hub { } impl Hub { - fn new(factory: &F) -> Self { + fn new() -> Self { Self { - adapters: Registry::new(A::VARIANT, factory), - devices: Registry::new(A::VARIANT, factory), - queues: Registry::new(A::VARIANT, factory), - pipeline_layouts: Registry::new(A::VARIANT, factory), - shader_modules: Registry::new(A::VARIANT, factory), - bind_group_layouts: Registry::new(A::VARIANT, factory), - bind_groups: Registry::new(A::VARIANT, factory), - command_buffers: Registry::new(A::VARIANT, factory), - render_bundles: Registry::new(A::VARIANT, factory), - render_pipelines: Registry::new(A::VARIANT, factory), - compute_pipelines: Registry::new(A::VARIANT, factory), - query_sets: Registry::new(A::VARIANT, factory), - buffers: Registry::new(A::VARIANT, factory), - staging_buffers: Registry::new(A::VARIANT, factory), - textures: Registry::new(A::VARIANT, factory), - texture_views: Registry::new(A::VARIANT, factory), - samplers: Registry::new(A::VARIANT, factory), + adapters: Registry::new(A::VARIANT), + devices: Registry::new(A::VARIANT), + queues: Registry::new(A::VARIANT), + pipeline_layouts: Registry::new(A::VARIANT), + shader_modules: Registry::new(A::VARIANT), + bind_group_layouts: Registry::new(A::VARIANT), + bind_groups: Registry::new(A::VARIANT), + command_buffers: Registry::new(A::VARIANT), + render_bundles: Registry::new(A::VARIANT), + render_pipelines: Registry::new(A::VARIANT), + compute_pipelines: Registry::new(A::VARIANT), + query_sets: Registry::new(A::VARIANT), + buffers: Registry::new(A::VARIANT), + staging_buffers: Registry::new(A::VARIANT), + textures: Registry::new(A::VARIANT), + texture_views: Registry::new(A::VARIANT), + samplers: Registry::new(A::VARIANT), } } @@ -313,18 +303,18 @@ pub struct Hubs { } impl Hubs { - pub(crate) fn new(factory: &F) -> Self { + pub(crate) fn new() -> Self { Self { #[cfg(vulkan)] - vulkan: Hub::new(factory), + vulkan: Hub::new(), #[cfg(metal)] - metal: Hub::new(factory), + metal: Hub::new(), #[cfg(dx12)] - dx12: Hub::new(factory), + dx12: Hub::new(), #[cfg(gles)] - gl: Hub::new(factory), + gl: Hub::new(), #[cfg(all(not(vulkan), not(metal), not(dx12), not(gles)))] - empty: Hub::new(factory), + empty: Hub::new(), } } } diff --git a/wgpu-core/src/id.rs b/wgpu-core/src/id.rs index 56eaf61058..0d5b1cb3fe 100644 --- a/wgpu-core/src/id.rs +++ b/wgpu-core/src/id.rs @@ -71,9 +71,15 @@ impl RawId { } } -/// Coerce a slice of identifiers into a slice of raw identifiers. -pub fn into_raw_slice(ids: &[Id]) -> &[RawId] { - // SAFETY: Any Id is repr(transparent) over `RawId`. +/// Coerce a slice of identifiers into a slice of optional raw identifiers. +/// +/// There's two reasons why we know this is correct: +/// * `Option` is guarnateed to be niche-filled to 0's. +/// * The `T` in `Option` can inhabit any representation except 0's, since +/// its underlying representation is `NonZero*`. +pub fn as_option_slice(ids: &[Id]) -> &[Option>] { + // SAFETY: Any Id is repr(transparent) over `Option`, since both + // are backed by non-zero types. unsafe { std::slice::from_raw_parts(ids.as_ptr().cast(), ids.len()) } } diff --git a/wgpu-core/src/identity.rs b/wgpu-core/src/identity.rs index 44989a6d40..0e34055c74 100644 --- a/wgpu-core/src/identity.rs +++ b/wgpu-core/src/identity.rs @@ -2,10 +2,10 @@ use parking_lot::Mutex; use wgt::Backend; use crate::{ - id::{self, Id, Marker}, + id::{Id, Marker}, Epoch, FastHashMap, Index, }; -use std::{fmt::Debug, marker::PhantomData, sync::Arc}; +use std::{fmt::Debug, marker::PhantomData}; /// A simple structure to allocate [`Id`] identifiers. /// @@ -112,74 +112,10 @@ impl IdentityManager { } } -/// A type that can produce [`IdentityManager`] filters for ids of type `I`. -/// -/// See the module-level documentation for details. -pub trait IdentityHandlerFactory { - type Input: Copy; - /// Create an [`IdentityManager`] implementation that can - /// transform proto-ids into ids of type `I`. - /// It can return None if ids are passed from outside - /// and are not generated by wgpu - /// - /// [`IdentityManager`]: IdentityManager - fn spawn(&self) -> Arc> { - Arc::new(IdentityManager::new()) - } - fn autogenerate_ids() -> bool; - fn input_to_id(id_in: Self::Input) -> Id; -} - -/// A global identity handler factory based on [`IdentityManager`]. -/// -/// Each of this type's `IdentityHandlerFactory::spawn` methods -/// returns a `Mutex>`, which allocates fresh `I` -/// ids itself, and takes `()` as its proto-id type. -#[derive(Debug)] -pub struct IdentityManagerFactory; - -impl IdentityHandlerFactory for IdentityManagerFactory { - type Input = (); - fn autogenerate_ids() -> bool { - true - } - - fn input_to_id(_id_in: Self::Input) -> Id { - unreachable!("It should not be called") - } -} - -/// A factory that can build [`IdentityManager`]s for all resource -/// types. -pub trait GlobalIdentityHandlerFactory: - IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory -{ -} - -impl GlobalIdentityHandlerFactory for IdentityManagerFactory {} - -pub type Input = >::Input; - #[test] fn test_epoch_end_of_life() { + use crate::id; + let man = IdentityManager::::new(); let forced_id = man.mark_as_used(id::BufferId::zip(0, 1, Backend::Empty)); assert_eq!(forced_id.unzip().0, 0); diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index cb5871d6b8..4c3134237e 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -7,8 +7,7 @@ use crate::{ global::Global, hal_api::HalApi, id::markers, - id::{AdapterId, DeviceId, QueueId, SurfaceId}, - identity::{GlobalIdentityHandlerFactory, Input}, + id::{AdapterId, DeviceId, Id, Marker, QueueId, SurfaceId}, present::Presentation, resource::{Resource, ResourceInfo, ResourceType}, resource_log, LabelHelpers, DOWNLEVEL_WARNING_MESSAGE, @@ -157,7 +156,7 @@ pub struct Surface { impl Resource for Surface { const TYPE: ResourceType = "Surface"; - type Marker = crate::id::markers::Surface; + type Marker = markers::Surface; fn as_info(&self) -> &ResourceInfo { &self.info @@ -388,7 +387,7 @@ impl Adapter { impl Resource for Adapter { const TYPE: ResourceType = "Adapter"; - type Marker = crate::id::markers::Adapter; + type Marker = markers::Adapter; fn as_info(&self) -> &ResourceInfo { &self.info @@ -439,15 +438,15 @@ pub enum RequestDeviceError { UnsupportedFeature(wgt::Features), } -pub enum AdapterInputs<'a, I> { - IdSet(&'a [I], fn(&I) -> Backend), - Mask(Backends, fn(Backend) -> I), +pub enum AdapterInputs<'a, M: Marker> { + IdSet(&'a [Id]), + Mask(Backends, fn(Backend) -> Option>), } -impl AdapterInputs<'_, I> { - fn find(&self, b: Backend) -> Option { +impl AdapterInputs<'_, M> { + fn find(&self, b: Backend) -> Option>> { match *self { - Self::IdSet(ids, ref fun) => ids.iter().find(|id| fun(id) == b).copied(), + Self::IdSet(ids) => Some(Some(ids.iter().find(|id| id.backend() == b).copied()?)), Self::Mask(bits, ref fun) => { if bits.contains(b.into()) { Some(fun(b)) @@ -472,7 +471,7 @@ pub enum RequestAdapterError { InvalidSurface(SurfaceId), } -impl Global { +impl Global { /// # Safety /// /// - `display_handle` must be a valid object to create a surface upon. @@ -483,7 +482,7 @@ impl Global { &self, display_handle: raw_window_handle::RawDisplayHandle, window_handle: raw_window_handle::RawWindowHandle, - id_in: Input, + id_in: Option, ) -> Result { profiling::scope!("Instance::create_surface"); @@ -531,7 +530,7 @@ impl Global { raw: hal_surface, }; - let (id, _) = self.surfaces.prepare::(id_in).assign(surface); + let (id, _) = self.surfaces.prepare(id_in).assign(surface); Ok(id) } @@ -542,7 +541,7 @@ impl Global { pub unsafe fn instance_create_surface_metal( &self, layer: *mut std::ffi::c_void, - id_in: Input, + id_in: Option, ) -> SurfaceId { profiling::scope!("Instance::create_surface_metal"); @@ -566,7 +565,7 @@ impl Global { }, }; - let (id, _) = self.surfaces.prepare::(id_in).assign(surface); + let (id, _) = self.surfaces.prepare(id_in).assign(surface); id } @@ -577,7 +576,7 @@ impl Global { pub unsafe fn instance_create_surface_from_visual( &self, visual: *mut std::ffi::c_void, - id_in: Input, + id_in: Option, ) -> SurfaceId { profiling::scope!("Instance::instance_create_surface_from_visual"); @@ -597,7 +596,7 @@ impl Global { }, }; - let (id, _) = self.surfaces.prepare::(id_in).assign(surface); + let (id, _) = self.surfaces.prepare(id_in).assign(surface); id } @@ -608,7 +607,7 @@ impl Global { pub unsafe fn instance_create_surface_from_surface_handle( &self, surface_handle: *mut std::ffi::c_void, - id_in: Input, + id_in: Option, ) -> SurfaceId { profiling::scope!("Instance::instance_create_surface_from_surface_handle"); @@ -630,7 +629,7 @@ impl Global { }, }; - let (id, _) = self.surfaces.prepare::(id_in).assign(surface); + let (id, _) = self.surfaces.prepare(id_in).assign(surface); id } @@ -641,7 +640,7 @@ impl Global { pub unsafe fn instance_create_surface_from_swap_chain_panel( &self, swap_chain_panel: *mut std::ffi::c_void, - id_in: Input, + id_in: Option, ) -> SurfaceId { profiling::scope!("Instance::instance_create_surface_from_swap_chain_panel"); @@ -663,7 +662,7 @@ impl Global { }, }; - let (id, _) = self.surfaces.prepare::(id_in).assign(surface); + let (id, _) = self.surfaces.prepare(id_in).assign(surface); id } @@ -672,11 +671,7 @@ impl Global { api_log!("Surface::drop {id:?}"); - fn unconfigure( - global: &Global, - surface: &AnySurface, - present: &Presentation, - ) { + fn unconfigure(global: &Global, surface: &AnySurface, present: &Presentation) { let hub = HalApi::hub(global); if let Some(hal_surface) = surface.downcast_ref::() { if let Some(device) = present.device.downcast_ref::() { @@ -689,13 +684,13 @@ impl Global { if let Some(surface) = Arc::into_inner(surface.unwrap()) { if let Some(present) = surface.presentation.lock().take() { #[cfg(vulkan)] - unconfigure::<_, hal::api::Vulkan>(self, &surface.raw, &present); + unconfigure::(self, &surface.raw, &present); #[cfg(metal)] - unconfigure::<_, hal::api::Metal>(self, &surface.raw, &present); + unconfigure::(self, &surface.raw, &present); #[cfg(dx12)] - unconfigure::<_, hal::api::Dx12>(self, &surface.raw, &present); + unconfigure::(self, &surface.raw, &present); #[cfg(gles)] - unconfigure::<_, hal::api::Gles>(self, &surface.raw, &present); + unconfigure::(self, &surface.raw, &present); } self.instance.destroy_surface(surface); @@ -708,7 +703,7 @@ impl Global { &self, _: A, instance: &Option, - inputs: &AdapterInputs>, + inputs: &AdapterInputs, list: &mut Vec, ) { let inst = match *instance { @@ -727,15 +722,12 @@ impl Global { for raw in hal_adapters { let adapter = Adapter::new(raw); log::info!("Adapter {:?} {:?}", A::VARIANT, adapter.raw.info); - let (id, _) = hub.adapters.prepare::(id_backend).assign(adapter); + let (id, _) = hub.adapters.prepare(id_backend).assign(adapter); list.push(id); } } - pub fn enumerate_adapters( - &self, - inputs: AdapterInputs>, - ) -> Vec { + pub fn enumerate_adapters(&self, inputs: AdapterInputs) -> Vec { profiling::scope!("Instance::enumerate_adapters"); api_log!("Instance::enumerate_adapters"); @@ -766,7 +758,7 @@ impl Global { fn select( &self, selected: &mut usize, - new_id: Option>, + new_id: Option, mut list: Vec>, ) -> Option { match selected.checked_sub(list.len()) { @@ -777,10 +769,7 @@ impl Global { None => { let adapter = Adapter::new(list.swap_remove(*selected)); log::info!("Adapter {:?} {:?}", A::VARIANT, adapter.raw.info); - let (id, _) = HalApi::hub(self) - .adapters - .prepare::(new_id.unwrap()) - .assign(adapter); + let (id, _) = HalApi::hub(self).adapters.prepare(new_id).assign(adapter); Some(id) } } @@ -789,22 +778,22 @@ impl Global { pub fn request_adapter( &self, desc: &RequestAdapterOptions, - inputs: AdapterInputs>, + inputs: AdapterInputs, ) -> Result { profiling::scope!("Instance::request_adapter"); api_log!("Instance::request_adapter"); - fn gather( + fn gather( _: A, instance: Option<&A::Instance>, - inputs: &AdapterInputs, + inputs: &AdapterInputs, compatible_surface: Option<&Surface>, force_software: bool, device_types: &mut Vec, - ) -> (Option, Vec>) { + ) -> (Option>, Vec>) { let id = inputs.find(A::VARIANT); - match instance { - Some(inst) if id.is_some() => { + match (id, instance) { + (Some(id), Some(inst)) => { let mut adapters = unsafe { inst.enumerate_adapters() }; if force_software { adapters.retain(|exposed| exposed.info.device_type == wgt::DeviceType::Cpu); @@ -824,7 +813,7 @@ impl Global { device_types.extend(adapters.iter().map(|ad| ad.info.device_type)); (id, adapters) } - _ => (id, Vec::new()), + _ => (None, Vec::new()), } } @@ -955,11 +944,11 @@ impl Global { pub unsafe fn create_adapter_from_hal( &self, hal_adapter: hal::ExposedAdapter, - input: Input, + input: Option, ) -> AdapterId { profiling::scope!("Instance::create_adapter_from_hal"); - let fid = A::hub(self).adapters.prepare::(input); + let fid = A::hub(self).adapters.prepare(input); let (id, _adapter): (_, Arc>) = match A::VARIANT { #[cfg(vulkan)] @@ -1066,21 +1055,21 @@ impl Global { } } -impl Global { +impl Global { pub fn adapter_request_device( &self, adapter_id: AdapterId, desc: &DeviceDescriptor, trace_path: Option<&std::path::Path>, - device_id_in: Input, - queue_id_in: Input, + device_id_in: Option, + queue_id_in: Option, ) -> (DeviceId, QueueId, Option) { profiling::scope!("Adapter::request_device"); api_log!("Adapter::request_device"); let hub = A::hub(self); - let device_fid = hub.devices.prepare::(device_id_in); - let queue_fid = hub.queues.prepare::(queue_id_in); + let device_fid = hub.devices.prepare(device_id_in); + let queue_fid = hub.queues.prepare(queue_id_in); let error = loop { let adapter = match hub.adapters.get(adapter_id) { @@ -1121,14 +1110,14 @@ impl Global { hal_device: OpenDevice, desc: &DeviceDescriptor, trace_path: Option<&std::path::Path>, - device_id_in: Input, - queue_id_in: Input, + device_id_in: Option, + queue_id_in: Option, ) -> (DeviceId, QueueId, Option) { profiling::scope!("Global::create_device_from_hal"); let hub = A::hub(self); - let devices_fid = hub.devices.prepare::(device_id_in); - let queues_fid = hub.queues.prepare::(queue_id_in); + let devices_fid = hub.devices.prepare(device_id_in); + let queues_fid = hub.queues.prepare(queue_id_in); let error = loop { let adapter = match hub.adapters.get(adapter_id) { diff --git a/wgpu-core/src/lib.rs b/wgpu-core/src/lib.rs index 5413be6b63..33a2887158 100644 --- a/wgpu-core/src/lib.rs +++ b/wgpu-core/src/lib.rs @@ -289,7 +289,7 @@ define_backend_caller! { gfx_if_empty, gfx_if_empty_hidden, "empty" if all( /// where the `device_create_buffer` method is defined like this: /// /// ```ignore -/// impl<...> Global<...> { +/// impl Global { /// pub fn device_create_buffer(&self, ...) -> ... /// { ... } /// } diff --git a/wgpu-core/src/present.rs b/wgpu-core/src/present.rs index 081ab736de..2452825aea 100644 --- a/wgpu-core/src/present.rs +++ b/wgpu-core/src/present.rs @@ -22,10 +22,7 @@ use crate::{ device::{DeviceError, MissingDownlevelFlags, WaitIdleError}, global::Global, hal_api::HalApi, - hal_label, - id::markers, - id::{SurfaceId, TextureId}, - identity::{GlobalIdentityHandlerFactory, Input}, + hal_label, id, init_tracker::TextureInitTracker, resource::{self, ResourceInfo}, snatch::Snatchable, @@ -43,7 +40,7 @@ const FRAME_TIMEOUT_MS: u32 = 1000; pub(crate) struct Presentation { pub(crate) device: AnyDevice, pub(crate) config: wgt::SurfaceConfiguration>, - pub(crate) acquired_texture: Option, + pub(crate) acquired_texture: Option, } #[derive(Clone, Debug, Error)] @@ -119,20 +116,20 @@ impl From for ConfigureSurfaceError { #[derive(Debug)] pub struct SurfaceOutput { pub status: Status, - pub texture_id: Option, + pub texture_id: Option, } -impl Global { +impl Global { pub fn surface_get_current_texture( &self, - surface_id: SurfaceId, - texture_id_in: Input, + surface_id: id::SurfaceId, + texture_id_in: Option, ) -> Result { profiling::scope!("SwapChain::get_next_texture"); let hub = A::hub(self); - let fid = hub.textures.prepare::(texture_id_in); + let fid = hub.textures.prepare(texture_id_in); let surface = self .surfaces @@ -281,7 +278,7 @@ impl Global { pub fn surface_present( &self, - surface_id: SurfaceId, + surface_id: id::SurfaceId, ) -> Result { profiling::scope!("SwapChain::present"); @@ -379,7 +376,7 @@ impl Global { pub fn surface_texture_discard( &self, - surface_id: SurfaceId, + surface_id: id::SurfaceId, ) -> Result<(), SurfaceError> { profiling::scope!("SwapChain::discard"); diff --git a/wgpu-core/src/registry.rs b/wgpu-core/src/registry.rs index c2b8c38d9a..f55809770b 100644 --- a/wgpu-core/src/registry.rs +++ b/wgpu-core/src/registry.rs @@ -4,8 +4,8 @@ use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use wgt::Backend; use crate::{ - id::{self, Id, Marker}, - identity::{IdentityHandlerFactory, IdentityManager}, + id::Id, + identity::IdentityManager, resource::Resource, storage::{Element, InvalidId, Storage}, }; @@ -44,16 +44,16 @@ pub struct Registry { } impl Registry { - pub(crate) fn new>(backend: Backend, factory: &F) -> Self { + pub(crate) fn new(backend: Backend) -> Self { Self { - identity: factory.spawn(), + identity: Arc::new(IdentityManager::new()), storage: RwLock::new(Storage::new()), backend, } } - pub(crate) fn without_backend>(factory: &F) -> Self { - Self::new(Backend::Empty, factory) + pub(crate) fn without_backend() -> Self { + Self::new(Backend::Empty) } } @@ -108,17 +108,14 @@ impl FutureId<'_, T> { } impl Registry { - pub(crate) fn prepare(&self, id_in: F::Input) -> FutureId - where - F: IdentityHandlerFactory, - T::Marker: id::transmute::Transmute, - { + pub(crate) fn prepare(&self, id_in: Option>) -> FutureId { FutureId { - id: if F::autogenerate_ids() { - self.identity.process(self.backend) - } else { - self.identity - .mark_as_used(F::input_to_id(id_in).transmute()) + id: match id_in { + Some(id_in) => { + self.identity.mark_as_used(id_in); + id_in + } + None => self.identity.process(self.backend), }, identity: self.identity.clone(), data: &self.storage, diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index fad1aa610c..07af19e14f 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -9,7 +9,7 @@ use crate::{ global::Global, hal_api::HalApi, id::{AdapterId, BufferId, DeviceId, Id, Marker, SurfaceId, TextureId}, - identity::{GlobalIdentityHandlerFactory, IdentityManager}, + identity::IdentityManager, init_tracker::{BufferInitTracker, TextureInitTracker}, resource, resource_log, snatch::{ExclusiveSnatchGuard, SnatchGuard, Snatchable}, @@ -926,7 +926,7 @@ impl Texture { } } -impl Global { +impl Global { /// # Safety /// /// - The raw texture handle must not be manually destroyed diff --git a/wgpu/src/backend/wgpu_core.rs b/wgpu/src/backend/wgpu_core.rs index 3aec48fb69..6a9d9fa4f9 100644 --- a/wgpu/src/backend/wgpu_core.rs +++ b/wgpu/src/backend/wgpu_core.rs @@ -28,7 +28,7 @@ use wgt::WasmNotSendSync; const LABEL: &str = "label"; -pub struct ContextWgpuCore(wgc::global::Global); +pub struct ContextWgpuCore(wgc::global::Global); impl Drop for ContextWgpuCore { fn drop(&mut self) { @@ -46,13 +46,7 @@ impl fmt::Debug for ContextWgpuCore { impl ContextWgpuCore { pub unsafe fn from_hal_instance(hal_instance: A::Instance) -> Self { - Self(unsafe { - wgc::global::Global::from_hal_instance::( - "wgpu", - wgc::identity::IdentityManagerFactory, - hal_instance, - ) - }) + Self(unsafe { wgc::global::Global::from_hal_instance::("wgpu", hal_instance) }) } /// # Safety @@ -63,25 +57,23 @@ impl ContextWgpuCore { } pub unsafe fn from_core_instance(core_instance: wgc::instance::Instance) -> Self { - Self(unsafe { - wgc::global::Global::from_instance(wgc::identity::IdentityManagerFactory, core_instance) - }) + Self(unsafe { wgc::global::Global::from_instance(core_instance) }) } - pub(crate) fn global(&self) -> &wgc::global::Global { + pub(crate) fn global(&self) -> &wgc::global::Global { &self.0 } pub fn enumerate_adapters(&self, backends: wgt::Backends) -> Vec { self.0 - .enumerate_adapters(wgc::instance::AdapterInputs::Mask(backends, |_| ())) + .enumerate_adapters(wgc::instance::AdapterInputs::Mask(backends, |_| None)) } pub unsafe fn create_adapter_from_hal( &self, hal_adapter: hal::ExposedAdapter, ) -> wgc::id::AdapterId { - unsafe { self.0.create_adapter_from_hal(hal_adapter, ()) } + unsafe { self.0.create_adapter_from_hal(hal_adapter, None) } } pub unsafe fn adapter_as_hal< @@ -112,8 +104,8 @@ impl ContextWgpuCore { hal_device, &desc.map_label(|l| l.map(Borrowed)), trace_dir, - (), - (), + None, + None, ) }; if let Some(err) = error { @@ -141,7 +133,7 @@ impl ContextWgpuCore { let descriptor = desc.map_label_and_view_formats(|l| l.map(Borrowed), |v| v.to_vec()); let (id, error) = unsafe { self.0 - .create_texture_from_hal::(hal_texture, device.id, &descriptor, ()) + .create_texture_from_hal::(hal_texture, device.id, &descriptor, None) }; if let Some(cause) = error { self.handle_error( @@ -169,7 +161,7 @@ impl ContextWgpuCore { hal_buffer, device.id, &desc.map_label(|l| l.map(Borrowed)), - (), + None, ) }; if let Some(cause) = error { @@ -509,11 +501,7 @@ impl crate::Context for ContextWgpuCore { type PopErrorScopeFuture = Ready>; fn init(instance_desc: wgt::InstanceDescriptor) -> Self { - Self(wgc::global::Global::new( - "wgpu", - wgc::identity::IdentityManagerFactory, - instance_desc, - )) + Self(wgc::global::Global::new("wgpu", instance_desc)) } unsafe fn instance_create_surface( @@ -526,29 +514,29 @@ impl crate::Context for ContextWgpuCore { raw_window_handle, } => unsafe { self.0 - .instance_create_surface(raw_display_handle, raw_window_handle, ())? + .instance_create_surface(raw_display_handle, raw_window_handle, None)? }, #[cfg(metal)] SurfaceTargetUnsafe::CoreAnimationLayer(layer) => unsafe { - self.0.instance_create_surface_metal(layer, ()) + self.0.instance_create_surface_metal(layer, None) }, #[cfg(dx12)] SurfaceTargetUnsafe::CompositionVisual(visual) => unsafe { - self.0.instance_create_surface_from_visual(visual, ()) + self.0.instance_create_surface_from_visual(visual, None) }, #[cfg(dx12)] SurfaceTargetUnsafe::SurfaceHandle(surface_handle) => unsafe { self.0 - .instance_create_surface_from_surface_handle(surface_handle, ()) + .instance_create_surface_from_surface_handle(surface_handle, None) }, #[cfg(dx12)] SurfaceTargetUnsafe::SwapChainPanel(swap_chain_panel) => unsafe { self.0 - .instance_create_surface_from_swap_chain_panel(swap_chain_panel, ()) + .instance_create_surface_from_swap_chain_panel(swap_chain_panel, None) }, }; @@ -571,7 +559,7 @@ impl crate::Context for ContextWgpuCore { force_fallback_adapter: options.force_fallback_adapter, compatible_surface: options.compatible_surface.map(|surface| surface.id.into()), }, - wgc::instance::AdapterInputs::Mask(wgt::Backends::all(), |_| ()), + wgc::instance::AdapterInputs::Mask(wgt::Backends::all(), |_| None), ); ready(id.ok().map(|id| (id, ()))) } @@ -587,8 +575,8 @@ impl crate::Context for ContextWgpuCore { *adapter, &desc.map_label(|l| l.map(Borrowed)), trace_dir, - (), - () + None, + None )); if let Some(err) = error { return ready(Err(err.into())); @@ -741,7 +729,7 @@ impl crate::Context for ContextWgpuCore { .lock() .expect("Surface was not configured?"); match wgc::gfx_select!( - device_id => self.0.surface_get_current_texture(*surface, ()) + device_id => self.0.surface_get_current_texture(*surface, None) ) { Ok(wgc::present::SurfaceOutput { status, texture_id }) => { let (id, data) = { @@ -861,7 +849,7 @@ impl crate::Context for ContextWgpuCore { ShaderSource::Dummy(_) => panic!("found `ShaderSource::Dummy`"), }; let (id, error) = wgc::gfx_select!( - device => self.0.device_create_shader_module(*device, &descriptor, source, ()) + device => self.0.device_create_shader_module(*device, &descriptor, source, None) ); if let Some(cause) = error { self.handle_error( @@ -888,7 +876,7 @@ impl crate::Context for ContextWgpuCore { shader_bound_checks: unsafe { wgt::ShaderBoundChecks::unchecked() }, }; let (id, error) = wgc::gfx_select!( - device => self.0.device_create_shader_module_spirv(*device, &descriptor, Borrowed(&desc.source), ()) + device => self.0.device_create_shader_module_spirv(*device, &descriptor, Borrowed(&desc.source), None) ); if let Some(cause) = error { self.handle_error( @@ -913,7 +901,7 @@ impl crate::Context for ContextWgpuCore { entries: Borrowed(desc.entries), }; let (id, error) = wgc::gfx_select!( - device => self.0.device_create_bind_group_layout(*device, &descriptor, ()) + device => self.0.device_create_bind_group_layout(*device, &descriptor, None) ); if let Some(cause) = error { self.handle_error( @@ -1027,7 +1015,7 @@ impl crate::Context for ContextWgpuCore { let (id, error) = wgc::gfx_select!(device => self.0.device_create_bind_group( *device, &descriptor, - () + None )); if let Some(cause) = error { self.handle_error( @@ -1069,7 +1057,7 @@ impl crate::Context for ContextWgpuCore { let (id, error) = wgc::gfx_select!(device => self.0.device_create_pipeline_layout( *device, &descriptor, - () + None )); if let Some(cause) = error { self.handle_error( @@ -1104,8 +1092,8 @@ impl crate::Context for ContextWgpuCore { let implicit_pipeline_ids = match desc.layout { Some(_) => None, None => Some(wgc::device::ImplicitPipelineIds { - root_id: (), - group_ids: &[(); wgc::MAX_BIND_GROUPS], + root_id: None, + group_ids: &[None; wgc::MAX_BIND_GROUPS], }), }; let descriptor = pipe::RenderPipelineDescriptor { @@ -1134,7 +1122,7 @@ impl crate::Context for ContextWgpuCore { let (id, error) = wgc::gfx_select!(device => self.0.device_create_render_pipeline( *device, &descriptor, - (), + None, implicit_pipeline_ids )); if let Some(cause) = error { @@ -1163,8 +1151,8 @@ impl crate::Context for ContextWgpuCore { let implicit_pipeline_ids = match desc.layout { Some(_) => None, None => Some(wgc::device::ImplicitPipelineIds { - root_id: (), - group_ids: &[(); wgc::MAX_BIND_GROUPS], + root_id: None, + group_ids: &[None; wgc::MAX_BIND_GROUPS], }), }; let descriptor = pipe::ComputePipelineDescriptor { @@ -1179,7 +1167,7 @@ impl crate::Context for ContextWgpuCore { let (id, error) = wgc::gfx_select!(device => self.0.device_create_compute_pipeline( *device, &descriptor, - (), + None, implicit_pipeline_ids )); if let Some(cause) = error { @@ -1210,7 +1198,7 @@ impl crate::Context for ContextWgpuCore { let (id, error) = wgc::gfx_select!(device => self.0.device_create_buffer( *device, &desc.map_label(|l| l.map(Borrowed)), - () + None )); if let Some(cause) = error { self.handle_error( @@ -1238,7 +1226,7 @@ impl crate::Context for ContextWgpuCore { let (id, error) = wgc::gfx_select!(device => self.0.device_create_texture( *device, &wgt_desc, - () + None )); if let Some(cause) = error { self.handle_error( @@ -1283,7 +1271,7 @@ impl crate::Context for ContextWgpuCore { let (id, error) = wgc::gfx_select!(device => self.0.device_create_sampler( *device, &descriptor, - () + None )); if let Some(cause) = error { self.handle_error( @@ -1305,7 +1293,7 @@ impl crate::Context for ContextWgpuCore { let (id, error) = wgc::gfx_select!(device => self.0.device_create_query_set( *device, &desc.map_label(|l| l.map(Borrowed)), - () + None )); if let Some(cause) = error { self.handle_error_nolabel(&device_data.error_sink, cause, "Device::create_query_set"); @@ -1321,7 +1309,7 @@ impl crate::Context for ContextWgpuCore { let (id, error) = wgc::gfx_select!(device => self.0.device_create_command_encoder( *device, &desc.map_label(|l| l.map(Borrowed)), - () + None )); if let Some(cause) = error { self.handle_error( @@ -1520,7 +1508,7 @@ impl crate::Context for ContextWgpuCore { }, }; let (id, error) = wgc::gfx_select!( - texture => self.0.texture_create_view(*texture, &descriptor, ()) + texture => self.0.texture_create_view(*texture, &descriptor, None) ); if let Some(cause) = error { self.handle_error( @@ -1654,7 +1642,7 @@ impl crate::Context for ContextWgpuCore { _pipeline_data: &Self::ComputePipelineData, index: u32, ) -> (Self::BindGroupLayoutId, Self::BindGroupLayoutData) { - let (id, error) = wgc::gfx_select!(*pipeline => self.0.compute_pipeline_get_bind_group_layout(*pipeline, index, ())); + let (id, error) = wgc::gfx_select!(*pipeline => self.0.compute_pipeline_get_bind_group_layout(*pipeline, index, None)); if let Some(err) = error { panic!("Error reflecting bind group {index}: {err}"); } @@ -1667,7 +1655,7 @@ impl crate::Context for ContextWgpuCore { _pipeline_data: &Self::RenderPipelineData, index: u32, ) -> (Self::BindGroupLayoutId, Self::BindGroupLayoutData) { - let (id, error) = wgc::gfx_select!(*pipeline => self.0.render_pipeline_get_bind_group_layout(*pipeline, index, ())); + let (id, error) = wgc::gfx_select!(*pipeline => self.0.render_pipeline_get_bind_group_layout(*pipeline, index, None)); if let Some(err) = error { panic!("Error reflecting bind group {index}: {err}"); } @@ -2064,7 +2052,7 @@ impl crate::Context for ContextWgpuCore { let (id, error) = wgc::gfx_select!(encoder_data.parent() => self.0.render_bundle_encoder_finish( encoder_data, &desc.map_label(|l| l.map(Borrowed)), - () + None )); if let Some(err) = error { self.handle_error_fatal(err, "RenderBundleEncoder::finish"); @@ -2118,7 +2106,7 @@ impl crate::Context for ContextWgpuCore { size: wgt::BufferSize, ) -> Option> { match wgc::gfx_select!( - *queue => self.0.queue_create_staging_buffer(*queue, size, ()) + *queue => self.0.queue_create_staging_buffer(*queue, size, None) ) { Ok((buffer_id, ptr)) => Some(Box::new(QueueWriteBuffer { buffer_id, From 8afb441ca7987a976b579e67bb0e46ae0d24a66a Mon Sep 17 00:00:00 2001 From: andristarr Date: Mon, 29 Jan 2024 20:50:35 +0100 Subject: [PATCH 062/101] adding internal error filter (#5160) Co-authored-by: Erich Gubler --- deno_webgpu/01_webgpu.js | 1 + deno_webgpu/webgpu.idl | 1 + wgpu/src/backend/webgpu.rs | 1 + wgpu/src/backend/wgpu_core.rs | 1 + wgpu/src/lib.rs | 19 +++++++++++++++++++ 5 files changed, 23 insertions(+) diff --git a/deno_webgpu/01_webgpu.js b/deno_webgpu/01_webgpu.js index 3f7b1ed570..9904f4d24b 100644 --- a/deno_webgpu/01_webgpu.js +++ b/deno_webgpu/01_webgpu.js @@ -6915,6 +6915,7 @@ webidl.converters["GPUErrorFilter"] = webidl.createEnumConverter( [ "out-of-memory", "validation", + "internal" ], ); diff --git a/deno_webgpu/webgpu.idl b/deno_webgpu/webgpu.idl index bf4da0124b..46d587874f 100644 --- a/deno_webgpu/webgpu.idl +++ b/deno_webgpu/webgpu.idl @@ -1176,6 +1176,7 @@ interface GPUOutOfMemoryError enum GPUErrorFilter { "validation", "out-of-memory", + "internal" }; partial interface GPUDevice { diff --git a/wgpu/src/backend/webgpu.rs b/wgpu/src/backend/webgpu.rs index 91115c3e07..4f758845b3 100644 --- a/wgpu/src/backend/webgpu.rs +++ b/wgpu/src/backend/webgpu.rs @@ -2009,6 +2009,7 @@ impl crate::context::Context for ContextWebGpu { device_data.0.push_error_scope(match filter { crate::ErrorFilter::OutOfMemory => web_sys::GpuErrorFilter::OutOfMemory, crate::ErrorFilter::Validation => web_sys::GpuErrorFilter::Validation, + crate::ErrorFilter::Internal => web_sys::GpuErrorFilter::Internal, }); } diff --git a/wgpu/src/backend/wgpu_core.rs b/wgpu/src/backend/wgpu_core.rs index 6a9d9fa4f9..3901e7d444 100644 --- a/wgpu/src/backend/wgpu_core.rs +++ b/wgpu/src/backend/wgpu_core.rs @@ -2959,6 +2959,7 @@ impl ErrorSinkRaw { let filter = match err { crate::Error::OutOfMemory { .. } => crate::ErrorFilter::OutOfMemory, crate::Error::Validation { .. } => crate::ErrorFilter::Validation, + crate::Error::Internal { .. } => crate::ErrorFilter::Internal, }; match self .scopes diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index b963fa695b..6becc7cde5 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -163,6 +163,8 @@ pub enum ErrorFilter { OutOfMemory, /// Catch only validation errors. Validation, + /// Catch only internal errors. + Internal, } static_assertions::assert_impl_all!(ErrorFilter: Send, Sync); @@ -5143,6 +5145,21 @@ pub enum Error { /// Description of the validation error. description: String, }, + /// Internal error. Used for signalling any failures not explicitly expected by WebGPU. + /// + /// These could be due to internal implementation or system limits being reached. + Internal { + /// Lower level source of the error. + #[cfg(send_sync)] + #[cfg_attr(docsrs, doc(cfg(all())))] + source: Box, + /// Lower level source of the error. + #[cfg(not(send_sync))] + #[cfg_attr(docsrs, doc(cfg(all())))] + source: Box, + /// Description of the internal GPU error. + description: String, + }, } #[cfg(send_sync)] static_assertions::assert_impl_all!(Error: Send); @@ -5152,6 +5169,7 @@ impl error::Error for Error { match self { Error::OutOfMemory { source } => Some(source.as_ref()), Error::Validation { source, .. } => Some(source.as_ref()), + Error::Internal { source, .. } => Some(source.as_ref()), } } } @@ -5161,6 +5179,7 @@ impl fmt::Display for Error { match self { Error::OutOfMemory { .. } => f.write_str("Out of Memory"), Error::Validation { description, .. } => f.write_str(description), + Error::Internal { description, .. } => f.write_str(description), } } } From a05cc37e3c6ed1a26fa5473b7eebff8626640f5c Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 26 Jan 2024 12:11:45 -0500 Subject: [PATCH 063/101] feat(const_eval): impl. `ceil` --- CHANGELOG.md | 2 ++ naga/src/proc/constant_evaluator.rs | 3 +++ naga/tests/out/glsl/variations.main.Fragment.glsl | 3 +-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 902a1bd1b6..f65b7e8857 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,6 +66,8 @@ Bottom level categories: - `step` - `tan` - `tanh` + - [#5098](https://github.com/gfx-rs/wgpu/pull/5098) by @ErichDonGubler: + - `ceil` - Eager release of GPU resources comes from device.trackers. By @bradwerth in [#5075](https://github.com/gfx-rs/wgpu/pull/5075) - `wgpu-types`'s `trace` and `replay` features have been replaced by the `serde` feature. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) - `wgpu-core`'s `serial-pass` feature has been removed. Use `serde` instead. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index a84863066e..d1ee99e02f 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -842,6 +842,9 @@ impl<'a> ConstantEvaluator<'a> { Ok([e1.powf(e2)]) }) } + crate::MathFunction::Ceil => { + component_wise_float!(self, span, [arg], |e| { Ok([e.ceil()]) }) + } crate::MathFunction::Clamp => { component_wise_scalar!( self, diff --git a/naga/tests/out/glsl/variations.main.Fragment.glsl b/naga/tests/out/glsl/variations.main.Fragment.glsl index 5ea3eb03cf..25b258987c 100644 --- a/naga/tests/out/glsl/variations.main.Fragment.glsl +++ b/naga/tests/out/glsl/variations.main.Fragment.glsl @@ -8,9 +8,8 @@ uniform highp samplerCube _group_0_binding_0_fs; void main_1() { ivec2 sizeCube = ivec2(0); - float a = 0.0; + float a = 1.0; sizeCube = ivec2(uvec2(textureSize(_group_0_binding_0_fs, 0).xy)); - a = ceil(1.0); return; } From 7f70df0c4724b60eea9f56b2ef660abdfbae8a58 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 26 Jan 2024 12:12:55 -0500 Subject: [PATCH 064/101] feat(const_eval): impl. `floor` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f65b7e8857..61da7136c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,6 +68,7 @@ Bottom level categories: - `tanh` - [#5098](https://github.com/gfx-rs/wgpu/pull/5098) by @ErichDonGubler: - `ceil` + - `floor` - Eager release of GPU resources comes from device.trackers. By @bradwerth in [#5075](https://github.com/gfx-rs/wgpu/pull/5075) - `wgpu-types`'s `trace` and `replay` features have been replaced by the `serde` feature. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) - `wgpu-core`'s `serial-pass` feature has been removed. Use `serde` instead. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index d1ee99e02f..4c6ae058a9 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -865,6 +865,9 @@ impl<'a> ConstantEvaluator<'a> { crate::MathFunction::Cosh => { component_wise_float!(self, span, [arg], |e| { Ok([e.cosh()]) }) } + crate::MathFunction::Floor => { + component_wise_float!(self, span, [arg], |e| { Ok([e.floor()]) }) + } crate::MathFunction::Round => { // TODO: Use `f{32,64}.round_ties_even()` when available on stable. This polyfill // is shamelessly [~~stolen from~~ inspired by `ndarray-image`][polyfill source], From ea044f039c756adfad892571fca8e4542b78c5ad Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 5 Jan 2024 10:56:24 -0500 Subject: [PATCH 065/101] feat(const_eval): impl. `countLeadingZeros` with new `component_wise_concrete_int` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 21 ++ .../glsl/math-functions.main.Fragment.glsl | 7 +- naga/tests/out/hlsl/math-functions.hlsl | 7 +- naga/tests/out/msl/math-functions.msl | 6 +- naga/tests/out/spv/math-functions.spvasm | 241 +++++++++--------- naga/tests/out/wgsl/math-functions.wgsl | 6 +- 7 files changed, 147 insertions(+), 142 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61da7136c6..41e68c7357 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,6 +68,7 @@ Bottom level categories: - `tanh` - [#5098](https://github.com/gfx-rs/wgpu/pull/5098) by @ErichDonGubler: - `ceil` + - `countLeadingZeros` - `floor` - Eager release of GPU resources comes from device.trackers. By @bradwerth in [#5075](https://github.com/gfx-rs/wgpu/pull/5075) - `wgpu-types`'s `trace` and `replay` features have been replaced by the `serde` feature. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 4c6ae058a9..88c59809a9 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -222,6 +222,18 @@ gen_component_wise_extractor! { ], } +gen_component_wise_extractor! { + component_wise_concrete_int -> ConcreteInt, + literals: [ + U32 => U32: u32, + I32 => I32: i32, + ], + scalar_kinds: [ + Sint, + Uint, + ], +} + #[derive(Debug)] enum Behavior { Wgsl, @@ -865,6 +877,15 @@ impl<'a> ConstantEvaluator<'a> { crate::MathFunction::Cosh => { component_wise_float!(self, span, [arg], |e| { Ok([e.cosh()]) }) } + crate::MathFunction::CountLeadingZeros => { + component_wise_concrete_int!(self, span, [arg], |e| { + #[allow(clippy::useless_conversion)] + Ok([e + .leading_zeros() + .try_into() + .expect("bit count overflowed 32 bits, somehow!?")]) + }) + } crate::MathFunction::Floor => { component_wise_float!(self, span, [arg], |e| { Ok([e.floor()]) }) } diff --git a/naga/tests/out/glsl/math-functions.main.Fragment.glsl b/naga/tests/out/glsl/math-functions.main.Fragment.glsl index bf0561f12e..2892157801 100644 --- a/naga/tests/out/glsl/math-functions.main.Fragment.glsl +++ b/naga/tests/out/glsl/math-functions.main.Fragment.glsl @@ -83,11 +83,8 @@ void main() { ivec2 ctz_f = ivec2(min(uvec2(findLSB(ivec2(0))), uvec2(32u))); uvec2 ctz_g = min(uvec2(findLSB(uvec2(1u))), uvec2(32u)); ivec2 ctz_h = ivec2(min(uvec2(findLSB(ivec2(1))), uvec2(32u))); - int clz_a = (-1 < 0 ? 0 : 31 - findMSB(-1)); - uint clz_b = uint(31 - findMSB(1u)); - ivec2 _e67 = ivec2(-1); - ivec2 clz_c = mix(ivec2(31) - findMSB(_e67), ivec2(0), lessThan(_e67, ivec2(0))); - uvec2 clz_d = uvec2(ivec2(31) - findMSB(uvec2(1u))); + ivec2 clz_c = ivec2(0, 0); + uvec2 clz_d = uvec2(31u, 31u); float lde_a = ldexp(1.0, 2); vec2 lde_b = ldexp(vec2(1.0, 2.0), ivec2(3, 4)); _modf_result_f32_ modf_a = naga_modf(1.5); diff --git a/naga/tests/out/hlsl/math-functions.hlsl b/naga/tests/out/hlsl/math-functions.hlsl index 5da3461dae..d576365fc4 100644 --- a/naga/tests/out/hlsl/math-functions.hlsl +++ b/naga/tests/out/hlsl/math-functions.hlsl @@ -93,11 +93,8 @@ void main() int2 ctz_f = asint(min((32u).xx, firstbitlow((0).xx))); uint2 ctz_g = min((32u).xx, firstbitlow((1u).xx)); int2 ctz_h = asint(min((32u).xx, firstbitlow((1).xx))); - int clz_a = (-1 < 0 ? 0 : 31 - asint(firstbithigh(-1))); - uint clz_b = (31u - firstbithigh(1u)); - int2 _expr67 = (-1).xx; - int2 clz_c = (_expr67 < (0).xx ? (0).xx : (31).xx - asint(firstbithigh(_expr67))); - uint2 clz_d = ((31u).xx - firstbithigh((1u).xx)); + int2 clz_c = int2(0, 0); + uint2 clz_d = uint2(31u, 31u); float lde_a = ldexp(1.0, 2); float2 lde_b = ldexp(float2(1.0, 2.0), int2(3, 4)); _modf_result_f32_ modf_a = naga_modf(1.5); diff --git a/naga/tests/out/msl/math-functions.msl b/naga/tests/out/msl/math-functions.msl index 45fbcd00a1..33fae07f78 100644 --- a/naga/tests/out/msl/math-functions.msl +++ b/naga/tests/out/msl/math-functions.msl @@ -88,10 +88,8 @@ fragment void main_( metal::int2 ctz_f = metal::ctz(metal::int2(0)); metal::uint2 ctz_g = metal::ctz(metal::uint2(1u)); metal::int2 ctz_h = metal::ctz(metal::int2(1)); - int clz_a = metal::clz(-1); - uint clz_b = metal::clz(1u); - metal::int2 clz_c = metal::clz(metal::int2(-1)); - metal::uint2 clz_d = metal::clz(metal::uint2(1u)); + metal::int2 clz_c = metal::int2(0, 0); + metal::uint2 clz_d = metal::uint2(31u, 31u); float lde_a = metal::ldexp(1.0, 2); metal::float2 lde_b = metal::ldexp(metal::float2(1.0, 2.0), metal::int2(3, 4)); _modf_result_f32_ modf_a = naga_modf(1.5); diff --git a/naga/tests/out/spv/math-functions.spvasm b/naga/tests/out/spv/math-functions.spvasm index bbbf370970..8450bdd21e 100644 --- a/naga/tests/out/spv/math-functions.spvasm +++ b/naga/tests/out/spv/math-functions.spvasm @@ -1,145 +1,138 @@ ; SPIR-V ; Version: 1.1 ; Generator: rspirv -; Bound: 125 +; Bound: 118 OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %15 "main" -OpExecutionMode %15 OriginUpperLeft -OpMemberDecorate %8 0 Offset 0 -OpMemberDecorate %8 1 Offset 4 -OpMemberDecorate %9 0 Offset 0 -OpMemberDecorate %9 1 Offset 8 +OpEntryPoint Fragment %17 "main" +OpExecutionMode %17 OriginUpperLeft OpMemberDecorate %10 0 Offset 0 -OpMemberDecorate %10 1 Offset 16 +OpMemberDecorate %10 1 Offset 4 OpMemberDecorate %11 0 Offset 0 -OpMemberDecorate %11 1 Offset 4 +OpMemberDecorate %11 1 Offset 8 +OpMemberDecorate %12 0 Offset 0 +OpMemberDecorate %12 1 Offset 16 OpMemberDecorate %13 0 Offset 0 -OpMemberDecorate %13 1 Offset 16 +OpMemberDecorate %13 1 Offset 4 +OpMemberDecorate %15 0 Offset 0 +OpMemberDecorate %15 1 Offset 16 %2 = OpTypeVoid %4 = OpTypeFloat 32 %3 = OpTypeVector %4 4 %6 = OpTypeInt 32 1 %5 = OpTypeVector %6 2 -%7 = OpTypeVector %4 2 -%8 = OpTypeStruct %4 %4 -%9 = OpTypeStruct %7 %7 -%10 = OpTypeStruct %3 %3 -%11 = OpTypeStruct %4 %6 -%12 = OpTypeVector %6 4 -%13 = OpTypeStruct %3 %12 -%16 = OpTypeFunction %2 -%17 = OpConstant %4 1.0 -%18 = OpConstant %4 0.0 -%19 = OpConstantComposite %3 %18 %18 %18 %18 -%20 = OpConstant %6 -1 -%21 = OpConstantComposite %12 %20 %20 %20 %20 -%22 = OpConstant %4 -1.0 -%23 = OpConstantComposite %3 %22 %22 %22 %22 -%24 = OpConstantNull %5 -%25 = OpTypeInt 32 0 -%26 = OpConstant %25 0 -%27 = OpConstantComposite %5 %20 %20 -%28 = OpConstant %25 1 -%29 = OpTypeVector %25 2 -%30 = OpConstantComposite %29 %28 %28 +%8 = OpTypeInt 32 0 +%7 = OpTypeVector %8 2 +%9 = OpTypeVector %4 2 +%10 = OpTypeStruct %4 %4 +%11 = OpTypeStruct %9 %9 +%12 = OpTypeStruct %3 %3 +%13 = OpTypeStruct %4 %6 +%14 = OpTypeVector %6 4 +%15 = OpTypeStruct %3 %14 +%18 = OpTypeFunction %2 +%19 = OpConstant %4 1.0 +%20 = OpConstant %4 0.0 +%21 = OpConstantComposite %3 %20 %20 %20 %20 +%22 = OpConstant %6 -1 +%23 = OpConstantComposite %14 %22 %22 %22 %22 +%24 = OpConstant %4 -1.0 +%25 = OpConstantComposite %3 %24 %24 %24 %24 +%26 = OpConstantNull %5 +%27 = OpConstant %8 0 +%28 = OpConstantComposite %5 %22 %22 +%29 = OpConstant %8 1 +%30 = OpConstantComposite %7 %29 %29 %31 = OpConstant %6 0 -%32 = OpConstant %25 4294967295 -%33 = OpConstantComposite %29 %26 %26 +%32 = OpConstant %8 4294967295 +%33 = OpConstantComposite %7 %27 %27 %34 = OpConstantComposite %5 %31 %31 %35 = OpConstant %6 1 %36 = OpConstantComposite %5 %35 %35 -%37 = OpConstant %6 2 -%38 = OpConstant %4 2.0 -%39 = OpConstantComposite %7 %17 %38 -%40 = OpConstant %6 3 -%41 = OpConstant %6 4 -%42 = OpConstantComposite %5 %40 %41 -%43 = OpConstant %4 1.5 -%44 = OpConstantComposite %7 %43 %43 -%45 = OpConstantComposite %3 %43 %43 %43 %43 -%52 = OpConstantComposite %3 %17 %17 %17 %17 -%59 = OpConstantNull %6 -%76 = OpConstant %25 32 -%85 = OpConstantComposite %29 %76 %76 -%94 = OpConstant %6 31 -%99 = OpConstantComposite %5 %94 %94 -%15 = OpFunction %2 None %16 -%14 = OpLabel -OpBranch %46 -%46 = OpLabel -%47 = OpExtInst %4 %1 Degrees %17 -%48 = OpExtInst %4 %1 Radians %17 -%49 = OpExtInst %3 %1 Degrees %19 -%50 = OpExtInst %3 %1 Radians %19 -%51 = OpExtInst %3 %1 FClamp %19 %19 %52 -%53 = OpExtInst %3 %1 Refract %19 %19 %17 -%54 = OpExtInst %6 %1 SSign %20 -%55 = OpExtInst %12 %1 SSign %21 -%56 = OpExtInst %4 %1 FSign %22 -%57 = OpExtInst %3 %1 FSign %23 -%60 = OpCompositeExtract %6 %24 0 -%61 = OpCompositeExtract %6 %24 0 -%62 = OpIMul %6 %60 %61 -%63 = OpIAdd %6 %59 %62 -%64 = OpCompositeExtract %6 %24 1 -%65 = OpCompositeExtract %6 %24 1 -%66 = OpIMul %6 %64 %65 -%58 = OpIAdd %6 %63 %66 -%67 = OpExtInst %25 %1 FindUMsb %26 -%68 = OpExtInst %6 %1 FindSMsb %20 -%69 = OpExtInst %5 %1 FindSMsb %27 -%70 = OpExtInst %29 %1 FindUMsb %30 -%71 = OpExtInst %6 %1 FindILsb %20 -%72 = OpExtInst %25 %1 FindILsb %28 -%73 = OpExtInst %5 %1 FindILsb %27 -%74 = OpExtInst %29 %1 FindILsb %30 -%77 = OpExtInst %25 %1 FindILsb %26 -%75 = OpExtInst %25 %1 UMin %76 %77 -%79 = OpExtInst %6 %1 FindILsb %31 -%78 = OpExtInst %6 %1 UMin %76 %79 -%81 = OpExtInst %25 %1 FindILsb %32 -%80 = OpExtInst %25 %1 UMin %76 %81 -%83 = OpExtInst %6 %1 FindILsb %20 -%82 = OpExtInst %6 %1 UMin %76 %83 -%86 = OpExtInst %29 %1 FindILsb %33 -%84 = OpExtInst %29 %1 UMin %85 %86 -%88 = OpExtInst %5 %1 FindILsb %34 -%87 = OpExtInst %5 %1 UMin %85 %88 -%90 = OpExtInst %29 %1 FindILsb %30 -%89 = OpExtInst %29 %1 UMin %85 %90 -%92 = OpExtInst %5 %1 FindILsb %36 -%91 = OpExtInst %5 %1 UMin %85 %92 -%95 = OpExtInst %6 %1 FindUMsb %20 -%93 = OpISub %6 %94 %95 -%97 = OpExtInst %6 %1 FindUMsb %28 -%96 = OpISub %25 %94 %97 -%100 = OpExtInst %5 %1 FindUMsb %27 -%98 = OpISub %5 %99 %100 -%102 = OpExtInst %5 %1 FindUMsb %30 -%101 = OpISub %29 %99 %102 -%103 = OpExtInst %4 %1 Ldexp %17 %37 -%104 = OpExtInst %7 %1 Ldexp %39 %42 -%105 = OpExtInst %8 %1 ModfStruct %43 -%106 = OpExtInst %8 %1 ModfStruct %43 -%107 = OpCompositeExtract %4 %106 0 -%108 = OpExtInst %8 %1 ModfStruct %43 +%37 = OpConstant %8 31 +%38 = OpConstantComposite %5 %31 %31 +%39 = OpConstantComposite %7 %37 %37 +%40 = OpConstant %6 2 +%41 = OpConstant %4 2.0 +%42 = OpConstantComposite %9 %19 %41 +%43 = OpConstant %6 3 +%44 = OpConstant %6 4 +%45 = OpConstantComposite %5 %43 %44 +%46 = OpConstant %4 1.5 +%47 = OpConstantComposite %9 %46 %46 +%48 = OpConstantComposite %3 %46 %46 %46 %46 +%55 = OpConstantComposite %3 %19 %19 %19 %19 +%62 = OpConstantNull %6 +%79 = OpConstant %8 32 +%88 = OpConstantComposite %7 %79 %79 +%17 = OpFunction %2 None %18 +%16 = OpLabel +OpBranch %49 +%49 = OpLabel +%50 = OpExtInst %4 %1 Degrees %19 +%51 = OpExtInst %4 %1 Radians %19 +%52 = OpExtInst %3 %1 Degrees %21 +%53 = OpExtInst %3 %1 Radians %21 +%54 = OpExtInst %3 %1 FClamp %21 %21 %55 +%56 = OpExtInst %3 %1 Refract %21 %21 %19 +%57 = OpExtInst %6 %1 SSign %22 +%58 = OpExtInst %14 %1 SSign %23 +%59 = OpExtInst %4 %1 FSign %24 +%60 = OpExtInst %3 %1 FSign %25 +%63 = OpCompositeExtract %6 %26 0 +%64 = OpCompositeExtract %6 %26 0 +%65 = OpIMul %6 %63 %64 +%66 = OpIAdd %6 %62 %65 +%67 = OpCompositeExtract %6 %26 1 +%68 = OpCompositeExtract %6 %26 1 +%69 = OpIMul %6 %67 %68 +%61 = OpIAdd %6 %66 %69 +%70 = OpExtInst %8 %1 FindUMsb %27 +%71 = OpExtInst %6 %1 FindSMsb %22 +%72 = OpExtInst %5 %1 FindSMsb %28 +%73 = OpExtInst %7 %1 FindUMsb %30 +%74 = OpExtInst %6 %1 FindILsb %22 +%75 = OpExtInst %8 %1 FindILsb %29 +%76 = OpExtInst %5 %1 FindILsb %28 +%77 = OpExtInst %7 %1 FindILsb %30 +%80 = OpExtInst %8 %1 FindILsb %27 +%78 = OpExtInst %8 %1 UMin %79 %80 +%82 = OpExtInst %6 %1 FindILsb %31 +%81 = OpExtInst %6 %1 UMin %79 %82 +%84 = OpExtInst %8 %1 FindILsb %32 +%83 = OpExtInst %8 %1 UMin %79 %84 +%86 = OpExtInst %6 %1 FindILsb %22 +%85 = OpExtInst %6 %1 UMin %79 %86 +%89 = OpExtInst %7 %1 FindILsb %33 +%87 = OpExtInst %7 %1 UMin %88 %89 +%91 = OpExtInst %5 %1 FindILsb %34 +%90 = OpExtInst %5 %1 UMin %88 %91 +%93 = OpExtInst %7 %1 FindILsb %30 +%92 = OpExtInst %7 %1 UMin %88 %93 +%95 = OpExtInst %5 %1 FindILsb %36 +%94 = OpExtInst %5 %1 UMin %88 %95 +%96 = OpExtInst %4 %1 Ldexp %19 %40 +%97 = OpExtInst %9 %1 Ldexp %42 %45 +%98 = OpExtInst %10 %1 ModfStruct %46 +%99 = OpExtInst %10 %1 ModfStruct %46 +%100 = OpCompositeExtract %4 %99 0 +%101 = OpExtInst %10 %1 ModfStruct %46 +%102 = OpCompositeExtract %4 %101 1 +%103 = OpExtInst %11 %1 ModfStruct %47 +%104 = OpExtInst %12 %1 ModfStruct %48 +%105 = OpCompositeExtract %3 %104 1 +%106 = OpCompositeExtract %4 %105 0 +%107 = OpExtInst %11 %1 ModfStruct %47 +%108 = OpCompositeExtract %9 %107 0 %109 = OpCompositeExtract %4 %108 1 -%110 = OpExtInst %9 %1 ModfStruct %44 -%111 = OpExtInst %10 %1 ModfStruct %45 -%112 = OpCompositeExtract %3 %111 1 -%113 = OpCompositeExtract %4 %112 0 -%114 = OpExtInst %9 %1 ModfStruct %44 -%115 = OpCompositeExtract %7 %114 0 -%116 = OpCompositeExtract %4 %115 1 -%117 = OpExtInst %11 %1 FrexpStruct %43 -%118 = OpExtInst %11 %1 FrexpStruct %43 -%119 = OpCompositeExtract %4 %118 0 -%120 = OpExtInst %11 %1 FrexpStruct %43 -%121 = OpCompositeExtract %6 %120 1 -%122 = OpExtInst %13 %1 FrexpStruct %45 -%123 = OpCompositeExtract %12 %122 1 -%124 = OpCompositeExtract %6 %123 0 +%110 = OpExtInst %13 %1 FrexpStruct %46 +%111 = OpExtInst %13 %1 FrexpStruct %46 +%112 = OpCompositeExtract %4 %111 0 +%113 = OpExtInst %13 %1 FrexpStruct %46 +%114 = OpCompositeExtract %6 %113 1 +%115 = OpExtInst %15 %1 FrexpStruct %48 +%116 = OpCompositeExtract %14 %115 1 +%117 = OpCompositeExtract %6 %116 0 OpReturn OpFunctionEnd \ No newline at end of file diff --git a/naga/tests/out/wgsl/math-functions.wgsl b/naga/tests/out/wgsl/math-functions.wgsl index ce38fee986..68c2ba329f 100644 --- a/naga/tests/out/wgsl/math-functions.wgsl +++ b/naga/tests/out/wgsl/math-functions.wgsl @@ -28,10 +28,8 @@ fn main() { let ctz_f = countTrailingZeros(vec2(0i)); let ctz_g = countTrailingZeros(vec2(1u)); let ctz_h = countTrailingZeros(vec2(1i)); - let clz_a = countLeadingZeros(-1i); - let clz_b = countLeadingZeros(1u); - let clz_c = countLeadingZeros(vec2(-1i)); - let clz_d = countLeadingZeros(vec2(1u)); + let clz_c = vec2(0i, 0i); + let clz_d = vec2(31u, 31u); let lde_a = ldexp(1f, 2i); let lde_b = ldexp(vec2(1f, 2f), vec2(3i, 4i)); let modf_a = modf(1.5f); From 2ccc4f49eed49936ce998b8b54abd4d35fee1466 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 5 Jan 2024 10:56:24 -0500 Subject: [PATCH 066/101] feat(const_eval): impl. `countOneBits` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41e68c7357..41cd22eefe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,6 +69,7 @@ Bottom level categories: - [#5098](https://github.com/gfx-rs/wgpu/pull/5098) by @ErichDonGubler: - `ceil` - `countLeadingZeros` + - `countOneBits` - `floor` - Eager release of GPU resources comes from device.trackers. By @bradwerth in [#5075](https://github.com/gfx-rs/wgpu/pull/5075) - `wgpu-types`'s `trace` and `replay` features have been replaced by the `serde` feature. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 88c59809a9..29fced23a8 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -886,6 +886,15 @@ impl<'a> ConstantEvaluator<'a> { .expect("bit count overflowed 32 bits, somehow!?")]) }) } + crate::MathFunction::CountOneBits => { + component_wise_concrete_int!(self, span, [arg], |e| { + #[allow(clippy::useless_conversion)] + Ok([e + .count_ones() + .try_into() + .expect("bit count overflowed 32 bits, somehow!?")]) + }) + } crate::MathFunction::Floor => { component_wise_float!(self, span, [arg], |e| { Ok([e.floor()]) }) } From 66fd1872abbbba6281af6a6f122cd8abc14f1788 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 5 Jan 2024 10:56:24 -0500 Subject: [PATCH 067/101] feat(const_eval): impl. `countTrailingZeros` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 9 ++ .../glsl/math-functions.main.Fragment.glsl | 12 +-- naga/tests/out/hlsl/math-functions.hlsl | 12 +-- naga/tests/out/msl/math-functions.msl | 12 +-- naga/tests/out/spv/math-functions.spvasm | 82 ++++++++----------- naga/tests/out/wgsl/math-functions.wgsl | 12 +-- 7 files changed, 58 insertions(+), 82 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41cd22eefe..a6ceb886aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -70,6 +70,7 @@ Bottom level categories: - `ceil` - `countLeadingZeros` - `countOneBits` + - `countTrailingZeros` - `floor` - Eager release of GPU resources comes from device.trackers. By @bradwerth in [#5075](https://github.com/gfx-rs/wgpu/pull/5075) - `wgpu-types`'s `trace` and `replay` features have been replaced by the `serde` feature. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 29fced23a8..ea8807d7b3 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -895,6 +895,15 @@ impl<'a> ConstantEvaluator<'a> { .expect("bit count overflowed 32 bits, somehow!?")]) }) } + crate::MathFunction::CountTrailingZeros => { + component_wise_concrete_int!(self, span, [arg], |e| { + #[allow(clippy::useless_conversion)] + Ok([e + .trailing_zeros() + .try_into() + .expect("bit count overflowed 32 bits, somehow!?")]) + }) + } crate::MathFunction::Floor => { component_wise_float!(self, span, [arg], |e| { Ok([e.floor()]) }) } diff --git a/naga/tests/out/glsl/math-functions.main.Fragment.glsl b/naga/tests/out/glsl/math-functions.main.Fragment.glsl index 2892157801..a68b613a3b 100644 --- a/naga/tests/out/glsl/math-functions.main.Fragment.glsl +++ b/naga/tests/out/glsl/math-functions.main.Fragment.glsl @@ -75,14 +75,10 @@ void main() { uint ftb_b = uint(findLSB(1u)); ivec2 ftb_c = findLSB(ivec2(-1)); uvec2 ftb_d = uvec2(findLSB(uvec2(1u))); - uint ctz_a = min(uint(findLSB(0u)), 32u); - int ctz_b = int(min(uint(findLSB(0)), 32u)); - uint ctz_c = min(uint(findLSB(4294967295u)), 32u); - int ctz_d = int(min(uint(findLSB(-1)), 32u)); - uvec2 ctz_e = min(uvec2(findLSB(uvec2(0u))), uvec2(32u)); - ivec2 ctz_f = ivec2(min(uvec2(findLSB(ivec2(0))), uvec2(32u))); - uvec2 ctz_g = min(uvec2(findLSB(uvec2(1u))), uvec2(32u)); - ivec2 ctz_h = ivec2(min(uvec2(findLSB(ivec2(1))), uvec2(32u))); + uvec2 ctz_e = uvec2(32u, 32u); + ivec2 ctz_f = ivec2(32, 32); + uvec2 ctz_g = uvec2(0u, 0u); + ivec2 ctz_h = ivec2(0, 0); ivec2 clz_c = ivec2(0, 0); uvec2 clz_d = uvec2(31u, 31u); float lde_a = ldexp(1.0, 2); diff --git a/naga/tests/out/hlsl/math-functions.hlsl b/naga/tests/out/hlsl/math-functions.hlsl index d576365fc4..b3b938da6b 100644 --- a/naga/tests/out/hlsl/math-functions.hlsl +++ b/naga/tests/out/hlsl/math-functions.hlsl @@ -85,14 +85,10 @@ void main() uint ftb_b = firstbitlow(1u); int2 ftb_c = asint(firstbitlow((-1).xx)); uint2 ftb_d = firstbitlow((1u).xx); - uint ctz_a = min(32u, firstbitlow(0u)); - int ctz_b = asint(min(32u, firstbitlow(0))); - uint ctz_c = min(32u, firstbitlow(4294967295u)); - int ctz_d = asint(min(32u, firstbitlow(-1))); - uint2 ctz_e = min((32u).xx, firstbitlow((0u).xx)); - int2 ctz_f = asint(min((32u).xx, firstbitlow((0).xx))); - uint2 ctz_g = min((32u).xx, firstbitlow((1u).xx)); - int2 ctz_h = asint(min((32u).xx, firstbitlow((1).xx))); + uint2 ctz_e = uint2(32u, 32u); + int2 ctz_f = int2(32, 32); + uint2 ctz_g = uint2(0u, 0u); + int2 ctz_h = int2(0, 0); int2 clz_c = int2(0, 0); uint2 clz_d = uint2(31u, 31u); float lde_a = ldexp(1.0, 2); diff --git a/naga/tests/out/msl/math-functions.msl b/naga/tests/out/msl/math-functions.msl index 33fae07f78..a9d37076e7 100644 --- a/naga/tests/out/msl/math-functions.msl +++ b/naga/tests/out/msl/math-functions.msl @@ -80,14 +80,10 @@ fragment void main_( uint ftb_b = (((metal::ctz(1u) + 1) % 33) - 1); metal::int2 ftb_c = (((metal::ctz(metal::int2(-1)) + 1) % 33) - 1); metal::uint2 ftb_d = (((metal::ctz(metal::uint2(1u)) + 1) % 33) - 1); - uint ctz_a = metal::ctz(0u); - int ctz_b = metal::ctz(0); - uint ctz_c = metal::ctz(4294967295u); - int ctz_d = metal::ctz(-1); - metal::uint2 ctz_e = metal::ctz(metal::uint2(0u)); - metal::int2 ctz_f = metal::ctz(metal::int2(0)); - metal::uint2 ctz_g = metal::ctz(metal::uint2(1u)); - metal::int2 ctz_h = metal::ctz(metal::int2(1)); + metal::uint2 ctz_e = metal::uint2(32u, 32u); + metal::int2 ctz_f = metal::int2(32, 32); + metal::uint2 ctz_g = metal::uint2(0u, 0u); + metal::int2 ctz_h = metal::int2(0, 0); metal::int2 clz_c = metal::int2(0, 0); metal::uint2 clz_d = metal::uint2(31u, 31u); float lde_a = metal::ldexp(1.0, 2); diff --git a/naga/tests/out/spv/math-functions.spvasm b/naga/tests/out/spv/math-functions.spvasm index 8450bdd21e..442b0ba0d0 100644 --- a/naga/tests/out/spv/math-functions.spvasm +++ b/naga/tests/out/spv/math-functions.spvasm @@ -1,7 +1,7 @@ ; SPIR-V ; Version: 1.1 ; Generator: rspirv -; Bound: 118 +; Bound: 100 OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 @@ -44,15 +44,15 @@ OpMemberDecorate %15 1 Offset 16 %28 = OpConstantComposite %5 %22 %22 %29 = OpConstant %8 1 %30 = OpConstantComposite %7 %29 %29 -%31 = OpConstant %6 0 -%32 = OpConstant %8 4294967295 -%33 = OpConstantComposite %7 %27 %27 -%34 = OpConstantComposite %5 %31 %31 -%35 = OpConstant %6 1 -%36 = OpConstantComposite %5 %35 %35 -%37 = OpConstant %8 31 -%38 = OpConstantComposite %5 %31 %31 -%39 = OpConstantComposite %7 %37 %37 +%31 = OpConstant %8 32 +%32 = OpConstant %6 32 +%33 = OpConstant %6 0 +%34 = OpConstantComposite %7 %31 %31 +%35 = OpConstantComposite %5 %32 %32 +%36 = OpConstantComposite %7 %27 %27 +%37 = OpConstantComposite %5 %33 %33 +%38 = OpConstant %8 31 +%39 = OpConstantComposite %7 %38 %38 %40 = OpConstant %6 2 %41 = OpConstant %4 2.0 %42 = OpConstantComposite %9 %19 %41 @@ -64,8 +64,6 @@ OpMemberDecorate %15 1 Offset 16 %48 = OpConstantComposite %3 %46 %46 %46 %46 %55 = OpConstantComposite %3 %19 %19 %19 %19 %62 = OpConstantNull %6 -%79 = OpConstant %8 32 -%88 = OpConstantComposite %7 %79 %79 %17 = OpFunction %2 None %18 %16 = OpLabel OpBranch %49 @@ -96,43 +94,27 @@ OpBranch %49 %75 = OpExtInst %8 %1 FindILsb %29 %76 = OpExtInst %5 %1 FindILsb %28 %77 = OpExtInst %7 %1 FindILsb %30 -%80 = OpExtInst %8 %1 FindILsb %27 -%78 = OpExtInst %8 %1 UMin %79 %80 -%82 = OpExtInst %6 %1 FindILsb %31 -%81 = OpExtInst %6 %1 UMin %79 %82 -%84 = OpExtInst %8 %1 FindILsb %32 -%83 = OpExtInst %8 %1 UMin %79 %84 -%86 = OpExtInst %6 %1 FindILsb %22 -%85 = OpExtInst %6 %1 UMin %79 %86 -%89 = OpExtInst %7 %1 FindILsb %33 -%87 = OpExtInst %7 %1 UMin %88 %89 -%91 = OpExtInst %5 %1 FindILsb %34 -%90 = OpExtInst %5 %1 UMin %88 %91 -%93 = OpExtInst %7 %1 FindILsb %30 -%92 = OpExtInst %7 %1 UMin %88 %93 -%95 = OpExtInst %5 %1 FindILsb %36 -%94 = OpExtInst %5 %1 UMin %88 %95 -%96 = OpExtInst %4 %1 Ldexp %19 %40 -%97 = OpExtInst %9 %1 Ldexp %42 %45 -%98 = OpExtInst %10 %1 ModfStruct %46 -%99 = OpExtInst %10 %1 ModfStruct %46 -%100 = OpCompositeExtract %4 %99 0 -%101 = OpExtInst %10 %1 ModfStruct %46 -%102 = OpCompositeExtract %4 %101 1 -%103 = OpExtInst %11 %1 ModfStruct %47 -%104 = OpExtInst %12 %1 ModfStruct %48 -%105 = OpCompositeExtract %3 %104 1 -%106 = OpCompositeExtract %4 %105 0 -%107 = OpExtInst %11 %1 ModfStruct %47 -%108 = OpCompositeExtract %9 %107 0 -%109 = OpCompositeExtract %4 %108 1 -%110 = OpExtInst %13 %1 FrexpStruct %46 -%111 = OpExtInst %13 %1 FrexpStruct %46 -%112 = OpCompositeExtract %4 %111 0 -%113 = OpExtInst %13 %1 FrexpStruct %46 -%114 = OpCompositeExtract %6 %113 1 -%115 = OpExtInst %15 %1 FrexpStruct %48 -%116 = OpCompositeExtract %14 %115 1 -%117 = OpCompositeExtract %6 %116 0 +%78 = OpExtInst %4 %1 Ldexp %19 %40 +%79 = OpExtInst %9 %1 Ldexp %42 %45 +%80 = OpExtInst %10 %1 ModfStruct %46 +%81 = OpExtInst %10 %1 ModfStruct %46 +%82 = OpCompositeExtract %4 %81 0 +%83 = OpExtInst %10 %1 ModfStruct %46 +%84 = OpCompositeExtract %4 %83 1 +%85 = OpExtInst %11 %1 ModfStruct %47 +%86 = OpExtInst %12 %1 ModfStruct %48 +%87 = OpCompositeExtract %3 %86 1 +%88 = OpCompositeExtract %4 %87 0 +%89 = OpExtInst %11 %1 ModfStruct %47 +%90 = OpCompositeExtract %9 %89 0 +%91 = OpCompositeExtract %4 %90 1 +%92 = OpExtInst %13 %1 FrexpStruct %46 +%93 = OpExtInst %13 %1 FrexpStruct %46 +%94 = OpCompositeExtract %4 %93 0 +%95 = OpExtInst %13 %1 FrexpStruct %46 +%96 = OpCompositeExtract %6 %95 1 +%97 = OpExtInst %15 %1 FrexpStruct %48 +%98 = OpCompositeExtract %14 %97 1 +%99 = OpCompositeExtract %6 %98 0 OpReturn OpFunctionEnd \ No newline at end of file diff --git a/naga/tests/out/wgsl/math-functions.wgsl b/naga/tests/out/wgsl/math-functions.wgsl index 68c2ba329f..8b8330738b 100644 --- a/naga/tests/out/wgsl/math-functions.wgsl +++ b/naga/tests/out/wgsl/math-functions.wgsl @@ -20,14 +20,10 @@ fn main() { let ftb_b = firstTrailingBit(1u); let ftb_c = firstTrailingBit(vec2(-1i)); let ftb_d = firstTrailingBit(vec2(1u)); - let ctz_a = countTrailingZeros(0u); - let ctz_b = countTrailingZeros(0i); - let ctz_c = countTrailingZeros(4294967295u); - let ctz_d = countTrailingZeros(-1i); - let ctz_e = countTrailingZeros(vec2(0u)); - let ctz_f = countTrailingZeros(vec2(0i)); - let ctz_g = countTrailingZeros(vec2(1u)); - let ctz_h = countTrailingZeros(vec2(1i)); + let ctz_e = vec2(32u, 32u); + let ctz_f = vec2(32i, 32i); + let ctz_g = vec2(0u, 0u); + let ctz_h = vec2(0i, 0i); let clz_c = vec2(0i, 0i); let clz_d = vec2(31u, 31u); let lde_a = ldexp(1f, 2i); From 01d02caca3ede1237d3e2484fddab36fbfe677ee Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 5 Jan 2024 10:56:24 -0500 Subject: [PATCH 068/101] feat(const_eval): impl. `exp` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6ceb886aa..04e4372cb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -71,6 +71,7 @@ Bottom level categories: - `countLeadingZeros` - `countOneBits` - `countTrailingZeros` + - `exp` - `floor` - Eager release of GPU resources comes from device.trackers. By @bradwerth in [#5075](https://github.com/gfx-rs/wgpu/pull/5075) - `wgpu-types`'s `trace` and `replay` features have been replaced by the `serde` feature. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index ea8807d7b3..a97a6e6a53 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -904,6 +904,9 @@ impl<'a> ConstantEvaluator<'a> { .expect("bit count overflowed 32 bits, somehow!?")]) }) } + crate::MathFunction::Exp => { + component_wise_float!(self, span, [arg], |e| { Ok([e.exp()]) }) + } crate::MathFunction::Floor => { component_wise_float!(self, span, [arg], |e| { Ok([e.floor()]) }) } From 0f8adae123d23ad698f58ca61eafeb4a5b66b130 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Thu, 18 Jan 2024 17:39:21 -0500 Subject: [PATCH 069/101] feat(const_eval): impl. `degrees` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04e4372cb5..10421f20cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -71,6 +71,7 @@ Bottom level categories: - `countLeadingZeros` - `countOneBits` - `countTrailingZeros` + - `degrees` - `exp` - `floor` - Eager release of GPU resources comes from device.trackers. By @bradwerth in [#5075](https://github.com/gfx-rs/wgpu/pull/5075) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index a97a6e6a53..0a8e4c0971 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -904,6 +904,9 @@ impl<'a> ConstantEvaluator<'a> { .expect("bit count overflowed 32 bits, somehow!?")]) }) } + crate::MathFunction::Degrees => { + component_wise_float!(self, span, [arg], |e| { Ok([e.to_degrees()]) }) + } crate::MathFunction::Exp => { component_wise_float!(self, span, [arg], |e| { Ok([e.exp()]) }) } From 7b274fc161b0efa6dca10bd83d7de9ec00d0c03a Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 5 Jan 2024 10:56:24 -0500 Subject: [PATCH 070/101] feat(const_eval): impl. `exp2` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10421f20cc..2bacf843b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,6 +73,7 @@ Bottom level categories: - `countTrailingZeros` - `degrees` - `exp` + - `exp2` - `floor` - Eager release of GPU resources comes from device.trackers. By @bradwerth in [#5075](https://github.com/gfx-rs/wgpu/pull/5075) - `wgpu-types`'s `trace` and `replay` features have been replaced by the `serde` feature. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 0a8e4c0971..66cccc947a 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -910,6 +910,9 @@ impl<'a> ConstantEvaluator<'a> { crate::MathFunction::Exp => { component_wise_float!(self, span, [arg], |e| { Ok([e.exp()]) }) } + crate::MathFunction::Exp2 => { + component_wise_float!(self, span, [arg], |e| { Ok([e.exp2()]) }) + } crate::MathFunction::Floor => { component_wise_float!(self, span, [arg], |e| { Ok([e.floor()]) }) } From 19f5e4d5e4fca6052af3190a5f3b3035423dd4e1 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 26 Jan 2024 12:13:43 -0500 Subject: [PATCH 071/101] feat(const_eval): impl. `fma` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bacf843b8..2835ed2c15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,6 +75,7 @@ Bottom level categories: - `exp` - `exp2` - `floor` + - `fma` - Eager release of GPU resources comes from device.trackers. By @bradwerth in [#5075](https://github.com/gfx-rs/wgpu/pull/5075) - `wgpu-types`'s `trace` and `replay` features have been replaced by the `serde` feature. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) - `wgpu-core`'s `serial-pass` feature has been removed. Use `serde` instead. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 66cccc947a..622fd46896 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -916,6 +916,14 @@ impl<'a> ConstantEvaluator<'a> { crate::MathFunction::Floor => { component_wise_float!(self, span, [arg], |e| { Ok([e.floor()]) }) } + crate::MathFunction::Fma => { + component_wise_float!( + self, + span, + [arg, arg1.unwrap(), arg2.unwrap()], + |e1, e2, e3| { Ok([e1.mul_add(e2, e3)]) } + ) + } crate::MathFunction::Round => { // TODO: Use `f{32,64}.round_ties_even()` when available on stable. This polyfill // is shamelessly [~~stolen from~~ inspired by `ndarray-image`][polyfill source], From fc045187505037b474d0ad4c35337216a2d2ec2a Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 26 Jan 2024 12:13:55 -0500 Subject: [PATCH 072/101] feat(const_eval): impl. `inverseSqrt` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2835ed2c15..2f1b46fa72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,6 +76,7 @@ Bottom level categories: - `exp2` - `floor` - `fma` + - `inverseSqrt` - Eager release of GPU resources comes from device.trackers. By @bradwerth in [#5075](https://github.com/gfx-rs/wgpu/pull/5075) - `wgpu-types`'s `trace` and `replay` features have been replaced by the `serde` feature. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) - `wgpu-core`'s `serial-pass` feature has been removed. Use `serde` instead. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 622fd46896..cf83e64264 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -924,6 +924,9 @@ impl<'a> ConstantEvaluator<'a> { |e1, e2, e3| { Ok([e1.mul_add(e2, e3)]) } ) } + crate::MathFunction::InverseSqrt => { + component_wise_float!(self, span, [arg], |e| { Ok([1. / e.sqrt()]) }) + } crate::MathFunction::Round => { // TODO: Use `f{32,64}.round_ties_even()` when available on stable. This polyfill // is shamelessly [~~stolen from~~ inspired by `ndarray-image`][polyfill source], From 4db02d1962b7f7bde067161ab38dc30b5f4d6786 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Thu, 18 Jan 2024 17:10:08 -0500 Subject: [PATCH 073/101] feat(const_eval): impl. `fract` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f1b46fa72..4ed36bda49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,6 +75,7 @@ Bottom level categories: - `exp` - `exp2` - `floor` + - `fract` - `fma` - `inverseSqrt` - Eager release of GPU resources comes from device.trackers. By @bradwerth in [#5075](https://github.com/gfx-rs/wgpu/pull/5075) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index cf83e64264..2398068691 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -916,6 +916,13 @@ impl<'a> ConstantEvaluator<'a> { crate::MathFunction::Floor => { component_wise_float!(self, span, [arg], |e| { Ok([e.floor()]) }) } + crate::MathFunction::Fract => { + component_wise_float!(self, span, [arg], |e| { + // N.B., Rust's definition of `fract` is `e - e.trunc()`, so we can't use that + // here. + Ok([e - e.floor()]) + }) + } crate::MathFunction::Fma => { component_wise_float!( self, From 39cb92cf88fd822ad07550f758f4a22b1af65156 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 26 Jan 2024 12:14:08 -0500 Subject: [PATCH 074/101] feat(const_eval): impl. `log` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ed36bda49..15d9373dfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -78,6 +78,7 @@ Bottom level categories: - `fract` - `fma` - `inverseSqrt` + - `log` - Eager release of GPU resources comes from device.trackers. By @bradwerth in [#5075](https://github.com/gfx-rs/wgpu/pull/5075) - `wgpu-types`'s `trace` and `replay` features have been replaced by the `serde` feature. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) - `wgpu-core`'s `serial-pass` feature has been removed. Use `serde` instead. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 2398068691..96192ec827 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -934,6 +934,9 @@ impl<'a> ConstantEvaluator<'a> { crate::MathFunction::InverseSqrt => { component_wise_float!(self, span, [arg], |e| { Ok([1. / e.sqrt()]) }) } + crate::MathFunction::Log => { + component_wise_float!(self, span, [arg], |e| { Ok([e.ln()]) }) + } crate::MathFunction::Round => { // TODO: Use `f{32,64}.round_ties_even()` when available on stable. This polyfill // is shamelessly [~~stolen from~~ inspired by `ndarray-image`][polyfill source], From e6f6eb7036f3023fcdd4bbf4717e3a6eee93d675 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 26 Jan 2024 12:14:18 -0500 Subject: [PATCH 075/101] feat(const_eval): impl. `log2` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15d9373dfb..60e98dd1eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -79,6 +79,7 @@ Bottom level categories: - `fma` - `inverseSqrt` - `log` + - `log2` - Eager release of GPU resources comes from device.trackers. By @bradwerth in [#5075](https://github.com/gfx-rs/wgpu/pull/5075) - `wgpu-types`'s `trace` and `replay` features have been replaced by the `serde` feature. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) - `wgpu-core`'s `serial-pass` feature has been removed. Use `serde` instead. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 96192ec827..1e132f66d4 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -937,6 +937,9 @@ impl<'a> ConstantEvaluator<'a> { crate::MathFunction::Log => { component_wise_float!(self, span, [arg], |e| { Ok([e.ln()]) }) } + crate::MathFunction::Log2 => { + component_wise_float!(self, span, [arg], |e| { Ok([e.log2()]) }) + } crate::MathFunction::Round => { // TODO: Use `f{32,64}.round_ties_even()` when available on stable. This polyfill // is shamelessly [~~stolen from~~ inspired by `ndarray-image`][polyfill source], From 7dedd002c0537db7238c9ff6862e71d3ced7b0da Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 26 Jan 2024 12:14:30 -0500 Subject: [PATCH 076/101] feat(const_eval): impl. `radians` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60e98dd1eb..62f41fec41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,6 +80,7 @@ Bottom level categories: - `inverseSqrt` - `log` - `log2` + - `radians` - Eager release of GPU resources comes from device.trackers. By @bradwerth in [#5075](https://github.com/gfx-rs/wgpu/pull/5075) - `wgpu-types`'s `trace` and `replay` features have been replaced by the `serde` feature. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) - `wgpu-core`'s `serial-pass` feature has been removed. Use `serde` instead. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 1e132f66d4..63b2ea0656 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -940,6 +940,9 @@ impl<'a> ConstantEvaluator<'a> { crate::MathFunction::Log2 => { component_wise_float!(self, span, [arg], |e| { Ok([e.log2()]) }) } + crate::MathFunction::Radians => { + component_wise_float!(self, span, [arg], |e1| { Ok([e1.to_radians()]) }) + } crate::MathFunction::Round => { // TODO: Use `f{32,64}.round_ties_even()` when available on stable. This polyfill // is shamelessly [~~stolen from~~ inspired by `ndarray-image`][polyfill source], From 0bd5f7760104368cb624f103f10692c0037c1d35 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 26 Jan 2024 12:14:40 -0500 Subject: [PATCH 077/101] feat(const_eval): impl. `reverseBits` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62f41fec41..ab12eb16bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -81,6 +81,7 @@ Bottom level categories: - `log` - `log2` - `radians` + - `reverseBits` - Eager release of GPU resources comes from device.trackers. By @bradwerth in [#5075](https://github.com/gfx-rs/wgpu/pull/5075) - `wgpu-types`'s `trace` and `replay` features have been replaced by the `serde` feature. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) - `wgpu-core`'s `serial-pass` feature has been removed. Use `serde` instead. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 63b2ea0656..585daf1fe3 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -943,6 +943,9 @@ impl<'a> ConstantEvaluator<'a> { crate::MathFunction::Radians => { component_wise_float!(self, span, [arg], |e1| { Ok([e1.to_radians()]) }) } + crate::MathFunction::ReverseBits => { + component_wise_concrete_int!(self, span, [arg], |e| { Ok([e.reverse_bits()]) }) + } crate::MathFunction::Round => { // TODO: Use `f{32,64}.round_ties_even()` when available on stable. This polyfill // is shamelessly [~~stolen from~~ inspired by `ndarray-image`][polyfill source], From 2d3005b74576fa19d894c6c58e682514478d4915 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 26 Jan 2024 12:14:51 -0500 Subject: [PATCH 078/101] feat(const_eval): impl. `sign` with new `component_wise_signed` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 19 +++ .../glsl/math-functions.main.Fragment.glsl | 6 +- naga/tests/out/hlsl/math-functions.hlsl | 6 +- naga/tests/out/msl/math-functions.msl | 15 +- naga/tests/out/spv/math-functions.spvasm | 144 +++++++++--------- naga/tests/out/wgsl/math-functions.wgsl | 6 +- 7 files changed, 102 insertions(+), 95 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab12eb16bd..560b29e768 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -82,6 +82,7 @@ Bottom level categories: - `log2` - `radians` - `reverseBits` + - `sign` - Eager release of GPU resources comes from device.trackers. By @bradwerth in [#5075](https://github.com/gfx-rs/wgpu/pull/5075) - `wgpu-types`'s `trace` and `replay` features have been replaced by the `serde` feature. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) - `wgpu-core`'s `serial-pass` feature has been removed. Use `serde` instead. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 585daf1fe3..6a2991fa66 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -234,6 +234,22 @@ gen_component_wise_extractor! { ], } +gen_component_wise_extractor! { + component_wise_signed -> Signed, + literals: [ + AbstractFloat => AbstractFloat: f64, + AbstractInt => AbstractInt: i64, + F32 => F32: f32, + I32 => I32: i32, + ], + scalar_kinds: [ + Sint, + AbstractInt, + Float, + AbstractFloat, + ], +} + #[derive(Debug)] enum Behavior { Wgsl, @@ -975,6 +991,9 @@ impl<'a> ConstantEvaluator<'a> { crate::MathFunction::Saturate => { component_wise_float!(self, span, [arg], |e| { Ok([e.clamp(0., 1.)]) }) } + crate::MathFunction::Sign => { + component_wise_signed!(self, span, [arg], |e| { Ok([e.signum()]) }) + } crate::MathFunction::Sin => { component_wise_float!(self, span, [arg], |e| { Ok([e.sin()]) }) } diff --git a/naga/tests/out/glsl/math-functions.main.Fragment.glsl b/naga/tests/out/glsl/math-functions.main.Fragment.glsl index a68b613a3b..7f91571dcc 100644 --- a/naga/tests/out/glsl/math-functions.main.Fragment.glsl +++ b/naga/tests/out/glsl/math-functions.main.Fragment.glsl @@ -62,10 +62,8 @@ void main() { vec4 d = radians(v); vec4 e = clamp(v, vec4(0.0), vec4(1.0)); vec4 g = refract(v, v, 1.0); - int sign_a = sign(-1); - ivec4 sign_b = sign(ivec4(-1)); - float sign_c = sign(-1.0); - vec4 sign_d = sign(vec4(-1.0)); + ivec4 sign_b = ivec4(-1, -1, -1, -1); + vec4 sign_d = vec4(-1.0, -1.0, -1.0, -1.0); int const_dot = ( + ivec2(0).x * ivec2(0).x + ivec2(0).y * ivec2(0).y); uint first_leading_bit_abs = uint(findMSB(0u)); int flb_a = findMSB(-1); diff --git a/naga/tests/out/hlsl/math-functions.hlsl b/naga/tests/out/hlsl/math-functions.hlsl index b3b938da6b..61c59f00c1 100644 --- a/naga/tests/out/hlsl/math-functions.hlsl +++ b/naga/tests/out/hlsl/math-functions.hlsl @@ -72,10 +72,8 @@ void main() float4 d = radians(v); float4 e = saturate(v); float4 g = refract(v, v, 1.0); - int sign_a = sign(-1); - int4 sign_b = sign((-1).xxxx); - float sign_c = sign(-1.0); - float4 sign_d = sign((-1.0).xxxx); + int4 sign_b = int4(-1, -1, -1, -1); + float4 sign_d = float4(-1.0, -1.0, -1.0, -1.0); int const_dot = dot((int2)0, (int2)0); uint first_leading_bit_abs = firstbithigh(0u); int flb_a = asint(firstbithigh(-1)); diff --git a/naga/tests/out/msl/math-functions.msl b/naga/tests/out/msl/math-functions.msl index a9d37076e7..0e6a5b24dc 100644 --- a/naga/tests/out/msl/math-functions.msl +++ b/naga/tests/out/msl/math-functions.msl @@ -64,18 +64,15 @@ fragment void main_( metal::float4 d = ((v) * 0.017453292519943295474); metal::float4 e = metal::saturate(v); metal::float4 g = metal::refract(v, v, 1.0); - int sign_a = metal::select(metal::select(-1, 1, (-1 > 0)), 0, (-1 == 0)); - metal::int4 _e12 = metal::int4(-1); - metal::int4 sign_b = metal::select(metal::select(int4(-1), int4(1), (_e12 > 0)), 0, (_e12 == 0)); - float sign_c = metal::sign(-1.0); - metal::float4 sign_d = metal::sign(metal::float4(-1.0)); + metal::int4 sign_b = metal::int4(-1, -1, -1, -1); + metal::float4 sign_d = metal::float4(-1.0, -1.0, -1.0, -1.0); int const_dot = ( + metal::int2 {}.x * metal::int2 {}.x + metal::int2 {}.y * metal::int2 {}.y); uint first_leading_bit_abs = metal::select(31 - metal::clz(0u), uint(-1), 0u == 0 || 0u == -1); int flb_a = metal::select(31 - metal::clz(metal::select(-1, ~-1, -1 < 0)), int(-1), -1 == 0 || -1 == -1); - metal::int2 _e27 = metal::int2(-1); - metal::int2 flb_b = metal::select(31 - metal::clz(metal::select(_e27, ~_e27, _e27 < 0)), int2(-1), _e27 == 0 || _e27 == -1); - metal::uint2 _e30 = metal::uint2(1u); - metal::uint2 flb_c = metal::select(31 - metal::clz(_e30), uint2(-1), _e30 == 0 || _e30 == -1); + metal::int2 _e29 = metal::int2(-1); + metal::int2 flb_b = metal::select(31 - metal::clz(metal::select(_e29, ~_e29, _e29 < 0)), int2(-1), _e29 == 0 || _e29 == -1); + metal::uint2 _e32 = metal::uint2(1u); + metal::uint2 flb_c = metal::select(31 - metal::clz(_e32), uint2(-1), _e32 == 0 || _e32 == -1); int ftb_a = (((metal::ctz(-1) + 1) % 33) - 1); uint ftb_b = (((metal::ctz(1u) + 1) % 33) - 1); metal::int2 ftb_c = (((metal::ctz(metal::int2(-1)) + 1) % 33) - 1); diff --git a/naga/tests/out/spv/math-functions.spvasm b/naga/tests/out/spv/math-functions.spvasm index 442b0ba0d0..6e07c6d7a6 100644 --- a/naga/tests/out/spv/math-functions.spvasm +++ b/naga/tests/out/spv/math-functions.spvasm @@ -1,69 +1,69 @@ ; SPIR-V ; Version: 1.1 ; Generator: rspirv -; Bound: 100 +; Bound: 96 OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %17 "main" OpExecutionMode %17 OriginUpperLeft -OpMemberDecorate %10 0 Offset 0 -OpMemberDecorate %10 1 Offset 4 OpMemberDecorate %11 0 Offset 0 -OpMemberDecorate %11 1 Offset 8 +OpMemberDecorate %11 1 Offset 4 OpMemberDecorate %12 0 Offset 0 -OpMemberDecorate %12 1 Offset 16 +OpMemberDecorate %12 1 Offset 8 OpMemberDecorate %13 0 Offset 0 -OpMemberDecorate %13 1 Offset 4 +OpMemberDecorate %13 1 Offset 16 +OpMemberDecorate %14 0 Offset 0 +OpMemberDecorate %14 1 Offset 4 OpMemberDecorate %15 0 Offset 0 OpMemberDecorate %15 1 Offset 16 %2 = OpTypeVoid %4 = OpTypeFloat 32 %3 = OpTypeVector %4 4 %6 = OpTypeInt 32 1 -%5 = OpTypeVector %6 2 -%8 = OpTypeInt 32 0 -%7 = OpTypeVector %8 2 -%9 = OpTypeVector %4 2 -%10 = OpTypeStruct %4 %4 -%11 = OpTypeStruct %9 %9 -%12 = OpTypeStruct %3 %3 -%13 = OpTypeStruct %4 %6 -%14 = OpTypeVector %6 4 -%15 = OpTypeStruct %3 %14 +%5 = OpTypeVector %6 4 +%7 = OpTypeVector %6 2 +%9 = OpTypeInt 32 0 +%8 = OpTypeVector %9 2 +%10 = OpTypeVector %4 2 +%11 = OpTypeStruct %4 %4 +%12 = OpTypeStruct %10 %10 +%13 = OpTypeStruct %3 %3 +%14 = OpTypeStruct %4 %6 +%15 = OpTypeStruct %3 %5 %18 = OpTypeFunction %2 %19 = OpConstant %4 1.0 %20 = OpConstant %4 0.0 %21 = OpConstantComposite %3 %20 %20 %20 %20 %22 = OpConstant %6 -1 -%23 = OpConstantComposite %14 %22 %22 %22 %22 +%23 = OpConstantComposite %5 %22 %22 %22 %22 %24 = OpConstant %4 -1.0 %25 = OpConstantComposite %3 %24 %24 %24 %24 -%26 = OpConstantNull %5 -%27 = OpConstant %8 0 -%28 = OpConstantComposite %5 %22 %22 -%29 = OpConstant %8 1 -%30 = OpConstantComposite %7 %29 %29 -%31 = OpConstant %8 32 +%26 = OpConstantNull %7 +%27 = OpConstant %9 0 +%28 = OpConstantComposite %7 %22 %22 +%29 = OpConstant %9 1 +%30 = OpConstantComposite %8 %29 %29 +%31 = OpConstant %9 32 %32 = OpConstant %6 32 %33 = OpConstant %6 0 -%34 = OpConstantComposite %7 %31 %31 -%35 = OpConstantComposite %5 %32 %32 -%36 = OpConstantComposite %7 %27 %27 -%37 = OpConstantComposite %5 %33 %33 -%38 = OpConstant %8 31 -%39 = OpConstantComposite %7 %38 %38 +%34 = OpConstantComposite %8 %31 %31 +%35 = OpConstantComposite %7 %32 %32 +%36 = OpConstantComposite %8 %27 %27 +%37 = OpConstantComposite %7 %33 %33 +%38 = OpConstant %9 31 +%39 = OpConstantComposite %8 %38 %38 %40 = OpConstant %6 2 %41 = OpConstant %4 2.0 -%42 = OpConstantComposite %9 %19 %41 +%42 = OpConstantComposite %10 %19 %41 %43 = OpConstant %6 3 %44 = OpConstant %6 4 -%45 = OpConstantComposite %5 %43 %44 +%45 = OpConstantComposite %7 %43 %44 %46 = OpConstant %4 1.5 -%47 = OpConstantComposite %9 %46 %46 +%47 = OpConstantComposite %10 %46 %46 %48 = OpConstantComposite %3 %46 %46 %46 %46 %55 = OpConstantComposite %3 %19 %19 %19 %19 -%62 = OpConstantNull %6 +%58 = OpConstantNull %6 %17 = OpFunction %2 None %18 %16 = OpLabel OpBranch %49 @@ -74,47 +74,43 @@ OpBranch %49 %53 = OpExtInst %3 %1 Radians %21 %54 = OpExtInst %3 %1 FClamp %21 %21 %55 %56 = OpExtInst %3 %1 Refract %21 %21 %19 -%57 = OpExtInst %6 %1 SSign %22 -%58 = OpExtInst %14 %1 SSign %23 -%59 = OpExtInst %4 %1 FSign %24 -%60 = OpExtInst %3 %1 FSign %25 -%63 = OpCompositeExtract %6 %26 0 -%64 = OpCompositeExtract %6 %26 0 +%59 = OpCompositeExtract %6 %26 0 +%60 = OpCompositeExtract %6 %26 0 +%61 = OpIMul %6 %59 %60 +%62 = OpIAdd %6 %58 %61 +%63 = OpCompositeExtract %6 %26 1 +%64 = OpCompositeExtract %6 %26 1 %65 = OpIMul %6 %63 %64 -%66 = OpIAdd %6 %62 %65 -%67 = OpCompositeExtract %6 %26 1 -%68 = OpCompositeExtract %6 %26 1 -%69 = OpIMul %6 %67 %68 -%61 = OpIAdd %6 %66 %69 -%70 = OpExtInst %8 %1 FindUMsb %27 -%71 = OpExtInst %6 %1 FindSMsb %22 -%72 = OpExtInst %5 %1 FindSMsb %28 -%73 = OpExtInst %7 %1 FindUMsb %30 -%74 = OpExtInst %6 %1 FindILsb %22 -%75 = OpExtInst %8 %1 FindILsb %29 -%76 = OpExtInst %5 %1 FindILsb %28 -%77 = OpExtInst %7 %1 FindILsb %30 -%78 = OpExtInst %4 %1 Ldexp %19 %40 -%79 = OpExtInst %9 %1 Ldexp %42 %45 -%80 = OpExtInst %10 %1 ModfStruct %46 -%81 = OpExtInst %10 %1 ModfStruct %46 -%82 = OpCompositeExtract %4 %81 0 -%83 = OpExtInst %10 %1 ModfStruct %46 -%84 = OpCompositeExtract %4 %83 1 -%85 = OpExtInst %11 %1 ModfStruct %47 -%86 = OpExtInst %12 %1 ModfStruct %48 -%87 = OpCompositeExtract %3 %86 1 -%88 = OpCompositeExtract %4 %87 0 -%89 = OpExtInst %11 %1 ModfStruct %47 -%90 = OpCompositeExtract %9 %89 0 -%91 = OpCompositeExtract %4 %90 1 -%92 = OpExtInst %13 %1 FrexpStruct %46 -%93 = OpExtInst %13 %1 FrexpStruct %46 -%94 = OpCompositeExtract %4 %93 0 -%95 = OpExtInst %13 %1 FrexpStruct %46 -%96 = OpCompositeExtract %6 %95 1 -%97 = OpExtInst %15 %1 FrexpStruct %48 -%98 = OpCompositeExtract %14 %97 1 -%99 = OpCompositeExtract %6 %98 0 +%57 = OpIAdd %6 %62 %65 +%66 = OpExtInst %9 %1 FindUMsb %27 +%67 = OpExtInst %6 %1 FindSMsb %22 +%68 = OpExtInst %7 %1 FindSMsb %28 +%69 = OpExtInst %8 %1 FindUMsb %30 +%70 = OpExtInst %6 %1 FindILsb %22 +%71 = OpExtInst %9 %1 FindILsb %29 +%72 = OpExtInst %7 %1 FindILsb %28 +%73 = OpExtInst %8 %1 FindILsb %30 +%74 = OpExtInst %4 %1 Ldexp %19 %40 +%75 = OpExtInst %10 %1 Ldexp %42 %45 +%76 = OpExtInst %11 %1 ModfStruct %46 +%77 = OpExtInst %11 %1 ModfStruct %46 +%78 = OpCompositeExtract %4 %77 0 +%79 = OpExtInst %11 %1 ModfStruct %46 +%80 = OpCompositeExtract %4 %79 1 +%81 = OpExtInst %12 %1 ModfStruct %47 +%82 = OpExtInst %13 %1 ModfStruct %48 +%83 = OpCompositeExtract %3 %82 1 +%84 = OpCompositeExtract %4 %83 0 +%85 = OpExtInst %12 %1 ModfStruct %47 +%86 = OpCompositeExtract %10 %85 0 +%87 = OpCompositeExtract %4 %86 1 +%88 = OpExtInst %14 %1 FrexpStruct %46 +%89 = OpExtInst %14 %1 FrexpStruct %46 +%90 = OpCompositeExtract %4 %89 0 +%91 = OpExtInst %14 %1 FrexpStruct %46 +%92 = OpCompositeExtract %6 %91 1 +%93 = OpExtInst %15 %1 FrexpStruct %48 +%94 = OpCompositeExtract %5 %93 1 +%95 = OpCompositeExtract %6 %94 0 OpReturn OpFunctionEnd \ No newline at end of file diff --git a/naga/tests/out/wgsl/math-functions.wgsl b/naga/tests/out/wgsl/math-functions.wgsl index 8b8330738b..228248b3ce 100644 --- a/naga/tests/out/wgsl/math-functions.wgsl +++ b/naga/tests/out/wgsl/math-functions.wgsl @@ -7,10 +7,8 @@ fn main() { let d = radians(v); let e = saturate(v); let g = refract(v, v, 1f); - let sign_a = sign(-1i); - let sign_b = sign(vec4(-1i)); - let sign_c = sign(-1f); - let sign_d = sign(vec4(-1f)); + let sign_b = vec4(-1i, -1i, -1i, -1i); + let sign_d = vec4(-1f, -1f, -1f, -1f); let const_dot = dot(vec2(), vec2()); let first_leading_bit_abs = firstLeadingBit(0u); let flb_a = firstLeadingBit(-1i); From 18f50092a69bb8ab398ac11d8a95d595b1ad3272 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 26 Jan 2024 12:14:59 -0500 Subject: [PATCH 079/101] feat(const_eval): impl. `trunc` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 560b29e768..a87770b5ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -83,6 +83,7 @@ Bottom level categories: - `radians` - `reverseBits` - `sign` + - `trunc` - Eager release of GPU resources comes from device.trackers. By @bradwerth in [#5075](https://github.com/gfx-rs/wgpu/pull/5075) - `wgpu-types`'s `trace` and `replay` features have been replaced by the `serde` feature. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) - `wgpu-core`'s `serial-pass` feature has been removed. Use `serde` instead. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 6a2991fa66..8a69acc820 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -1014,6 +1014,9 @@ impl<'a> ConstantEvaluator<'a> { Ok([if edge <= x { 1.0 } else { 0.0 }]) }) } + crate::MathFunction::Trunc => { + component_wise_float!(self, span, [arg], |e| { Ok([e.trunc()]) }) + } fun => Err(ConstantEvaluatorError::NotImplemented(format!( "{fun:?} built-in function" ))), From abcc6ddff3df6f100e953f0b87e2f130effa278c Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 26 Jan 2024 12:17:11 -0500 Subject: [PATCH 080/101] feat(const_eval): impl. `max` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a87770b5ab..c08bf98dfc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,6 +80,7 @@ Bottom level categories: - `inverseSqrt` - `log` - `log2` + - `max` - `radians` - `reverseBits` - `sign` diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 8a69acc820..062209a4e6 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -956,6 +956,11 @@ impl<'a> ConstantEvaluator<'a> { crate::MathFunction::Log2 => { component_wise_float!(self, span, [arg], |e| { Ok([e.log2()]) }) } + crate::MathFunction::Max => { + component_wise_scalar!(self, span, [arg, arg1.unwrap()], |e1, e2| { + Ok([e1.max(e2)]) + }) + } crate::MathFunction::Radians => { component_wise_float!(self, span, [arg], |e1| { Ok([e1.to_radians()]) }) } From c559be933bc515361a179a307a9276f1adc22a96 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 26 Jan 2024 12:17:31 -0500 Subject: [PATCH 081/101] feat(const_eval): impl. `min` --- CHANGELOG.md | 1 + naga/src/proc/constant_evaluator.rs | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c08bf98dfc..58a01f23eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -81,6 +81,7 @@ Bottom level categories: - `log` - `log2` - `max` + - `min` - `radians` - `reverseBits` - `sign` diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 062209a4e6..95d8484392 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -961,6 +961,11 @@ impl<'a> ConstantEvaluator<'a> { Ok([e1.max(e2)]) }) } + crate::MathFunction::Min => { + component_wise_scalar!(self, span, [arg, arg1.unwrap()], |e1, e2| { + Ok([e1.min(e2)]) + }) + } crate::MathFunction::Radians => { component_wise_float!(self, span, [arg], |e1| { Ok([e1.to_radians()]) }) } From 443d5f93dc7a74bf2ca759f86c813a3c99818b18 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 26 Jan 2024 12:43:30 -0500 Subject: [PATCH 082/101] style(const_eval): match variant decl. order of current `MathFunction` impls. --- naga/src/proc/constant_evaluator.rs | 221 +++++++++++++++------------- 1 file changed, 117 insertions(+), 104 deletions(-) diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 95d8484392..b3884b04b1 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -837,7 +837,9 @@ impl<'a> ConstantEvaluator<'a> { )); } + // NOTE: We try to match the declaration order of `MathFunction` here. match fun { + // comparison crate::MathFunction::Abs => { component_wise_scalar(self, span, [arg], |args| match args { Scalar::AbstractFloat([e]) => Ok(Scalar::AbstractFloat([e.abs()])), @@ -847,31 +849,15 @@ impl<'a> ConstantEvaluator<'a> { Scalar::U32([e]) => Ok(Scalar::U32([e])), // TODO: just re-use the expression, ezpz }) } - crate::MathFunction::Acos => { - component_wise_float!(self, span, [arg], |e| { Ok([e.acos()]) }) - } - crate::MathFunction::Acosh => { - component_wise_float!(self, span, [arg], |e| { Ok([e.acosh()]) }) - } - crate::MathFunction::Asin => { - component_wise_float!(self, span, [arg], |e| { Ok([e.asin()]) }) - } - crate::MathFunction::Asinh => { - component_wise_float!(self, span, [arg], |e| { Ok([e.asinh()]) }) - } - crate::MathFunction::Atan => { - component_wise_float!(self, span, [arg], |e| { Ok([e.atan()]) }) - } - crate::MathFunction::Atanh => { - component_wise_float!(self, span, [arg], |e| { Ok([e.atanh()]) }) - } - crate::MathFunction::Pow => { - component_wise_float!(self, span, [arg, arg1.unwrap()], |e1, e2| { - Ok([e1.powf(e2)]) + crate::MathFunction::Min => { + component_wise_scalar!(self, span, [arg, arg1.unwrap()], |e1, e2| { + Ok([e1.min(e2)]) }) } - crate::MathFunction::Ceil => { - component_wise_float!(self, span, [arg], |e| { Ok([e.ceil()]) }) + crate::MathFunction::Max => { + component_wise_scalar!(self, span, [arg, arg1.unwrap()], |e1, e2| { + Ok([e1.max(e2)]) + }) } crate::MathFunction::Clamp => { component_wise_scalar!( @@ -887,90 +873,60 @@ impl<'a> ConstantEvaluator<'a> { } ) } + crate::MathFunction::Saturate => { + component_wise_float!(self, span, [arg], |e| { Ok([e.clamp(0., 1.)]) }) + } + + // trigonometry crate::MathFunction::Cos => { component_wise_float!(self, span, [arg], |e| { Ok([e.cos()]) }) } crate::MathFunction::Cosh => { component_wise_float!(self, span, [arg], |e| { Ok([e.cosh()]) }) } - crate::MathFunction::CountLeadingZeros => { - component_wise_concrete_int!(self, span, [arg], |e| { - #[allow(clippy::useless_conversion)] - Ok([e - .leading_zeros() - .try_into() - .expect("bit count overflowed 32 bits, somehow!?")]) - }) - } - crate::MathFunction::CountOneBits => { - component_wise_concrete_int!(self, span, [arg], |e| { - #[allow(clippy::useless_conversion)] - Ok([e - .count_ones() - .try_into() - .expect("bit count overflowed 32 bits, somehow!?")]) - }) - } - crate::MathFunction::CountTrailingZeros => { - component_wise_concrete_int!(self, span, [arg], |e| { - #[allow(clippy::useless_conversion)] - Ok([e - .trailing_zeros() - .try_into() - .expect("bit count overflowed 32 bits, somehow!?")]) - }) - } - crate::MathFunction::Degrees => { - component_wise_float!(self, span, [arg], |e| { Ok([e.to_degrees()]) }) - } - crate::MathFunction::Exp => { - component_wise_float!(self, span, [arg], |e| { Ok([e.exp()]) }) + crate::MathFunction::Sin => { + component_wise_float!(self, span, [arg], |e| { Ok([e.sin()]) }) } - crate::MathFunction::Exp2 => { - component_wise_float!(self, span, [arg], |e| { Ok([e.exp2()]) }) + crate::MathFunction::Sinh => { + component_wise_float!(self, span, [arg], |e| { Ok([e.sinh()]) }) } - crate::MathFunction::Floor => { - component_wise_float!(self, span, [arg], |e| { Ok([e.floor()]) }) + crate::MathFunction::Tan => { + component_wise_float!(self, span, [arg], |e| { Ok([e.tan()]) }) } - crate::MathFunction::Fract => { - component_wise_float!(self, span, [arg], |e| { - // N.B., Rust's definition of `fract` is `e - e.trunc()`, so we can't use that - // here. - Ok([e - e.floor()]) - }) + crate::MathFunction::Tanh => { + component_wise_float!(self, span, [arg], |e| { Ok([e.tanh()]) }) } - crate::MathFunction::Fma => { - component_wise_float!( - self, - span, - [arg, arg1.unwrap(), arg2.unwrap()], - |e1, e2, e3| { Ok([e1.mul_add(e2, e3)]) } - ) + crate::MathFunction::Acos => { + component_wise_float!(self, span, [arg], |e| { Ok([e.acos()]) }) } - crate::MathFunction::InverseSqrt => { - component_wise_float!(self, span, [arg], |e| { Ok([1. / e.sqrt()]) }) + crate::MathFunction::Asin => { + component_wise_float!(self, span, [arg], |e| { Ok([e.asin()]) }) } - crate::MathFunction::Log => { - component_wise_float!(self, span, [arg], |e| { Ok([e.ln()]) }) + crate::MathFunction::Atan => { + component_wise_float!(self, span, [arg], |e| { Ok([e.atan()]) }) } - crate::MathFunction::Log2 => { - component_wise_float!(self, span, [arg], |e| { Ok([e.log2()]) }) + crate::MathFunction::Asinh => { + component_wise_float!(self, span, [arg], |e| { Ok([e.asinh()]) }) } - crate::MathFunction::Max => { - component_wise_scalar!(self, span, [arg, arg1.unwrap()], |e1, e2| { - Ok([e1.max(e2)]) - }) + crate::MathFunction::Acosh => { + component_wise_float!(self, span, [arg], |e| { Ok([e.acosh()]) }) } - crate::MathFunction::Min => { - component_wise_scalar!(self, span, [arg, arg1.unwrap()], |e1, e2| { - Ok([e1.min(e2)]) - }) + crate::MathFunction::Atanh => { + component_wise_float!(self, span, [arg], |e| { Ok([e.atanh()]) }) } crate::MathFunction::Radians => { component_wise_float!(self, span, [arg], |e1| { Ok([e1.to_radians()]) }) } - crate::MathFunction::ReverseBits => { - component_wise_concrete_int!(self, span, [arg], |e| { Ok([e.reverse_bits()]) }) + crate::MathFunction::Degrees => { + component_wise_float!(self, span, [arg], |e| { Ok([e.to_degrees()]) }) + } + + // decomposition + crate::MathFunction::Ceil => { + component_wise_float!(self, span, [arg], |e| { Ok([e.ceil()]) }) + } + crate::MathFunction::Floor => { + component_wise_float!(self, span, [arg], |e| { Ok([e.floor()]) }) } crate::MathFunction::Round => { // TODO: Use `f{32,64}.round_ties_even()` when available on stable. This polyfill @@ -998,35 +954,92 @@ impl<'a> ConstantEvaluator<'a> { Float::F32([e]) => Ok(Float::F32([(round_ties_even(e as f64) as f32)])), }) } - crate::MathFunction::Saturate => { - component_wise_float!(self, span, [arg], |e| { Ok([e.clamp(0., 1.)]) }) + crate::MathFunction::Fract => { + component_wise_float!(self, span, [arg], |e| { + // N.B., Rust's definition of `fract` is `e - e.trunc()`, so we can't use that + // here. + Ok([e - e.floor()]) + }) } - crate::MathFunction::Sign => { - component_wise_signed!(self, span, [arg], |e| { Ok([e.signum()]) }) + crate::MathFunction::Trunc => { + component_wise_float!(self, span, [arg], |e| { Ok([e.trunc()]) }) } - crate::MathFunction::Sin => { - component_wise_float!(self, span, [arg], |e| { Ok([e.sin()]) }) + + // exponent + crate::MathFunction::Exp => { + component_wise_float!(self, span, [arg], |e| { Ok([e.exp()]) }) } - crate::MathFunction::Sinh => { - component_wise_float!(self, span, [arg], |e| { Ok([e.sinh()]) }) + crate::MathFunction::Exp2 => { + component_wise_float!(self, span, [arg], |e| { Ok([e.exp2()]) }) } - crate::MathFunction::Tan => { - component_wise_float!(self, span, [arg], |e| { Ok([e.tan()]) }) + crate::MathFunction::Log => { + component_wise_float!(self, span, [arg], |e| { Ok([e.ln()]) }) } - crate::MathFunction::Tanh => { - component_wise_float!(self, span, [arg], |e| { Ok([e.tanh()]) }) + crate::MathFunction::Log2 => { + component_wise_float!(self, span, [arg], |e| { Ok([e.log2()]) }) } - crate::MathFunction::Sqrt => { - component_wise_float!(self, span, [arg], |e| { Ok([e.sqrt()]) }) + crate::MathFunction::Pow => { + component_wise_float!(self, span, [arg, arg1.unwrap()], |e1, e2| { + Ok([e1.powf(e2)]) + }) + } + + // computational + crate::MathFunction::Sign => { + component_wise_signed!(self, span, [arg], |e| { Ok([e.signum()]) }) + } + crate::MathFunction::Fma => { + component_wise_float!( + self, + span, + [arg, arg1.unwrap(), arg2.unwrap()], + |e1, e2, e3| { Ok([e1.mul_add(e2, e3)]) } + ) } crate::MathFunction::Step => { component_wise_float!(self, span, [arg, arg1.unwrap()], |edge, x| { Ok([if edge <= x { 1.0 } else { 0.0 }]) }) } - crate::MathFunction::Trunc => { - component_wise_float!(self, span, [arg], |e| { Ok([e.trunc()]) }) + crate::MathFunction::Sqrt => { + component_wise_float!(self, span, [arg], |e| { Ok([e.sqrt()]) }) + } + crate::MathFunction::InverseSqrt => { + component_wise_float!(self, span, [arg], |e| { Ok([1. / e.sqrt()]) }) } + + // bits + crate::MathFunction::CountTrailingZeros => { + component_wise_concrete_int!(self, span, [arg], |e| { + #[allow(clippy::useless_conversion)] + Ok([e + .trailing_zeros() + .try_into() + .expect("bit count overflowed 32 bits, somehow!?")]) + }) + } + crate::MathFunction::CountLeadingZeros => { + component_wise_concrete_int!(self, span, [arg], |e| { + #[allow(clippy::useless_conversion)] + Ok([e + .leading_zeros() + .try_into() + .expect("bit count overflowed 32 bits, somehow!?")]) + }) + } + crate::MathFunction::CountOneBits => { + component_wise_concrete_int!(self, span, [arg], |e| { + #[allow(clippy::useless_conversion)] + Ok([e + .count_ones() + .try_into() + .expect("bit count overflowed 32 bits, somehow!?")]) + }) + } + crate::MathFunction::ReverseBits => { + component_wise_concrete_int!(self, span, [arg], |e| { Ok([e.reverse_bits()]) }) + } + fun => Err(ConstantEvaluatorError::NotImplemented(format!( "{fun:?} built-in function" ))), From ecd5836aed091569bf13f5fce1df1b6b1b000d97 Mon Sep 17 00:00:00 2001 From: Nathan Adams Date: Tue, 30 Jan 2024 22:04:11 +0100 Subject: [PATCH 083/101] ci: Update to macos-14, xlarge runner is no longer needed (#5165) --- .github/workflows/ci.yml | 10 +++++----- .github/workflows/shaders.yml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index df275a43ab..410fd7b842 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -92,18 +92,18 @@ jobs: # MacOS - name: MacOS x86_64 - os: macos-12 + os: macos-14 target: x86_64-apple-darwin kind: native - name: MacOS aarch64 - os: macos-12 + os: macos-14 target: aarch64-apple-darwin kind: native # IOS - name: IOS aarch64 - os: macos-12 + os: macos-14 target: aarch64-apple-ios kind: native @@ -249,7 +249,7 @@ jobs: # MacOS - name: MacOS x86_64 - os: macos-12 + os: macos-14 target: x86_64-apple-darwin # Linux @@ -383,7 +383,7 @@ jobs: # Mac - name: Mac aarch64 - os: macos-13-xlarge + os: macos-14 # Linux - name: Linux x86_64 diff --git a/.github/workflows/shaders.yml b/.github/workflows/shaders.yml index d598e3ce75..183a459c6c 100644 --- a/.github/workflows/shaders.yml +++ b/.github/workflows/shaders.yml @@ -62,7 +62,7 @@ jobs: naga-validate-macos: name: "Validate: MSL" - runs-on: macos-latest + runs-on: macos-14 steps: - uses: actions/checkout@v4 From 4aab8a839980b6c4c5b236d19e6d899c1d6b85d8 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Thu, 11 Jan 2024 14:09:12 -0500 Subject: [PATCH 084/101] feat(dx12): enable GPU-based validation for DX12 backend Logic for doing this was sourced from . --- d3d12/src/debug.rs | 15 ++++++++++++++- wgpu-hal/src/dx12/instance.rs | 3 +++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/d3d12/src/debug.rs b/d3d12/src/debug.rs index 3a6abc46b7..f321d878d8 100644 --- a/d3d12/src/debug.rs +++ b/d3d12/src/debug.rs @@ -1,7 +1,10 @@ use crate::com::ComPtr; -use winapi::um::d3d12sdklayers; #[cfg(any(feature = "libloading", feature = "implicit-link"))] use winapi::Interface as _; +use winapi::{ + shared::{minwindef::TRUE, winerror::S_OK}, + um::d3d12sdklayers, +}; pub type Debug = ComPtr; @@ -40,4 +43,14 @@ impl Debug { pub fn enable_layer(&self) { unsafe { self.EnableDebugLayer() } } + + pub fn enable_gpu_based_validation(&self) -> bool { + let (ptr, hr) = unsafe { self.cast::() }; + if hr == S_OK { + unsafe { ptr.SetEnableGPUBasedValidation(TRUE) }; + true + } else { + false + } + } } diff --git a/wgpu-hal/src/dx12/instance.rs b/wgpu-hal/src/dx12/instance.rs index 47e4463d2b..d7ed762195 100644 --- a/wgpu-hal/src/dx12/instance.rs +++ b/wgpu-hal/src/dx12/instance.rs @@ -26,6 +26,9 @@ impl crate::Instance for super::Instance { Ok(pair) => match pair.into_result() { Ok(debug_controller) => { debug_controller.enable_layer(); + if !debug_controller.enable_gpu_based_validation() { + log::warn!("Failed to enable GPU-based validation"); + } } Err(err) => { log::warn!("Unable to enable D3D12 debug interface: {}", err); From c28466cc21b0a36b85b9c32d703b255238e56a5d Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 26 Jan 2024 13:16:34 -0500 Subject: [PATCH 085/101] feat: make GPU-based validation opt-in with new `InstanceFlags::GPU_BASED_VALIDATION` --- CHANGELOG.md | 5 +++++ wgpu-hal/src/dx12/instance.rs | 19 +++++++++++++++---- wgpu-types/src/lib.rs | 13 ++++++++++++- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58a01f23eb..839ae0572a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -89,6 +89,11 @@ Bottom level categories: - Eager release of GPU resources comes from device.trackers. By @bradwerth in [#5075](https://github.com/gfx-rs/wgpu/pull/5075) - `wgpu-types`'s `trace` and `replay` features have been replaced by the `serde` feature. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) - `wgpu-core`'s `serial-pass` feature has been removed. Use `serde` instead. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) +- Added `InstanceFlags::GPU_BASED_VALIDATION`, which enables GPU-based validation for shaders. This is currently only supported on the DX12 back end; other platforms ignore this flag, for now. + - This has been added to the set of flags set by `InstanceFlags::debugging` and `InstanceFlags::from_build_config`. If you notice your graphics workloads running more slowly, this may be the culprit. + - As with other instance flags, this flag can be changed in calls to `InstanceFlags::with_env` with the new `WGPU_GPU_BASED_VALIDATION` environment variable. + + By @ErichDonGubler in [#5046](https://github.com/gfx-rs/wgpu/pull/5046). ### Bug Fixes diff --git a/wgpu-hal/src/dx12/instance.rs b/wgpu-hal/src/dx12/instance.rs index d7ed762195..020809328e 100644 --- a/wgpu-hal/src/dx12/instance.rs +++ b/wgpu-hal/src/dx12/instance.rs @@ -20,14 +20,25 @@ impl crate::Instance for super::Instance { crate::InstanceError::with_source(String::from("failed to load d3d12.dll"), e) })?; - if desc.flags.contains(wgt::InstanceFlags::VALIDATION) { + if desc + .flags + .intersects(wgt::InstanceFlags::VALIDATION | wgt::InstanceFlags::GPU_BASED_VALIDATION) + { // Enable debug layer match lib_main.get_debug_interface() { Ok(pair) => match pair.into_result() { Ok(debug_controller) => { - debug_controller.enable_layer(); - if !debug_controller.enable_gpu_based_validation() { - log::warn!("Failed to enable GPU-based validation"); + if desc.flags.intersects(wgt::InstanceFlags::VALIDATION) { + debug_controller.enable_layer(); + } + if desc + .flags + .intersects(wgt::InstanceFlags::GPU_BASED_VALIDATION) + { + #[allow(clippy::collapsible_if)] + if !debug_controller.enable_gpu_based_validation() { + log::warn!("Failed to enable GPU-based validation"); + } } } Err(err) => { diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 7c39c32e03..6cd8c54d07 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -895,6 +895,14 @@ bitflags::bitflags! { /// This mainly applies to a Vulkan driver's compliance version. If the major compliance version /// is `0`, then the driver is ignored. This flag allows that driver to be enabled for testing. const ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER = 1 << 3; + /// Enable GPU-based validation. Currently, this only changes behavior on DX12 and Vulkan + /// back ends. + /// + /// Supported platforms: + /// + /// - D3D12; called ["GPU-based validation", or + /// "GBV"](https://web.archive.org/web/20230206120404/https://learn.microsoft.com/en-us/windows/win32/direct3d12/using-d3d12-debug-layer-gpu-based-validation) + const GPU_BASED_VALIDATION = 1 << 4; } } @@ -907,7 +915,7 @@ impl Default for InstanceFlags { impl InstanceFlags { /// Enable debugging and validation flags. pub fn debugging() -> Self { - InstanceFlags::DEBUG | InstanceFlags::VALIDATION + InstanceFlags::DEBUG | InstanceFlags::VALIDATION | InstanceFlags::GPU_BASED_VALIDATION } /// Infer good defaults from the build type @@ -950,6 +958,9 @@ impl InstanceFlags { if let Some(bit) = env("WGPU_ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER") { self.set(Self::ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER, bit); } + if let Some(bit) = env("WGPU_GPU_BASED_VALIDATION") { + self.set(Self::GPU_BASED_VALIDATION, bit); + } self } From 01f77667a037ba4d37c8d6ac72fe7a88976306cd Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Thu, 11 Jan 2024 15:27:16 -0500 Subject: [PATCH 086/101] docs: note that `InstanceFlags::debugging` enables _all_ recommended flags --- wgpu-types/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 6cd8c54d07..f36c18c54d 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -913,7 +913,7 @@ impl Default for InstanceFlags { } impl InstanceFlags { - /// Enable debugging and validation flags. + /// Enable recommended debugging and validation flags. pub fn debugging() -> Self { InstanceFlags::DEBUG | InstanceFlags::VALIDATION | InstanceFlags::GPU_BASED_VALIDATION } From d239361c1f5d5cfb8cee73382b1e8bc8476e3b29 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Tue, 30 Jan 2024 21:39:20 -0500 Subject: [PATCH 087/101] Update wgpu-types/src/lib.rs --- wgpu-types/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index f36c18c54d..bd3845b75c 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -895,8 +895,8 @@ bitflags::bitflags! { /// This mainly applies to a Vulkan driver's compliance version. If the major compliance version /// is `0`, then the driver is ignored. This flag allows that driver to be enabled for testing. const ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER = 1 << 3; - /// Enable GPU-based validation. Currently, this only changes behavior on DX12 and Vulkan - /// back ends. + /// Enable GPU-based validation. Currently, this only changes behavior on the DX12 + /// backend. /// /// Supported platforms: /// From 0888a630a0ed6400a955e12646cfa7994a6f41d6 Mon Sep 17 00:00:00 2001 From: Brad Werth Date: Tue, 30 Jan 2024 23:15:45 -0800 Subject: [PATCH 088/101] Call device lost callback when it is replaced, or when the global is dropped. (#5168) This fixes two cases where a DeviceLostClosureC might not be consumed before it is dropped, which is a requirement: 1) When the closure is replaced, this ensures the to-be-dropped closure is invoked. 2) When the global is dropped, this ensures that the closure is invoked before it is dropped. The first of these two cases is tested in a new test, DEVICE_LOST_REPLACED_CALLBACK. The second case has a stub, always-skipped test, DROPPED_GLOBAL_THEN_DEVICE_LOST. The test is always-skipped because there does not appear to be a way to drop the global from within a test. Nor is there any other way to reach Device.prepare_to_die without having first dropping the device. --- CHANGELOG.md | 1 + tests/tests/device.rs | 66 ++++++++++++++++++++++++++++++++ wgpu-core/src/device/global.rs | 10 ++++- wgpu-core/src/device/resource.rs | 5 +++ wgpu-types/src/lib.rs | 7 ++++ 5 files changed, 87 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 839ae0572a..99bbcbc48b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -102,6 +102,7 @@ Bottom level categories: - Fix `panic!` when dropping `Instance` without `InstanceFlags::VALIDATION`. By @hakolao in [#5134](https://github.com/gfx-rs/wgpu/pull/5134) - Fix `serde` feature not compiling for `wgpu-types`. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) - Fix the validation of vertex and index ranges. By @nical in [#5144](https://github.com/gfx-rs/wgpu/pull/5144) and [#5156](https://github.com/gfx-rs/wgpu/pull/5156) +- Device lost callbacks are invoked when replaced and when global is dropped. By @bradwerth in [#5168](https://github.com/gfx-rs/wgpu/pull/5168) #### WGL diff --git a/tests/tests/device.rs b/tests/tests/device.rs index 56f5251b92..7743be7242 100644 --- a/tests/tests/device.rs +++ b/tests/tests/device.rs @@ -549,3 +549,69 @@ static DEVICE_DROP_THEN_LOST: GpuTestConfiguration = GpuTestConfiguration::new() "Device lost callback should have been called." ); }); + +#[gpu_test] +static DEVICE_LOST_REPLACED_CALLBACK: GpuTestConfiguration = GpuTestConfiguration::new() + .parameters(TestParameters::default()) + .run_sync(|ctx| { + // This test checks that a device_lost_callback is called when it is + // replaced by another callback. + let was_called = std::sync::Arc::::new(false.into()); + + // Set a LoseDeviceCallback on the device. + let was_called_clone = was_called.clone(); + let callback = Box::new(move |reason, _m| { + was_called_clone.store(true, std::sync::atomic::Ordering::SeqCst); + assert!( + matches!(reason, wgt::DeviceLostReason::ReplacedCallback), + "Device lost info reason should match DeviceLostReason::ReplacedCallback." + ); + }); + ctx.device.set_device_lost_callback(callback); + + // Replace the callback. + let replacement_callback = Box::new(move |_r, _m| {}); + ctx.device.set_device_lost_callback(replacement_callback); + + assert!( + was_called.load(std::sync::atomic::Ordering::SeqCst), + "Device lost callback should have been called." + ); + }); + +#[gpu_test] +static DROPPED_GLOBAL_THEN_DEVICE_LOST: GpuTestConfiguration = GpuTestConfiguration::new() + .parameters(TestParameters::default().skip(FailureCase::always())) + .run_sync(|ctx| { + // What we want to do is to drop the Global, forcing a code path that + // eventually calls Device.prepare_to_die, without having first dropped + // the device. This models what might happen in a user agent that kills + // wgpu without providing a more orderly shutdown. In such a case, the + // device lost callback should be invoked with the message "Device is + // dying." + let was_called = std::sync::Arc::::new(false.into()); + + // Set a LoseDeviceCallback on the device. + let was_called_clone = was_called.clone(); + let callback = Box::new(move |reason, message| { + was_called_clone.store(true, std::sync::atomic::Ordering::SeqCst); + assert!( + matches!(reason, wgt::DeviceLostReason::Dropped), + "Device lost info reason should match DeviceLostReason::Dropped." + ); + assert!( + message == "Device is dying.", + "Device lost info message is \"{}\" and it should be \"Device is dying.\".", + message + ); + }); + ctx.device.set_device_lost_callback(callback); + + // TODO: Drop the Global, somehow. + + // Confirm that the callback was invoked. + assert!( + was_called.load(std::sync::atomic::Ordering::SeqCst), + "Device lost callback should have been called." + ); + }); diff --git a/wgpu-core/src/device/global.rs b/wgpu-core/src/device/global.rs index daa42fddef..a6fe43835c 100644 --- a/wgpu-core/src/device/global.rs +++ b/wgpu-core/src/device/global.rs @@ -2266,8 +2266,8 @@ impl Global { } } - // This closure will be called exactly once during "lose the device" - // or when the device is dropped, if it was never lost. + // This closure will be called exactly once during "lose the device", + // or when it is replaced. pub fn device_set_device_lost_closure( &self, device_id: DeviceId, @@ -2277,6 +2277,12 @@ impl Global { if let Ok(device) = hub.devices.get(device_id) { let mut life_tracker = device.lock_life(); + if let Some(existing_closure) = life_tracker.device_lost_closure.take() { + // It's important to not hold the lock while calling the closure. + drop(life_tracker); + existing_closure.call(DeviceLostReason::ReplacedCallback, "".to_string()); + life_tracker = device.lock_life(); + } life_tracker.device_lost_closure = Some(device_lost_closure); } } diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index b9b942449e..78f7ddee0a 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -3433,6 +3433,11 @@ impl Device { current_index, self.command_allocator.lock().as_mut().unwrap(), ); + if let Some(device_lost_closure) = life_tracker.device_lost_closure.take() { + // It's important to not hold the lock while calling the closure. + drop(life_tracker); + device_lost_closure.call(DeviceLostReason::Dropped, "Device is dying.".to_string()); + } #[cfg(feature = "trace")] { *self.trace.lock() = None; diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index bd3845b75c..34a7f130ff 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -7062,4 +7062,11 @@ pub enum DeviceLostReason { /// we invoke the callback on drop to help with managing memory owned by /// the callback. Dropped = 2, + /// After replacing the device_lost_callback + /// + /// WebGPU does not have a concept of a device lost callback, but wgpu + /// does. wgpu guarantees that any supplied callback will be invoked + /// exactly once before it is dropped, which helps with managing the + /// memory owned by the callback. + ReplacedCallback = 3, } From 45957088ade7b909eb35f57cd254eb1f6c6e2b7f Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Wed, 31 Jan 2024 09:48:33 +0100 Subject: [PATCH 089/101] Fix panic when creating a surface while no backend is available (#5166) * Fix panic when creating a surface while no backend is available * changelog entry --- CHANGELOG.md | 1 + wgpu-core/src/instance.rs | 14 +++++++++++--- wgpu/src/lib.rs | 6 +++--- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 99bbcbc48b..db05ec3608 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -103,6 +103,7 @@ Bottom level categories: - Fix `serde` feature not compiling for `wgpu-types`. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) - Fix the validation of vertex and index ranges. By @nical in [#5144](https://github.com/gfx-rs/wgpu/pull/5144) and [#5156](https://github.com/gfx-rs/wgpu/pull/5156) - Device lost callbacks are invoked when replaced and when global is dropped. By @bradwerth in [#5168](https://github.com/gfx-rs/wgpu/pull/5168) +- Fix panic when creating a surface while no backend is available. By @wumpf [#5166](https://github.com/gfx-rs/wgpu/pull/5166) #### WGL diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 4c3134237e..5ef090defe 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -471,6 +471,15 @@ pub enum RequestAdapterError { InvalidSurface(SurfaceId), } +#[derive(Clone, Debug, Error)] +#[non_exhaustive] +pub enum CreateSurfaceError { + #[error("No backend is available")] + NoSupportedBackend, + #[error(transparent)] + InstanceError(#[from] hal::InstanceError), +} + impl Global { /// # Safety /// @@ -483,7 +492,7 @@ impl Global { display_handle: raw_window_handle::RawDisplayHandle, window_handle: raw_window_handle::RawWindowHandle, id_in: Option, - ) -> Result { + ) -> Result { profiling::scope!("Instance::create_surface"); fn init( @@ -521,8 +530,7 @@ impl Global { hal_surface = init::(&self.instance.gl, display_handle, window_handle); } - // This is only None if there's no instance at all. - let hal_surface = hal_surface.unwrap()?; + let hal_surface = hal_surface.ok_or(CreateSurfaceError::NoSupportedBackend)??; let surface = Surface { presentation: Mutex::new(None), diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 6becc7cde5..1e52369a37 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -2812,7 +2812,7 @@ pub struct CreateSurfaceError { enum CreateSurfaceErrorKind { /// Error from [`wgpu_hal`]. #[cfg(wgpu_core)] - Hal(hal::InstanceError), + Hal(wgc::instance::CreateSurfaceError), /// Error from WebGPU surface creation. #[allow(dead_code)] // may be unused depending on target and features @@ -2847,8 +2847,8 @@ impl error::Error for CreateSurfaceError { } #[cfg(wgpu_core)] -impl From for CreateSurfaceError { - fn from(e: hal::InstanceError) -> Self { +impl From for CreateSurfaceError { + fn from(e: wgc::instance::CreateSurfaceError) -> Self { Self { inner: CreateSurfaceErrorKind::Hal(e), } From 62cc81cbfdb38701a3ce4cb02d52801f6393941e Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Wed, 31 Jan 2024 10:17:59 +0100 Subject: [PATCH 090/101] Allow wgpu::Instance to report which backends were enabled (#5167) * Replace `Instance::any_backend_feature_enabled` with `Instance::enabled_backend_features` which reports all available backends instead of just reporting if none is available. * add changelog entry * update enabled_backend_features in doc * fix not enabling any backend on android, fix related doc issues --- CHANGELOG.md | 6 +++- wgpu/Cargo.toml | 2 +- wgpu/src/lib.rs | 75 ++++++++++++++++++++++++++++++++----------------- 3 files changed, 55 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db05ec3608..f0886693c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -94,7 +94,11 @@ Bottom level categories: - As with other instance flags, this flag can be changed in calls to `InstanceFlags::with_env` with the new `WGPU_GPU_BASED_VALIDATION` environment variable. By @ErichDonGubler in [#5046](https://github.com/gfx-rs/wgpu/pull/5046). - +- `wgpu::Instance` can now report which `wgpu::Backends` are available based on the build configuration. By @wumpf [#5167](https://github.com/gfx-rs/wgpu/pull/5167) +```diff +-wgpu::Instance::any_backend_feature_enabled() ++!wgpu::Instance::enabled_backend_features().is_empty() +``` ### Bug Fixes diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index a0c1926713..2c2b8af2e0 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -29,7 +29,7 @@ default = ["wgsl", "dx12", "metal", "webgpu"] #! ### Backends # -------------------------------------------------------------------- #! ⚠️ WIP: Not all backends can be manually configured today. -#! On Windows & Linux the Vulkan & GLES backends are always enabled. +#! On Windows, Linux & Android the Vulkan & GLES backends are always enabled. #! See [#3514](https://github.com/gfx-rs/wgpu/issues/3514) for more details. ## Enables the DX12 backend on Windows. diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 1e52369a37..11cc1b6a77 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -1748,39 +1748,62 @@ impl Default for Instance { /// # Panics /// /// If no backend feature for the active target platform is enabled, - /// this method will panic, see [`Instance::any_backend_feature_enabled()`]. + /// this method will panic, see [`Instance::enabled_backend_features()`]. fn default() -> Self { Self::new(InstanceDescriptor::default()) } } impl Instance { - /// Returns `true` if any backend feature is enabled for the current build configuration. + /// Returns which backends can be picked for the current build configuration. /// - /// Which feature makes this method return true depends on the target platform: - /// * MacOS/iOS: `metal`, `vulkan-portability` or `angle` - /// * Wasm32: `webgpu`, `webgl` or Emscripten target. - /// * All other: Always returns true + /// The returned set depends on a combination of target platform and enabled features. + /// This does *not* do any runtime checks and is exclusively based on compile time information. /// - /// TODO: Right now it's otherwise not possible yet to opt-out of all features on most platforms. + /// `InstanceDescriptor::backends` does not need to be a subset of this, + /// but any backend that is not in this set, will not be picked. + /// + /// TODO: Right now it's otherwise not possible yet to opt-out of all features on some platforms. /// See - /// * Windows: always enables Vulkan and GLES with no way to opt out - /// * Linux: always enables Vulkan and GLES with no way to opt out - pub const fn any_backend_feature_enabled() -> bool { - // Method intentionally kept verbose to keep it a bit easier to follow! - - // On macOS and iOS, at least one of Metal, Vulkan or GLES backend must be enabled. - let is_mac_or_ios = cfg!(target_os = "macos") || cfg!(target_os = "ios"); - if is_mac_or_ios { - cfg!(feature = "metal") - || cfg!(feature = "vulkan-portability") - || cfg!(feature = "angle") - // On the web, either WebGPU or WebGL must be enabled. - } else if cfg!(target_arch = "wasm32") { - cfg!(feature = "webgpu") || cfg!(feature = "webgl") || cfg!(target_os = "emscripten") + /// * Windows/Linux/Android: always enables Vulkan and GLES with no way to opt out + pub const fn enabled_backend_features() -> Backends { + let mut backends = Backends::empty(); + + if cfg!(native) { + if cfg!(metal) { + backends = backends.union(Backends::METAL); + } + if cfg!(dx12) { + backends = backends.union(Backends::DX12); + } + + // Windows, Android, Linux currently always enable Vulkan and OpenGL. + // See + if cfg!(target_os = "windows") || cfg!(unix) { + backends = backends.union(Backends::VULKAN).union(Backends::GL); + } + + // Vulkan on Mac/iOS is only available through vulkan-portability. + if (cfg!(target_os = "ios") || cfg!(target_os = "macos")) + && cfg!(feature = "vulkan-portability") + { + backends = backends.union(Backends::VULKAN); + } + + // GL Vulkan on Mac is only available through angle. + if cfg!(target_os = "macos") && cfg!(feature = "angle") { + backends = backends.union(Backends::VULKAN); + } } else { - true + if cfg!(webgpu) { + backends = backends.union(Backends::BROWSER_WEBGPU); + } + if cfg!(webgl) { + backends = backends.union(Backends::GL); + } } + + backends } /// Create an new instance of wgpu. @@ -1802,13 +1825,13 @@ impl Instance { /// # Panics /// /// If no backend feature for the active target platform is enabled, - /// this method will panic, see [`Instance::any_backend_feature_enabled()`]. + /// this method will panic, see [`Instance::enabled_backend_features()`]. #[allow(unreachable_code)] pub fn new(_instance_desc: InstanceDescriptor) -> Self { - if !Self::any_backend_feature_enabled() { + if Self::enabled_backend_features().is_empty() { panic!( "No wgpu backend feature that is implemented for the target platform was enabled. \ - See `wgpu::Instance::any_backend_feature_enabled()` for more information." + See `wgpu::Instance::enabled_backend_features()` for more information." ); } @@ -1834,7 +1857,7 @@ impl Instance { } unreachable!( - "Earlier check of `any_backend_feature_enabled` should have prevented getting here!" + "Earlier check of `enabled_backend_features` should have prevented getting here!" ); } From d7bbababa7ffd2708e994df472aae27697de3bfa Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Wed, 31 Jan 2024 15:55:46 +0100 Subject: [PATCH 091/101] Add information to some of the api logging (#5174) --- wgpu-core/src/device/global.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wgpu-core/src/device/global.rs b/wgpu-core/src/device/global.rs index a6fe43835c..cb5438ebba 100644 --- a/wgpu-core/src/device/global.rs +++ b/wgpu-core/src/device/global.rs @@ -645,7 +645,7 @@ impl Global { RwLock::new(TextureInitTracker::new(desc.mip_level_count, 0)); let (id, resource) = fid.assign(texture); - api_log!("Device::create_texture -> {id:?}"); + api_log!("Device::create_texture({desc:?}) -> {id:?}"); device.trackers.lock().textures.insert_single( id, @@ -2339,7 +2339,7 @@ impl Global { range: Range, op: BufferMapOperation, ) -> BufferAccessResult { - api_log!("Buffer::map_async {buffer_id:?}"); + api_log!("Buffer::map_async {buffer_id:?} range {range:?} op: {op:?}"); // User callbacks must not be called while holding buffer_map_async_inner's locks, so we // defer the error callback if it needs to be called immediately (typically when running @@ -2466,7 +2466,7 @@ impl Global { size: Option, ) -> Result<(*mut u8, u64), BufferAccessError> { profiling::scope!("Buffer::get_mapped_range"); - api_log!("Buffer::get_mapped_range {buffer_id:?}"); + api_log!("Buffer::get_mapped_range {buffer_id:?} offset {offset:?} size {size:?}"); let hub = A::hub(self); From 87b6513df32e8a9c588962ba8509019c277438e2 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Thu, 1 Feb 2024 01:24:12 +0100 Subject: [PATCH 092/101] Update docs for `Backend` and implement `std::fmt::Display` (#5170) * Update docs for `Backend` and implement `std::fmt::Display` * Update wgpu-types/src/lib.rs Co-authored-by: Connor Fitzgerald --------- Co-authored-by: Connor Fitzgerald --- tests/src/image.rs | 2 +- wgpu-types/src/lib.rs | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/src/image.rs b/tests/src/image.rs index 4c1f6b8b74..c80edb955d 100644 --- a/tests/src/image.rs +++ b/tests/src/image.rs @@ -183,7 +183,7 @@ pub async fn compare_image_output( let file_stem = reference_path.file_stem().unwrap().to_string_lossy(); let renderer = format!( "{}-{}-{}", - adapter_info.backend.to_str(), + adapter_info.backend, sanitize_for_path(&adapter_info.name), sanitize_for_path(&adapter_info.driver) ); diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 34a7f130ff..8428fb69e3 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -98,13 +98,13 @@ pub const QUERY_SIZE: u32 = 8; pub enum Backend { /// Dummy backend, used for testing. Empty = 0, - /// Vulkan API + /// Vulkan API (Windows, Linux, Android, MacOS via `vulkan-portability`/MoltenVK) Vulkan = 1, /// Metal API (Apple platforms) Metal = 2, /// Direct3D-12 (Windows) Dx12 = 3, - /// OpenGL ES-3 (Linux, Android) + /// OpenGL 3.3+ (Windows), OpenGL ES 3.0+ (Linux, Android, MacOS via Angle), and WebGL2 Gl = 4, /// WebGPU in the browser BrowserWebGpu = 5, @@ -112,7 +112,7 @@ pub enum Backend { impl Backend { /// Returns the string name of the backend. - pub fn to_str(self) -> &'static str { + pub const fn to_str(self) -> &'static str { match self { Backend::Empty => "empty", Backend::Vulkan => "vulkan", @@ -124,6 +124,12 @@ impl Backend { } } +impl std::fmt::Display for Backend { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(self.to_str()) + } +} + /// Power Preference when choosing a physical adapter. /// /// Corresponds to [WebGPU `GPUPowerPreference`]( From d0c52d70fd4e3885e0949269593c2875114182a5 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Thu, 1 Feb 2024 03:29:34 -0500 Subject: [PATCH 093/101] Ord for Id (#5176) --- CHANGELOG.md | 1 + wgpu/src/lib.rs | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0886693c4..ff76b8d889 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -99,6 +99,7 @@ Bottom level categories: -wgpu::Instance::any_backend_feature_enabled() +!wgpu::Instance::enabled_backend_features().is_empty() ``` +- `wgpu::Id` now implements `PartialOrd`/`Ord` allowing it to be put in `BTreeMap`s. By @cwfitzgerald and @9291Sam in [#5176](https://github.com/gfx-rs/wgpu/pull/5176) ### Bug Fixes diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 11cc1b6a77..8c7fed9753 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -75,6 +75,7 @@ mod macros; use std::{ any::Any, borrow::Cow, + cmp::Ordering, error, fmt, future::Future, marker::PhantomData, @@ -4971,6 +4972,18 @@ impl PartialEq for Id { impl Eq for Id {} +impl PartialOrd for Id { + fn partial_cmp(&self, other: &Id) -> Option { + self.0.partial_cmp(&other.0) + } +} + +impl Ord for Id { + fn cmp(&self, other: &Id) -> Ordering { + self.0.cmp(&other.0) + } +} + impl std::hash::Hash for Id { fn hash(&self, state: &mut H) { self.0.hash(state) From c87e3d403738ba1fceaa782959c01ad78918db8d Mon Sep 17 00:00:00 2001 From: ark Date: Wed, 31 Jan 2024 22:22:58 +0100 Subject: [PATCH 094/101] using non alpha channeled texture --- wgpu-hal/src/gles/conv.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/wgpu-hal/src/gles/conv.rs b/wgpu-hal/src/gles/conv.rs index 7b3bf6c8f8..bde69b8629 100644 --- a/wgpu-hal/src/gles/conv.rs +++ b/wgpu-hal/src/gles/conv.rs @@ -115,12 +115,7 @@ impl super::AdapterShared { glow::RGBA, 0, ), - Tf::Etc2Rgba8Unorm => ( - //TODO: this is a lie, it's not sRGB - glow::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, - glow::RGBA, - 0, - ), + Tf::Etc2Rgba8Unorm => (glow::COMPRESSED_RGBA8_ETC2_EAC, glow::RGBA, 0), Tf::Etc2Rgba8UnormSrgb => (glow::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, glow::RGBA, 0), Tf::EacR11Unorm => (glow::COMPRESSED_R11_EAC, glow::RED, 0), Tf::EacR11Snorm => (glow::COMPRESSED_SIGNED_R11_EAC, glow::RED, 0), From 617050ec161279b1ac1f7ad90c831d0262b66071 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Thu, 1 Feb 2024 13:29:50 +0100 Subject: [PATCH 095/101] Always serialize and deserialize ids the same way (#5182) --- wgpu-core/src/id.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/wgpu-core/src/id.rs b/wgpu-core/src/id.rs index 0d5b1cb3fe..5f1e5eefdf 100644 --- a/wgpu-core/src/id.rs +++ b/wgpu-core/src/id.rs @@ -19,10 +19,16 @@ pub const EPOCH_MASK: u32 = (1 << (EPOCH_BITS)) - 1; /// The raw underlying representation of an identifier. #[repr(transparent)] -#[cfg_attr(any(feature = "serde", feature = "trace"), derive(serde::Serialize))] -#[cfg_attr(any(feature = "serde", feature = "replay"), derive(serde::Deserialize))] -#[cfg_attr(feature = "trace", serde(into = "SerialId"))] -#[cfg_attr(feature = "replay", serde(from = "SerialId"))] +#[cfg_attr( + any(feature = "serde", feature = "trace"), + derive(serde::Serialize), + serde(into = "SerialId") +)] +#[cfg_attr( + any(feature = "serde", feature = "replay"), + derive(serde::Deserialize), + serde(from = "SerialId") +)] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct RawId(NonZeroId); @@ -129,7 +135,6 @@ enum SerialId { Id(Index, Epoch, Backend), } -#[cfg(feature = "trace")] impl From for SerialId { fn from(id: RawId) -> Self { let (index, epoch, backend) = id.unzip(); @@ -137,7 +142,6 @@ impl From for SerialId { } } -#[cfg(feature = "replay")] impl From for RawId { fn from(id: SerialId) -> Self { match id { From 84ba4e5461fd1f305f8591cb086c40a488fbdb71 Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Thu, 1 Feb 2024 14:03:46 +0100 Subject: [PATCH 096/101] Remove another unused A: HalApi parameter (#5181) --- wgpu-core/src/track/buffer.rs | 18 +++++++++--------- wgpu-core/src/track/metadata.rs | 20 +++++++------------- wgpu-core/src/track/mod.rs | 20 ++++++++++---------- wgpu-core/src/track/stateless.rs | 13 +++++-------- wgpu-core/src/track/texture.rs | 18 +++++++++--------- 5 files changed, 40 insertions(+), 49 deletions(-) diff --git a/wgpu-core/src/track/buffer.rs b/wgpu-core/src/track/buffer.rs index a9d61f9e00..4c831c4f94 100644 --- a/wgpu-core/src/track/buffer.rs +++ b/wgpu-core/src/track/buffer.rs @@ -109,7 +109,7 @@ impl BufferBindGroupState { pub(crate) struct BufferUsageScope { state: Vec, - metadata: ResourceMetadata>, + metadata: ResourceMetadata>, } impl BufferUsageScope { @@ -287,7 +287,7 @@ pub(crate) struct BufferTracker { start: Vec, end: Vec, - metadata: ResourceMetadata>, + metadata: ResourceMetadata>, temp: Vec>, } @@ -653,11 +653,11 @@ impl BufferStateProvider<'_> { unsafe fn insert_or_merge( start_states: Option<&mut [BufferUses]>, current_states: &mut [BufferUses], - resource_metadata: &mut ResourceMetadata>, + resource_metadata: &mut ResourceMetadata>, index32: u32, index: usize, state_provider: BufferStateProvider<'_>, - metadata_provider: ResourceMetadataProvider<'_, A, Buffer>, + metadata_provider: ResourceMetadataProvider<'_, Buffer>, ) -> Result<(), UsageConflict> { let currently_owned = unsafe { resource_metadata.contains_unchecked(index) }; @@ -708,11 +708,11 @@ unsafe fn insert_or_merge( unsafe fn insert_or_barrier_update( start_states: Option<&mut [BufferUses]>, current_states: &mut [BufferUses], - resource_metadata: &mut ResourceMetadata>, + resource_metadata: &mut ResourceMetadata>, index: usize, start_state_provider: BufferStateProvider<'_>, end_state_provider: Option>, - metadata_provider: ResourceMetadataProvider<'_, A, Buffer>, + metadata_provider: ResourceMetadataProvider<'_, Buffer>, barriers: &mut Vec>, ) { let currently_owned = unsafe { resource_metadata.contains_unchecked(index) }; @@ -742,11 +742,11 @@ unsafe fn insert_or_barrier_update( unsafe fn insert( start_states: Option<&mut [BufferUses]>, current_states: &mut [BufferUses], - resource_metadata: &mut ResourceMetadata>, + resource_metadata: &mut ResourceMetadata>, index: usize, start_state_provider: BufferStateProvider<'_>, end_state_provider: Option>, - metadata_provider: ResourceMetadataProvider<'_, A, Buffer>, + metadata_provider: ResourceMetadataProvider<'_, Buffer>, ) { let new_start_state = unsafe { start_state_provider.get_state(index) }; let new_end_state = @@ -776,7 +776,7 @@ unsafe fn merge( index32: u32, index: usize, state_provider: BufferStateProvider<'_>, - metadata_provider: ResourceMetadataProvider<'_, A, Buffer>, + metadata_provider: ResourceMetadataProvider<'_, Buffer>, ) -> Result<(), UsageConflict> { let current_state = unsafe { current_states.get_unchecked_mut(index) }; let new_state = unsafe { state_provider.get_state(index) }; diff --git a/wgpu-core/src/track/metadata.rs b/wgpu-core/src/track/metadata.rs index 76f6582061..e5f4d5e969 100644 --- a/wgpu-core/src/track/metadata.rs +++ b/wgpu-core/src/track/metadata.rs @@ -1,8 +1,8 @@ //! The `ResourceMetadata` type. -use crate::{hal_api::HalApi, resource::Resource, Epoch}; +use crate::{resource::Resource, Epoch}; use bit_vec::BitVec; -use std::{borrow::Cow, marker::PhantomData, mem, sync::Arc}; +use std::{borrow::Cow, mem, sync::Arc}; use wgt::strict_assert; /// A set of resources, holding a `Arc` and epoch for each member. @@ -13,23 +13,19 @@ use wgt::strict_assert; /// members, but a bit vector tracks occupancy, so iteration touches /// only occupied elements. #[derive(Debug)] -pub(super) struct ResourceMetadata { +pub(super) struct ResourceMetadata { /// If the resource with index `i` is a member, `owned[i]` is `true`. owned: BitVec, /// A vector holding clones of members' `T`s. resources: Vec>>, - - /// This tells Rust that this type should be covariant with `A`. - _phantom: PhantomData, } -impl ResourceMetadata { +impl ResourceMetadata { pub(super) fn new() -> Self { Self { owned: BitVec::default(), resources: Vec::new(), - _phantom: PhantomData, } } @@ -172,15 +168,13 @@ impl ResourceMetadata { /// /// This is used to abstract over the various places /// trackers can get new resource metadata from. -pub(super) enum ResourceMetadataProvider<'a, A: HalApi, T: Resource> { +pub(super) enum ResourceMetadataProvider<'a, T: Resource> { /// Comes directly from explicit values. Direct { resource: Cow<'a, Arc> }, /// Comes from another metadata tracker. - Indirect { - metadata: &'a ResourceMetadata, - }, + Indirect { metadata: &'a ResourceMetadata }, } -impl ResourceMetadataProvider<'_, A, T> { +impl ResourceMetadataProvider<'_, T> { /// Get the epoch and an owned refcount from this. /// /// # Safety diff --git a/wgpu-core/src/track/mod.rs b/wgpu-core/src/track/mod.rs index 68975c931e..a437f95ece 100644 --- a/wgpu-core/src/track/mod.rs +++ b/wgpu-core/src/track/mod.rs @@ -352,9 +352,9 @@ pub(crate) struct RenderBundleScope { pub buffers: RwLock>, pub textures: RwLock>, // Don't need to track views and samplers, they are never used directly, only by bind groups. - pub bind_groups: RwLock>>, - pub render_pipelines: RwLock>>, - pub query_sets: RwLock>>, + pub bind_groups: RwLock>>, + pub render_pipelines: RwLock>>, + pub query_sets: RwLock>>, } impl RenderBundleScope { @@ -489,13 +489,13 @@ where pub(crate) struct Tracker { pub buffers: BufferTracker, pub textures: TextureTracker, - pub views: StatelessTracker>, - pub samplers: StatelessTracker>, - pub bind_groups: StatelessTracker>, - pub compute_pipelines: StatelessTracker>, - pub render_pipelines: StatelessTracker>, - pub bundles: StatelessTracker>, - pub query_sets: StatelessTracker>, + pub views: StatelessTracker>, + pub samplers: StatelessTracker>, + pub bind_groups: StatelessTracker>, + pub compute_pipelines: StatelessTracker>, + pub render_pipelines: StatelessTracker>, + pub bundles: StatelessTracker>, + pub query_sets: StatelessTracker>, } impl Tracker { diff --git a/wgpu-core/src/track/stateless.rs b/wgpu-core/src/track/stateless.rs index c1380e1248..6b1533fd41 100644 --- a/wgpu-core/src/track/stateless.rs +++ b/wgpu-core/src/track/stateless.rs @@ -8,10 +8,7 @@ use std::sync::Arc; use parking_lot::Mutex; -use crate::{ - hal_api::HalApi, id::Id, resource::Resource, resource_log, storage::Storage, - track::ResourceMetadata, -}; +use crate::{id::Id, resource::Resource, resource_log, storage::Storage, track::ResourceMetadata}; use super::ResourceTracker; @@ -73,11 +70,11 @@ impl StatelessBindGroupSate { /// Stores all resource state within a command buffer or device. #[derive(Debug)] -pub(crate) struct StatelessTracker { - metadata: ResourceMetadata, +pub(crate) struct StatelessTracker { + metadata: ResourceMetadata, } -impl ResourceTracker for StatelessTracker { +impl ResourceTracker for StatelessTracker { /// Try to remove the given resource from the tracker iff we have the last reference to the /// resource and the epoch matches. /// @@ -120,7 +117,7 @@ impl ResourceTracker for StatelessTracker { } } -impl StatelessTracker { +impl StatelessTracker { pub fn new() -> Self { Self { metadata: ResourceMetadata::new(), diff --git a/wgpu-core/src/track/texture.rs b/wgpu-core/src/track/texture.rs index f42740bf46..a0cfe8ab75 100644 --- a/wgpu-core/src/track/texture.rs +++ b/wgpu-core/src/track/texture.rs @@ -231,7 +231,7 @@ impl TextureStateSet { #[derive(Debug)] pub(crate) struct TextureUsageScope { set: TextureStateSet, - metadata: ResourceMetadata>, + metadata: ResourceMetadata>, } impl TextureUsageScope { @@ -386,7 +386,7 @@ pub(crate) struct TextureTracker { start_set: TextureStateSet, end_set: TextureStateSet, - metadata: ResourceMetadata>, + metadata: ResourceMetadata>, temp: Vec>, @@ -863,10 +863,10 @@ impl<'a> TextureStateProvider<'a> { unsafe fn insert_or_merge( texture_selector: &TextureSelector, current_state_set: &mut TextureStateSet, - resource_metadata: &mut ResourceMetadata>, + resource_metadata: &mut ResourceMetadata>, index: usize, state_provider: TextureStateProvider<'_>, - metadata_provider: ResourceMetadataProvider<'_, A, Texture>, + metadata_provider: ResourceMetadataProvider<'_, Texture>, ) -> Result<(), UsageConflict> { let currently_owned = unsafe { resource_metadata.contains_unchecked(index) }; @@ -919,11 +919,11 @@ unsafe fn insert_or_barrier_update( texture_selector: &TextureSelector, start_state: Option<&mut TextureStateSet>, current_state_set: &mut TextureStateSet, - resource_metadata: &mut ResourceMetadata>, + resource_metadata: &mut ResourceMetadata>, index: usize, start_state_provider: TextureStateProvider<'_>, end_state_provider: Option>, - metadata_provider: ResourceMetadataProvider<'_, A, Texture>, + metadata_provider: ResourceMetadataProvider<'_, Texture>, barriers: &mut Vec>, ) { let currently_owned = unsafe { resource_metadata.contains_unchecked(index) }; @@ -972,11 +972,11 @@ unsafe fn insert( texture_selector: Option<&TextureSelector>, start_state: Option<&mut TextureStateSet>, end_state: &mut TextureStateSet, - resource_metadata: &mut ResourceMetadata>, + resource_metadata: &mut ResourceMetadata>, index: usize, start_state_provider: TextureStateProvider<'_>, end_state_provider: Option>, - metadata_provider: ResourceMetadataProvider<'_, A, Texture>, + metadata_provider: ResourceMetadataProvider<'_, Texture>, ) { let start_layers = unsafe { start_state_provider.get_state(texture_selector, index) }; match start_layers { @@ -1059,7 +1059,7 @@ unsafe fn merge( current_state_set: &mut TextureStateSet, index: usize, state_provider: TextureStateProvider<'_>, - metadata_provider: ResourceMetadataProvider<'_, A, Texture>, + metadata_provider: ResourceMetadataProvider<'_, Texture>, ) -> Result<(), UsageConflict> { let current_simple = unsafe { current_state_set.simple.get_unchecked_mut(index) }; let current_state = if *current_simple == TextureUses::COMPLEX { From f45d500c1ca33aa16ae82963440449569ff87834 Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Wed, 17 Jan 2024 18:41:02 +0100 Subject: [PATCH 097/101] Remove HalSurface and fix layout assumptions in AnySurface and AnyDerive --- wgpu-core/src/any_surface.rs | 135 +++++++++++++++-------------- wgpu-core/src/device/any_device.rs | 108 ++++++++++++++--------- wgpu-core/src/device/global.rs | 7 +- wgpu-core/src/hal_api.rs | 22 ++--- wgpu-core/src/hub.rs | 8 +- wgpu-core/src/instance.rs | 77 ++++++---------- wgpu-core/src/present.rs | 7 +- wgpu-core/src/resource.rs | 5 +- 8 files changed, 182 insertions(+), 187 deletions(-) diff --git a/wgpu-core/src/any_surface.rs b/wgpu-core/src/any_surface.rs index 48d4b1d45a..cb6f9eb570 100644 --- a/wgpu-core/src/any_surface.rs +++ b/wgpu-core/src/any_surface.rs @@ -1,92 +1,93 @@ use wgt::Backend; -/// The `AnySurface` type: a `Arc` of a `HalSurface` for any backend `A`. +/// The `AnySurface` type: a `Arc` of a `A::Surface` for any backend `A`. use crate::hal_api::HalApi; -use crate::instance::HalSurface; -use std::any::Any; use std::fmt; -use std::sync::Arc; +use std::mem::ManuallyDrop; +use std::ptr::NonNull; -/// A `Arc` of a `HalSurface`, for any backend `A`. +struct AnySurfaceVtable { + // We oppurtunistically store the backend here, since we now it will be used + // with backend selection and it can be stored in static memory. + backend: Backend, + // Drop glue which knows how to drop the stored data. + drop: unsafe fn(*mut ()), +} + +/// An `A::Surface`, for any backend `A`. /// -/// Any `AnySurface` is just like an `Arc>`, except that the -/// `A` type parameter is erased. To access the `Surface`, you must -/// downcast to a particular backend with the \[`downcast_ref`\] or -/// \[`take`\] methods. -pub struct AnySurface(Arc); +/// Any `AnySurface` is just like an `A::Surface`, except that the `A` type +/// parameter is erased. To access the `Surface`, you must downcast to a +/// particular backend with the \[`downcast_ref`\] or \[`take`\] methods. +pub struct AnySurface { + data: NonNull<()>, + vtable: &'static AnySurfaceVtable, +} impl AnySurface { - /// Return an `AnySurface` that holds an owning `Arc` to `HalSurface`. - pub fn new(surface: HalSurface) -> AnySurface { - AnySurface(Arc::new(surface)) + /// Construct an `AnySurface` that owns an `A::Surface`. + pub fn new(surface: A::Surface) -> AnySurface { + unsafe fn drop_glue(ptr: *mut ()) { + unsafe { + _ = Box::from_raw(ptr.cast::()); + } + } + + let data = NonNull::from(Box::leak(Box::new(surface))); + + AnySurface { + data: data.cast(), + vtable: &AnySurfaceVtable { + backend: A::VARIANT, + drop: drop_glue::, + }, + } } + /// Get the backend this surface was created through. pub fn backend(&self) -> Backend { - #[cfg(vulkan)] - if self.downcast_ref::().is_some() { - return Backend::Vulkan; - } - #[cfg(metal)] - if self.downcast_ref::().is_some() { - return Backend::Metal; - } - #[cfg(dx12)] - if self.downcast_ref::().is_some() { - return Backend::Dx12; - } - #[cfg(gles)] - if self.downcast_ref::().is_some() { - return Backend::Gl; - } - Backend::Empty + self.vtable.backend } - /// If `self` is an `Arc>`, return a reference to the - /// HalSurface. - pub fn downcast_ref(&self) -> Option<&HalSurface> { - self.0.downcast_ref::>() + /// If `self` refers to an `A::Surface`, returns a reference to it. + pub fn downcast_ref(&self) -> Option<&A::Surface> { + if A::VARIANT != self.vtable.backend { + return None; + } + + // SAFETY: We just checked the instance above implicitly by the backend + // that it was statically constructed through. + Some(unsafe { &*self.data.as_ptr().cast::() }) } - /// If `self` is an `Arc>`, returns that. - pub fn take(self) -> Option>> { - // `Arc::downcast` returns `Arc`, but requires that `T` be `Sync` and - // `Send`, and this is not the case for `HalSurface` in wasm builds. - // - // But as far as I can see, `Arc::downcast` has no particular reason to - // require that `T` be `Sync` and `Send`; the steps used here are sound. - if (self.0).is::>() { - // Turn the `Arc`, which is a pointer to an `ArcInner` struct, into - // a pointer to the `ArcInner`'s `data` field. Carry along the - // vtable from the original `Arc`. - let raw_erased: *const (dyn Any + 'static) = Arc::into_raw(self.0); - // Remove the vtable, and supply the concrete type of the `data`. - let raw_typed: *const HalSurface = raw_erased.cast::>(); - // Convert the pointer to the `data` field back into a pointer to - // the `ArcInner`, and restore reference-counting behavior. - let arc_typed: Arc> = unsafe { - // Safety: - // - We checked that the `dyn Any` was indeed a `HalSurface` above. - // - We're calling `Arc::from_raw` on the same pointer returned - // by `Arc::into_raw`, except that we stripped off the vtable - // pointer. - // - The pointer must still be live, because we've borrowed `self`, - // which holds another reference to it. - // - The format of a `ArcInner` must be the same as - // that of an `ArcInner>`, or else `AnyHalSurface::new` - // wouldn't be possible. - Arc::from_raw(raw_typed) - }; - Some(arc_typed) - } else { - None + /// If `self` is an `Arc`, returns that. + pub fn take(self) -> Option { + if A::VARIANT != self.vtable.backend { + return None; } + + // Disable drop glue, since we're returning the owned surface. The + // caller will be responsible for dropping it. + let this = ManuallyDrop::new(self); + + // SAFETY: We just checked the instance above implicitly by the backend + // that it was statically constructed through. + Some(unsafe { *Box::from_raw(this.data.as_ptr().cast::()) }) + } +} + +impl Drop for AnySurface { + fn drop(&mut self) { + unsafe { (self.vtable.drop)(self.data.as_ptr()) } } } impl fmt::Debug for AnySurface { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("AnySurface") + f.debug_tuple("AnySurface") + .field(&self.vtable.backend) + .finish() } } diff --git a/wgpu-core/src/device/any_device.rs b/wgpu-core/src/device/any_device.rs index b3c4a31839..d08c23cf99 100644 --- a/wgpu-core/src/device/any_device.rs +++ b/wgpu-core/src/device/any_device.rs @@ -1,72 +1,98 @@ +use wgt::Backend; + use super::Device; /// The `AnyDevice` type: a pointer to a `Device` for any backend `A`. use crate::hal_api::HalApi; -use std::any::Any; use std::fmt; +use std::mem::ManuallyDrop; +use std::ptr::NonNull; use std::sync::Arc; +struct AnyDeviceVtable { + // We oppurtunistically store the backend here, since we now it will be used + // with backend selection and it can be stored in static memory. + backend: Backend, + // Drop glue which knows how to drop the stored data. + drop: unsafe fn(*mut ()), +} + /// A pointer to a `Device`, for any backend `A`. /// -/// Any `AnyDevice` is just like an `Arc>`, except that the -/// `A` type parameter is erased. To access the `Device`, you must -/// downcast to a particular backend with the \[`downcast_ref`\] or -/// \[`downcast_clone`\] methods. -pub struct AnyDevice(Arc); +/// Any `AnyDevice` is just like an `Arc>`, except that the `A` type +/// parameter is erased. To access the `Device`, you must downcast to a +/// particular backend with the \[`downcast_ref`\] or \[`downcast_clone`\] +/// methods. +pub struct AnyDevice { + data: NonNull<()>, + vtable: &'static AnyDeviceVtable, +} impl AnyDevice { /// Return an `AnyDevice` that holds an owning `Arc` pointer to `device`. pub fn new(device: Arc>) -> AnyDevice { - AnyDevice(device) + unsafe fn drop_glue(ptr: *mut ()) { + // Drop the arc this instance is holding. + unsafe { + _ = Arc::from_raw(ptr.cast::()); + } + } + + // SAFETY: The pointer returned by Arc::into_raw is gauranteed to be + // non-null. + let data = unsafe { NonNull::new_unchecked(Arc::into_raw(device).cast_mut()) }; + + AnyDevice { + data: data.cast(), + vtable: &AnyDeviceVtable { + backend: A::VARIANT, + drop: drop_glue::, + }, + } } /// If `self` is an `Arc>`, return a reference to the /// device. pub fn downcast_ref(&self) -> Option<&Device> { - self.0.downcast_ref::>() + if self.vtable.backend != A::VARIANT { + return None; + } + + // SAFETY: We just checked the instance above implicitly by the backend + // that it was statically constructed through. + Some(unsafe { &*(self.data.as_ptr().cast::>()) }) } /// If `self` is an `Arc>`, return a clone of that. pub fn downcast_clone(&self) -> Option>> { - // `Arc::downcast` returns `Arc`, but requires that `T` be `Sync` and - // `Send`, and this is not the case for `Device` in wasm builds. - // - // But as far as I can see, `Arc::downcast` has no particular reason to - // require that `T` be `Sync` and `Send`; the steps used here are sound. - if (self.0).is::>() { - // Get an owned Arc. - let clone = self.0.clone(); - // Turn the `Arc`, which is a pointer to an `ArcInner` struct, into - // a pointer to the `ArcInner`'s `data` field. Carry along the - // vtable from the original `Arc`. - let raw_erased: *const (dyn Any + 'static) = Arc::into_raw(clone); - // Remove the vtable, and supply the concrete type of the `data`. - let raw_typed: *const Device = raw_erased.cast::>(); - // Convert the pointer to the `data` field back into a pointer to - // the `ArcInner`, and restore reference-counting behavior. - let arc_typed: Arc> = unsafe { - // Safety: - // - We checked that the `dyn Any` was indeed a `Device` above. - // - We're calling `Arc::from_raw` on the same pointer returned - // by `Arc::into_raw`, except that we stripped off the vtable - // pointer. - // - The pointer must still be live, because we've borrowed `self`, - // which holds another reference to it. - // - The format of a `ArcInner` must be the same as - // that of an `ArcInner>`, or else `AnyDevice::new` - // wouldn't be possible. - Arc::from_raw(raw_typed) - }; - Some(arc_typed) - } else { - None + if self.vtable.backend != A::VARIANT { + return None; } + + // We need to prevent the destructor of the arc from running, since it + // refers to the instance held by this object. Dropping it would + // invalidate this object. + // + // SAFETY: We just checked the instance above implicitly by the backend + // that it was statically constructed through. + let this = + ManuallyDrop::new(unsafe { Arc::from_raw(self.data.as_ptr().cast::>()) }); + + // Cloning it increases the reference count, and we return a new arc + // instance. + Some((*this).clone()) + } +} + +impl Drop for AnyDevice { + fn drop(&mut self) { + unsafe { (self.vtable.drop)(self.data.as_ptr()) } } } impl fmt::Debug for AnyDevice { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("AnyDevice") + write!(f, "AnyDevice") } } diff --git a/wgpu-core/src/device/global.rs b/wgpu-core/src/device/global.rs index cb5438ebba..6b9a6f6469 100644 --- a/wgpu-core/src/device/global.rs +++ b/wgpu-core/src/device/global.rs @@ -1966,11 +1966,7 @@ impl Global { let caps = unsafe { let suf = A::get_surface(surface); let adapter = &device.adapter; - match adapter - .raw - .adapter - .surface_capabilities(suf.unwrap().raw.as_ref()) - { + match adapter.raw.adapter.surface_capabilities(suf.unwrap()) { Some(caps) => caps, None => break E::UnsupportedQueueFamily, } @@ -2055,7 +2051,6 @@ impl Global { match unsafe { A::get_surface(surface) .unwrap() - .raw .configure(device.raw(), &hal_config) } { Ok(()) => (), diff --git a/wgpu-core/src/hal_api.rs b/wgpu-core/src/hal_api.rs index 7de5073791..179024baed 100644 --- a/wgpu-core/src/hal_api.rs +++ b/wgpu-core/src/hal_api.rs @@ -3,7 +3,7 @@ use wgt::{Backend, WasmNotSendSync}; use crate::{ global::Global, hub::Hub, - instance::{HalSurface, Instance, Surface}, + instance::{Instance, Surface}, }; pub trait HalApi: hal::Api + 'static + WasmNotSendSync { @@ -11,7 +11,7 @@ pub trait HalApi: hal::Api + 'static + WasmNotSendSync { fn create_instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance; fn instance_as_hal(instance: &Instance) -> Option<&Self::Instance>; fn hub(global: &Global) -> &Hub; - fn get_surface(surface: &Surface) -> Option<&HalSurface>; + fn get_surface(surface: &Surface) -> Option<&Self::Surface>; } impl HalApi for hal::api::Empty { @@ -25,7 +25,7 @@ impl HalApi for hal::api::Empty { fn hub(_: &Global) -> &Hub { unimplemented!("called empty api") } - fn get_surface(_: &Surface) -> Option<&HalSurface> { + fn get_surface(_: &Surface) -> Option<&Self::Surface> { unimplemented!("called empty api") } } @@ -46,8 +46,8 @@ impl HalApi for hal::api::Vulkan { fn hub(global: &Global) -> &Hub { &global.hubs.vulkan } - fn get_surface(surface: &Surface) -> Option<&HalSurface> { - surface.raw.downcast_ref() + fn get_surface(surface: &Surface) -> Option<&Self::Surface> { + surface.raw.downcast_ref::() } } @@ -67,8 +67,8 @@ impl HalApi for hal::api::Metal { fn hub(global: &Global) -> &Hub { &global.hubs.metal } - fn get_surface(surface: &Surface) -> Option<&HalSurface> { - surface.raw.downcast_ref() + fn get_surface(surface: &Surface) -> Option<&Self::Surface> { + surface.raw.downcast_ref::() } } @@ -88,8 +88,8 @@ impl HalApi for hal::api::Dx12 { fn hub(global: &Global) -> &Hub { &global.hubs.dx12 } - fn get_surface(surface: &Surface) -> Option<&HalSurface> { - surface.raw.downcast_ref() + fn get_surface(surface: &Surface) -> Option<&Self::Surface> { + surface.raw.downcast_ref::() } } @@ -110,7 +110,7 @@ impl HalApi for hal::api::Gles { fn hub(global: &Global) -> &Hub { &global.hubs.gl } - fn get_surface(surface: &Surface) -> Option<&HalSurface> { - surface.raw.downcast_ref() + fn get_surface(surface: &Surface) -> Option<&Self::Surface> { + surface.raw.downcast_ref::() } } diff --git a/wgpu-core/src/hub.rs b/wgpu-core/src/hub.rs index 7829484aa8..0f4589c8b3 100644 --- a/wgpu-core/src/hub.rs +++ b/wgpu-core/src/hub.rs @@ -109,7 +109,7 @@ use crate::{ command::{CommandBuffer, RenderBundle}, device::{queue::Queue, Device}, hal_api::HalApi, - instance::{Adapter, HalSurface, Surface}, + instance::{Adapter, Surface}, pipeline::{ComputePipeline, RenderPipeline, ShaderModule}, registry::{Registry, RegistryReport}, resource::{Buffer, QuerySet, Sampler, StagingBuffer, Texture, TextureView}, @@ -243,7 +243,7 @@ impl Hub { if let Some(device) = present.device.downcast_ref::() { let suf = A::get_surface(surface); unsafe { - suf.unwrap().raw.unconfigure(device.raw()); + suf.unwrap().unconfigure(device.raw()); //TODO: we could destroy the surface here } } @@ -260,10 +260,10 @@ impl Hub { } } - pub(crate) fn surface_unconfigure(&self, device: &Device, surface: &HalSurface) { + pub(crate) fn surface_unconfigure(&self, device: &Device, surface: &A::Surface) { unsafe { use hal::Surface; - surface.raw.unconfigure(device.raw()); + surface.unconfigure(device.raw()); } } diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 5ef090defe..582571c2b8 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -21,11 +21,6 @@ use thiserror::Error; pub type RequestAdapterOptions = wgt::RequestAdapterOptions; type HalInstance = ::Instance; -//TODO: remove this -#[derive(Clone)] -pub struct HalSurface { - pub raw: Arc, -} #[derive(Clone, Debug, Error)] #[error("Limit '{name}' value {requested} is better than allowed {allowed}")] @@ -118,30 +113,22 @@ impl Instance { } pub(crate) fn destroy_surface(&self, surface: Surface) { - fn destroy(_: A, instance: &Option, surface: AnySurface) { + fn destroy(instance: &Option, surface: AnySurface) { unsafe { - if let Some(surface) = surface.take::() { - if let Some(suf) = Arc::into_inner(surface) { - if let Some(raw) = Arc::into_inner(suf.raw) { - instance.as_ref().unwrap().destroy_surface(raw); - } else { - panic!("Surface cannot be destroyed because is still in use"); - } - } else { - panic!("Surface cannot be destroyed because is still in use"); - } + if let Some(suf) = surface.take::() { + instance.as_ref().unwrap().destroy_surface(suf); } } } match surface.raw.backend() { #[cfg(vulkan)] - Backend::Vulkan => destroy(hal::api::Vulkan, &self.vulkan, surface.raw), + Backend::Vulkan => destroy::(&self.vulkan, surface.raw), #[cfg(metal)] - Backend::Metal => destroy(hal::api::Metal, &self.metal, surface.raw), + Backend::Metal => destroy::(&self.metal, surface.raw), #[cfg(dx12)] - Backend::Dx12 => destroy(hal::api::Dx12, &self.dx12, surface.raw), + Backend::Dx12 => destroy::(&self.dx12, surface.raw), #[cfg(gles)] - Backend::Gl => destroy(hal::api::Gles, &self.gl, surface.raw), + Backend::Gl => destroy::(&self.gl, surface.raw), _ => unreachable!(), } } @@ -182,7 +169,7 @@ impl Surface { adapter .raw .adapter - .surface_capabilities(&suf.raw) + .surface_capabilities(suf) .ok_or(GetSurfaceSupportError::Unsupported)? }; @@ -223,7 +210,7 @@ impl Adapter { // This could occur if the user is running their app on Wayland but Vulkan does not support // VK_KHR_wayland_surface. match suf { - Some(suf) => unsafe { self.raw.adapter.surface_capabilities(&suf.raw) }.is_some(), + Some(suf) => unsafe { self.raw.adapter.surface_capabilities(suf) }.is_some(), None => false, } } @@ -502,7 +489,7 @@ impl Global { ) -> Option> { inst.as_ref().map(|inst| unsafe { match inst.create_surface(display_handle, window_handle) { - Ok(raw) => Ok(AnySurface::new(HalSurface:: { raw: Arc::new(raw) })), + Ok(raw) => Ok(AnySurface::new::(raw)), Err(e) => Err(e), } }) @@ -557,19 +544,17 @@ impl Global { presentation: Mutex::new(None), info: ResourceInfo::new(""), raw: { - let hal_surface: HalSurface = self + let hal_surface = self .instance .metal .as_ref() - .map(|inst| HalSurface { - raw: Arc::new( - // we don't want to link to metal-rs for this - #[allow(clippy::transmute_ptr_to_ref)] - inst.create_surface_from_layer(unsafe { std::mem::transmute(layer) }), - ), //acquired_texture: None, + .map(|inst| { + // we don't want to link to metal-rs for this + #[allow(clippy::transmute_ptr_to_ref)] + inst.create_surface_from_layer(unsafe { std::mem::transmute(layer) }) }) .unwrap(); - AnySurface::new(hal_surface) + AnySurface::new::(hal_surface) }, }; @@ -592,15 +577,13 @@ impl Global { presentation: Mutex::new(None), info: ResourceInfo::new(""), raw: { - let hal_surface: HalSurface = self + let hal_surface = self .instance .dx12 .as_ref() - .map(|inst| HalSurface { - raw: Arc::new(unsafe { inst.create_surface_from_visual(visual as _) }), - }) + .map(|inst| unsafe { inst.create_surface_from_visual(visual as _) }) .unwrap(); - AnySurface::new(hal_surface) + AnySurface::new::(hal_surface) }, }; @@ -623,17 +606,13 @@ impl Global { presentation: Mutex::new(None), info: ResourceInfo::new(""), raw: { - let hal_surface: HalSurface = self + let hal_surface = self .instance .dx12 .as_ref() - .map(|inst| HalSurface { - raw: Arc::new(unsafe { - inst.create_surface_from_surface_handle(surface_handle) - }), - }) + .map(|inst| unsafe { inst.create_surface_from_surface_handle(surface_handle) }) .unwrap(); - AnySurface::new(hal_surface) + AnySurface::new::(hal_surface) }, }; @@ -656,17 +635,15 @@ impl Global { presentation: Mutex::new(None), info: ResourceInfo::new(""), raw: { - let hal_surface: HalSurface = self + let hal_surface = self .instance .dx12 .as_ref() - .map(|inst| HalSurface { - raw: Arc::new(unsafe { - inst.create_surface_from_swap_chain_panel(swap_chain_panel as _) - }), + .map(|inst| unsafe { + inst.create_surface_from_swap_chain_panel(swap_chain_panel as _) }) .unwrap(); - AnySurface::new(hal_surface) + AnySurface::new::(hal_surface) }, }; @@ -814,7 +791,7 @@ impl Global { surface.is_some() && exposed .adapter - .surface_capabilities(&surface.unwrap().raw) + .surface_capabilities(surface.unwrap()) .is_some() }); } diff --git a/wgpu-core/src/present.rs b/wgpu-core/src/present.rs index 2452825aea..4d8e1df73e 100644 --- a/wgpu-core/src/present.rs +++ b/wgpu-core/src/present.rs @@ -163,7 +163,6 @@ impl Global { let suf = A::get_surface(surface.as_ref()); let (texture_id, status) = match unsafe { suf.unwrap() - .raw .acquire_texture(Some(std::time::Duration::from_millis( FRAME_TIMEOUT_MS as u64, ))) @@ -339,7 +338,7 @@ impl Global { Err(hal::SurfaceError::Lost) } else if !has_work.load(Ordering::Relaxed) { log::error!("No work has been submitted for this frame"); - unsafe { suf.unwrap().raw.discard_texture(raw.take().unwrap()) }; + unsafe { suf.unwrap().discard_texture(raw.take().unwrap()) }; Err(hal::SurfaceError::Outdated) } else { unsafe { @@ -347,7 +346,7 @@ impl Global { .raw .as_ref() .unwrap() - .present(&suf.unwrap().raw, raw.take().unwrap()) + .present(suf.unwrap(), raw.take().unwrap()) } } } @@ -427,7 +426,7 @@ impl Global { has_work: _, } => { if surface_id == parent_id { - unsafe { suf.unwrap().raw.discard_texture(raw.take().unwrap()) }; + unsafe { suf.unwrap().discard_texture(raw.take().unwrap()) }; } else { log::warn!("Surface texture is outdated"); } diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index 07af19e14f..cc3ac2780d 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -1007,10 +1007,7 @@ impl Global { profiling::scope!("Surface::as_hal"); let surface = self.surfaces.get(id).ok(); - let hal_surface = surface - .as_ref() - .and_then(|surface| A::get_surface(surface)) - .map(|surface| &*surface.raw); + let hal_surface = surface.as_ref().and_then(|surface| A::get_surface(surface)); hal_surface_callback(hal_surface) } From c038b5c433aeb3bc55f2091da56216e3f1c07e74 Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Thu, 1 Feb 2024 05:42:47 +0100 Subject: [PATCH 098/101] Consistent debug formatting --- wgpu-core/src/any_surface.rs | 4 +--- wgpu-core/src/device/any_device.rs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/wgpu-core/src/any_surface.rs b/wgpu-core/src/any_surface.rs index cb6f9eb570..94edfc4433 100644 --- a/wgpu-core/src/any_surface.rs +++ b/wgpu-core/src/any_surface.rs @@ -85,9 +85,7 @@ impl Drop for AnySurface { impl fmt::Debug for AnySurface { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("AnySurface") - .field(&self.vtable.backend) - .finish() + write!(f, "AnySurface<{}>", self.vtable.backend) } } diff --git a/wgpu-core/src/device/any_device.rs b/wgpu-core/src/device/any_device.rs index d08c23cf99..43ea9411d4 100644 --- a/wgpu-core/src/device/any_device.rs +++ b/wgpu-core/src/device/any_device.rs @@ -92,7 +92,7 @@ impl Drop for AnyDevice { impl fmt::Debug for AnyDevice { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "AnyDevice") + write!(f, "AnyDevice<{}>", self.vtable.backend) } } From 41133c4579d680ee2e4b39a9f3d7a3846eae75de Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Sat, 3 Feb 2024 14:48:45 -0800 Subject: [PATCH 099/101] WIP fix rebase --- wgpu-core/src/command/ray_tracing.rs | 11 +++-- wgpu-core/src/device/ray_tracing.rs | 11 +++-- wgpu-core/src/hub.rs | 40 +++++++++-------- wgpu-core/src/id.rs | 6 +-- wgpu-core/src/identity.rs | 66 ---------------------------- wgpu-core/src/resource.rs | 22 ++++++---- wgpu-core/src/track/mod.rs | 38 +++++++++------- 7 files changed, 67 insertions(+), 127 deletions(-) diff --git a/wgpu-core/src/command/ray_tracing.rs b/wgpu-core/src/command/ray_tracing.rs index c161686597..8324fb99f6 100644 --- a/wgpu-core/src/command/ray_tracing.rs +++ b/wgpu-core/src/command/ray_tracing.rs @@ -3,8 +3,7 @@ use crate::{ device::queue::TempResource, global::Global, hal_api::HalApi, - id::{BlasId, CommandEncoderId, TlasId}, - identity::GlobalIdentityHandlerFactory, + id::CommandEncoderId, init_tracker::MemoryInitKind, ray_tracing::{ tlas_instance_into_bytes, BlasAction, BlasBuildEntry, BlasGeometries, @@ -32,7 +31,7 @@ use super::BakedCommands; // This should be queried from the device, maybe the the hal api should pre aline it, since I am unsure how else we can idiomatically get this value. const SCRATCH_BUFFER_ALIGNMENT: u32 = 256; -impl Global { +impl Global { pub fn command_encoder_build_acceleration_structures_unsafe_tlas<'a, A: HalApi>( &self, command_encoder_id: CommandEncoderId, @@ -1557,7 +1556,7 @@ impl BakedCommands { // makes sure a blas is build before it is used pub(crate) fn validate_blas_actions( &mut self, - blas_guard: &mut Storage, BlasId>, + blas_guard: &mut Storage>, ) -> Result<(), ValidateBlasActionsError> { profiling::scope!("CommandEncoder::[submission]::validate_blas_actions"); let mut built = FastHashSet::default(); @@ -1588,8 +1587,8 @@ impl BakedCommands { // makes sure a tlas is build before it is used pub(crate) fn validate_tlas_actions( &mut self, - blas_guard: &Storage, BlasId>, - tlas_guard: &mut Storage, TlasId>, + blas_guard: &Storage>, + tlas_guard: &mut Storage>, ) -> Result<(), ValidateTlasActionsError> { profiling::scope!("CommandEncoder::[submission]::validate_tlas_actions"); for action in self.tlas_actions.drain(..) { diff --git a/wgpu-core/src/device/ray_tracing.rs b/wgpu-core/src/device/ray_tracing.rs index f329847f3c..1925b06b64 100644 --- a/wgpu-core/src/device/ray_tracing.rs +++ b/wgpu-core/src/device/ray_tracing.rs @@ -5,7 +5,6 @@ use crate::{ global::Global, hal_api::HalApi, id::{self, BlasId, TlasId}, - identity::{GlobalIdentityHandlerFactory, Input}, ray_tracing::{get_raw_tlas_instance_size, CreateBlasError, CreateTlasError}, resource, LabelHelpers, }; @@ -156,18 +155,18 @@ impl Device { } } -impl Global { +impl Global { pub fn device_create_blas( &self, device_id: id::DeviceId, desc: &resource::BlasDescriptor, sizes: wgt::BlasGeometrySizeDescriptors, - id_in: Input, + id_in: Option, ) -> (BlasId, Option, Option) { profiling::scope!("Device::create_blas"); let hub = A::hub(self); - let fid = hub.blas_s.prepare::(id_in); + let fid = hub.blas_s.prepare(id_in); let device_guard = hub.devices.read(); let error = loop { @@ -210,12 +209,12 @@ impl Global { &self, device_id: id::DeviceId, desc: &resource::TlasDescriptor, - id_in: Input, + id_in: Option, ) -> (TlasId, Option) { profiling::scope!("Device::create_tlas"); let hub = A::hub(self); - let fid = hub.tlas_s.prepare::(id_in); + let fid = hub.tlas_s.prepare(id_in); let device_guard = hub.devices.read(); let error = loop { diff --git a/wgpu-core/src/hub.rs b/wgpu-core/src/hub.rs index f9c55f43df..b88b710382 100644 --- a/wgpu-core/src/hub.rs +++ b/wgpu-core/src/hub.rs @@ -186,30 +186,32 @@ pub struct Hub { pub textures: Registry>, pub texture_views: Registry>, pub samplers: Registry>, - pub blas_s: Registry>, - pub tlas_s: Registry>, + pub blas_s: Registry>, + pub tlas_s: Registry>, } impl Hub { fn new() -> Self { Self { - adapters: Registry::new(A::VARIANT, factory), - devices: Registry::new(A::VARIANT, factory), - queues: Registry::new(A::VARIANT, factory), - pipeline_layouts: Registry::new(A::VARIANT, factory), - shader_modules: Registry::new(A::VARIANT, factory), - bind_group_layouts: Registry::new(A::VARIANT, factory), - bind_groups: Registry::new(A::VARIANT, factory), - command_buffers: Registry::new(A::VARIANT, factory), - render_bundles: Registry::new(A::VARIANT, factory), - render_pipelines: Registry::new(A::VARIANT, factory), - compute_pipelines: Registry::new(A::VARIANT, factory), - query_sets: Registry::new(A::VARIANT, factory), - buffers: Registry::new(A::VARIANT, factory), - staging_buffers: Registry::new(A::VARIANT, factory), - textures: Registry::new(A::VARIANT, factory), - texture_views: Registry::new(A::VARIANT, factory), - samplers: Registry::new(A::VARIANT, factory), + adapters: Registry::new(A::VARIANT), + devices: Registry::new(A::VARIANT), + queues: Registry::new(A::VARIANT), + pipeline_layouts: Registry::new(A::VARIANT), + shader_modules: Registry::new(A::VARIANT), + bind_group_layouts: Registry::new(A::VARIANT), + bind_groups: Registry::new(A::VARIANT), + command_buffers: Registry::new(A::VARIANT), + render_bundles: Registry::new(A::VARIANT), + render_pipelines: Registry::new(A::VARIANT), + compute_pipelines: Registry::new(A::VARIANT), + query_sets: Registry::new(A::VARIANT), + buffers: Registry::new(A::VARIANT), + staging_buffers: Registry::new(A::VARIANT), + textures: Registry::new(A::VARIANT), + texture_views: Registry::new(A::VARIANT), + samplers: Registry::new(A::VARIANT), + blas_s: Registry::new(A::VARIANT), + tlas_s: Registry::new(A::VARIANT), } } diff --git a/wgpu-core/src/id.rs b/wgpu-core/src/id.rs index d40e7423bd..cb7fe9dc88 100644 --- a/wgpu-core/src/id.rs +++ b/wgpu-core/src/id.rs @@ -347,12 +347,10 @@ ids! { pub type RenderBundleEncoderId RenderBundleEncoder; pub type RenderBundleId RenderBundle; pub type QuerySetId QuerySet; + pub type BlasId Blas; + pub type TlasId Tlas; } -// Ray tracing -pub type BlasId = Id>; -pub type TlasId = Id>; - #[test] fn test_id_backend() { for &b in &[ diff --git a/wgpu-core/src/identity.rs b/wgpu-core/src/identity.rs index c0175c582e..0e34055c74 100644 --- a/wgpu-core/src/identity.rs +++ b/wgpu-core/src/identity.rs @@ -112,72 +112,6 @@ impl IdentityManager { } } -/// A type that can produce [`IdentityManager`] filters for ids of type `I`. -/// -/// See the module-level documentation for details. -pub trait IdentityHandlerFactory { - type Input: Copy; - /// Create an [`IdentityManager`] implementation that can - /// transform proto-ids into ids of type `I`. - /// It can return None if ids are passed from outside - /// and are not generated by wgpu - /// - /// [`IdentityManager`]: IdentityManager - fn spawn(&self) -> Arc> { - Arc::new(IdentityManager::new()) - } - fn autogenerate_ids() -> bool; - fn input_to_id(id_in: Self::Input) -> I; -} - -/// A global identity handler factory based on [`IdentityManager`]. -/// -/// Each of this type's `IdentityHandlerFactory::spawn` methods -/// returns a `Mutex>`, which allocates fresh `I` -/// ids itself, and takes `()` as its proto-id type. -#[derive(Debug)] -pub struct IdentityManagerFactory; - -impl IdentityHandlerFactory for IdentityManagerFactory { - type Input = (); - fn autogenerate_ids() -> bool { - true - } - - fn input_to_id(_id_in: Self::Input) -> I { - unreachable!("It should not be called") - } -} - -/// A factory that can build [`IdentityManager`]s for all resource -/// types. -pub trait GlobalIdentityHandlerFactory: - IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory -{ -} - -impl GlobalIdentityHandlerFactory for IdentityManagerFactory {} - -pub type Input = >::Input; - #[test] fn test_epoch_end_of_life() { use crate::id; diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index 3a1663e032..f9763687a9 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -36,7 +36,7 @@ use std::{ }, }; -use crate::id::{BlasId, TlasId}; +use crate::id::BlasId; use std::num::NonZeroU64; /// Information about the wgpu-core resource. @@ -1544,7 +1544,7 @@ pub type TlasDescriptor<'a> = wgt::CreateTlasDescriptor>; pub struct Blas { pub(crate) raw: Option, pub(crate) device: Arc>, - pub(crate) info: ResourceInfo, + pub(crate) info: ResourceInfo>, pub(crate) size_info: hal::AccelerationStructureBuildSizes, pub(crate) sizes: wgt::BlasGeometrySizeDescriptors, pub(crate) flags: wgt::AccelerationStructureFlags, @@ -1569,14 +1569,16 @@ impl Drop for Blas { } } -impl Resource for Blas { +impl Resource for Blas { const TYPE: &'static str = "Blas"; - fn as_info(&self) -> &ResourceInfo { + type Marker = crate::id::markers::Blas; + + fn as_info(&self) -> &ResourceInfo { &self.info } - fn as_info_mut(&mut self) -> &mut ResourceInfo { + fn as_info_mut(&mut self) -> &mut ResourceInfo { &mut self.info } } @@ -1585,7 +1587,7 @@ impl Resource for Blas { pub struct Tlas { pub(crate) raw: Option, pub(crate) device: Arc>, - pub(crate) info: ResourceInfo, + pub(crate) info: ResourceInfo>, pub(crate) size_info: hal::AccelerationStructureBuildSizes, pub(crate) max_instance_count: u32, pub(crate) flags: wgt::AccelerationStructureFlags, @@ -1614,14 +1616,16 @@ impl Drop for Tlas { } } -impl Resource for Tlas { +impl Resource for Tlas { const TYPE: &'static str = "Tlas"; - fn as_info(&self) -> &ResourceInfo { + type Marker = crate::id::markers::Tlas; + + fn as_info(&self) -> &ResourceInfo { &self.info } - fn as_info_mut(&mut self) -> &mut ResourceInfo { + fn as_info_mut(&mut self) -> &mut ResourceInfo { &mut self.info } } diff --git a/wgpu-core/src/track/mod.rs b/wgpu-core/src/track/mod.rs index d39abc06a0..0fa3647350 100644 --- a/wgpu-core/src/track/mod.rs +++ b/wgpu-core/src/track/mod.rs @@ -320,7 +320,7 @@ pub(crate) struct BindGroupStates { pub textures: TextureBindGroupState, pub views: StatelessBindGroupSate>, pub samplers: StatelessBindGroupSate>, - pub acceleration_structures: StatelessBindGroupSate>, + pub acceleration_structures: StatelessBindGroupSate>, } impl BindGroupStates { @@ -492,13 +492,15 @@ where pub(crate) struct Tracker { pub buffers: BufferTracker, pub textures: TextureTracker, - pub views: StatelessTracker>, - pub samplers: StatelessTracker>, - pub bind_groups: StatelessTracker>, - pub compute_pipelines: StatelessTracker>, - pub render_pipelines: StatelessTracker>, - pub bundles: StatelessTracker>, - pub query_sets: StatelessTracker>, + pub views: StatelessTracker>, + pub samplers: StatelessTracker>, + pub bind_groups: StatelessTracker>, + pub compute_pipelines: StatelessTracker>, + pub render_pipelines: StatelessTracker>, + pub bundles: StatelessTracker>, + pub query_sets: StatelessTracker>, + pub blas_s: StatelessTracker>, + pub tlas_s: StatelessTracker>, } impl Tracker { @@ -521,15 +523,17 @@ impl Tracker { /// Pull the maximum IDs from the hubs. pub fn set_size( &mut self, - buffers: Option<&Storage, id::BufferId>>, - textures: Option<&Storage, id::TextureId>>, - views: Option<&Storage, id::TextureViewId>>, - samplers: Option<&Storage, id::SamplerId>>, - bind_groups: Option<&Storage, id::BindGroupId>>, - compute_pipelines: Option<&Storage, id::ComputePipelineId>>, - render_pipelines: Option<&Storage, id::RenderPipelineId>>, - bundles: Option<&Storage, id::RenderBundleId>>, - query_sets: Option<&Storage, id::QuerySetId>>, + buffers: Option<&Storage>>, + textures: Option<&Storage>>, + views: Option<&Storage>>, + samplers: Option<&Storage>>, + bind_groups: Option<&Storage>>, + compute_pipelines: Option<&Storage>>, + render_pipelines: Option<&Storage>>, + bundles: Option<&Storage>>, + query_sets: Option<&Storage>>, + blas_s: Option<&Storage>>, + tlas_s: Option<&Storage>>, ) { if let Some(buffers) = buffers { self.buffers.set_size(buffers.len()); From 41fe261bb4040781c57f5ccaa775405e726c7179 Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Sat, 3 Feb 2024 22:30:23 -0800 Subject: [PATCH 100/101] Fix compile issues --- player/src/lib.rs | 4 +-- wgpu-types/src/lib.rs | 57 ++++++++++++++++------------------- wgpu/src/backend/wgpu_core.rs | 4 +-- 3 files changed, 30 insertions(+), 35 deletions(-) diff --git a/player/src/lib.rs b/player/src/lib.rs index b471f393a1..9913ba6d17 100644 --- a/player/src/lib.rs +++ b/player/src/lib.rs @@ -460,7 +460,7 @@ impl GlobalPlay for wgc::global::Global { } Action::CreateBlas { id, desc, sizes } => { self.device_maintain_ids::(device).unwrap(); - self.device_create_blas::(device, &desc, sizes, id); + self.device_create_blas::(device, &desc, sizes, Some(id)); } Action::FreeBlas(id) => { self.blas_destroy::(id).unwrap(); @@ -470,7 +470,7 @@ impl GlobalPlay for wgc::global::Global { } Action::CreateTlas { id, desc } => { self.device_maintain_ids::(device).unwrap(); - self.device_create_tlas::(device, &desc, id); + self.device_create_tlas::(device, &desc, Some(id)); } Action::FreeTlas(id) => { self.tlas_destroy::(id).unwrap(); diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index ac09dffcc0..a9ca11ee69 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -94,7 +94,7 @@ pub const QUERY_SIZE: u32 = 8; /// Backends supported by wgpu. #[repr(u8)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum Backend { /// Dummy backend, used for testing. Empty = 0, @@ -1385,7 +1385,7 @@ impl Limits { /// Represents the sets of additional limits on an adapter, /// which take place when running on downlevel backends. #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct DownlevelLimits {} #[allow(unknown_lints)] // derivable_impls is nightly only currently @@ -1398,7 +1398,7 @@ impl Default for DownlevelLimits { /// Lists various ways the underlying platform does not conform to the WebGPU standard. #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct DownlevelCapabilities { /// Combined boolean flags. pub flags: DownlevelFlags, @@ -1607,7 +1607,7 @@ impl DownlevelFlags { /// Collections of shader features a device supports if they support less than WebGPU normally allows. // TODO: Fill out the differences between shader models more completely #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum ShaderModel { /// Extremely limited shaders, including a total instruction limit. Sm2, @@ -1620,7 +1620,7 @@ pub enum ShaderModel { /// Supported physical device types. #[repr(u8)] #[derive(Clone, Copy, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum DeviceType { /// Other or Unknown. Other, @@ -1638,7 +1638,7 @@ pub enum DeviceType { /// Information about an adapter. #[derive(Clone, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct AdapterInfo { /// Adapter name pub name: String, @@ -2216,7 +2216,7 @@ impl_bitflags!(TextureFormatFeatureFlags); /// /// Features are defined by WebGPU specification unless `Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES` is enabled. #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct TextureFormatFeatures { /// Valid bits for `TextureDescriptor::Usage` provided for format creation. pub allowed_usages: TextureUsages, @@ -2227,7 +2227,7 @@ pub struct TextureFormatFeatures { /// ASTC block dimensions #[repr(C)] #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum AstcBlock { /// 4x4 block compressed texture. 16 bytes per block (8 bit/px). B4x4, @@ -2262,7 +2262,7 @@ pub enum AstcBlock { /// ASTC RGBA channel #[repr(C)] #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum AstcChannel { /// 8 bit integer RGBA, [0, 255] converted to/from linear-color float [0, 1] in shader. /// @@ -5255,7 +5255,7 @@ impl PresentationTimestamp { /// This is not to be used as a generic color type, only for specific wgpu interfaces. #[repr(C)] #[derive(Clone, Copy, Debug, Default, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] pub struct Color { /// Red component of the color @@ -5850,7 +5850,7 @@ impl CommandBufferDescriptor { /// https://gpuweb.github.io/gpuweb/#dictdef-gpurenderbundleencoderdescriptor). #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct RenderBundleDepthStencil { /// Format of the attachment. pub format: TextureFormat, @@ -5913,7 +5913,7 @@ impl Default for RenderBundleDescriptor> { /// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagedatalayout). #[repr(C)] #[derive(Clone, Copy, Debug, Default)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct ImageDataLayout { /// Offset into the buffer that is the start of the texture. Must be a multiple of texture block size. /// For non-compressed textures, this is 1. @@ -6355,7 +6355,7 @@ pub struct BindGroupLayoutEntry { /// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopybuffer). #[repr(C)] #[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct ImageCopyBuffer { /// The buffer to be copied to/from. pub buffer: B, @@ -6369,7 +6369,7 @@ pub struct ImageCopyBuffer { /// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopytexture). #[repr(C)] #[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct ImageCopyTexture { /// The texture to be copied to/from. pub texture: T, @@ -6501,7 +6501,7 @@ unsafe impl Sync for ExternalImageSource {} /// Corresponds to [HTML Canvas `PredefinedColorSpace`]( /// https://html.spec.whatwg.org/multipage/canvas.html#predefinedcolorspace). #[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum PredefinedColorSpace { /// sRGB color space @@ -6516,7 +6516,7 @@ pub enum PredefinedColorSpace { /// Corresponds to [WebGPU `GPUImageCopyTextureTagged`]( /// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopytexturetagged). #[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct ImageCopyTextureTagged { /// The texture to be copied to/from. pub texture: T, @@ -6547,7 +6547,7 @@ impl ImageCopyTextureTagged { /// Subresource range within an image #[repr(C)] #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] pub struct ImageSubresourceRange { /// Aspect of the texture. Color textures must be [`TextureAspect::All`][TAA]. @@ -6648,7 +6648,7 @@ impl ImageSubresourceRange { /// Color variation to use when sampler addressing mode is [`AddressMode::ClampToBorder`] #[repr(C)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum SamplerBorderColor { /// [0, 0, 0, 0] TransparentBlack, @@ -6670,7 +6670,7 @@ pub enum SamplerBorderColor { /// Corresponds to [WebGPU `GPUQuerySetDescriptor`]( /// https://gpuweb.github.io/gpuweb/#dictdef-gpuquerysetdescriptor). #[derive(Clone, Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct QuerySetDescriptor { /// Debug label for the query set. pub label: L, @@ -6697,7 +6697,7 @@ impl QuerySetDescriptor { /// Corresponds to [WebGPU `GPUQueryType`]( /// https://gpuweb.github.io/gpuweb/#enumdef-gpuquerytype). #[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum QueryType { /// Query returns a single 64-bit number, serving as an occlusion boolean. Occlusion, @@ -6843,7 +6843,7 @@ impl DispatchIndirectArgs { /// Describes how shader bound checks should be performed. #[derive(Clone, Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct ShaderBoundChecks { runtime_checks: bool, } @@ -6953,8 +6953,7 @@ impl Default for InstanceDescriptor { } #[derive(Clone, Debug, PartialEq, Eq)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] /// Descriptor for all size definiing attributes of a single triangle geometry inside a bottom level acceleration structure. pub struct BlasTriangleGeometrySizeDescriptor { /// Format of a vertex position. @@ -6972,8 +6971,7 @@ pub struct BlasTriangleGeometrySizeDescriptor { } #[derive(Clone, Debug)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] /// Descriptor for all size definiing attributes of all geometries inside a bottom level acceleration structure. pub enum BlasGeometrySizeDescriptors { /// Triangle geometry version. @@ -6985,8 +6983,7 @@ pub enum BlasGeometrySizeDescriptors { #[repr(u8)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] /// Update mode for acceleration structure builds. pub enum AccelerationStructureUpdateMode { /// Allwasy perform a full build. @@ -6999,8 +6996,7 @@ pub enum AccelerationStructureUpdateMode { #[repr(C)] #[derive(Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] /// Descriptor for creating a bottom level acceleration structure. pub struct CreateBlasDescriptor { /// Label for the bottom level acceleration structure. @@ -7024,8 +7020,7 @@ impl CreateBlasDescriptor { #[repr(C)] #[derive(Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "trace", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] /// Descriptor for creating a top level acceleration structure. pub struct CreateTlasDescriptor { /// Label for the top level acceleration structure. diff --git a/wgpu/src/backend/wgpu_core.rs b/wgpu/src/backend/wgpu_core.rs index 525c49dec4..51853513f2 100644 --- a/wgpu/src/backend/wgpu_core.rs +++ b/wgpu/src/backend/wgpu_core.rs @@ -2938,7 +2938,7 @@ impl crate::Context for ContextWgpuCore { *device, &desc.map_label(|l| l.map(Borrowed)), sizes, - () + None, )); if let Some(cause) = error { self.handle_error( @@ -2968,7 +2968,7 @@ impl crate::Context for ContextWgpuCore { let (id, error) = wgc::gfx_select!(device => global.device_create_tlas( *device, &desc.map_label(|l| l.map(Borrowed)), - () + None, )); if let Some(cause) = error { self.handle_error( From d94cbebfdb9e5dfd07795b86d15e0c0f71291a3d Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Sat, 3 Feb 2024 22:35:14 -0800 Subject: [PATCH 101/101] More fixes --- wgpu-core/src/ray_tracing.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/wgpu-core/src/ray_tracing.rs b/wgpu-core/src/ray_tracing.rs index 2ae30a2491..4dba07cb52 100644 --- a/wgpu-core/src/ray_tracing.rs +++ b/wgpu-core/src/ray_tracing.rs @@ -153,8 +153,7 @@ pub struct BlasBuildEntry<'a> { } #[derive(Debug, Clone)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TlasBuildEntry { pub tlas_id: TlasId, pub instance_buffer_id: BufferId, @@ -203,8 +202,7 @@ pub(crate) struct TlasAction { } #[derive(Debug, Clone)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TraceBlasTriangleGeometry { pub size: wgt::BlasTriangleGeometrySizeDescriptor, pub vertex_buffer: BufferId, @@ -217,23 +215,20 @@ pub struct TraceBlasTriangleGeometry { } #[derive(Debug, Clone)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum TraceBlasGeometries { TriangleGeometries(Vec), } #[derive(Debug, Clone)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TraceBlasBuildEntry { pub blas_id: BlasId, pub geometries: TraceBlasGeometries, } #[derive(Debug, Clone)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TraceTlasInstance { pub blas_id: BlasId, pub transform: [f32; 12], @@ -242,8 +237,7 @@ pub struct TraceTlasInstance { } #[derive(Debug, Clone)] -#[cfg_attr(feature = "trace", derive(serde::Serialize))] -#[cfg_attr(feature = "replay", derive(serde::Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TraceTlasPackage { pub tlas_id: TlasId, pub instances: Vec>,