diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a371cec5186..c9449f0a118 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -302,10 +302,12 @@ 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 naga --no-default-features + cargo clippy --target ${{ matrix.target }} ${{ matrix.extra-flags }} -p wgpu-hal --no-default-features # Check with all compatible features 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 naga --no-default-features --features dot-out,compact + 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/CHANGELOG.md b/CHANGELOG.md index da28485901e..a951f182938 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -106,6 +106,10 @@ Naga now infers the correct binding layout when a resource appears only in an as - The type of the `size` parameter to `copy_buffer_to_buffer` has changed from `BufferAddress` to `impl Into>`. This achieves the spec-defined behavior of the value being optional, while still accepting existing calls without changes. By @andyleiserson in [#7659](https://github.com/gfx-rs/wgpu/pull/7659). +#### HAL + +- Added initial `no_std` support to `wgpu-hal`. By @bushrat011899 in [#7599](https://github.com/gfx-rs/wgpu/pull/7599) + ### Bug Fixes #### Naga diff --git a/Cargo.lock b/Cargo.lock index 6909582af8c..1102bf9b7a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4927,10 +4927,10 @@ dependencies = [ "naga", "ndk-sys 0.6.0+11769913", "objc", - "once_cell", "ordered-float", "parking_lot", "portable-atomic", + "portable-atomic-util", "profiling", "range-alloc", "raw-window-handle 0.5.2", @@ -5007,6 +5007,7 @@ dependencies = [ "wasm-bindgen-test", "web-sys", "wgpu", + "wgpu-hal", "wgpu-macros", ] diff --git a/Cargo.toml b/Cargo.toml index a3b49c50cca..75b1c8df90a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -78,7 +78,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 } # These _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 @@ -159,7 +159,8 @@ pico-args = { version = "0.5", features = [ ] } png = "0.17.6" pollster = "0.4" -portable-atomic = "1.2" +portable-atomic = "1.8" +portable-atomic-util = "0.2.4" pp-rs = "0.2.1" profiling = { version = "1", default-features = false } quote = "1.0.38" diff --git a/deno_webgpu/Cargo.toml b/deno_webgpu/Cargo.toml index 29786bf4c11..08545ef8d2a 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 2df3ca318cf..93ca92b37dc 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 0f0346ece7b..aadf4e5e8ff 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 5c206d4ba80..5e741847e50 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 4f48698173f..94dc0e07e0c 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", @@ -105,7 +107,6 @@ gles = [ "naga/glsl-out", "dep:arrayvec", "dep:bytemuck", - "dep:cfg-if", "dep:glow", "dep:glutin_wgl_sys", "dep:hashbrown", @@ -115,6 +116,7 @@ gles = [ "dep:log", "dep:ndk-sys", "dep:objc", + "dep:parking_lot", "dep:profiling", "dep:wasm-bindgen", "dep:web-sys", @@ -134,6 +136,7 @@ dx12 = [ "dep:libloading", "dep:log", "dep:ordered-float", + "dep:parking_lot", "dep:profiling", "dep:range-alloc", "dep:windows-core", @@ -161,7 +164,7 @@ renderdoc = ["dep:libloading", "dep:renderdoc-sys", "dep:log"] fragile-send-sync-non-atomic-wasm = [ "wgpu-types/fragile-send-sync-non-atomic-wasm", ] -portable-atomic = ["dep:portable-atomic"] +portable-atomic = ["dep:portable-atomic", "dep:portable-atomic-util"] ################################### ### Internal Debugging Features ### @@ -175,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 ### @@ -197,12 +202,13 @@ 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 +cfg-if.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. @@ -210,14 +216,12 @@ arrayvec = { workspace = true, optional = true } bytemuck = { workspace = true, optional = true, features = ["derive"] } hashbrown = { workspace = true, optional = true } log = { workspace = true, optional = true } -once_cell = { workspace = true, optional = true } ordered-float = { workspace = true, optional = true } profiling = { workspace = true, optional = true, default-features = false } rustc-hash = { workspace = true, optional = true } # Backend: GLES glow = { workspace = true, optional = true } -cfg-if = { workspace = true, optional = true } ######################## ### Platform: Native ### @@ -312,14 +316,18 @@ khronos-egl = { workspace = true, optional = true, features = [ # Note: it's unused by emscripten, but we keep it to have single code base in egl.rs libloading = { workspace = true, optional = true } -[target.'cfg(not(target_has_atomic = "64"))'.dependencies] +[target.'cfg(any(not(target_has_atomic = "64"), not(target_has_atomic = "ptr")))'.dependencies] portable-atomic = { workspace = true, optional = true } +[target.'cfg(not(target_has_atomic = "ptr"))'.dependencies] +portable-atomic-util = { workspace = true, features = [ + "alloc", +], optional = true } + [build-dependencies] cfg_aliases.workspace = true [dev-dependencies] -cfg-if.workspace = true env_logger.workspace = true glam.workspace = true # for ray-traced-triangle example naga = { workspace = true, features = ["wgsl-in", "termcolor"] } diff --git a/wgpu-hal/build.rs b/wgpu-hal/build.rs index 960f6453008..a89db73d53c 100644 --- a/wgpu-hal/build.rs +++ b/wgpu-hal/build.rs @@ -25,6 +25,7 @@ fn main() { vulkan: { all(not(target_arch = "wasm32"), feature = "vulkan") }, // ⚠️ Keep in sync with target.cfg() definition in Cargo.toml and cfg_alias in `wgpu` crate ⚠️ static_dxc: { all(target_os = "windows", feature = "static-dxc", not(target_arch = "aarch64")) }, - supports_64bit_atomics: { target_has_atomic = "64" } + supports_64bit_atomics: { target_has_atomic = "64" }, + supports_ptr_atomics: { target_has_atomic = "ptr" } } } diff --git a/wgpu-hal/src/auxil/dxgi/exception.rs b/wgpu-hal/src/auxil/dxgi/exception.rs index dcc8cc9a4b4..b938da31ffa 100644 --- a/wgpu-hal/src/auxil/dxgi/exception.rs +++ b/wgpu-hal/src/auxil/dxgi/exception.rs @@ -1,7 +1,4 @@ -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}; @@ -86,7 +83,10 @@ unsafe extern "system" fn output_debug_string_handler( log::log!(level, "{}", message); }); + #[cfg(feature = "validation_canary")] if cfg!(debug_assertions) && level == log::Level::Error { + use alloc::string::ToString as _; + // 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 c09fc21d248..c96973281c3 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -1087,6 +1087,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 b469aa4f443..ae3b087b229 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -275,6 +275,11 @@ 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::{ @@ -287,7 +292,7 @@ pub use dynamic::{ #[allow(unused)] use alloc::boxed::Box; -use alloc::{borrow::Cow, string::String, sync::Arc, vec::Vec}; +use alloc::{borrow::Cow, string::String, vec::Vec}; use core::{ borrow::Borrow, error::Error, @@ -298,10 +303,17 @@ use core::{ }; use bitflags::bitflags; -use parking_lot::Mutex; use thiserror::Error; use wgt::WasmNotSendSync; +cfg_if::cfg_if! { + if #[cfg(supports_ptr_atomics)] { + use alloc::sync::Arc; + } else if #[cfg(feature = "portable-atomic")] { + use portable_atomic_util::Arc; + } +} + // - Vertex + Fragment // - Compute // Task + Mesh + Fragment @@ -446,9 +458,18 @@ impl InstanceError { } #[allow(dead_code)] // may be unused on some platforms pub(crate) fn with_source(message: String, source: impl Error + Send + Sync + 'static) -> Self { + cfg_if::cfg_if! { + if #[cfg(supports_ptr_atomics)] { + let source = Arc::new(source); + } else { + // TODO(https://github.com/rust-lang/rust/issues/18598): avoid indirection via Box once arbitrary types support unsized coercion + let source: Box = Box::new(source); + let source = Arc::from(source); + } + } Self { message, - source: Some(Arc::new(source)), + source: Some(source), } } } @@ -2375,42 +2396,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/noop/buffer.rs b/wgpu-hal/src/noop/buffer.rs index 6e9572ef8fe..9b8ab17a1fb 100644 --- a/wgpu-hal/src/noop/buffer.rs +++ b/wgpu-hal/src/noop/buffer.rs @@ -1,6 +1,14 @@ -use alloc::{sync::Arc, vec::Vec}; +use alloc::vec::Vec; use core::{cell::UnsafeCell, ops::Range, ptr}; +cfg_if::cfg_if! { + if #[cfg(supports_ptr_atomics)] { + use alloc::sync::Arc; + } else if #[cfg(feature = "portable-atomic")] { + use portable_atomic_util::Arc; + } +} + #[derive(Clone, Debug)] pub struct Buffer { /// This data is potentially accessed mutably in arbitrary non-overlapping slices, diff --git a/wgpu-hal/src/validation_canary.rs b/wgpu-hal/src/validation_canary.rs new file mode 100644 index 00000000000..37e41754863 --- /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 + pub(crate) 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 b734b689ff0..d946b2848c1 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, @@ -145,7 +138,10 @@ unsafe extern "system" fn debug_utils_messenger_callback( }); } + #[cfg(feature = "validation_canary")] if cfg!(debug_assertions) && level == log::Level::Error { + use alloc::string::ToString as _; + // Set canary and continue crate::VALIDATION_CANARY.add(message.to_string()); }