From 973cd3ebf8fae01c6c85dea244b8ce8323f6efa2 Mon Sep 17 00:00:00 2001 From: Leo Kettmeir Date: Wed, 28 Jun 2023 12:30:28 +0200 Subject: [PATCH 1/7] feat: add link feature (#3853) --- Cargo.lock | 5 ++--- wgpu-core/Cargo.toml | 6 +++++- wgpu-hal/Cargo.toml | 5 +++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8f0573de9a..aaa0ba425a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1463,10 +1463,9 @@ dependencies = [ [[package]] name = "metal" version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "550b24b0cd4cf923f36bae78eca457b3a10d8a6a14a9c84cb2687b527e6a84af" +source = "git+https://github.com/gfx-rs/metal-rs.git?rev=a6a0446#a6a04463db388e8fd3e99095ab4fbb87cbe9d69c" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.3.1", "block", "core-graphics-types", "foreign-types 0.5.0", diff --git a/wgpu-core/Cargo.toml b/wgpu-core/Cargo.toml index a2654d2a9f..2cfbe2d426 100644 --- a/wgpu-core/Cargo.toml +++ b/wgpu-core/Cargo.toml @@ -22,7 +22,7 @@ targets = [ [lib] [features] -default = [] +default = ["link"] # Backends, passed through to wgpu-hal metal = ["hal/metal"] @@ -31,6 +31,9 @@ gles = ["hal/gles"] dx11 = ["hal/dx11"] dx12 = ["hal/dx12"] +# Use static linking for libraries. Disale to manually link. Enabled by default. +link = ["hal/link"] + # Support the Renderdoc graphics debugger: # https://renderdoc.org/ renderdoc = ["hal/renderdoc"] @@ -80,6 +83,7 @@ version = "0.16" package = "wgpu-hal" path = "../wgpu-hal" version = "0.16" +default_features = false [target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies] web-sys = { version = "0.3.60", features = ["HtmlCanvasElement", "OffscreenCanvas"] } diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index 6baa39ce9a..79eb40bffb 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -33,7 +33,7 @@ targets = [ [lib] [features] -default = [] +default = ["link"] metal = ["naga/msl-out", "block"] vulkan = ["naga/spv-out", "ash", "gpu-alloc", "gpu-descriptor", "libloading", "smallvec"] gles = ["naga/glsl-out", "glow", "khronos-egl", "libloading"] @@ -43,6 +43,7 @@ dx12 = ["naga/hlsl-out", "d3d12", "bit-set", "range-alloc", "winapi/std", "winap windows_rs = ["gpu-allocator"] dxc_shader_compiler = ["hassle-rs"] renderdoc = ["libloading", "renderdoc-sys"] +link = ["metal/link"] [[example]] name = "halmark" @@ -101,7 +102,7 @@ d3d12 = { version = "0.6.0", git = "https://github.com/gfx-rs/d3d12-rs", rev = " # backend: Metal block = { version = "0.1", optional = true } -metal = "0.25.0" +metal = { git = "https://github.com/gfx-rs/metal-rs.git", rev = "a6a0446", default_features = false } objc = "0.2.5" core-graphics-types = "0.1" From 6158692654e97a97161a77858b6d9f65987c6f80 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 29 Jun 2023 12:07:30 +0200 Subject: [PATCH 2/7] Add Quartzcore behind link feature flag (#3897) --- wgpu-hal/src/metal/surface.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wgpu-hal/src/metal/surface.rs b/wgpu-hal/src/metal/surface.rs index 8101d52969..3b25e55729 100644 --- a/wgpu-hal/src/metal/surface.rs +++ b/wgpu-hal/src/metal/surface.rs @@ -17,7 +17,7 @@ use objc::{ use parking_lot::Mutex; #[cfg(target_os = "macos")] -#[link(name = "QuartzCore", kind = "framework")] +#[cfg_attr(feature = "link", link(name = "QuartzCore", kind = "framework"))] extern "C" { #[allow(non_upper_case_globals)] static kCAGravityTopLeft: *mut Object; From 7c34cc86e89632ba4eb65c58ce6de08651261646 Mon Sep 17 00:00:00 2001 From: AlbinBernhardssonARM <60749571+AlbinBernhardssonARM@users.noreply.github.com> Date: Thu, 29 Jun 2023 22:15:21 +0200 Subject: [PATCH 3/7] Implement depth-clip-control using depthClamp (#3892) --- CHANGELOG.md | 1 + wgpu-hal/src/vulkan/adapter.rs | 31 ++----------------------------- wgpu-hal/src/vulkan/device.rs | 10 ++-------- 3 files changed, 5 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94acb283f6..cf48c37ecf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,7 @@ Bottom level categories: #### Vulkan - Work around [Vulkan-ValidationLayers#5671](https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/5671) by ignoring reports of violations of [VUID-vkCmdEndDebugUtilsLabelEXT-commandBuffer-01912](https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdEndDebugUtilsLabelEXT-commandBuffer-01912). By @jimblandy in [#3809](https://github.com/gfx-rs/wgpu/pull/3809). +- Implement depth-clip-control using depthClamp instead of VK_EXT_depth_clip_enable. By @AlbinBernhardssonARM [#3892](https://github.com/gfx-rs/wgpu/pull/3892). ### Added/New Features diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index f8f26e422f..bfee8545b1 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -24,7 +24,6 @@ pub struct PhysicalDeviceFeatures { timeline_semaphore: Option, image_robustness: Option, robustness2: Option, - depth_clip_enable: Option, multiview: Option, astc_hdr: Option, shader_float16: Option<( @@ -61,9 +60,6 @@ impl PhysicalDeviceFeatures { if let Some(ref mut feature) = self.robustness2 { info = info.push_next(feature); } - if let Some(ref mut feature) = self.depth_clip_enable { - info = info.push_next(feature); - } if let Some(ref mut feature) = self.astc_hdr { info = info.push_next(feature); } @@ -179,6 +175,7 @@ impl PhysicalDeviceFeatures { .shader_int16(requested_features.contains(wgt::Features::SHADER_I16)) //.shader_resource_residency(requested_features.contains(wgt::Features::SHADER_RESOURCE_RESIDENCY)) .geometry_shader(requested_features.contains(wgt::Features::SHADER_PRIMITIVE_INDEX)) + .depth_clamp(requested_features.contains(wgt::Features::DEPTH_CLIP_CONTROL)) .build(), descriptor_indexing: if requested_features.intersects(indexing_features()) { Some( @@ -247,17 +244,6 @@ impl PhysicalDeviceFeatures { } else { None }, - depth_clip_enable: if enabled_extensions.contains(&vk::ExtDepthClipEnableFn::name()) { - Some( - vk::PhysicalDeviceDepthClipEnableFeaturesEXT::builder() - .depth_clip_enable( - requested_features.contains(wgt::Features::DEPTH_CLIP_CONTROL), - ) - .build(), - ) - } else { - None - }, multiview: if effective_api_version >= vk::API_VERSION_1_1 || enabled_extensions.contains(&vk::KhrMultiviewFn::name()) { @@ -472,9 +458,7 @@ impl PhysicalDeviceFeatures { } } - if let Some(ref feature) = self.depth_clip_enable { - features.set(F::DEPTH_CLIP_CONTROL, feature.depth_clip_enable != 0); - } + features.set(F::DEPTH_CLIP_CONTROL, self.core.depth_clamp != 0); if let Some(ref multiview) = self.multiview { features.set(F::MULTIVIEW, multiview.multiview != 0); @@ -699,11 +683,6 @@ impl PhysicalDeviceCapabilities { extensions.push(vk::ExtConservativeRasterizationFn::name()); } - // Require `VK_EXT_depth_clip_enable` if the associated feature was requested - if requested_features.contains(wgt::Features::DEPTH_CLIP_CONTROL) { - extensions.push(vk::ExtDepthClipEnableFn::name()); - } - // Require `VK_KHR_portability_subset` on macOS/iOS #[cfg(any(target_os = "macos", target_os = "ios"))] extensions.push(vk::KhrPortabilitySubsetFn::name()); @@ -898,12 +877,6 @@ impl super::InstanceShared { .insert(vk::PhysicalDeviceRobustness2FeaturesEXT::default()); builder = builder.push_next(next); } - if capabilities.supports_extension(vk::ExtDepthClipEnableFn::name()) { - let next = features - .depth_clip_enable - .insert(vk::PhysicalDeviceDepthClipEnableFeaturesEXT::default()); - builder = builder.push_next(next); - } if capabilities.supports_extension(vk::ExtTextureCompressionAstcHdrFn::name()) { let next = features .astc_hdr diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index 09b887772c..5e73044c89 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -1611,7 +1611,8 @@ impl crate::Device for super::Device { let mut vk_rasterization = vk::PipelineRasterizationStateCreateInfo::builder() .polygon_mode(conv::map_polygon_mode(desc.primitive.polygon_mode)) .front_face(conv::map_front_face(desc.primitive.front_face)) - .line_width(1.0); + .line_width(1.0) + .depth_clamp_enable(desc.primitive.unclipped_depth); if let Some(face) = desc.primitive.cull_mode { vk_rasterization = vk_rasterization.cull_mode(conv::map_cull_face(face)) } @@ -1622,13 +1623,6 @@ impl crate::Device for super::Device { if desc.primitive.conservative { vk_rasterization = vk_rasterization.push_next(&mut vk_rasterization_conservative_state); } - let mut vk_depth_clip_state = - vk::PipelineRasterizationDepthClipStateCreateInfoEXT::builder() - .depth_clip_enable(false) - .build(); - if desc.primitive.unclipped_depth { - vk_rasterization = vk_rasterization.push_next(&mut vk_depth_clip_state); - } let mut vk_depth_stencil = vk::PipelineDepthStencilStateCreateInfo::builder(); if let Some(ref ds) = desc.depth_stencil { From 88f18ed190ebd5e823abb898a41272398652131b Mon Sep 17 00:00:00 2001 From: daxpedda Date: Thu, 29 Jun 2023 22:31:18 +0200 Subject: [PATCH 4/7] Don't implement `Send` or `Sync` on Wasm (#3691) Co-authored-by: Connor Fitzgerald --- .github/workflows/ci.yml | 1 + CHANGELOG.md | 1 + wgpu-core/Cargo.toml | 2 + wgpu-core/src/command/bundle.rs | 14 ++ wgpu-core/src/device/queue.rs | 34 ++- wgpu-core/src/error.rs | 15 ++ wgpu-core/src/global.rs | 11 +- wgpu-core/src/resource.rs | 48 +++- wgpu-hal/Cargo.toml | 1 + wgpu-hal/src/gles/adapter.rs | 13 +- wgpu-hal/src/gles/device.rs | 13 +- wgpu-hal/src/gles/mod.rs | 85 +++++-- wgpu-hal/src/gles/queue.rs | 13 +- wgpu-hal/src/gles/web.rs | 24 +- wgpu-hal/src/lib.rs | 41 ++-- wgpu-types/Cargo.toml | 1 + wgpu-types/src/lib.rs | 83 ++++++- wgpu/Cargo.toml | 2 + wgpu/src/backend/direct.rs | 25 ++- wgpu/src/backend/web.rs | 32 ++- wgpu/src/context.rs | 204 ++++++++++++----- wgpu/src/lib.rs | 383 +++++++++++++++++++++++++++++++- 22 files changed, 908 insertions(+), 138 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 50c3038615..079ac59038 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -138,6 +138,7 @@ jobs: set -e # build for WebGPU + cargo clippy --target ${{ matrix.target }} --tests --features glsl,spirv,fragile-send-sync-non-atomic-wasm cargo clippy --target ${{ matrix.target }} --tests --features glsl,spirv cargo doc --target ${{ matrix.target }} --no-deps --features glsl,spirv diff --git a/CHANGELOG.md b/CHANGELOG.md index cf48c37ecf..6bceb0e7ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,6 +68,7 @@ Bottom level categories: - Document feature requirements for `DEPTH32FLOAT_STENCIL8` by @ErichDonGubler in [#3734](https://github.com/gfx-rs/wgpu/pull/3734). - Flesh out docs. for `AdapterInfo::{device,vendor}` by @ErichDonGubler in [#3763](https://github.com/gfx-rs/wgpu/pull/3763). - Spell out which sizes are in bytes. By @jimblandy in [#3773](https://github.com/gfx-rs/wgpu/pull/3773). +- On Web, types don't implement `Send` or `Sync` anymore. By @daxpedda in [#3691](https://github.com/gfx-rs/wgpu/pull/3691) ### Bug Fixes diff --git a/wgpu-core/Cargo.toml b/wgpu-core/Cargo.toml index 2cfbe2d426..7c8213e8b0 100644 --- a/wgpu-core/Cargo.toml +++ b/wgpu-core/Cargo.toml @@ -51,6 +51,8 @@ serial-pass = ["serde", "wgt/serde", "arrayvec/serde"] id32 = [] # Enable `ShaderModuleSource::Wgsl` wgsl = ["naga/wgsl-in"] +# Implement `Send` and `Sync` on Wasm. +fragile-send-sync-non-atomic-wasm = ["hal/fragile-send-sync-non-atomic-wasm", "wgt/fragile-send-sync-non-atomic-wasm"] [dependencies] arrayvec = "0.7" diff --git a/wgpu-core/src/command/bundle.rs b/wgpu-core/src/command/bundle.rs index 7a99c90bd6..5c4ca122a8 100644 --- a/wgpu-core/src/command/bundle.rs +++ b/wgpu-core/src/command/bundle.rs @@ -746,7 +746,21 @@ pub struct RenderBundle { pub(crate) life_guard: LifeGuard, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] unsafe impl Send for RenderBundle {} +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] unsafe impl Sync for RenderBundle {} impl RenderBundle { diff --git a/wgpu-core/src/device/queue.rs b/wgpu-core/src/device/queue.rs index 98095f4490..6e0be3b297 100644 --- a/wgpu-core/src/device/queue.rs +++ b/wgpu-core/src/device/queue.rs @@ -37,6 +37,13 @@ pub struct SubmittedWorkDoneClosureC { pub user_data: *mut u8, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] unsafe impl Send for SubmittedWorkDoneClosureC {} pub struct SubmittedWorkDoneClosure { @@ -45,17 +52,30 @@ pub struct SubmittedWorkDoneClosure { inner: SubmittedWorkDoneClosureInner, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] +type SubmittedWorkDoneCallback = Box; +#[cfg(not(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +)))] +type SubmittedWorkDoneCallback = Box; + enum SubmittedWorkDoneClosureInner { - Rust { - callback: Box, - }, - C { - inner: SubmittedWorkDoneClosureC, - }, + Rust { callback: SubmittedWorkDoneCallback }, + C { inner: SubmittedWorkDoneClosureC }, } impl SubmittedWorkDoneClosure { - pub fn from_rust(callback: Box) -> Self { + pub fn from_rust(callback: SubmittedWorkDoneCallback) -> Self { Self { inner: SubmittedWorkDoneClosureInner::Rust { callback }, } diff --git a/wgpu-core/src/error.rs b/wgpu-core/src/error.rs index 3cdecc5369..62ecebe9b9 100644 --- a/wgpu-core/src/error.rs +++ b/wgpu-core/src/error.rs @@ -162,7 +162,22 @@ pub fn format_pretty_any( #[derive(Debug)] pub struct ContextError { pub string: &'static str, + #[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) + ))] pub cause: Box, + #[cfg(not(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) + )))] + pub cause: Box, pub label_key: &'static str, pub label: String, } diff --git a/wgpu-core/src/global.rs b/wgpu-core/src/global.rs index 5331265962..e3ed2be761 100644 --- a/wgpu-core/src/global.rs +++ b/wgpu-core/src/global.rs @@ -155,7 +155,16 @@ impl Drop for Global { } } -#[cfg(test)] +#[cfg(all( + test, + any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) + ) +))] fn _test_send_sync(global: &Global) { fn test_internal(_: T) {} test_internal(global) diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index 4aca271e9e..fe881c2d06 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -79,7 +79,21 @@ pub(crate) enum BufferMapState { Idle, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] unsafe impl Send for BufferMapState {} +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] unsafe impl Sync for BufferMapState {} #[repr(C)] @@ -88,6 +102,13 @@ pub struct BufferMapCallbackC { pub user_data: *mut u8, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] unsafe impl Send for BufferMapCallbackC {} pub struct BufferMapCallback { @@ -96,17 +117,30 @@ pub struct BufferMapCallback { inner: Option, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] +type BufferMapCallbackCallback = Box; +#[cfg(not(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +)))] +type BufferMapCallbackCallback = Box; + enum BufferMapCallbackInner { - Rust { - callback: Box, - }, - C { - inner: BufferMapCallbackC, - }, + Rust { callback: BufferMapCallbackCallback }, + C { inner: BufferMapCallbackC }, } impl BufferMapCallback { - pub fn from_rust(callback: Box) -> Self { + pub fn from_rust(callback: BufferMapCallbackCallback) -> Self { Self { inner: Some(BufferMapCallbackInner::Rust { callback }), } diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index 79eb40bffb..46ca5de24b 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -43,6 +43,7 @@ dx12 = ["naga/hlsl-out", "d3d12", "bit-set", "range-alloc", "winapi/std", "winap windows_rs = ["gpu-allocator"] dxc_shader_compiler = ["hassle-rs"] renderdoc = ["libloading", "renderdoc-sys"] +fragile-send-sync-non-atomic-wasm = ["wgt/fragile-send-sync-non-atomic-wasm"] link = ["metal/link"] [[example]] diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index fc68b437e8..d7e72619c5 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -936,10 +936,17 @@ impl super::AdapterShared { } } -// SAFE: Wasm doesn't have threads -#[cfg(target_arch = "wasm32")] +#[cfg(all( + target_arch = "wasm32", + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] unsafe impl Sync for super::Adapter {} -#[cfg(target_arch = "wasm32")] +#[cfg(all( + target_arch = "wasm32", + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] unsafe impl Send for super::Adapter {} #[cfg(test)] diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 14bbb36601..ecd68b4b8d 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -1321,8 +1321,15 @@ impl crate::Device for super::Device { } } -// SAFE: Wasm doesn't have threads -#[cfg(target_arch = "wasm32")] +#[cfg(all( + target_arch = "wasm32", + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] unsafe impl Sync for super::Device {} -#[cfg(target_arch = "wasm32")] +#[cfg(all( + target_arch = "wasm32", + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] unsafe impl Send for super::Device {} diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 1b5e3f1422..5c53b3a281 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -246,10 +246,17 @@ pub struct Buffer { data: Option>>>, } -// Safe: Wasm doesn't have threads -#[cfg(target_arch = "wasm32")] +#[cfg(all( + target_arch = "wasm32", + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] unsafe impl Sync for Buffer {} -#[cfg(target_arch = "wasm32")] +#[cfg(all( + target_arch = "wasm32", + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] unsafe impl Send for Buffer {} #[derive(Clone, Debug)] @@ -268,11 +275,18 @@ pub enum TextureInner { }, } -// SAFE: Wasm doesn't have threads -#[cfg(target_arch = "wasm32")] -unsafe impl Send for TextureInner {} -#[cfg(target_arch = "wasm32")] +#[cfg(all( + target_arch = "wasm32", + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] unsafe impl Sync for TextureInner {} +#[cfg(all( + target_arch = "wasm32", + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] +unsafe impl Send for TextureInner {} impl TextureInner { fn as_native(&self) -> (glow::Texture, BindTarget) { @@ -462,10 +476,17 @@ struct UniformDesc { utype: u32, } -// Safe: Wasm doesn't have threads -#[cfg(target_arch = "wasm32")] +#[cfg(all( + target_arch = "wasm32", + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] unsafe impl Sync for UniformDesc {} -#[cfg(target_arch = "wasm32")] +#[cfg(all( + target_arch = "wasm32", + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] unsafe impl Send for UniformDesc {} /// For each texture in the pipeline layout, store the index of the only @@ -530,21 +551,35 @@ pub struct RenderPipeline { alpha_to_coverage_enabled: bool, } -// SAFE: Wasm doesn't have threads -#[cfg(target_arch = "wasm32")] -unsafe impl Send for RenderPipeline {} -#[cfg(target_arch = "wasm32")] +#[cfg(all( + target_arch = "wasm32", + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] unsafe impl Sync for RenderPipeline {} +#[cfg(all( + target_arch = "wasm32", + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] +unsafe impl Send for RenderPipeline {} pub struct ComputePipeline { inner: Arc, } -// SAFE: Wasm doesn't have threads -#[cfg(target_arch = "wasm32")] -unsafe impl Send for ComputePipeline {} -#[cfg(target_arch = "wasm32")] +#[cfg(all( + target_arch = "wasm32", + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] unsafe impl Sync for ComputePipeline {} +#[cfg(all( + target_arch = "wasm32", + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] +unsafe impl Send for ComputePipeline {} #[derive(Debug)] pub struct QuerySet { @@ -558,7 +593,21 @@ pub struct Fence { pending: Vec<(crate::FenceValue, glow::Fence)>, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] unsafe impl Send for Fence {} +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] unsafe impl Sync for Fence {} impl Fence { diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index ec2a18d422..6eacfdd88a 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -1525,8 +1525,15 @@ impl crate::Queue for super::Queue { } } -// SAFE: Wasm doesn't have threads -#[cfg(target_arch = "wasm32")] +#[cfg(all( + target_arch = "wasm32", + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] unsafe impl Sync for super::Queue {} -#[cfg(target_arch = "wasm32")] +#[cfg(all( + target_arch = "wasm32", + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] unsafe impl Send for super::Queue {} diff --git a/wgpu-hal/src/gles/web.rs b/wgpu-hal/src/gles/web.rs index a6f807857b..49bc5656de 100644 --- a/wgpu-hal/src/gles/web.rs +++ b/wgpu-hal/src/gles/web.rs @@ -106,8 +106,15 @@ impl Instance { } } -// SAFE: Wasm doesn't have threads +#[cfg(all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] unsafe impl Sync for Instance {} +#[cfg(all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] unsafe impl Send for Instance {} impl crate::Instance for Instance { @@ -171,16 +178,23 @@ pub struct Surface { srgb_present_program: Option, } +#[cfg(all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] +unsafe impl Sync for Surface {} +#[cfg(all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] +unsafe impl Send for Surface {} + #[derive(Clone, Debug)] enum Canvas { Canvas(web_sys::HtmlCanvasElement), Offscreen(web_sys::OffscreenCanvas), } -// SAFE: Because web doesn't have threads ( yet ) -unsafe impl Sync for Surface {} -unsafe impl Send for Surface {} - #[derive(Clone, Debug)] pub struct Swapchain { pub(crate) extent: wgt::Extent3d, diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 1758149380..910e46ca25 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -95,6 +95,7 @@ use std::{ use bitflags::bitflags; use thiserror::Error; +use wgt::{WasmNotSend, WasmNotSync}; pub const MAX_ANISOTROPY: u8 = 16; pub const MAX_BIND_GROUPS: usize = 8; @@ -161,25 +162,25 @@ pub trait Api: Clone + Sized { type Queue: Queue; type CommandEncoder: CommandEncoder; - type CommandBuffer: Send + Sync + fmt::Debug; + type CommandBuffer: WasmNotSend + WasmNotSync + fmt::Debug; - type Buffer: fmt::Debug + Send + Sync + 'static; - type Texture: fmt::Debug + Send + Sync + 'static; - type SurfaceTexture: fmt::Debug + Send + Sync + Borrow; - type TextureView: fmt::Debug + Send + Sync; - type Sampler: fmt::Debug + Send + Sync; - type QuerySet: fmt::Debug + Send + Sync; - type Fence: fmt::Debug + Send + Sync; + type Buffer: fmt::Debug + WasmNotSend + WasmNotSync + 'static; + type Texture: fmt::Debug + WasmNotSend + WasmNotSync + 'static; + type SurfaceTexture: fmt::Debug + WasmNotSend + WasmNotSync + Borrow; + type TextureView: fmt::Debug + WasmNotSend + WasmNotSync; + type Sampler: fmt::Debug + WasmNotSend + WasmNotSync; + type QuerySet: fmt::Debug + WasmNotSend + WasmNotSync; + type Fence: fmt::Debug + WasmNotSend + WasmNotSync; - type BindGroupLayout: Send + Sync; - type BindGroup: fmt::Debug + Send + Sync; - type PipelineLayout: Send + Sync; - type ShaderModule: fmt::Debug + Send + Sync; - type RenderPipeline: Send + Sync; - type ComputePipeline: Send + Sync; + type BindGroupLayout: WasmNotSend + WasmNotSync; + type BindGroup: fmt::Debug + WasmNotSend + WasmNotSync; + type PipelineLayout: WasmNotSend + WasmNotSync; + type ShaderModule: fmt::Debug + WasmNotSend + WasmNotSync; + type RenderPipeline: WasmNotSend + WasmNotSync; + type ComputePipeline: WasmNotSend + WasmNotSync; } -pub trait Instance: Sized + Send + Sync { +pub trait Instance: Sized + WasmNotSend + WasmNotSync { unsafe fn init(desc: &InstanceDescriptor) -> Result; unsafe fn create_surface( &self, @@ -190,7 +191,7 @@ pub trait Instance: Sized + Send + Sync { unsafe fn enumerate_adapters(&self) -> Vec>; } -pub trait Surface: Send + Sync { +pub trait Surface: WasmNotSend + WasmNotSync { unsafe fn configure( &mut self, device: &A::Device, @@ -216,7 +217,7 @@ pub trait Surface: Send + Sync { unsafe fn discard_texture(&mut self, texture: A::SurfaceTexture); } -pub trait Adapter: Send + Sync { +pub trait Adapter: WasmNotSend + WasmNotSync { unsafe fn open( &self, features: wgt::Features, @@ -240,7 +241,7 @@ pub trait Adapter: Send + Sync { unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp; } -pub trait Device: Send + Sync { +pub trait Device: WasmNotSend + WasmNotSync { /// Exit connection to this logical device. unsafe fn exit(self, queue: A::Queue); /// Creates a new buffer. @@ -336,7 +337,7 @@ pub trait Device: Send + Sync { unsafe fn stop_capture(&self); } -pub trait Queue: Send + Sync { +pub trait Queue: WasmNotSend + WasmNotSync { /// Submits the command buffers for execution on GPU. /// /// Valid usage: @@ -360,7 +361,7 @@ pub trait Queue: Send + Sync { /// Serves as a parent for all the encoded command buffers. /// Works in bursts of action: one or more command buffers are recorded, /// then submitted to a queue, and then it needs to be `reset_all()`. -pub trait CommandEncoder: Send + Sync + fmt::Debug { +pub trait CommandEncoder: WasmNotSend + WasmNotSync + fmt::Debug { /// Begin encoding a new command buffer. unsafe fn begin_encoding(&mut self, label: Label) -> Result<(), DeviceError>; /// Discard currently recorded list, if any. diff --git a/wgpu-types/Cargo.toml b/wgpu-types/Cargo.toml index 8a4e7e0075..6b30c02ae5 100644 --- a/wgpu-types/Cargo.toml +++ b/wgpu-types/Cargo.toml @@ -25,6 +25,7 @@ targets = [ trace = ["serde"] replay = ["serde"] strict_asserts = [] +fragile-send-sync-non-atomic-wasm = [] [dependencies] bitflags = "2" diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index ebfc9f65aa..a5e838653b 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -5917,9 +5917,17 @@ impl std::ops::Deref for ExternalImageSource { } } -#[cfg(target_arch = "wasm32")] +#[cfg(all( + target_arch = "wasm32", + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] unsafe impl Send for ExternalImageSource {} -#[cfg(target_arch = "wasm32")] +#[cfg(all( + target_arch = "wasm32", + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] unsafe impl Sync for ExternalImageSource {} /// Color spaces supported on the web. @@ -6317,3 +6325,74 @@ impl Default for InstanceDescriptor { } } } + +pub use send_sync::*; + +#[doc(hidden)] +mod send_sync { + #[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) + ))] + pub trait WasmNotSend: Send {} + #[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) + ))] + impl WasmNotSend for T {} + #[cfg(not(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) + )))] + pub trait WasmNotSend {} + #[cfg(not(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) + )))] + impl WasmNotSend for T {} + + #[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) + ))] + pub trait WasmNotSync: Sync {} + #[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) + ))] + impl WasmNotSync for T {} + #[cfg(not(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) + )))] + pub trait WasmNotSync {} + #[cfg(not(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) + )))] + impl WasmNotSync for T {} +} diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index 1047e7bf47..2842281a19 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -38,6 +38,8 @@ angle = ["wgc/angle"] webgl = ["hal", "wgc"] vulkan-portability = ["wgc/vulkan"] expose-ids = [] +# Implement `Send` and `Sync` on Wasm. +fragile-send-sync-non-atomic-wasm = ["hal/fragile-send-sync-non-atomic-wasm", "wgc/fragile-send-sync-non-atomic-wasm", "wgt/fragile-send-sync-non-atomic-wasm"] # wgpu-core is always available as an optional dependency, "wgc". # Whenever wgpu-core is selected, we want the GLES backend and raw diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index d9e1085935..a5c9f30511 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -23,6 +23,7 @@ use std::{ }; use wgc::command::{bundle_ffi::*, compute_ffi::*, render_ffi::*}; use wgc::id::TypedId; +use wgt::{WasmNotSend, WasmNotSync}; const LABEL: &str = "label"; @@ -263,7 +264,7 @@ impl Context { fn handle_error( &self, sink_mutex: &Mutex, - cause: impl Error + Send + Sync + 'static, + cause: impl Error + WasmNotSend + WasmNotSync + 'static, label_key: &'static str, label: Label, string: &'static str, @@ -297,7 +298,7 @@ impl Context { fn handle_error_nolabel( &self, sink_mutex: &Mutex, - cause: impl Error + Send + Sync + 'static, + cause: impl Error + WasmNotSend + WasmNotSync + 'static, string: &'static str, ) { self.handle_error(sink_mutex, cause, "", None, string) @@ -306,7 +307,7 @@ impl Context { #[track_caller] fn handle_error_fatal( &self, - cause: impl Error + Send + Sync + 'static, + cause: impl Error + WasmNotSend + WasmNotSync + 'static, operation: &'static str, ) -> ! { panic!("Error in {operation}: {f}", f = self.format_error(&cause)); @@ -1467,7 +1468,7 @@ impl crate::Context for Context { buffer_data: &Self::BufferData, mode: MapMode, range: Range, - callback: Box) + Send + 'static>, + callback: crate::context::BufferMapCallback, ) { let operation = wgc::resource::BufferMapOperation { host: match mode { @@ -2279,7 +2280,7 @@ impl crate::Context for Context { &self, queue: &Self::QueueId, _queue_data: &Self::QueueData, - callback: Box, + callback: crate::context::SubmittedWorkDoneCallback, ) { let closure = wgc::device::queue::SubmittedWorkDoneClosure::from_rust(callback); @@ -3051,7 +3052,21 @@ pub struct BufferMappedRange { size: usize, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] unsafe impl Send for BufferMappedRange {} +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] unsafe impl Sync for BufferMappedRange {} impl crate::context::BufferMappedRange for BufferMappedRange { diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index 239c663630..1dc5c712ab 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -65,7 +65,15 @@ impl From> for ObjectId { #[derive(Clone, Debug)] pub(crate) struct Sendable(T); +#[cfg(all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] unsafe impl Send for Sendable {} +#[cfg(all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] unsafe impl Sync for Sendable {} #[derive(Clone, Debug)] @@ -73,11 +81,27 @@ pub(crate) struct Identified( #[cfg(feature = "expose-ids")] std::num::NonZeroU64, PhantomData, ); +#[cfg(all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] unsafe impl Send for Identified {} +#[cfg(all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] unsafe impl Sync for Identified {} pub(crate) struct Context(web_sys::Gpu); +#[cfg(all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] unsafe impl Send for Context {} +#[cfg(all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] unsafe impl Sync for Context {} impl fmt::Debug for Context { @@ -134,6 +158,10 @@ impl MakeSendFuture { } } +#[cfg(all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") +))] unsafe impl Send for MakeSendFuture {} fn map_texture_format(texture_format: wgt::TextureFormat) -> web_sys::GpuTextureFormat { @@ -1838,7 +1866,7 @@ impl crate::context::Context for Context { buffer_data: &Self::BufferData, mode: crate::MapMode, range: Range, - callback: Box) + Send + 'static>, + callback: crate::context::BufferMapCallback, ) { let map_promise = buffer_data.0.map_async_with_f64_and_f64( map_map_mode(mode), @@ -2531,7 +2559,7 @@ impl crate::context::Context for Context { &self, _queue: &Self::QueueId, _queue_data: &Self::QueueData, - _callback: Box, + _callback: crate::context::SubmittedWorkDoneCallback, ) { unimplemented!() } diff --git a/wgpu/src/context.rs b/wgpu/src/context.rs index 6633e61b61..33e8b5a5e4 100644 --- a/wgpu/src/context.rs +++ b/wgpu/src/context.rs @@ -4,13 +4,13 @@ use wgt::{ strict_assert, strict_assert_eq, AdapterInfo, BufferAddress, BufferSize, Color, DownlevelCapabilities, DynamicOffset, Extent3d, Features, ImageDataLayout, ImageSubresourceRange, IndexFormat, Limits, ShaderStages, SurfaceStatus, TextureFormat, - TextureFormatFeatures, + TextureFormatFeatures, WasmNotSend, WasmNotSync, }; use crate::{ - BindGroupDescriptor, BindGroupLayoutDescriptor, Buffer, BufferAsyncError, BufferDescriptor, - CommandEncoderDescriptor, ComputePassDescriptor, ComputePipelineDescriptor, DeviceDescriptor, - Error, ErrorFilter, ImageCopyBuffer, ImageCopyTexture, Maintain, MapMode, + AnyWasmNotSendSync, BindGroupDescriptor, BindGroupLayoutDescriptor, Buffer, BufferAsyncError, + BufferDescriptor, CommandEncoderDescriptor, ComputePassDescriptor, ComputePipelineDescriptor, + DeviceDescriptor, Error, ErrorFilter, ImageCopyBuffer, ImageCopyTexture, Maintain, MapMode, PipelineLayoutDescriptor, QuerySetDescriptor, RenderBundleDescriptor, RenderBundleEncoderDescriptor, RenderPassDescriptor, RenderPipelineDescriptor, RequestAdapterOptions, RequestDeviceError, SamplerDescriptor, ShaderModuleDescriptor, @@ -27,59 +27,59 @@ impl + From + Debug + 'static> ContextId for T {} /// Meta trait for an data associated with an id tracked by a context. /// /// There is no need to manually implement this trait since there is a blanket implementation for this trait. -pub trait ContextData: Debug + Send + Sync + 'static {} -impl ContextData for T {} +pub trait ContextData: Debug + WasmNotSend + WasmNotSync + 'static {} +impl ContextData for T {} -pub trait Context: Debug + Send + Sized + Sync { - type AdapterId: ContextId + Send + Sync; +pub trait Context: Debug + WasmNotSend + WasmNotSync + Sized { + type AdapterId: ContextId + WasmNotSend + WasmNotSync; type AdapterData: ContextData; - type DeviceId: ContextId + Send + Sync; + type DeviceId: ContextId + WasmNotSend + WasmNotSync; type DeviceData: ContextData; - type QueueId: ContextId + Send + Sync; + type QueueId: ContextId + WasmNotSend + WasmNotSync; type QueueData: ContextData; - type ShaderModuleId: ContextId + Send + Sync; + type ShaderModuleId: ContextId + WasmNotSend + WasmNotSync; type ShaderModuleData: ContextData; - type BindGroupLayoutId: ContextId + Send + Sync; + type BindGroupLayoutId: ContextId + WasmNotSend + WasmNotSync; type BindGroupLayoutData: ContextData; - type BindGroupId: ContextId + Send + Sync; + type BindGroupId: ContextId + WasmNotSend + WasmNotSync; type BindGroupData: ContextData; - type TextureViewId: ContextId + Send + Sync; + type TextureViewId: ContextId + WasmNotSend + WasmNotSync; type TextureViewData: ContextData; - type SamplerId: ContextId + Send + Sync; + type SamplerId: ContextId + WasmNotSend + WasmNotSync; type SamplerData: ContextData; - type BufferId: ContextId + Send + Sync; + type BufferId: ContextId + WasmNotSend + WasmNotSync; type BufferData: ContextData; - type TextureId: ContextId + Send + Sync; + type TextureId: ContextId + WasmNotSend + WasmNotSync; type TextureData: ContextData; - type QuerySetId: ContextId + Send + Sync; + type QuerySetId: ContextId + WasmNotSend + WasmNotSync; type QuerySetData: ContextData; - type PipelineLayoutId: ContextId + Send + Sync; + type PipelineLayoutId: ContextId + WasmNotSend + WasmNotSync; type PipelineLayoutData: ContextData; - type RenderPipelineId: ContextId + Send + Sync; + type RenderPipelineId: ContextId + WasmNotSend + WasmNotSync; type RenderPipelineData: ContextData; - type ComputePipelineId: ContextId + Send + Sync; + type ComputePipelineId: ContextId + WasmNotSend + WasmNotSync; type ComputePipelineData: ContextData; - type CommandEncoderId: ContextId + Send + Sync; + type CommandEncoderId: ContextId + WasmNotSend + WasmNotSync; type CommandEncoderData: ContextData; type ComputePassId: ContextId; type ComputePassData: ContextData; type RenderPassId: ContextId; type RenderPassData: ContextData; - type CommandBufferId: ContextId + Send + Sync; + type CommandBufferId: ContextId + WasmNotSend + WasmNotSync; type CommandBufferData: ContextData; type RenderBundleEncoderId: ContextId; type RenderBundleEncoderData: ContextData; - type RenderBundleId: ContextId + Send + Sync; + type RenderBundleId: ContextId + WasmNotSend + WasmNotSync; type RenderBundleData: ContextData; - type SurfaceId: ContextId + Send + Sync; + type SurfaceId: ContextId + WasmNotSend + WasmNotSync; type SurfaceData: ContextData; - type SurfaceOutputDetail: Send + Sync + 'static; - type SubmissionIndex: ContextId + Clone + Copy + Send + Sync; + type SurfaceOutputDetail: WasmNotSend + WasmNotSync + 'static; + type SubmissionIndex: ContextId + Clone + Copy + WasmNotSend + WasmNotSync; type SubmissionIndexData: ContextData + Copy; type RequestAdapterFuture: Future> - + Send + + WasmNotSend + 'static; type RequestDeviceFuture: Future< Output = Result< @@ -91,9 +91,9 @@ pub trait Context: Debug + Send + Sized + Sync { ), RequestDeviceError, >, - > + Send + > + WasmNotSend + 'static; - type PopErrorScopeFuture: Future> + Send + 'static; + type PopErrorScopeFuture: Future> + WasmNotSend + 'static; fn init(instance_desc: wgt::InstanceDescriptor) -> Self; fn instance_create_surface( @@ -299,7 +299,7 @@ pub trait Context: Debug + Send + Sized + Sync { buffer_data: &Self::BufferData, mode: MapMode, range: Range, - callback: Box) + Send + 'static>, + callback: BufferMapCallback, ); fn buffer_get_mapped_range( &self, @@ -585,7 +585,7 @@ pub trait Context: Debug + Send + Sized + Sync { &self, queue: &Self::QueueId, queue_data: &Self::QueueData, - callback: Box, + callback: SubmittedWorkDoneCallback, ); fn device_start_capture(&self, device: &Self::DeviceId, device_data: &Self::DeviceData); @@ -1039,15 +1039,24 @@ impl ObjectId { } } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(ObjectId: Send, Sync); -pub(crate) fn downcast_ref(data: &crate::Data) -> &T { +pub(crate) fn downcast_ref( + data: &crate::Data, +) -> &T { strict_assert!(data.is::()); // Copied from std. unsafe { &*(data as *const dyn Any as *const T) } } -fn downcast_mut(data: &mut crate::Data) -> &mut T { +fn downcast_mut(data: &mut crate::Data) -> &mut T { strict_assert!(data.is::()); // Copied from std. unsafe { &mut *(data as *mut dyn Any as *mut T) } @@ -1079,8 +1088,97 @@ pub(crate) struct DeviceRequest { pub queue_data: Box, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] +pub type BufferMapCallback = Box) + Send + 'static>; +#[cfg(not(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +)))] +pub type BufferMapCallback = Box) + 'static>; + +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] +pub(crate) type AdapterRequestDeviceFuture = + Box> + Send>; +#[cfg(not(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +)))] +pub(crate) type AdapterRequestDeviceFuture = + Box>>; + +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] +pub type InstanceRequestAdapterFuture = + Box)>> + Send>; +#[cfg(not(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +)))] +pub type InstanceRequestAdapterFuture = + Box)>>>; + +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] +pub type DevicePopErrorFuture = Box> + Send>; +#[cfg(not(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +)))] +pub type DevicePopErrorFuture = Box>>; + +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] +pub type SubmittedWorkDoneCallback = Box; +#[cfg(not(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +)))] +pub type SubmittedWorkDoneCallback = Box; + /// An object safe variant of [`Context`] implemented by all types that implement [`Context`]. -pub(crate) trait DynContext: Debug + Send + Sync { +pub(crate) trait DynContext: Debug + WasmNotSend + WasmNotSync { fn as_any(&self) -> &dyn Any; fn instance_create_surface( @@ -1092,14 +1190,14 @@ pub(crate) trait DynContext: Debug + Send + Sync { fn instance_request_adapter( &self, options: &RequestAdapterOptions<'_>, - ) -> Pin)>> + Send>>; + ) -> Pin; fn adapter_request_device( &self, adapter: &ObjectId, adapter_data: &crate::Data, desc: &DeviceDescriptor, trace_dir: Option<&std::path::Path>, - ) -> Pin> + Send>>; + ) -> Pin; fn instance_poll_all_devices(&self, force_wait: bool) -> bool; fn adapter_is_surface_supported( @@ -1152,10 +1250,10 @@ pub(crate) trait DynContext: Debug + Send + Sync { Option, Option>, SurfaceStatus, - Box, + Box, ); - fn surface_present(&self, texture: &ObjectId, detail: &(dyn Any + Send + Sync)); - fn surface_texture_discard(&self, texture: &ObjectId, detail: &(dyn Any + Send + Sync)); + fn surface_present(&self, texture: &ObjectId, detail: &dyn AnyWasmNotSendSync); + fn surface_texture_discard(&self, texture: &ObjectId, detail: &dyn AnyWasmNotSendSync); fn device_features(&self, device: &ObjectId, device_data: &crate::Data) -> Features; fn device_limits(&self, device: &ObjectId, device_data: &crate::Data) -> Limits; @@ -1262,14 +1360,14 @@ pub(crate) trait DynContext: Debug + Send + Sync { &self, device: &ObjectId, device_data: &crate::Data, - ) -> Pin> + Send + 'static>>; + ) -> Pin; fn buffer_map_async( &self, buffer: &ObjectId, buffer_data: &crate::Data, mode: MapMode, range: Range, - callback: Box) + Send + 'static>, + callback: BufferMapCallback, ); fn buffer_get_mapped_range( &self, @@ -1511,7 +1609,7 @@ pub(crate) trait DynContext: Debug + Send + Sync { &self, queue: &ObjectId, queue_data: &crate::Data, - callback: Box, + callback: SubmittedWorkDoneCallback, ); fn device_start_capture(&self, device: &ObjectId, data: &crate::Data); @@ -1931,7 +2029,7 @@ where fn instance_request_adapter( &self, options: &RequestAdapterOptions<'_>, - ) -> Pin)>> + Send>> { + ) -> Pin { let future: T::RequestAdapterFuture = Context::instance_request_adapter(self, options); Box::pin(async move { let result: Option<(T::AdapterId, T::AdapterData)> = future.await; @@ -1945,7 +2043,7 @@ where adapter_data: &crate::Data, desc: &DeviceDescriptor, trace_dir: Option<&std::path::Path>, - ) -> Pin> + Send>> { + ) -> Pin { let adapter = ::from(*adapter); let adapter_data = downcast_ref(adapter_data); let future = Context::adapter_request_device(self, &adapter, adapter_data, desc, trace_dir); @@ -2064,13 +2162,13 @@ where Option, Option>, SurfaceStatus, - Box, + Box, ) { let surface = ::from(*surface); let surface_data = downcast_ref(surface_data); let (texture, texture_data, status, detail) = Context::surface_get_current_texture(self, &surface, surface_data); - let detail = Box::new(detail) as Box; + let detail = Box::new(detail) as Box; ( texture.map(Into::into), texture_data.map(|b| Box::new(b) as _), @@ -2079,12 +2177,12 @@ where ) } - fn surface_present(&self, texture: &ObjectId, detail: &(dyn Any + Send + Sync)) { + fn surface_present(&self, texture: &ObjectId, detail: &dyn AnyWasmNotSendSync) { let texture = ::from(*texture); Context::surface_present(self, &texture, detail.downcast_ref().unwrap()) } - fn surface_texture_discard(&self, texture: &ObjectId, detail: &(dyn Any + Send + Sync)) { + fn surface_texture_discard(&self, texture: &ObjectId, detail: &dyn AnyWasmNotSendSync) { let texture = ::from(*texture); Context::surface_texture_discard(self, &texture, detail.downcast_ref().unwrap()) } @@ -2325,7 +2423,7 @@ where &self, device: &ObjectId, device_data: &crate::Data, - ) -> Pin> + Send + 'static>> { + ) -> Pin { let device = ::from(*device); let device_data = downcast_ref(device_data); Box::pin(Context::device_pop_error_scope(self, &device, device_data)) @@ -2337,7 +2435,7 @@ where buffer_data: &crate::Data, mode: MapMode, range: Range, - callback: Box) + Send + 'static>, + callback: BufferMapCallback, ) { let buffer = ::from(*buffer); let buffer_data = downcast_ref(buffer_data); @@ -2928,7 +3026,7 @@ where &self, queue: &ObjectId, queue_data: &crate::Data, - callback: Box, + callback: SubmittedWorkDoneCallback, ) { let queue = ::from(*queue); let queue_data = downcast_ref(queue_data); @@ -3861,7 +3959,7 @@ where } } -pub trait QueueWriteBuffer: Send + Sync { +pub trait QueueWriteBuffer: WasmNotSend + WasmNotSync { fn slice(&self) -> &[u8]; fn slice_mut(&mut self) -> &mut [u8]; diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index a9a45ffaa1..2ab86419a1 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -43,8 +43,9 @@ pub use wgt::{ StorageTextureAccess, SurfaceCapabilities, SurfaceStatus, TextureAspect, TextureDimension, TextureFormat, TextureFormatFeatureFlags, TextureFormatFeatures, TextureSampleType, TextureUsages, TextureViewDimension, VertexAttribute, VertexFormat, VertexStepMode, - COPY_BUFFER_ALIGNMENT, COPY_BYTES_PER_ROW_ALIGNMENT, MAP_ALIGNMENT, PUSH_CONSTANT_ALIGNMENT, - QUERY_RESOLVE_BUFFER_ALIGNMENT, QUERY_SET_MAX_QUERIES, QUERY_SIZE, VERTEX_STRIDE_ALIGNMENT, + WasmNotSend, WasmNotSync, COPY_BUFFER_ALIGNMENT, COPY_BYTES_PER_ROW_ALIGNMENT, MAP_ALIGNMENT, + PUSH_CONSTANT_ALIGNMENT, QUERY_RESOLVE_BUFFER_ALIGNMENT, QUERY_SET_MAX_QUERIES, QUERY_SIZE, + VERTEX_STRIDE_ALIGNMENT, }; #[cfg(any( @@ -66,8 +67,6 @@ pub use ::wgc as core; // specific, but these need to depend on web-sys. #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] pub use wgt::{ExternalImageSource, ImageCopyExternalImage}; -#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] -static_assertions::assert_impl_all!(ExternalImageSource: Send, Sync); /// Filter for error scopes. #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd)] @@ -80,7 +79,22 @@ pub enum ErrorFilter { static_assertions::assert_impl_all!(ErrorFilter: Send, Sync); type C = dyn DynContext; +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] type Data = dyn Any + Send + Sync; +#[cfg(not(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +)))] +type Data = dyn Any; /// Context for all other wgpu objects. Instance of wgpu. /// @@ -94,6 +108,13 @@ type Data = dyn Any + Send + Sync; pub struct Instance { context: Arc, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(Instance: Send, Sync); /// Handle to a physical graphics and/or compute device. @@ -110,6 +131,13 @@ pub struct Adapter { id: ObjectId, data: Box, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(Adapter: Send, Sync); impl Drop for Adapter { @@ -134,6 +162,13 @@ pub struct Device { id: ObjectId, data: Box, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(Device: Send, Sync); /// Identifier for a particular call to [`Queue::submit`]. Can be used @@ -144,6 +179,13 @@ static_assertions::assert_impl_all!(Device: Send, Sync); /// There is no analogue in the WebGPU specification. #[derive(Debug, Clone)] pub struct SubmissionIndex(ObjectId, Arc); +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(SubmissionIndex: Send, Sync); /// The main purpose of this struct is to resolve mapped ranges (convert sizes @@ -220,6 +262,13 @@ pub struct Buffer { usage: BufferUsages, // Todo: missing map_state https://www.w3.org/TR/webgpu/#dom-gpubuffer-mapstate } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(Buffer: Send, Sync); /// Slice into a [`Buffer`]. @@ -236,6 +285,13 @@ pub struct BufferSlice<'a> { offset: BufferAddress, size: Option, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(BufferSlice: Send, Sync); /// Handle to a texture on the GPU. @@ -251,6 +307,13 @@ pub struct Texture { owned: bool, descriptor: TextureDescriptor<'static>, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(Texture: Send, Sync); /// Handle to a texture view. @@ -265,6 +328,13 @@ pub struct TextureView { id: ObjectId, data: Box, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(TextureView: Send, Sync); /// Handle to a sampler. @@ -282,6 +352,13 @@ pub struct Sampler { id: ObjectId, data: Box, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(Sampler: Send, Sync); impl Drop for Sampler { @@ -322,6 +399,13 @@ pub struct Surface { // been created is is additionally wrapped in an option. config: Mutex>, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(Surface: Send, Sync); impl Drop for Surface { @@ -349,6 +433,13 @@ pub struct BindGroupLayout { id: ObjectId, data: Box, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(BindGroupLayout: Send, Sync); impl Drop for BindGroupLayout { @@ -374,6 +465,13 @@ pub struct BindGroup { id: ObjectId, data: Box, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(BindGroup: Send, Sync); impl Drop for BindGroup { @@ -398,6 +496,13 @@ pub struct ShaderModule { id: ObjectId, data: Box, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(ShaderModule: Send, Sync); impl Drop for ShaderModule { @@ -490,6 +595,13 @@ pub struct PipelineLayout { id: ObjectId, data: Box, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(PipelineLayout: Send, Sync); impl Drop for PipelineLayout { @@ -513,6 +625,13 @@ pub struct RenderPipeline { id: ObjectId, data: Box, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(RenderPipeline: Send, Sync); impl Drop for RenderPipeline { @@ -547,6 +666,13 @@ pub struct ComputePipeline { id: ObjectId, data: Box, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(ComputePipeline: Send, Sync); impl Drop for ComputePipeline { @@ -584,6 +710,13 @@ pub struct CommandBuffer { id: Option, data: Option>, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(CommandBuffer: Send, Sync); impl Drop for CommandBuffer { @@ -612,6 +745,13 @@ pub struct CommandEncoder { id: Option, data: Box, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(CommandEncoder: Send, Sync); impl Drop for CommandEncoder { @@ -688,6 +828,13 @@ pub struct RenderBundle { id: ObjectId, data: Box, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(RenderBundle: Send, Sync); impl Drop for RenderBundle { @@ -709,6 +856,13 @@ pub struct QuerySet { id: ObjectId, data: Box, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(QuerySet: Send, Sync); impl Drop for QuerySet { @@ -732,6 +886,13 @@ pub struct Queue { id: ObjectId, data: Box, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(Queue: Send, Sync); /// Resource that can be bound to a pipeline. @@ -777,6 +938,13 @@ pub enum BindingResource<'a> { /// [`BindGroupLayoutEntry::count`] set to Some. TextureViewArray(&'a [&'a TextureView]), } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(BindingResource: Send, Sync); /// Describes the segment of a buffer to bind. @@ -808,6 +976,13 @@ pub struct BufferBinding<'a> { /// Size of the binding in bytes, or `None` for using the rest of the buffer. pub size: Option, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(BufferBinding: Send, Sync); /// Operation to perform to the output attachment at the start of a render pass. @@ -869,6 +1044,13 @@ pub struct RenderPassColorAttachment<'tex> { /// What operations will be performed on this color attachment. pub ops: Operations, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(RenderPassColorAttachment: Send, Sync); /// Describes a depth/stencil attachment to a [`RenderPass`]. @@ -886,6 +1068,13 @@ pub struct RenderPassDepthStencilAttachment<'tex> { /// What operations will be performed on the stencil part of the attachment. pub stencil_ops: Option>, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(RenderPassDepthStencilAttachment: Send, Sync); // The underlying types are also exported so that documentation shows up for them @@ -900,6 +1089,13 @@ pub use wgt::RequestAdapterOptions as RequestAdapterOptionsBase; /// Corresponds to [WebGPU `GPURequestAdapterOptions`]( /// https://gpuweb.github.io/gpuweb/#dictdef-gpurequestadapteroptions). pub type RequestAdapterOptions<'a> = RequestAdapterOptionsBase<&'a Surface>; +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(RequestAdapterOptions: Send, Sync); /// Describes a [`Device`]. /// @@ -952,6 +1148,13 @@ static_assertions::assert_impl_all!(QuerySetDescriptor: Send, Sync); pub use wgt::Maintain as MaintainBase; /// Passed to [`Device::poll`] to control how and if it should block. pub type Maintain = wgt::Maintain; +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(Maintain: Send, Sync); /// Describes a [`TextureView`]. @@ -1007,6 +1210,13 @@ pub struct PipelineLayoutDescriptor<'a> { /// If this array is non-empty, the [`Features::PUSH_CONSTANTS`] must be enabled. pub push_constant_ranges: &'a [PushConstantRange], } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(PipelineLayoutDescriptor: Send, Sync); /// Describes a [`Sampler`]. @@ -1076,6 +1286,13 @@ pub struct BindGroupEntry<'a> { /// Resource to attach to the binding pub resource: BindingResource<'a>, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(BindGroupEntry: Send, Sync); /// Describes a group of bindings and the resources to be bound. @@ -1093,6 +1310,13 @@ pub struct BindGroupDescriptor<'a> { /// The resources to bind to this bind group. pub entries: &'a [BindGroupEntry<'a>], } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(BindGroupDescriptor: Send, Sync); /// Describes the attachments of a render pass. @@ -1113,6 +1337,13 @@ pub struct RenderPassDescriptor<'tex, 'desc> { /// The depth and stencil attachment of the render pass, if any. pub depth_stencil_attachment: Option>, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(RenderPassDescriptor: Send, Sync); /// Describes how the vertex buffer is interpreted. @@ -1148,6 +1379,13 @@ pub struct VertexState<'a> { /// The format of any vertex buffers used with this pipeline. pub buffers: &'a [VertexBufferLayout<'a>], } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(VertexState: Send, Sync); /// Describes the fragment processing in a render pipeline. @@ -1166,6 +1404,13 @@ pub struct FragmentState<'a> { /// The color state of the render targets. pub targets: &'a [Option], } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(FragmentState: Send, Sync); /// Describes a render (graphics) pipeline. @@ -1194,6 +1439,13 @@ pub struct RenderPipelineDescriptor<'a> { /// layers the attachments will have. pub multiview: Option, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(RenderPipelineDescriptor: Send, Sync); /// Describes the attachments of a compute pass. @@ -1227,6 +1479,13 @@ pub struct ComputePipelineDescriptor<'a> { /// and no return value in the shader. pub entry_point: &'a str, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(ComputePipelineDescriptor: Send, Sync); pub use wgt::ImageCopyBuffer as ImageCopyBufferBase; @@ -1235,6 +1494,13 @@ pub use wgt::ImageCopyBuffer as ImageCopyBufferBase; /// Corresponds to [WebGPU `GPUImageCopyBuffer`]( /// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopybuffer). pub type ImageCopyBuffer<'a> = ImageCopyBufferBase<&'a Buffer>; +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(ImageCopyBuffer: Send, Sync); pub use wgt::ImageCopyTexture as ImageCopyTextureBase; @@ -1243,6 +1509,13 @@ pub use wgt::ImageCopyTexture as ImageCopyTextureBase; /// Corresponds to [WebGPU `GPUImageCopyTexture`]( /// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopytexture). pub type ImageCopyTexture<'a> = ImageCopyTextureBase<&'a Texture>; +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(ImageCopyTexture: Send, Sync); pub use wgt::ImageCopyTextureTagged as ImageCopyTextureTaggedBase; @@ -1252,6 +1525,13 @@ pub use wgt::ImageCopyTextureTagged as ImageCopyTextureTaggedBase; /// Corresponds to [WebGPU `GPUImageCopyTextureTagged`]( /// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopytexturetagged). pub type ImageCopyTextureTagged<'a> = ImageCopyTextureTaggedBase<&'a Texture>; +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(ImageCopyTexture: Send, Sync); /// Describes a [`BindGroupLayout`]. @@ -1308,8 +1588,15 @@ pub struct SurfaceTexture { /// but should be recreated for maximum performance. pub suboptimal: bool, presented: bool, - detail: Box, + detail: Box, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(SurfaceTexture: Send, Sync); /// Result of an unsuccessful call to [`Surface::get_current_texture`]. @@ -1463,7 +1750,7 @@ impl Instance { pub fn request_adapter( &self, options: &RequestAdapterOptions, - ) -> impl Future> + Send { + ) -> impl Future> + WasmNotSend { let context = Arc::clone(&self.context); let adapter = self.context.instance_request_adapter(options); async move { @@ -1743,7 +2030,7 @@ impl Adapter { &self, desc: &DeviceDescriptor, trace_path: Option<&std::path::Path>, - ) -> impl Future> + Send { + ) -> impl Future> + WasmNotSend { let context = Arc::clone(&self.context); let device = DynContext::adapter_request_device( &*self.context, @@ -2257,7 +2544,7 @@ impl Device { } /// Pop an error scope. - pub fn pop_error_scope(&self) -> impl Future> + Send { + pub fn pop_error_scope(&self) -> impl Future> + WasmNotSend { self.context .device_pop_error_scope(&self.id, self.data.as_ref()) } @@ -2562,7 +2849,7 @@ impl<'a> BufferSlice<'a> { pub fn map_async( &self, mode: MapMode, - callback: impl FnOnce(Result<(), BufferAsyncError>) + Send + 'static, + callback: impl FnOnce(Result<(), BufferAsyncError>) + WasmNotSend + 'static, ) { let mut mc = self.buffer.map_context.lock(); assert_eq!( @@ -3970,6 +4257,13 @@ pub struct QueueWriteBufferView<'a> { offset: BufferAddress, inner: Box, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(QueueWriteBufferView: Send, Sync); impl Deref for QueueWriteBufferView<'_> { @@ -4609,16 +4903,55 @@ pub enum Error { /// Out of memory error OutOfMemory { /// Lower level source of the error. + #[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) + ))] source: Box, + /// Lower level source of the error. + #[cfg(not(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) + )))] + source: Box, }, /// Validation error, signifying a bug in code or data Validation { /// Lower level source of the error. + #[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) + ))] source: Box, + /// Lower level source of the error. + #[cfg(not(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) + )))] + source: Box, /// Description of the validation error. description: String, }, } +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] static_assertions::assert_impl_all!(Error: Send); impl error::Error for Error { @@ -4638,3 +4971,35 @@ impl Display for Error { } } } + +use send_sync::*; + +mod send_sync { + use std::any::Any; + use std::fmt; + + use wgt::{WasmNotSend, WasmNotSync}; + + pub trait AnyWasmNotSendSync: Any + WasmNotSend + WasmNotSync { + fn upcast_any_ref(&self) -> &dyn Any; + } + impl AnyWasmNotSendSync for T { + #[inline] + fn upcast_any_ref(&self) -> &dyn Any { + self + } + } + + impl dyn AnyWasmNotSendSync + 'static { + #[inline] + pub fn downcast_ref(&self) -> Option<&T> { + self.upcast_any_ref().downcast_ref::() + } + } + + impl fmt::Debug for dyn AnyWasmNotSendSync { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Any").finish_non_exhaustive() + } + } +} From 17143c149c13ea5af36909ef6033e776cecad28c Mon Sep 17 00:00:00 2001 From: Fredrik Fornwall Date: Fri, 30 Jun 2023 00:30:34 +0200 Subject: [PATCH 5/7] Make shader write&read storage buffers match non readonly layouts (#3893) --- CHANGELOG.md | 1 + wgpu-core/src/validation.rs | 71 ++++++++++++++++++++++++++++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bceb0e7ec..367acb563a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,6 +74,7 @@ Bottom level categories: - Fix order of arguments to glPolygonOffset by @komadori in [#3783](https://github.com/gfx-rs/wgpu/pull/3783). - Fix OpenGL/EGL backend not respecting non-sRGB texture formats in `SurfaceConfiguration`. by @liquidev in [#3817](https://github.com/gfx-rs/wgpu/pull/3817) +- Make write- and read-only marked buffers match non-readonly layouts. by @fornwall in [#3893](https://github.com/gfx-rs/wgpu/pull/3893) #### Metal diff --git a/wgpu-core/src/validation.rs b/wgpu-core/src/validation.rs index 83cb90530a..771adba731 100644 --- a/wgpu-core/src/validation.rs +++ b/wgpu-core/src/validation.rs @@ -409,7 +409,7 @@ impl Resource { ) } }; - if self.class != class { + if !address_space_matches(self.class, class) { return Err(BindingError::WrongAddressSpace { binding: class, shader: self.class, @@ -1237,3 +1237,72 @@ impl Interface { Ok(outputs) } } + +fn address_space_matches(shader: naga::AddressSpace, binding: naga::AddressSpace) -> bool { + match (shader, binding) { + ( + naga::AddressSpace::Storage { + access: access_shader, + }, + naga::AddressSpace::Storage { + access: access_pipeline, + }, + ) => { + // Allow read- and write-only usages to match read-write layouts: + (access_shader & access_pipeline) == access_shader + } + (a, b) => a == b, + } +} + +#[cfg(test)] +mod test { + use super::address_space_matches; + + #[test] + fn address_space_matches_correctly() { + assert!(address_space_matches( + naga::AddressSpace::Uniform, + naga::AddressSpace::Uniform + )); + + assert!(!address_space_matches( + naga::AddressSpace::Uniform, + naga::AddressSpace::Storage { + access: naga::StorageAccess::LOAD + } + )); + + let test_cases = [ + (naga::StorageAccess::LOAD, naga::StorageAccess::LOAD, true), + (naga::StorageAccess::STORE, naga::StorageAccess::LOAD, false), + (naga::StorageAccess::LOAD, naga::StorageAccess::STORE, false), + (naga::StorageAccess::STORE, naga::StorageAccess::STORE, true), + ( + naga::StorageAccess::LOAD | naga::StorageAccess::STORE, + naga::StorageAccess::LOAD | naga::StorageAccess::STORE, + true, + ), + ( + naga::StorageAccess::STORE, + naga::StorageAccess::LOAD | naga::StorageAccess::STORE, + true, + ), + ( + naga::StorageAccess::LOAD, + naga::StorageAccess::LOAD | naga::StorageAccess::STORE, + true, + ), + ]; + + for (shader, binding, expect_match) in test_cases { + assert_eq!( + expect_match, + address_space_matches( + naga::AddressSpace::Storage { access: shader }, + naga::AddressSpace::Storage { access: binding } + ) + ); + } + } +} From 1c43272d2a09367291aa02485a412ccac9257ca8 Mon Sep 17 00:00:00 2001 From: Fredrik Fornwall Date: Wed, 5 Jul 2023 18:21:39 +0200 Subject: [PATCH 6/7] Remove backend_bits from initialize_adapter_from_env (#3904) Remove backend_bits from initialize_adapter_from_env, backends can be specified using the backends field in InstanceDescriptor instead. --- CHANGELOG.md | 1 + examples/common/src/framework.rs | 7 +++---- tests/src/lib.rs | 1 - wgpu/src/util/init.rs | 12 ++++-------- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 367acb563a..92ee4deddc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ Bottom level categories: #### Misc Breaking Changes - Change `AdapterInfo::{device,vendor}` to be `u32` instead of `usize`. By @ameknite in [#3760](https://github.com/gfx-rs/wgpu/pull/3760) +- Remove the `backend_bits` parameter in `initialize_adapter_from_env` and `initialize_adapter_from_env_or_default` - use [InstanceDescriptor::backends](https://docs.rs/wgpu/latest/wgpu/struct.InstanceDescriptor.html#structfield.backends) instead. By @fornwall in [#3904](https://github.com/gfx-rs/wgpu/pull/3904) #### DX12 diff --git a/examples/common/src/framework.rs b/examples/common/src/framework.rs index 27b76bf86b..af8a3b963b 100644 --- a/examples/common/src/framework.rs +++ b/examples/common/src/framework.rs @@ -180,10 +180,9 @@ async fn setup(title: &str) -> Setup { (size, surface) }; - let adapter = - wgpu::util::initialize_adapter_from_env_or_default(&instance, backends, Some(&surface)) - .await - .expect("No suitable GPU adapters found on the system!"); + let adapter = wgpu::util::initialize_adapter_from_env_or_default(&instance, Some(&surface)) + .await + .expect("No suitable GPU adapters found on the system!"); #[cfg(not(target_arch = "wasm32"))] { diff --git a/tests/src/lib.rs b/tests/src/lib.rs index b8a0fb2443..401e4cd273 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -392,7 +392,6 @@ fn initialize_adapter() -> (Adapter, SurfaceGuard) { let compatible_surface: Option<&Surface> = compatible_surface.as_ref(); let adapter = pollster::block_on(wgpu::util::initialize_adapter_from_env_or_default( &instance, - backends, compatible_surface, )) .expect("could not find suitable adapter on the system"); diff --git a/wgpu/src/util/init.rs b/wgpu/src/util/init.rs index d5c7c6ad47..e47a08a304 100644 --- a/wgpu/src/util/init.rs +++ b/wgpu/src/util/init.rs @@ -37,13 +37,13 @@ pub fn power_preference_from_env() -> Option { /// Initialize the adapter obeying the WGPU_ADAPTER_NAME environment variable. #[cfg(not(target_arch = "wasm32"))] -pub fn initialize_adapter_from_env(instance: &Instance, backend_bits: Backends) -> Option { +pub fn initialize_adapter_from_env(instance: &Instance) -> Option { let desired_adapter_name = std::env::var("WGPU_ADAPTER_NAME") .as_deref() .map(str::to_lowercase) .ok()?; - let adapters = instance.enumerate_adapters(backend_bits); + let adapters = instance.enumerate_adapters(Backends::all()); let mut chosen_adapter = None; for adapter in adapters { @@ -60,20 +60,16 @@ pub fn initialize_adapter_from_env(instance: &Instance, backend_bits: Backends) /// Initialize the adapter obeying the WGPU_ADAPTER_NAME environment variable. #[cfg(target_arch = "wasm32")] -pub fn initialize_adapter_from_env( - _instance: &Instance, - _backend_bits: Backends, -) -> Option { +pub fn initialize_adapter_from_env(_instance: &Instance) -> Option { None } /// Initialize the adapter obeying the WGPU_ADAPTER_NAME environment variable and if it doesn't exist fall back on a default adapter. pub async fn initialize_adapter_from_env_or_default( instance: &Instance, - backend_bits: wgt::Backends, compatible_surface: Option<&Surface>, ) -> Option { - match initialize_adapter_from_env(instance, backend_bits) { + match initialize_adapter_from_env(instance) { Some(a) => Some(a), None => { instance From 234dea18c4a63d63d461f5695fb1a54b5bcb4e1a Mon Sep 17 00:00:00 2001 From: Fredrik Fornwall Date: Thu, 6 Jul 2023 00:17:43 +0200 Subject: [PATCH 7/7] Fix link to GPUVertexBufferLayout Fixes #3342. --- CHANGELOG.md | 1 + wgpu/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92ee4deddc..247a7f41be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,6 +63,7 @@ Bottom level categories: ### Documentation - Better documentation for draw, draw_indexed, set_viewport and set_scissor_rect. By @genusistimelord in [#3860](https://github.com/gfx-rs/wgpu/pull/3860) +- Fix link to `GPUVertexBufferLayout`. By @fornwall in [#3906](https://github.com/gfx-rs/wgpu/pull/3906) #### General diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 2ab86419a1..78c71a77ee 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -1351,7 +1351,7 @@ static_assertions::assert_impl_all!(RenderPassDescriptor: Send, Sync); /// For use in [`VertexState`]. /// /// Corresponds to [WebGPU `GPUVertexBufferLayout`]( -/// https://gpuweb.github.io/gpuweb/#dictdef-gpurenderpassdescriptor). +/// https://gpuweb.github.io/gpuweb/#dictdef-gpuvertexbufferlayout). #[derive(Clone, Debug, Hash, Eq, PartialEq)] pub struct VertexBufferLayout<'a> { /// The stride, in bytes, between elements of this buffer.