From 1eaf9d321cdb1d6b46dd14853e4b37a8476103f3 Mon Sep 17 00:00:00 2001 From: Raphael Hetzel Date: Thu, 17 Apr 2025 13:39:34 +0200 Subject: [PATCH 1/3] Optional web-specific deps for wasm32 --- wgpu-core/Cargo.toml | 2 +- wgpu-types/Cargo.toml | 8 +++++--- wgpu-types/src/lib.rs | 12 +++++++----- wgpu/Cargo.toml | 19 +++++++++++++++---- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/wgpu-core/Cargo.toml b/wgpu-core/Cargo.toml index fedec7bffe..ee131dc9f8 100644 --- a/wgpu-core/Cargo.toml +++ b/wgpu-core/Cargo.toml @@ -147,7 +147,7 @@ gles = [ ] ## WebGL backend, only available on Emscripten -webgl = ["wgpu-core-deps-wasm/webgl"] +webgl = ["wgpu-core-deps-wasm/webgl", "wgpu-types/web"] ## OpenGL backend, on macOS only angle = ["wgpu-core-deps-apple/angle"] ## Vulkan portability backend, only available on macOS diff --git a/wgpu-types/Cargo.toml b/wgpu-types/Cargo.toml index 9715538da3..921f319592 100644 --- a/wgpu-types/Cargo.toml +++ b/wgpu-types/Cargo.toml @@ -37,7 +37,7 @@ alloc_instead_of_core = "warn" [features] default = ["std"] -std = ["js-sys/std", "web-sys/std", "thiserror/std"] +std = ["js-sys?/std", "web-sys?/std", "thiserror/std"] strict_asserts = [] fragile-send-sync-non-atomic-wasm = [] serde = ["dep:serde", "bitflags/serde"] @@ -45,6 +45,8 @@ serde = ["dep:serde", "bitflags/serde"] counters = [] # Enables variants of `Trace` other than `Trace::Off` trace = ["std"] +# Enable web-specific dependencies for wasm. +web = ["dep:js-sys", "dep:web-sys"] [dependencies] bitflags = { workspace = true, features = ["serde"] } @@ -57,8 +59,8 @@ serde = { workspace = true, default-features = false, features = [ ], optional = true } [target.'cfg(target_arch = "wasm32")'.dependencies] -js-sys = { workspace = true, default-features = false } -web-sys = { workspace = true, default-features = false, features = [ +js-sys = { workspace = true, optional = true, default-features = false } +web-sys = { workspace = true, optional = true, default-features = false, features = [ "ImageBitmap", "ImageData", "HtmlImageElement", diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 77b0774346..b681ada4ec 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -6838,7 +6838,7 @@ pub type ImageCopyTexture = TexelCopyTextureInfo; /// /// Corresponds to [WebGPU `GPUCopyExternalImageSourceInfo`]( /// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopyexternalimage). -#[cfg(target_arch = "wasm32")] +#[cfg(all(target_arch = "wasm32", feature = "web"))] #[derive(Clone, Debug)] pub struct CopyExternalImageSourceInfo { /// The texture to be copied from. The copy source data is captured at the moment @@ -6862,14 +6862,14 @@ pub struct CopyExternalImageSourceInfo { since = "24.0.0", note = "This has been renamed to `CopyExternalImageSourceInfo`, and will be removed in 25.0.0." )] -#[cfg(target_arch = "wasm32")] +#[cfg(all(target_arch = "wasm32", feature = "web"))] pub type ImageCopyExternalImage = CopyExternalImageSourceInfo; /// Source of an external texture copy. /// /// Corresponds to the [implicit union type on WebGPU `GPUCopyExternalImageSourceInfo.source`]( /// https://gpuweb.github.io/gpuweb/#dom-gpuimagecopyexternalimage-source). -#[cfg(target_arch = "wasm32")] +#[cfg(all(target_arch = "wasm32", feature = "web"))] #[derive(Clone, Debug)] pub enum ExternalImageSource { /// Copy from a previously-decoded image bitmap. @@ -6891,7 +6891,7 @@ pub enum ExternalImageSource { VideoFrame(web_sys::VideoFrame), } -#[cfg(target_arch = "wasm32")] +#[cfg(all(target_arch = "wasm32", feature = "web"))] impl ExternalImageSource { /// Gets the pixel, not css, width of the source. pub fn width(&self) -> u32 { @@ -6922,7 +6922,7 @@ impl ExternalImageSource { } } -#[cfg(target_arch = "wasm32")] +#[cfg(all(target_arch = "wasm32", feature = "web"))] impl core::ops::Deref for ExternalImageSource { type Target = js_sys::Object; @@ -6942,12 +6942,14 @@ impl core::ops::Deref for ExternalImageSource { #[cfg(all( target_arch = "wasm32", + feature = "web", feature = "fragile-send-sync-non-atomic-wasm", not(target_feature = "atomics") ))] unsafe impl Send for ExternalImageSource {} #[cfg(all( target_arch = "wasm32", + feature = "web", feature = "fragile-send-sync-non-atomic-wasm", not(target_feature = "atomics") ))] diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index ff5865348b..929ab14f1e 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -50,6 +50,9 @@ gles = ["wgpu-core?/gles"] webgpu = [ "naga?/wgsl-out", "dep:wasm-bindgen-futures", + "dep:wasm-bindgen", + "dep:js-sys", + "dep:web-sys", "web-sys/Document", "web-sys/Event", "web-sys/Navigator", @@ -57,6 +60,7 @@ webgpu = [ "web-sys/Window", "web-sys/WorkerGlobalScope", "web-sys/WorkerNavigator", + "wgpu-types/web", ] #! ### Conditional Backends @@ -68,7 +72,14 @@ angle = ["wgpu-core?/angle"] vulkan-portability = ["wgpu-core?/vulkan-portability"] ## Enables the GLES backend on WebAssembly only. -webgl = ["wgpu-core/webgl", "dep:wgpu-hal", "dep:smallvec"] +webgl = [ + "wgpu-core/webgl", + "dep:wgpu-hal", + "dep:smallvec", + "dep:wasm-bindgen", + "dep:js-sys", + "dep:web-sys", +] ## Enables the noop backend for testing. ## @@ -192,9 +203,9 @@ smallvec.workspace = true ############### [target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies] # Needed for all backends -js-sys = { workspace = true, features = ["default"] } -wasm-bindgen.workspace = true -web-sys = { workspace = true, features = [ +js-sys = { workspace = true, optional = true, features = ["default"] } +wasm-bindgen = { workspace = true, optional = true } +web-sys = { workspace = true, optional = true, features = [ "HtmlCanvasElement", "OffscreenCanvas", ] } From 2823d7e6b5829fb3889b6961b25929ac3832a03f Mon Sep 17 00:00:00 2001 From: Raphael Hetzel Date: Sun, 20 Apr 2025 10:33:55 +0200 Subject: [PATCH 2/3] Dependency tests for web-specific bindings --- tests/tests/wgpu-dependency/main.rs | 48 +++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tests/tests/wgpu-dependency/main.rs b/tests/tests/wgpu-dependency/main.rs index 3b06ca5ed0..1cf37d8961 100644 --- a/tests/tests/wgpu-dependency/main.rs +++ b/tests/tests/wgpu-dependency/main.rs @@ -139,6 +139,54 @@ fn wasm32_with_webgl_depends_on_glow() { }); } +#[test] +fn wasm32_with_only_custom_backend_does_not_depend_on_web_specifics() { + check_feature_dependency(Requirement { + human_readable_name: "wasm32 with only the `custom` backend does not depend on web-specific bindings [`wasm-bindgen`, `js-sys`, `web-sys`]", + target: "wasm32-unknown-unknown", + packages: &["wgpu"], + features: &["custom"], + default_features: false, + search_terms: &[Search::Negative("wasm-bindgen"), Search::Negative("js-sys"), Search::Negative("web-sys")], + }); +} + +#[test] +fn wasm32_with_webgpu_backend_does_depend_on_web_specifics() { + check_feature_dependency(Requirement { + human_readable_name: "wasm32 with the `webgpu` backend depends on web-specific bindings [`wasm-bindgen`, `js-sys`, `web-sys`]", + target: "wasm32-unknown-unknown", + packages: &["wgpu"], + features: &["webgpu"], + default_features: false, + search_terms: &[Search::Positive("wasm-bindgen"), Search::Positive("js-sys"), Search::Positive("web-sys")], + }); +} + +#[test] +fn wasm32_with_webgl_backend_does_depend_on_web_specifics() { + check_feature_dependency(Requirement { + human_readable_name: "wasm32 with the `webgl` backend depends on web-specific bindings [`wasm-bindgen`, `js-sys`, `web-sys`]", + target: "wasm32-unknown-unknown", + packages: &["wgpu"], + features: &["webgl"], + default_features: false, + search_terms: &[Search::Positive("wasm-bindgen"), Search::Positive("js-sys"), Search::Positive("web-sys")], + }); +} + +#[test] +fn windows_with_webgpu_webgl_backend_does_not_depend_on_web_specifics() { + check_feature_dependency(Requirement { + human_readable_name: "windows with the `webgpu` and `webgl` backends enabled does not depend on web-specific bindings [`wasm-bindgen`, `js-sys`, `web-sys`]", + target: "x86_64-pc-windows-msvc", + packages: &["wgpu"], + features: &["webgpu", "webgl"], + default_features: false, + search_terms: &[Search::Negative("wasm-bindgen"), Search::Negative("js-sys"), Search::Negative("web-sys")], + }); +} + #[test] fn windows_with_webgl_does_not_depend_on_glow() { check_feature_dependency(Requirement { From 10d0d705f55d8bc0951e0217ae67a9e9793e46df Mon Sep 17 00:00:00 2001 From: Raphael Hetzel Date: Mon, 21 Apr 2025 11:27:43 +0200 Subject: [PATCH 3/3] Add 'web' feature, add missing feature enables/checks. --- .github/workflows/ci.yml | 6 +++--- examples/standalone/custom_backend/Cargo.toml | 4 ++++ .../standalone/custom_backend/src/custom.rs | 2 +- wgpu-hal/Cargo.toml | 1 + wgpu/Cargo.toml | 21 ++++++++----------- wgpu/build.rs | 1 + wgpu/src/api/instance.rs | 4 ++-- wgpu/src/api/queue.rs | 2 +- wgpu/src/api/surface.rs | 4 ++-- wgpu/src/backend/wgpu_core.rs | 2 +- wgpu/src/dispatch.rs | 2 +- wgpu/src/lib.rs | 6 +++--- 12 files changed, 29 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2e5030c153..de95ce3761 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -269,8 +269,8 @@ jobs: cargo clippy --target ${{ matrix.target }} ${{ matrix.extra-flags }} --tests --features glsl,spirv cargo doc --target ${{ matrix.target }} ${{ matrix.extra-flags }} --no-deps --features glsl,spirv - # check with no features - cargo clippy --target ${{ matrix.target }} ${{ matrix.extra-flags }} --no-default-features + # check with only the web feature + cargo clippy --target ${{ matrix.target }} ${{ matrix.extra-flags }} --no-default-features --features=web # all features cargo clippy --target ${{ matrix.target }} ${{ matrix.extra-flags }} --tests --all-features @@ -481,7 +481,7 @@ jobs: - name: Execute tests run: | cd wgpu - wasm-pack test --headless --chrome --no-default-features --features wgsl,webgl --workspace + wasm-pack test --headless --chrome --no-default-features --features wgsl,webgl,web --workspace gpu-test: # runtime is normally 5-15 minutes diff --git a/examples/standalone/custom_backend/Cargo.toml b/examples/standalone/custom_backend/Cargo.toml index 4a676297c9..de0dde6db2 100644 --- a/examples/standalone/custom_backend/Cargo.toml +++ b/examples/standalone/custom_backend/Cargo.toml @@ -4,6 +4,10 @@ edition = "2021" rust-version = "1.84" publish = false +[features] +default = ["web"] +web = ["wgpu/web"] + [dependencies] wgpu = { version = "25.0.0", features = [ "custom", diff --git a/examples/standalone/custom_backend/src/custom.rs b/examples/standalone/custom_backend/src/custom.rs index a8e7d9b413..40752b694e 100644 --- a/examples/standalone/custom_backend/src/custom.rs +++ b/examples/standalone/custom_backend/src/custom.rs @@ -337,7 +337,7 @@ impl QueueInterface for CustomQueue { unimplemented!() } - #[cfg(target_arch = "wasm32")] + #[cfg(all(target_arch = "wasm32", feature = "web"))] fn copy_external_image_to_texture( &self, _source: &wgpu::CopyExternalImageSourceInfo, diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index 520c82545f..8983a10215 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -118,6 +118,7 @@ gles = [ "dep:profiling", "dep:wasm-bindgen", "dep:web-sys", + "wgpu-types/web", "windows/Win32_Graphics_OpenGL", "windows/Win32_Graphics_Gdi", "windows/Win32_System_LibraryLoader", diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index 929ab14f1e..353f7b2f75 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -48,11 +48,9 @@ gles = ["wgpu-core?/gles"] ## Enables the WebGPU backend on WebAssembly. webgpu = [ + "web", "naga?/wgsl-out", "dep:wasm-bindgen-futures", - "dep:wasm-bindgen", - "dep:js-sys", - "dep:web-sys", "web-sys/Document", "web-sys/Event", "web-sys/Navigator", @@ -60,7 +58,6 @@ webgpu = [ "web-sys/Window", "web-sys/WorkerGlobalScope", "web-sys/WorkerNavigator", - "wgpu-types/web", ] #! ### Conditional Backends @@ -72,14 +69,7 @@ angle = ["wgpu-core?/angle"] vulkan-portability = ["wgpu-core?/vulkan-portability"] ## Enables the GLES backend on WebAssembly only. -webgl = [ - "wgpu-core/webgl", - "dep:wgpu-hal", - "dep:smallvec", - "dep:wasm-bindgen", - "dep:js-sys", - "dep:web-sys", -] +webgl = ["web", "wgpu-core/webgl", "dep:wgpu-hal", "dep:smallvec"] ## Enables the noop backend for testing. ## @@ -159,6 +149,13 @@ fragile-send-sync-non-atomic-wasm = [ "wgpu-types/fragile-send-sync-non-atomic-wasm", ] +## Use web-specific libraries on WASM +## +## Those libraties (wasm-bindgen, web-sys, js-sys) can only be used when there is a JavaScript +## context around the WASM VM, e.g., when the WASM binary is used in a browser. +web = ["dep:wasm-bindgen", "dep:js-sys", "dep:web-sys", "wgpu-types/web"] + + ######################### # Standard Dependencies # ######################### diff --git a/wgpu/build.rs b/wgpu/build.rs index c3f78fd536..3f998d6490 100644 --- a/wgpu/build.rs +++ b/wgpu/build.rs @@ -2,6 +2,7 @@ fn main() { cfg_aliases::cfg_aliases! { native: { not(target_arch = "wasm32") }, Emscripten: { all(target_arch = "wasm32", target_os = "emscripten") }, + web: { all(target_arch = "wasm32", not(Emscripten), feature = "web") }, send_sync: { any( native, diff --git a/wgpu/src/api/instance.rs b/wgpu/src/api/instance.rs index 24815df64b..ca0e9532bf 100644 --- a/wgpu/src/api/instance.rs +++ b/wgpu/src/api/instance.rs @@ -303,7 +303,7 @@ impl Instance { surface }?, - #[cfg(any(webgpu, webgl))] + #[cfg(web)] SurfaceTarget::Canvas(canvas) => { handle_source = None; @@ -322,7 +322,7 @@ impl Instance { }? } - #[cfg(any(webgpu, webgl))] + #[cfg(web)] SurfaceTarget::OffscreenCanvas(canvas) => { handle_source = None; diff --git a/wgpu/src/api/queue.rs b/wgpu/src/api/queue.rs index d19d00a5ad..bc8d581823 100644 --- a/wgpu/src/api/queue.rs +++ b/wgpu/src/api/queue.rs @@ -232,7 +232,7 @@ impl Queue { } /// Schedule a copy of data from `image` into `texture`. - #[cfg(any(webgpu, webgl))] + #[cfg(web)] pub fn copy_external_image_to_texture( &self, source: &wgt::CopyExternalImageSourceInfo, diff --git a/wgpu/src/api/surface.rs b/wgpu/src/api/surface.rs index 773d0123d9..ada8622476 100644 --- a/wgpu/src/api/surface.rs +++ b/wgpu/src/api/surface.rs @@ -243,7 +243,7 @@ pub enum SurfaceTarget<'window> { /// /// - On WebGL2: surface creation will return an error if the browser does not support WebGL2, /// or declines to provide GPU access (such as due to a resource shortage). - #[cfg(any(webgpu, webgl))] + #[cfg(web)] Canvas(web_sys::HtmlCanvasElement), /// Surface from a `web_sys::OffscreenCanvas`. @@ -255,7 +255,7 @@ pub enum SurfaceTarget<'window> { /// /// - On WebGL2: surface creation will return an error if the browser does not support WebGL2, /// or declines to provide GPU access (such as due to a resource shortage). - #[cfg(any(webgpu, webgl))] + #[cfg(web)] OffscreenCanvas(web_sys::OffscreenCanvas), } diff --git a/wgpu/src/backend/wgpu_core.rs b/wgpu/src/backend/wgpu_core.rs index 16501e69e1..0daf049993 100644 --- a/wgpu/src/backend/wgpu_core.rs +++ b/wgpu/src/backend/wgpu_core.rs @@ -1845,7 +1845,7 @@ impl dispatch::QueueInterface for CoreQueue { // This method needs to exist if either webgpu or webgl is enabled, // but we only actually have an implementation if webgl is enabled. - #[cfg(any(webgpu, webgl))] + #[cfg(web)] #[cfg_attr(not(webgl), expect(unused_variables))] fn copy_external_image_to_texture( &self, diff --git a/wgpu/src/dispatch.rs b/wgpu/src/dispatch.rs index 9a606c1be2..ee9f4e5ff2 100644 --- a/wgpu/src/dispatch.rs +++ b/wgpu/src/dispatch.rs @@ -210,7 +210,7 @@ pub trait QueueInterface: CommonTraits { data_layout: crate::TexelCopyBufferLayout, size: crate::Extent3d, ); - #[cfg(any(webgpu, webgl))] + #[cfg(web)] fn copy_external_image_to_texture( &self, source: &crate::CopyExternalImageSourceInfo, diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index d1ec8a17ff..40c7d2e7cb 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -94,10 +94,10 @@ pub use wgt::{ pub use wgt::{ImageCopyBuffer, ImageCopyTexture, ImageCopyTextureTagged, ImageDataLayout}; // 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))] +#[cfg(web)] #[expect(deprecated)] pub use wgt::ImageCopyExternalImage; -#[cfg(any(webgpu, webgl))] +#[cfg(web)] pub use wgt::{CopyExternalImageSourceInfo, ExternalImageSource}; /// Re-export of our `naga` dependency. @@ -119,7 +119,7 @@ pub use raw_window_handle as rwh; /// Re-export of our `web-sys` dependency. /// -#[cfg(any(webgl, webgpu))] +#[cfg(web)] pub use web_sys; #[doc(hidden)]