From 8c3b38f37aaf3afd467cdc59d95192be7a7101d5 Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Wed, 23 Apr 2025 13:38:56 +1000 Subject: [PATCH 1/4] MVP `no_std` support in `wgpu-hal` --- .github/workflows/ci.yml | 2 ++ Cargo.lock | 1 + Cargo.toml | 2 +- deno_webgpu/Cargo.toml | 2 +- examples/features/Cargo.toml | 1 + player/Cargo.toml | 2 +- tests/Cargo.toml | 1 + wgpu-hal/Cargo.toml | 10 +++++-- wgpu-hal/src/auxil/dxgi/exception.rs | 1 + wgpu-hal/src/gles/mod.rs | 1 + wgpu-hal/src/lib.rs | 43 ++++------------------------ wgpu-hal/src/validation_canary.rs | 39 +++++++++++++++++++++++++ wgpu-hal/src/vulkan/instance.rs | 1 + 13 files changed, 64 insertions(+), 42 deletions(-) create mode 100644 wgpu-hal/src/validation_canary.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2e5030c153..19de6f5896 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -301,9 +301,11 @@ jobs: # check with no features cargo clippy --target ${{ matrix.target }} ${{ matrix.extra-flags }} -p wgpu-types --no-default-features + cargo clippy --target ${{ matrix.target }} ${{ matrix.extra-flags }} -p wgpu-hal --no-default-features # Check with all features except "std". cargo clippy --target ${{ matrix.target }} ${{ matrix.extra-flags }} -p wgpu-types --no-default-features --features strict_asserts,fragile-send-sync-non-atomic-wasm,serde,counters + cargo clippy --target ${{ matrix.target }} ${{ matrix.extra-flags }} -p wgpu-hal --no-default-features --features fragile-send-sync-non-atomic-wasm # Building for native platforms with standard tests. - name: Check native diff --git a/Cargo.lock b/Cargo.lock index 509c9aa217..5d67e800fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4919,6 +4919,7 @@ dependencies = [ "wasm-bindgen-test", "web-sys", "wgpu", + "wgpu-hal", "wgpu-macros", ] diff --git a/Cargo.toml b/Cargo.toml index 0d425aeea2..0c0e65287b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -74,7 +74,7 @@ wgpu-core = { version = "25.0.0", path = "./wgpu-core" } wgpu-hal = { version = "25.0.0", path = "./wgpu-hal" } wgpu-macros = { version = "25.0.0", path = "./wgpu-macros" } wgpu-test = { version = "25.0.0", path = "./tests" } -wgpu-types = { version = "25.0.0", path = "./wgpu-types" } +wgpu-types = { version = "25.0.0", path = "./wgpu-types", default-features = false } wgpu-core-deps-windows-linux-android = { version = "25.0.0", path = "./wgpu-core/platform-deps/windows-linux-android" } wgpu-core-deps-apple = { version = "25.0.0", path = "./wgpu-core/platform-deps/apple" } diff --git a/deno_webgpu/Cargo.toml b/deno_webgpu/Cargo.toml index 29786bf4c1..08545ef8d2 100644 --- a/deno_webgpu/Cargo.toml +++ b/deno_webgpu/Cargo.toml @@ -25,7 +25,7 @@ wgpu-core = { workspace = true, features = [ "wgsl", "gles", ] } -wgpu-types = { workspace = true, features = ["serde"] } +wgpu-types = { workspace = true, features = ["serde", "std"] } deno_core.workspace = true deno_error.workspace = true diff --git a/examples/features/Cargo.toml b/examples/features/Cargo.toml index 2df3ca318c..93ca92b37d 100644 --- a/examples/features/Cargo.toml +++ b/examples/features/Cargo.toml @@ -45,6 +45,7 @@ png.workspace = true pollster.workspace = true web-time.workspace = true wgpu-types = { workspace = true, features = [ + "std", "trace", # TODO(#5974): this should be a dep on wgpu/trace and not wgpu-types at all ] } winit.workspace = true diff --git a/player/Cargo.toml b/player/Cargo.toml index 0f0346ece7..aadf4e5e8f 100644 --- a/player/Cargo.toml +++ b/player/Cargo.toml @@ -19,7 +19,7 @@ name = "play" test = false [dependencies] -wgpu-types = { workspace = true, features = ["serde"] } +wgpu-types = { workspace = true, features = ["serde", "std"] } env_logger.workspace = true log.workspace = true diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 5c206d4ba8..5e741847e5 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -32,6 +32,7 @@ webgl = ["wgpu/webgl"] [dependencies] wgpu = { workspace = true, features = ["noop"] } +wgpu-hal = { workspace = true, features = ["validation_canary"] } wgpu-macros.workspace = true anyhow.workspace = true diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index 8ec740d60f..ffeeb988c8 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -81,6 +81,7 @@ metal = [ "dep:log", "dep:metal", "dep:objc", + "dep:parking_lot", "dep:profiling", ] vulkan = [ @@ -96,6 +97,7 @@ vulkan = [ "dep:libloading", "dep:log", "dep:ordered-float", + "dep:parking_lot", "dep:profiling", "dep:smallvec", "dep:windows", @@ -115,6 +117,7 @@ gles = [ "dep:log", "dep:ndk-sys", "dep:objc", + "dep:parking_lot", "dep:profiling", "dep:wasm-bindgen", "dep:web-sys", @@ -133,6 +136,7 @@ dx12 = [ "dep:libloading", "dep:log", "dep:ordered-float", + "dep:parking_lot", "dep:profiling", "dep:range-alloc", "dep:windows-core", @@ -174,6 +178,8 @@ device_lost_panic = [] # # Only affects the d3d12 and vulkan backends. internal_error_panic = [] +# Tracks validation errors in a `VALIDATION_CANARY` static. +validation_canary = ["dep:parking_lot"] ################### ### Workarounds ### @@ -196,12 +202,12 @@ required-features = ["gles"] [dependencies] naga.workspace = true -wgpu-types.workspace = true +wgpu-types = { workspace = true, default-features = false } # Dependencies in the lib and empty backend bitflags.workspace = true raw-window-handle.workspace = true -parking_lot.workspace = true +parking_lot = { workspace = true, optional = true } thiserror.workspace = true # Target agnostic dependencies used only in backends. diff --git a/wgpu-hal/src/auxil/dxgi/exception.rs b/wgpu-hal/src/auxil/dxgi/exception.rs index dcc8cc9a4b..537f6c10a2 100644 --- a/wgpu-hal/src/auxil/dxgi/exception.rs +++ b/wgpu-hal/src/auxil/dxgi/exception.rs @@ -86,6 +86,7 @@ unsafe extern "system" fn output_debug_string_handler( log::log!(level, "{}", message); }); + #[cfg(feature = "validation_canary")] if cfg!(debug_assertions) && level == log::Level::Error { // Set canary and continue crate::VALIDATION_CANARY.add(message.to_string()); diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 94b169daa1..a33cc7216c 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -1086,6 +1086,7 @@ fn gl_debug_message_callback(source: u32, gltype: u32, id: u32, severity: u32, m ); }); + #[cfg(feature = "validation_canary")] if cfg!(debug_assertions) && log_severity == log::Level::Error { // Set canary and continue crate::VALIDATION_CANARY.add(message.to_string()); diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 7618b0ea3e..cb4d233285 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -276,6 +276,12 @@ pub mod api { mod dynamic; +#[cfg(feature = "validation_canary")] +mod validation_canary; + +#[cfg(feature = "validation_canary")] +pub use validation_canary::{ValidationCanary, VALIDATION_CANARY}; + pub(crate) use dynamic::impl_dyn_resource; pub use dynamic::{ DynAccelerationStructure, DynAcquiredSurfaceTexture, DynAdapter, DynBindGroup, @@ -298,7 +304,6 @@ use core::{ }; use bitflags::bitflags; -use parking_lot::Mutex; use thiserror::Error; use wgt::WasmNotSendSync; @@ -2374,42 +2379,6 @@ pub struct ComputePassDescriptor<'a, Q: DynQuerySet + ?Sized> { pub timestamp_writes: Option>, } -/// Stores the text of any validation errors that have occurred since -/// the last call to `get_and_reset`. -/// -/// Each value is a validation error and a message associated with it, -/// or `None` if the error has no message from the api. -/// -/// This is used for internal wgpu testing only and _must not_ be used -/// as a way to check for errors. -/// -/// This works as a static because `cargo nextest` runs all of our -/// tests in separate processes, so each test gets its own canary. -/// -/// This prevents the issue of one validation error terminating the -/// entire process. -pub static VALIDATION_CANARY: ValidationCanary = ValidationCanary { - inner: Mutex::new(Vec::new()), -}; - -/// Flag for internal testing. -pub struct ValidationCanary { - inner: Mutex>, -} - -impl ValidationCanary { - #[allow(dead_code)] // in some configurations this function is dead - fn add(&self, msg: String) { - self.inner.lock().push(msg); - } - - /// Returns any API validation errors that have occurred in this process - /// since the last call to this function. - pub fn get_and_reset(&self) -> Vec { - self.inner.lock().drain(..).collect() - } -} - #[test] fn test_default_limits() { let limits = wgt::Limits::default(); diff --git a/wgpu-hal/src/validation_canary.rs b/wgpu-hal/src/validation_canary.rs new file mode 100644 index 0000000000..65b197e209 --- /dev/null +++ b/wgpu-hal/src/validation_canary.rs @@ -0,0 +1,39 @@ +use alloc::{string::String, vec::Vec}; + +use parking_lot::Mutex; + +/// Stores the text of any validation errors that have occurred since +/// the last call to `get_and_reset`. +/// +/// Each value is a validation error and a message associated with it, +/// or `None` if the error has no message from the api. +/// +/// This is used for internal wgpu testing only and _must not_ be used +/// as a way to check for errors. +/// +/// This works as a static because `cargo nextest` runs all of our +/// tests in separate processes, so each test gets its own canary. +/// +/// This prevents the issue of one validation error terminating the +/// entire process. +pub static VALIDATION_CANARY: ValidationCanary = ValidationCanary { + inner: Mutex::new(Vec::new()), +}; + +/// Flag for internal testing. +pub struct ValidationCanary { + inner: Mutex>, +} + +impl ValidationCanary { + #[allow(dead_code)] // in some configurations this function is dead + fn add(&self, msg: String) { + self.inner.lock().push(msg); + } + + /// Returns any API validation errors that have occurred in this process + /// since the last call to this function. + pub fn get_and_reset(&self) -> Vec { + self.inner.lock().drain(..).collect() + } +} diff --git a/wgpu-hal/src/vulkan/instance.rs b/wgpu-hal/src/vulkan/instance.rs index 6426e4b6ea..32625f757f 100644 --- a/wgpu-hal/src/vulkan/instance.rs +++ b/wgpu-hal/src/vulkan/instance.rs @@ -145,6 +145,7 @@ unsafe extern "system" fn debug_utils_messenger_callback( }); } + #[cfg(feature = "validation_canary")] if cfg!(debug_assertions) && level == log::Level::Error { // Set canary and continue crate::VALIDATION_CANARY.add(message.to_string()); From cf06ad4879d3a0091a91c2c776552fa18b419d3f Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Wed, 23 Apr 2025 13:46:35 +1000 Subject: [PATCH 2/4] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 944af45653..9b9e111117 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,6 +73,10 @@ Naga now infers the correct binding layout when a resource appears only in an as - Remove the need for dxil.dll. By @teoxoy in [#7566](https://github.com/gfx-rs/wgpu/pull/7566) +#### HAL + +- Added initial `no_std` support to `wgpu-hal`. By @bushrat011899 in [#7599](https://github.com/gfx-rs/wgpu/pull/7599) + ### Bug Fixes #### Naga From ca6ace151422f5e041d81208908bedd2f1adb8e2 Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Wed, 23 Apr 2025 13:47:49 +1000 Subject: [PATCH 3/4] Fix visibility --- wgpu-hal/src/validation_canary.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wgpu-hal/src/validation_canary.rs b/wgpu-hal/src/validation_canary.rs index 65b197e209..37e4175486 100644 --- a/wgpu-hal/src/validation_canary.rs +++ b/wgpu-hal/src/validation_canary.rs @@ -27,7 +27,7 @@ pub struct ValidationCanary { impl ValidationCanary { #[allow(dead_code)] // in some configurations this function is dead - fn add(&self, msg: String) { + pub(crate) fn add(&self, msg: String) { self.inner.lock().push(msg); } From fe3cae4b6c930d6c173b080eede5e2bc1e8d8e1f Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Wed, 23 Apr 2025 13:52:41 +1000 Subject: [PATCH 4/4] Fix unused imports --- wgpu-hal/src/auxil/dxgi/exception.rs | 8 ++++---- wgpu-hal/src/vulkan/instance.rs | 12 ++++-------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/wgpu-hal/src/auxil/dxgi/exception.rs b/wgpu-hal/src/auxil/dxgi/exception.rs index 537f6c10a2..65bec3b43c 100644 --- a/wgpu-hal/src/auxil/dxgi/exception.rs +++ b/wgpu-hal/src/auxil/dxgi/exception.rs @@ -1,11 +1,11 @@ -use alloc::{ - borrow::Cow, - string::{String, ToString as _}, -}; +use alloc::{borrow::Cow, string::String}; use parking_lot::Mutex; use windows::Win32::{Foundation, System::Diagnostics::Debug}; +#[cfg(feature = "validation_canary")] +use alloc::string::ToString as _; + // This is a mutex as opposed to an atomic as we need to completely // lock everyone out until we have registered or unregistered the // exception handler, otherwise really nasty races could happen. diff --git a/wgpu-hal/src/vulkan/instance.rs b/wgpu-hal/src/vulkan/instance.rs index 32625f757f..892a775f02 100644 --- a/wgpu-hal/src/vulkan/instance.rs +++ b/wgpu-hal/src/vulkan/instance.rs @@ -1,11 +1,4 @@ -use alloc::{ - borrow::ToOwned as _, - boxed::Box, - ffi::CString, - string::{String, ToString as _}, - sync::Arc, - vec::Vec, -}; +use alloc::{borrow::ToOwned as _, boxed::Box, ffi::CString, string::String, sync::Arc, vec::Vec}; use core::{ ffi::{c_void, CStr}, slice, @@ -17,6 +10,9 @@ use arrayvec::ArrayVec; use ash::{ext, khr, vk}; use parking_lot::RwLock; +#[cfg(feature = "validation_canary")] +use alloc::string::ToString as _; + unsafe extern "system" fn debug_utils_messenger_callback( message_severity: vk::DebugUtilsMessageSeverityFlagsEXT, message_type: vk::DebugUtilsMessageTypeFlagsEXT,