From 8bf6ff290269605f9e45dbff2cb38c1175f42b53 Mon Sep 17 00:00:00 2001 From: TheOnlyMrCat Date: Sat, 8 Oct 2022 19:37:14 +1100 Subject: [PATCH 1/7] Add expose-ids feature and BackendId trait --- wgpu/Cargo.toml | 1 + wgpu/src/backend/direct.rs | 43 +++++++++++++++++++++++++++++++++++ wgpu/src/backend/mod.rs | 4 ++-- wgpu/src/backend/web.rs | 29 +++++++++++++++++++++++- wgpu/src/lib.rs | 46 ++++++++++++++++++++++---------------- 5 files changed, 101 insertions(+), 22 deletions(-) diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index 3f0489013a..67332c7e76 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -86,6 +86,7 @@ angle = ["wgc/angle"] webgl = ["wgc"] emscripten = ["webgl"] vulkan-portability = ["wgc/vulkan-portability"] +expose-ids = [] [target.'cfg(not(target_arch = "wasm32"))'.dependencies.wgc] package = "wgpu-core" diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index 06fcbb6f36..2955bfb64a 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -801,6 +801,49 @@ pub(crate) struct CommandEncoder { open: bool, } +pub(crate) type Id = (u32, u32, wgt::Backend); + +impl crate::BikeshedBackendId for T { + fn id(&self) -> Id { + self.unzip() + } +} + +impl crate::BikeshedBackendId for Surface { + fn id(&self) -> Id { + use wgc::id::TypedId; + self.id.unzip() + } +} + +impl crate::BikeshedBackendId for Device { + fn id(&self) -> Id { + use wgc::id::TypedId; + self.id.unzip() + } +} + +impl crate::BikeshedBackendId for Buffer { + fn id(&self) -> Id { + use wgc::id::TypedId; + self.id.unzip() + } +} + +impl crate::BikeshedBackendId for Texture { + fn id(&self) -> Id { + use wgc::id::TypedId; + self.id.unzip() + } +} + +impl crate::BikeshedBackendId for CommandEncoder { + fn id(&self) -> Id { + use wgc::id::TypedId; + self.id.unzip() + } +} + impl crate::Context for Context { type AdapterId = wgc::id::AdapterId; type DeviceId = Device; diff --git a/wgpu/src/backend/mod.rs b/wgpu/src/backend/mod.rs index d3f88c6928..1e5adc26e5 100644 --- a/wgpu/src/backend/mod.rs +++ b/wgpu/src/backend/mod.rs @@ -1,9 +1,9 @@ #[cfg(all(target_arch = "wasm32", not(feature = "webgl")))] mod web; #[cfg(all(target_arch = "wasm32", not(feature = "webgl")))] -pub(crate) use web::{BufferMappedRange, Context, QueueWriteBuffer}; +pub(crate) use web::{BufferMappedRange, Context, Id, QueueWriteBuffer}; #[cfg(any(not(target_arch = "wasm32"), feature = "webgl"))] mod direct; #[cfg(any(not(target_arch = "wasm32"), feature = "webgl"))] -pub(crate) use direct::{BufferMappedRange, Context, QueueWriteBuffer}; +pub(crate) use direct::{BufferMappedRange, Context, Id, QueueWriteBuffer}; diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index 01d454601e..c72867fc53 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -25,7 +25,25 @@ pub(crate) struct Sendable(T); unsafe impl Send for Sendable {} unsafe impl Sync for Sendable {} -pub(crate) struct Context(web_sys::Gpu); +impl crate::BikeshedBackendId for Sendable { + fn id(&self) -> Id { + 0 + } +} + +// For QuerySetId +impl crate::BikeshedBackendId for () { + fn id(&self) -> Id { + 0 + } +} + +pub(crate) type Id = u64; + +pub(crate) struct Context( + web_sys::Gpu, + #[cfg(feature = "expose-ids")] std::sync::atomic::AtomicU64, +); unsafe impl Send for Context {} unsafe impl Sync for Context {} @@ -1073,6 +1091,7 @@ impl crate::Context for Context { type PopErrorScopeFuture = MakeSendFuture Option>; + #[cfg(not(feature = "expose-ids"))] fn init(_backends: wgt::Backends) -> Self { let global: Global = js_sys::global().unchecked_into(); let gpu = if !global.window().is_undefined() { @@ -1090,6 +1109,14 @@ impl crate::Context for Context { Context(gpu) } + #[cfg(feature = "expose-ids")] + fn init(_backends: wgt::Backends) -> Self { + Context( + web_sys::window().unwrap().navigator().gpu(), + std::sync::atomic::AtomicU64::new(0), + ) + } + fn instance_create_surface( &self, _display_handle: raw_window_handle::RawDisplayHandle, diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 2804244573..ec4d939291 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -43,7 +43,7 @@ pub use wgt::{ QUERY_RESOLVE_BUFFER_ALIGNMENT, QUERY_SET_MAX_QUERIES, QUERY_SIZE, VERTEX_STRIDE_ALIGNMENT, }; -use backend::{BufferMappedRange, Context as C, QueueWriteBuffer}; +use backend::{BufferMappedRange, Context as C, Id as BackendId, QueueWriteBuffer}; /// Filter for error scopes. #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd)] @@ -164,28 +164,32 @@ trait RenderPassInner: RenderInner { ); } +trait BikeshedBackendId { + fn id(&self) -> BackendId; +} + trait Context: Debug + Send + Sized + Sync { - type AdapterId: Debug + Send + Sync + 'static; - type DeviceId: Debug + Send + Sync + 'static; - type QueueId: Debug + Send + Sync + 'static; - type ShaderModuleId: Debug + Send + Sync + 'static; - type BindGroupLayoutId: Debug + Send + Sync + 'static; - type BindGroupId: Debug + Send + Sync + 'static; - type TextureViewId: Debug + Send + Sync + 'static; - type SamplerId: Debug + Send + Sync + 'static; - type BufferId: Debug + Send + Sync + 'static; - type TextureId: Debug + Send + Sync + 'static; - type QuerySetId: Debug + Send + Sync + 'static; - type PipelineLayoutId: Debug + Send + Sync + 'static; - type RenderPipelineId: Debug + Send + Sync + 'static; - type ComputePipelineId: Debug + Send + Sync + 'static; - type CommandEncoderId: Debug; + type AdapterId: BikeshedBackendId + Debug + Send + Sync + 'static; + type DeviceId: BikeshedBackendId + Debug + Send + Sync + 'static; + type QueueId: BikeshedBackendId + Debug + Send + Sync + 'static; + type ShaderModuleId: BikeshedBackendId + Debug + Send + Sync + 'static; + type BindGroupLayoutId: BikeshedBackendId + Debug + Send + Sync + 'static; + type BindGroupId: BikeshedBackendId + Debug + Send + Sync + 'static; + type TextureViewId: BikeshedBackendId + Debug + Send + Sync + 'static; + type SamplerId: BikeshedBackendId + Debug + Send + Sync + 'static; + type BufferId: BikeshedBackendId + Debug + Send + Sync + 'static; + type TextureId: BikeshedBackendId + Debug + Send + Sync + 'static; + type QuerySetId: BikeshedBackendId + Debug + Send + Sync + 'static; + type PipelineLayoutId: BikeshedBackendId + Debug + Send + Sync + 'static; + type RenderPipelineId: BikeshedBackendId + Debug + Send + Sync + 'static; + type ComputePipelineId: BikeshedBackendId + Debug + Send + Sync + 'static; + type CommandEncoderId: BikeshedBackendId + Debug; type ComputePassId: Debug + ComputePassInner; type RenderPassId: Debug + RenderPassInner; - type CommandBufferId: Debug + Send + Sync; + type CommandBufferId: BikeshedBackendId + Debug + Send + Sync; type RenderBundleEncoderId: Debug + RenderInner; - type RenderBundleId: Debug + Send + Sync + 'static; - type SurfaceId: Debug + Send + Sync + 'static; + type RenderBundleId: BikeshedBackendId + Debug + Send + Sync + 'static; + type SurfaceId: BikeshedBackendId + Debug + Send + Sync + 'static; type SurfaceOutputDetail: Send; type SubmissionIndex: Debug + Copy + Clone + Send + 'static; @@ -593,6 +597,10 @@ pub struct Device { } static_assertions::assert_impl_all!(Device: Send, Sync); +/// Opaque globally-unique identifier +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct Id(BackendId); + /// Identifier for a particular call to [`Queue::submit`]. Can be used /// as part of an argument to [`Device::poll`] to block for a particular /// submission to finish. From ea99b30afeac1b6db28a185db9be2067a664efdc Mon Sep 17 00:00:00 2001 From: TheOnlyMrCat Date: Sat, 8 Oct 2022 20:39:02 +1100 Subject: [PATCH 2/7] Add IDs to Sendable struct in web backend --- wgpu/src/backend/web.rs | 78 ++++++++++++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 20 deletions(-) diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index c72867fc53..471d8a528c 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -21,14 +21,20 @@ use wasm_bindgen::{prelude::*, JsCast}; // is integrated (or not integrated) with values like those in webgpu, this may become unsound. #[derive(Clone, Debug)] -pub(crate) struct Sendable(T); +pub(crate) struct Sendable(T, #[cfg(feature = "expose-ids")] u64); unsafe impl Send for Sendable {} unsafe impl Sync for Sendable {} impl crate::BikeshedBackendId for Sendable { + #[cfg(not(feature = "expose-ids"))] fn id(&self) -> Id { 0 } + + #[cfg(feature = "expose-ids")] + fn id(&self) -> Id { + self.1 + } } // For QuerySetId @@ -921,6 +927,7 @@ fn map_map_mode(mode: crate::MapMode) -> u32 { type JsFutureResult = Result; +#[cfg(not(feature = "expose-ids"))] fn future_request_adapter(result: JsFutureResult) -> Option> { match result.and_then(wasm_bindgen::JsCast::dyn_into) { Ok(adapter) => Some(Sendable(adapter)), @@ -928,6 +935,14 @@ fn future_request_adapter(result: JsFutureResult) -> Option Option> { + match result.and_then(wasm_bindgen::JsCast::dyn_into) { + Ok(adapter) => Some(Sendable(adapter, 0)), + Err(_) => None, + } +} + fn future_request_device( result: JsFutureResult, ) -> Result<(Sendable, Sendable), crate::RequestDeviceError> @@ -936,7 +951,13 @@ fn future_request_device( .map(|js_value| { let device_id = web_sys::GpuDevice::from(js_value); let queue_id = device_id.queue(); - (Sendable(device_id), Sendable(queue_id)) + + #[cfg(not(feature = "expose-ids"))] + let sendable = (Sendable(device_id), Sendable(queue_id)); + #[cfg(feature = "expose-ids")] + let sendable = (Sendable(device_id, 0), Sendable(queue_id, 0)); + + sendable }) .map_err(|_| crate::RequestDeviceError) } @@ -993,6 +1014,23 @@ where *rc_callback.borrow_mut() = Some((closure_success, closure_rejected, callback)); } +impl Context { + #[cfg(not(feature = "expose-ids"))] + fn create_sendable(&self, item: T) -> Sendable { + Sendable(item) + } + + #[cfg(feature = "expose-ids")] + fn create_sendable(&self, item: T) -> Sendable { + Sendable(item, self.next_id()) + } + + #[cfg(feature = "expose-ids")] + fn next_id(&self) -> u64 { + self.1.fetch_add(1, std::sync::atomic::Ordering::Relaxed) + } +} + impl Context { pub fn instance_create_surface_from_canvas( &self, @@ -1002,7 +1040,7 @@ impl Context { Ok(Some(ctx)) => ctx.into(), _ => panic!("expected to get context from canvas"), }; - Sendable(context.into()) + self.create_sendable(context.into()) } pub fn instance_create_surface_from_offscreen_canvas( @@ -1013,7 +1051,7 @@ impl Context { Ok(Some(ctx)) => ctx.into(), _ => panic!("expected to get context from canvas"), }; - Sendable(context.into()) + self.create_sendable(context.into()) } pub fn queue_copy_external_image_to_texture( @@ -1365,7 +1403,7 @@ impl crate::Context for Context { Self::SurfaceOutputDetail, ) { ( - Some(Sendable(surface.0.get_current_texture())), + Some(self.create_sendable(surface.0.get_current_texture())), wgt::SurfaceStatus::Good, (), ) @@ -1489,7 +1527,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { descriptor.label(label); } - Sendable(device.0.create_shader_module(&descriptor)) + self.create_sendable(device.0.create_shader_module(&descriptor)) } fn device_create_bind_group_layout( @@ -1587,7 +1625,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { mapped_desc.label(label); } - Sendable(device.0.create_bind_group_layout(&mapped_desc)) + self.create_sendable(device.0.create_bind_group_layout(&mapped_desc)) } unsafe fn device_create_shader_module_spirv( @@ -1645,7 +1683,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { mapped_desc.label(label); } - Sendable(device.0.create_bind_group(&mapped_desc)) + self.create_sendable(device.0.create_bind_group(&mapped_desc)) } fn device_create_pipeline_layout( @@ -1662,7 +1700,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { mapped_desc.label(label); } - Sendable(device.0.create_pipeline_layout(&mapped_desc)) + self.create_sendable(device.0.create_pipeline_layout(&mapped_desc)) } fn device_create_render_pipeline( @@ -1753,7 +1791,7 @@ impl crate::Context for Context { let mapped_primitive = map_primitive_state(&desc.primitive); mapped_desc.primitive(&mapped_primitive); - Sendable(device.0.create_render_pipeline(&mapped_desc)) + self.create_sendable(device.0.create_render_pipeline(&mapped_desc)) } fn device_create_compute_pipeline( @@ -1774,7 +1812,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { mapped_desc.label(label); } - Sendable(device.0.create_compute_pipeline(&mapped_desc)) + self.create_sendable(device.0.create_compute_pipeline(&mapped_desc)) } fn device_create_buffer( @@ -1788,7 +1826,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { mapped_desc.label(label); } - Sendable(device.0.create_buffer(&mapped_desc)) + self.create_sendable(device.0.create_buffer(&mapped_desc)) } fn device_create_texture( @@ -1807,7 +1845,7 @@ impl crate::Context for Context { mapped_desc.dimension(map_texture_dimension(desc.dimension)); mapped_desc.mip_level_count(desc.mip_level_count); mapped_desc.sample_count(desc.sample_count); - Sendable(device.0.create_texture(&mapped_desc)) + self.create_sendable(device.0.create_texture(&mapped_desc)) } fn device_create_sampler( @@ -1832,7 +1870,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { mapped_desc.label(label); } - Sendable(device.0.create_sampler_with_descriptor(&mapped_desc)) + self.create_sendable(device.0.create_sampler_with_descriptor(&mapped_desc)) } fn device_create_query_set( @@ -1861,7 +1899,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { mapped_desc.label(label); } - Sendable( + self.create_sendable( device .0 .create_command_encoder_with_descriptor(&mapped_desc), @@ -1995,7 +2033,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { mapped.label(label); } - Sendable(texture.0.create_view_with_descriptor(&mapped)) + self.create_sendable(texture.0.create_view_with_descriptor(&mapped)) } fn surface_drop(&self, _surface: &Self::SurfaceId) { @@ -2075,7 +2113,7 @@ impl crate::Context for Context { pipeline: &Self::ComputePipelineId, index: u32, ) -> Self::BindGroupLayoutId { - Sendable(pipeline.0.get_bind_group_layout(index)) + self.create_sendable(pipeline.0.get_bind_group_layout(index)) } fn render_pipeline_get_bind_group_layout( @@ -2083,7 +2121,7 @@ impl crate::Context for Context { pipeline: &Self::RenderPipelineId, index: u32, ) -> Self::BindGroupLayoutId { - Sendable(pipeline.0.get_bind_group_layout(index)) + self.create_sendable(pipeline.0.get_bind_group_layout(index)) } fn command_encoder_copy_buffer_to_buffer( @@ -2263,7 +2301,7 @@ impl crate::Context for Context { fn command_encoder_finish(&self, encoder: Self::CommandEncoderId) -> Self::CommandBufferId { let label = encoder.0.label(); - Sendable(if label.is_empty() { + self.create_sendable(if label.is_empty() { encoder.0.finish() } else { let mut mapped_desc = web_sys::GpuCommandBufferDescriptor::new(); @@ -2332,7 +2370,7 @@ impl crate::Context for Context { encoder: Self::RenderBundleEncoderId, desc: &crate::RenderBundleDescriptor, ) -> Self::RenderBundleId { - Sendable(match desc.label { + self.create_sendable(match desc.label { Some(label) => { let mut mapped_desc = web_sys::GpuRenderBundleDescriptor::new(); mapped_desc.label(label); From 8992793283ba2cffdbdee829941709fa8c6a4492 Mon Sep 17 00:00:00 2001 From: TheOnlyMrCat Date: Wed, 12 Oct 2022 13:54:11 +1100 Subject: [PATCH 3/7] Expose ids in opaque wrapper --- wgpu/src/backend/direct.rs | 24 ++-- wgpu/src/backend/web.rs | 10 +- wgpu/src/lib.rs | 226 +++++++++++++++++++++++++++++++++---- 3 files changed, 219 insertions(+), 41 deletions(-) diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index 2955bfb64a..1661e89749 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -803,42 +803,42 @@ pub(crate) struct CommandEncoder { pub(crate) type Id = (u32, u32, wgt::Backend); -impl crate::BikeshedBackendId for T { - fn id(&self) -> Id { +impl crate::GlobalId for T { + fn global_id(&self) -> Id { self.unzip() } } -impl crate::BikeshedBackendId for Surface { - fn id(&self) -> Id { +impl crate::GlobalId for Surface { + fn global_id(&self) -> Id { use wgc::id::TypedId; self.id.unzip() } } -impl crate::BikeshedBackendId for Device { - fn id(&self) -> Id { +impl crate::GlobalId for Device { + fn global_id(&self) -> Id { use wgc::id::TypedId; self.id.unzip() } } -impl crate::BikeshedBackendId for Buffer { - fn id(&self) -> Id { +impl crate::GlobalId for Buffer { + fn global_id(&self) -> Id { use wgc::id::TypedId; self.id.unzip() } } -impl crate::BikeshedBackendId for Texture { - fn id(&self) -> Id { +impl crate::GlobalId for Texture { + fn global_id(&self) -> Id { use wgc::id::TypedId; self.id.unzip() } } -impl crate::BikeshedBackendId for CommandEncoder { - fn id(&self) -> Id { +impl crate::GlobalId for CommandEncoder { + fn global_id(&self) -> Id { use wgc::id::TypedId; self.id.unzip() } diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index 471d8a528c..0d5e6ccf70 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -25,21 +25,21 @@ pub(crate) struct Sendable(T, #[cfg(feature = "expose-ids")] u64); unsafe impl Send for Sendable {} unsafe impl Sync for Sendable {} -impl crate::BikeshedBackendId for Sendable { +impl crate::GlobalId for Sendable { #[cfg(not(feature = "expose-ids"))] - fn id(&self) -> Id { + fn global_id(&self) -> Id { 0 } #[cfg(feature = "expose-ids")] - fn id(&self) -> Id { + fn global_id(&self) -> Id { self.1 } } // For QuerySetId -impl crate::BikeshedBackendId for () { - fn id(&self) -> Id { +impl crate::GlobalId for () { + fn global_id(&self) -> Id { 0 } } diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index ec4d939291..9257e67926 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -164,32 +164,32 @@ trait RenderPassInner: RenderInner { ); } -trait BikeshedBackendId { - fn id(&self) -> BackendId; +trait GlobalId { + fn global_id(&self) -> BackendId; } trait Context: Debug + Send + Sized + Sync { - type AdapterId: BikeshedBackendId + Debug + Send + Sync + 'static; - type DeviceId: BikeshedBackendId + Debug + Send + Sync + 'static; - type QueueId: BikeshedBackendId + Debug + Send + Sync + 'static; - type ShaderModuleId: BikeshedBackendId + Debug + Send + Sync + 'static; - type BindGroupLayoutId: BikeshedBackendId + Debug + Send + Sync + 'static; - type BindGroupId: BikeshedBackendId + Debug + Send + Sync + 'static; - type TextureViewId: BikeshedBackendId + Debug + Send + Sync + 'static; - type SamplerId: BikeshedBackendId + Debug + Send + Sync + 'static; - type BufferId: BikeshedBackendId + Debug + Send + Sync + 'static; - type TextureId: BikeshedBackendId + Debug + Send + Sync + 'static; - type QuerySetId: BikeshedBackendId + Debug + Send + Sync + 'static; - type PipelineLayoutId: BikeshedBackendId + Debug + Send + Sync + 'static; - type RenderPipelineId: BikeshedBackendId + Debug + Send + Sync + 'static; - type ComputePipelineId: BikeshedBackendId + Debug + Send + Sync + 'static; - type CommandEncoderId: BikeshedBackendId + Debug; + type AdapterId: GlobalId + Debug + Send + Sync + 'static; + type DeviceId: GlobalId + Debug + Send + Sync + 'static; + type QueueId: GlobalId + Debug + Send + Sync + 'static; + type ShaderModuleId: GlobalId + Debug + Send + Sync + 'static; + type BindGroupLayoutId: GlobalId + Debug + Send + Sync + 'static; + type BindGroupId: GlobalId + Debug + Send + Sync + 'static; + type TextureViewId: GlobalId + Debug + Send + Sync + 'static; + type SamplerId: GlobalId + Debug + Send + Sync + 'static; + type BufferId: GlobalId + Debug + Send + Sync + 'static; + type TextureId: GlobalId + Debug + Send + Sync + 'static; + type QuerySetId: GlobalId + Debug + Send + Sync + 'static; + type PipelineLayoutId: GlobalId + Debug + Send + Sync + 'static; + type RenderPipelineId: GlobalId + Debug + Send + Sync + 'static; + type ComputePipelineId: GlobalId + Debug + Send + Sync + 'static; + type CommandEncoderId: Debug; type ComputePassId: Debug + ComputePassInner; type RenderPassId: Debug + RenderPassInner; - type CommandBufferId: BikeshedBackendId + Debug + Send + Sync; + type CommandBufferId: Debug + Send + Sync; type RenderBundleEncoderId: Debug + RenderInner; - type RenderBundleId: BikeshedBackendId + Debug + Send + Sync + 'static; - type SurfaceId: BikeshedBackendId + Debug + Send + Sync + 'static; + type RenderBundleId: GlobalId + Debug + Send + Sync + 'static; + type SurfaceId: GlobalId + Debug + Send + Sync + 'static; type SurfaceOutputDetail: Send; type SubmissionIndex: Debug + Copy + Clone + Send + 'static; @@ -597,10 +597,6 @@ pub struct Device { } static_assertions::assert_impl_all!(Device: Send, Sync); -/// Opaque globally-unique identifier -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct Id(BackendId); - /// Identifier for a particular call to [`Queue::submit`]. Can be used /// as part of an argument to [`Device::poll`] to block for a particular /// submission to finish. @@ -3783,6 +3779,188 @@ impl Surface { } } +/// Opaque globally-unique identifier +#[cfg(feature = "expose-ids")] +#[repr(transparent)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct Id(BackendId); + +#[cfg(feature = "expose-ids")] +impl Adapter { + /// Returns a globally-unique identifier for this `Adapter`. + /// + /// Calling this method multiple times on the same object will always return the same value. + /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + pub fn global_id(&self) -> Id { + Id(self.id.global_id()) + } +} + +#[cfg(feature = "expose-ids")] +impl Device { + /// Returns a globally-unique identifier for this `Device`. + /// + /// Calling this method multiple times on the same object will always return the same value. + /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + pub fn global_id(&self) -> Id { + Id(self.id.global_id()) + } +} + +#[cfg(feature = "expose-ids")] +impl Queue { + /// Returns a globally-unique identifier for this `Queue`. + /// + /// Calling this method multiple times on the same object will always return the same value. + /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + pub fn global_id(&self) -> Id { + Id(self.id.global_id()) + } +} + +#[cfg(feature = "expose-ids")] +impl ShaderModule { + /// Returns a globally-unique identifier for this `ShaderModule`. + /// + /// Calling this method multiple times on the same object will always return the same value. + /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + pub fn global_id(&self) -> Id { + Id(self.id.global_id()) + } +} + +#[cfg(feature = "expose-ids")] +impl BindGroupLayout { + /// Returns a globally-unique identifier for this `BindGroupLayout`. + /// + /// Calling this method multiple times on the same object will always return the same value. + /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + pub fn global_id(&self) -> Id { + Id(self.id.global_id()) + } +} + +#[cfg(feature = "expose-ids")] +impl BindGroup { + /// Returns a globally-unique identifier for this `BindGroup`. + /// + /// Calling this method multiple times on the same object will always return the same value. + /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + pub fn global_id(&self) -> Id { + Id(self.id.global_id()) + } +} + +#[cfg(feature = "expose-ids")] +impl TextureView { + /// Returns a globally-unique identifier for this `TextureView`. + /// + /// Calling this method multiple times on the same object will always return the same value. + /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + pub fn global_id(&self) -> Id { + Id(self.id.global_id()) + } +} + +#[cfg(feature = "expose-ids")] +impl Sampler { + /// Returns a globally-unique identifier for this `Sampler`. + /// + /// Calling this method multiple times on the same object will always return the same value. + /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + pub fn global_id(&self) -> Id { + Id(self.id.global_id()) + } +} + +#[cfg(feature = "expose-ids")] +impl Buffer { + /// Returns a globally-unique identifier for this `Buffer`. + /// + /// Calling this method multiple times on the same object will always return the same value. + /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + pub fn global_id(&self) -> Id { + Id(self.id.global_id()) + } +} + +#[cfg(feature = "expose-ids")] +impl Texture { + /// Returns a globally-unique identifier for this `Texture`. + /// + /// Calling this method multiple times on the same object will always return the same value. + /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + pub fn global_id(&self) -> Id { + Id(self.id.global_id()) + } +} + +#[cfg(feature = "expose-ids")] +impl QuerySet { + /// Returns a globally-unique identifier for this `QuerySet`. + /// + /// Calling this method multiple times on the same object will always return the same value. + /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + pub fn global_id(&self) -> Id { + Id(self.id.global_id()) + } +} + +#[cfg(feature = "expose-ids")] +impl PipelineLayout { + /// Returns a globally-unique identifier for this `PipelineLayout`. + /// + /// Calling this method multiple times on the same object will always return the same value. + /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + pub fn global_id(&self) -> Id { + Id(self.id.global_id()) + } +} + +#[cfg(feature = "expose-ids")] +impl RenderPipeline { + /// Returns a globally-unique identifier for this `RenderPipeline`. + /// + /// Calling this method multiple times on the same object will always return the same value. + /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + pub fn global_id(&self) -> Id { + Id(self.id.global_id()) + } +} + +#[cfg(feature = "expose-ids")] +impl ComputePipeline { + /// Returns a globally-unique identifier for this `ComputePipeline`. + /// + /// Calling this method multiple times on the same object will always return the same value. + /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + pub fn global_id(&self) -> Id { + Id(self.id.global_id()) + } +} + +#[cfg(feature = "expose-ids")] +impl RenderBundle { + /// Returns a globally-unique identifier for this `RenderBundle`. + /// + /// Calling this method multiple times on the same object will always return the same value. + /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + pub fn global_id(&self) -> Id { + Id(self.id.global_id()) + } +} + +#[cfg(feature = "expose-ids")] +impl Surface { + /// Returns a globally-unique identifier for this `Surface`. + /// + /// Calling this method multiple times on the same object will always return the same value. + /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + pub fn global_id(&self) -> Id { + Id(self.id.global_id()) + } +} + /// Type for the callback of uncaptured error handler pub trait UncapturedErrorHandler: Fn(Error) + Send + 'static {} impl UncapturedErrorHandler for T where T: Fn(Error) + Send + 'static {} From 06e70ee784e679e67fe9708f5d986f51316fc9d5 Mon Sep 17 00:00:00 2001 From: TheOnlyMrCat Date: Fri, 14 Oct 2022 10:22:57 +1100 Subject: [PATCH 4/7] Separate Sendable and Identified structs --- wgpu/src/backend/web.rs | 266 ++++++++++++++++++++++++---------------- 1 file changed, 162 insertions(+), 104 deletions(-) diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index 0d5e6ccf70..04fb3adafc 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -21,11 +21,16 @@ use wasm_bindgen::{prelude::*, JsCast}; // is integrated (or not integrated) with values like those in webgpu, this may become unsound. #[derive(Clone, Debug)] -pub(crate) struct Sendable(T, #[cfg(feature = "expose-ids")] u64); +pub(crate) struct Sendable(T); unsafe impl Send for Sendable {} unsafe impl Sync for Sendable {} -impl crate::GlobalId for Sendable { +#[derive(Clone, Debug)] +pub(crate) struct Identified(T, #[cfg(feature = "expose-ids")] u64); +unsafe impl Send for Identified {} +unsafe impl Sync for Identified {} + +impl crate::GlobalId for Identified { #[cfg(not(feature = "expose-ids"))] fn global_id(&self) -> Id { 0 @@ -37,13 +42,6 @@ impl crate::GlobalId for Sendable { } } -// For QuerySetId -impl crate::GlobalId for () { - fn global_id(&self) -> Id { - 0 - } -} - pub(crate) type Id = u64; pub(crate) struct Context( @@ -116,14 +114,44 @@ impl MakeSendFuture { unsafe impl Send for MakeSendFuture {} +pub(crate) struct MakeIdentifiedFuture { + future: F, + map: M, + id: u64, +} + +impl T, T> Future for MakeIdentifiedFuture { + type Output = T; + + fn poll(self: Pin<&mut Self>, cx: &mut task::Context) -> Poll { + // This is safe because we have no Drop implementation to violate the Pin requirements and + // do not provide any means of moving the inner future. + unsafe { + let this = self.get_unchecked_mut(); + match Pin::new_unchecked(&mut this.future).poll(cx) { + task::Poll::Ready(value) => task::Poll::Ready((this.map)(value, this.id)), + task::Poll::Pending => task::Poll::Pending, + } + } + } +} + +impl MakeIdentifiedFuture { + fn new(future: F, map: M, id: u64) -> Self { + Self { future, map, id } + } +} + +unsafe impl Send for MakeIdentifiedFuture {} + impl crate::ComputePassInner for ComputePass { - fn set_pipeline(&mut self, pipeline: &Sendable) { + fn set_pipeline(&mut self, pipeline: &Identified) { self.0.set_pipeline(&pipeline.0); } fn set_bind_group( &mut self, index: u32, - bind_group: &Sendable, + bind_group: &Identified, offsets: &[wgt::DynamicOffset], ) { self.0 @@ -161,20 +189,24 @@ impl crate::ComputePassInner for ComputePass { } fn dispatch_workgroups_indirect( &mut self, - indirect_buffer: &Sendable, + indirect_buffer: &Identified, indirect_offset: wgt::BufferAddress, ) { self.0 .dispatch_workgroups_indirect_with_f64(&indirect_buffer.0, indirect_offset as f64); } - fn write_timestamp(&mut self, _query_set: &Sendable, _query_index: u32) { + fn write_timestamp( + &mut self, + _query_set: &Identified, + _query_index: u32, + ) { panic!("WRITE_TIMESTAMP_INSIDE_PASSES feature must be enabled to call write_timestamp in a compute pass") } fn begin_pipeline_statistics_query( &mut self, - _query_set: &Sendable, + _query_set: &Identified, _query_index: u32, ) { // Not available in gecko yet @@ -186,13 +218,13 @@ impl crate::ComputePassInner for ComputePass { } impl crate::RenderInner for RenderPass { - fn set_pipeline(&mut self, pipeline: &Sendable) { + fn set_pipeline(&mut self, pipeline: &Identified) { self.0.set_pipeline(&pipeline.0); } fn set_bind_group( &mut self, index: u32, - bind_group: &Sendable, + bind_group: &Identified, offsets: &[wgt::DynamicOffset], ) { self.0 @@ -206,7 +238,7 @@ impl crate::RenderInner for RenderPass { } fn set_index_buffer( &mut self, - buffer: &Sendable, + buffer: &Identified, index_format: wgt::IndexFormat, offset: wgt::BufferAddress, size: Option, @@ -232,7 +264,7 @@ impl crate::RenderInner for RenderPass { fn set_vertex_buffer( &mut self, slot: u32, - buffer: &Sendable, + buffer: &Identified, offset: wgt::BufferAddress, size: Option, ) { @@ -275,7 +307,7 @@ impl crate::RenderInner for RenderPass { } fn draw_indirect( &mut self, - indirect_buffer: &Sendable, + indirect_buffer: &Identified, indirect_offset: wgt::BufferAddress, ) { self.0 @@ -283,7 +315,7 @@ impl crate::RenderInner for RenderPass { } fn draw_indexed_indirect( &mut self, - indirect_buffer: &Sendable, + indirect_buffer: &Identified, indirect_offset: wgt::BufferAddress, ) { self.0 @@ -291,7 +323,7 @@ impl crate::RenderInner for RenderPass { } fn multi_draw_indirect( &mut self, - _indirect_buffer: &Sendable, + _indirect_buffer: &Identified, _indirect_offset: wgt::BufferAddress, _count: u32, ) { @@ -299,7 +331,7 @@ impl crate::RenderInner for RenderPass { } fn multi_draw_indexed_indirect( &mut self, - _indirect_buffer: &Sendable, + _indirect_buffer: &Identified, _indirect_offset: wgt::BufferAddress, _count: u32, ) { @@ -307,9 +339,9 @@ impl crate::RenderInner for RenderPass { } fn multi_draw_indirect_count( &mut self, - _indirect_buffer: &Sendable, + _indirect_buffer: &Identified, _indirect_offset: wgt::BufferAddress, - _count_buffer: &Sendable, + _count_buffer: &Identified, _count_buffer_offset: wgt::BufferAddress, _max_count: u32, ) { @@ -319,9 +351,9 @@ impl crate::RenderInner for RenderPass { } fn multi_draw_indexed_indirect_count( &mut self, - _indirect_buffer: &Sendable, + _indirect_buffer: &Identified, _indirect_offset: wgt::BufferAddress, - _count_buffer: &Sendable, + _count_buffer: &Identified, _count_buffer_offset: wgt::BufferAddress, _max_count: u32, ) { @@ -330,13 +362,13 @@ impl crate::RenderInner for RenderPass { } impl crate::RenderInner for RenderBundleEncoder { - fn set_pipeline(&mut self, pipeline: &Sendable) { + fn set_pipeline(&mut self, pipeline: &Identified) { self.0.set_pipeline(&pipeline.0); } fn set_bind_group( &mut self, index: u32, - bind_group: &Sendable, + bind_group: &Identified, offsets: &[wgt::DynamicOffset], ) { self.0 @@ -350,7 +382,7 @@ impl crate::RenderInner for RenderBundleEncoder { } fn set_index_buffer( &mut self, - buffer: &Sendable, + buffer: &Identified, index_format: wgt::IndexFormat, offset: wgt::BufferAddress, size: Option, @@ -376,7 +408,7 @@ impl crate::RenderInner for RenderBundleEncoder { fn set_vertex_buffer( &mut self, slot: u32, - buffer: &Sendable, + buffer: &Identified, offset: wgt::BufferAddress, size: Option, ) { @@ -419,7 +451,7 @@ impl crate::RenderInner for RenderBundleEncoder { } fn draw_indirect( &mut self, - indirect_buffer: &Sendable, + indirect_buffer: &Identified, indirect_offset: wgt::BufferAddress, ) { self.0 @@ -427,7 +459,7 @@ impl crate::RenderInner for RenderBundleEncoder { } fn draw_indexed_indirect( &mut self, - indirect_buffer: &Sendable, + indirect_buffer: &Identified, indirect_offset: wgt::BufferAddress, ) { self.0 @@ -435,7 +467,7 @@ impl crate::RenderInner for RenderBundleEncoder { } fn multi_draw_indirect( &mut self, - _indirect_buffer: &Sendable, + _indirect_buffer: &Identified, _indirect_offset: wgt::BufferAddress, _count: u32, ) { @@ -443,7 +475,7 @@ impl crate::RenderInner for RenderBundleEncoder { } fn multi_draw_indexed_indirect( &mut self, - _indirect_buffer: &Sendable, + _indirect_buffer: &Identified, _indirect_offset: wgt::BufferAddress, _count: u32, ) { @@ -451,9 +483,9 @@ impl crate::RenderInner for RenderBundleEncoder { } fn multi_draw_indirect_count( &mut self, - _indirect_buffer: &Sendable, + _indirect_buffer: &Identified, _indirect_offset: wgt::BufferAddress, - _count_buffer: &Sendable, + _count_buffer: &Identified, _count_buffer_offset: wgt::BufferAddress, _max_count: u32, ) { @@ -463,9 +495,9 @@ impl crate::RenderInner for RenderBundleEncoder { } fn multi_draw_indexed_indirect_count( &mut self, - _indirect_buffer: &Sendable, + _indirect_buffer: &Identified, _indirect_offset: wgt::BufferAddress, - _count_buffer: &Sendable, + _count_buffer: &Identified, _count_buffer_offset: wgt::BufferAddress, _max_count: u32, ) { @@ -512,7 +544,7 @@ impl crate::RenderPassInner for RenderPass { // self.0.pop_debug_group(); } - fn execute_bundles<'a, I: Iterator>>( + fn execute_bundles<'a, I: Iterator>>( &mut self, render_bundles: I, ) { @@ -522,13 +554,17 @@ impl crate::RenderPassInner for RenderPass { self.0.execute_bundles(&mapped); } - fn write_timestamp(&mut self, _query_set: &Sendable, _query_index: u32) { + fn write_timestamp( + &mut self, + _query_set: &Identified, + _query_index: u32, + ) { panic!("WRITE_TIMESTAMP_INSIDE_PASSES feature must be enabled to call write_timestamp in a compute pass") } fn begin_pipeline_statistics_query( &mut self, - _query_set: &Sendable, + _query_set: &Identified, _query_index: u32, ) { // Not available in gecko yet @@ -928,36 +964,44 @@ fn map_map_mode(mode: crate::MapMode) -> u32 { type JsFutureResult = Result; #[cfg(not(feature = "expose-ids"))] -fn future_request_adapter(result: JsFutureResult) -> Option> { - match result.and_then(wasm_bindgen::JsCast::dyn_into) { - Ok(adapter) => Some(Sendable(adapter)), - Err(_) => None, - } +fn create_identified(value: T, _id: u64) -> Identified { + Identified(value) } #[cfg(feature = "expose-ids")] -fn future_request_adapter(result: JsFutureResult) -> Option> { +fn create_identified(value: T, id: u64) -> Identified { + Identified(value, id) +} + +fn future_request_adapter( + result: JsFutureResult, + id: u64, +) -> Option> { match result.and_then(wasm_bindgen::JsCast::dyn_into) { - Ok(adapter) => Some(Sendable(adapter, 0)), + Ok(adapter) => Some(create_identified(adapter, id)), Err(_) => None, } } fn future_request_device( result: JsFutureResult, -) -> Result<(Sendable, Sendable), crate::RequestDeviceError> -{ + id: u64, +) -> Result< + ( + Identified, + Identified, + ), + crate::RequestDeviceError, +> { result .map(|js_value| { let device_id = web_sys::GpuDevice::from(js_value); let queue_id = device_id.queue(); - #[cfg(not(feature = "expose-ids"))] - let sendable = (Sendable(device_id), Sendable(queue_id)); - #[cfg(feature = "expose-ids")] - let sendable = (Sendable(device_id, 0), Sendable(queue_id, 0)); - - sendable + ( + create_identified(device_id, id), + create_identified(queue_id, id + 1), + ) }) .map_err(|_| crate::RequestDeviceError) } @@ -1016,18 +1060,27 @@ where impl Context { #[cfg(not(feature = "expose-ids"))] - fn create_sendable(&self, item: T) -> Sendable { - Sendable(item) + fn create_identified(&self, item: T) -> Identified { + Identified(item) + } + + #[cfg(not(feature = "expose-ids"))] + fn allocate_id(&self, _count: u64) -> u64 { + 0 } #[cfg(feature = "expose-ids")] - fn create_sendable(&self, item: T) -> Sendable { - Sendable(item, self.next_id()) + fn create_identified(&self, item: T) -> Identified { + Identified( + item, + self.1.fetch_add(1, std::sync::atomic::Ordering::Relaxed), + ) } #[cfg(feature = "expose-ids")] - fn next_id(&self) -> u64 { - self.1.fetch_add(1, std::sync::atomic::Ordering::Relaxed) + fn allocate_id(&self, count: u64) -> u64 { + self.1 + .fetch_add(count, std::sync::atomic::Ordering::Relaxed) } } @@ -1040,7 +1093,7 @@ impl Context { Ok(Some(ctx)) => ctx.into(), _ => panic!("expected to get context from canvas"), }; - self.create_sendable(context.into()) + self.create_identified(context.into()) } pub fn instance_create_surface_from_offscreen_canvas( @@ -1051,12 +1104,12 @@ impl Context { Ok(Some(ctx)) => ctx.into(), _ => panic!("expected to get context from canvas"), }; - self.create_sendable(context.into()) + self.create_identified(context.into()) } pub fn queue_copy_external_image_to_texture( &self, - queue: &Sendable, + queue: &Identified, image: &web_sys::ImageBitmap, texture: crate::ImageCopyTexture, size: wgt::Extent3d, @@ -1093,38 +1146,41 @@ extern "C" { pub struct SubmissionIndex; impl crate::Context for Context { - type AdapterId = Sendable; - type DeviceId = Sendable; - type QueueId = Sendable; - type ShaderModuleId = Sendable; - type BindGroupLayoutId = Sendable; - type BindGroupId = Sendable; - type TextureViewId = Sendable; - type SamplerId = Sendable; - type BufferId = Sendable; - type TextureId = Sendable; - type QuerySetId = Sendable; - type PipelineLayoutId = Sendable; - type RenderPipelineId = Sendable; - type ComputePipelineId = Sendable; + type AdapterId = Identified; + type DeviceId = Identified; + type QueueId = Identified; + type ShaderModuleId = Identified; + type BindGroupLayoutId = Identified; + type BindGroupId = Identified; + type TextureViewId = Identified; + type SamplerId = Identified; + type BufferId = Identified; + type TextureId = Identified; + type QuerySetId = Identified; + type PipelineLayoutId = Identified; + type RenderPipelineId = Identified; + type ComputePipelineId = Identified; type CommandEncoderId = Sendable; type ComputePassId = ComputePass; type RenderPassId = RenderPass; type CommandBufferId = Sendable; type RenderBundleEncoderId = RenderBundleEncoder; - type RenderBundleId = Sendable; - type SurfaceId = Sendable; + type RenderBundleId = Identified; + type SurfaceId = Identified; type SurfaceOutputDetail = SurfaceOutputDetail; type SubmissionIndex = SubmissionIndex; - type RequestAdapterFuture = MakeSendFuture< + type RequestAdapterFuture = MakeIdentifiedFuture< wasm_bindgen_futures::JsFuture, - fn(JsFutureResult) -> Option, + fn(JsFutureResult, u64) -> Option, >; - type RequestDeviceFuture = MakeSendFuture< + type RequestDeviceFuture = MakeIdentifiedFuture< wasm_bindgen_futures::JsFuture, - fn(JsFutureResult) -> Result<(Self::DeviceId, Self::QueueId), crate::RequestDeviceError>, + fn( + JsFutureResult, + u64, + ) -> Result<(Self::DeviceId, Self::QueueId), crate::RequestDeviceError>, >; type PopErrorScopeFuture = MakeSendFuture Option>; @@ -1201,9 +1257,10 @@ impl crate::Context for Context { mapped_options.power_preference(mapped_power_preference); let adapter_promise = self.0.request_adapter_with_options(&mapped_options); - MakeSendFuture::new( + MakeIdentifiedFuture::new( wasm_bindgen_futures::JsFuture::from(adapter_promise), future_request_adapter, + self.allocate_id(1), ) } @@ -1272,9 +1329,10 @@ impl crate::Context for Context { let device_promise = adapter.0.request_device_with_descriptor(&mapped_desc); - MakeSendFuture::new( + MakeIdentifiedFuture::new( wasm_bindgen_futures::JsFuture::from(device_promise), future_request_device, + self.allocate_id(2), ) } @@ -1403,7 +1461,7 @@ impl crate::Context for Context { Self::SurfaceOutputDetail, ) { ( - Some(self.create_sendable(surface.0.get_current_texture())), + Some(self.create_identified(surface.0.get_current_texture())), wgt::SurfaceStatus::Good, (), ) @@ -1527,7 +1585,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { descriptor.label(label); } - self.create_sendable(device.0.create_shader_module(&descriptor)) + self.create_identified(device.0.create_shader_module(&descriptor)) } fn device_create_bind_group_layout( @@ -1625,7 +1683,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { mapped_desc.label(label); } - self.create_sendable(device.0.create_bind_group_layout(&mapped_desc)) + self.create_identified(device.0.create_bind_group_layout(&mapped_desc)) } unsafe fn device_create_shader_module_spirv( @@ -1683,7 +1741,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { mapped_desc.label(label); } - self.create_sendable(device.0.create_bind_group(&mapped_desc)) + self.create_identified(device.0.create_bind_group(&mapped_desc)) } fn device_create_pipeline_layout( @@ -1700,7 +1758,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { mapped_desc.label(label); } - self.create_sendable(device.0.create_pipeline_layout(&mapped_desc)) + self.create_identified(device.0.create_pipeline_layout(&mapped_desc)) } fn device_create_render_pipeline( @@ -1791,7 +1849,7 @@ impl crate::Context for Context { let mapped_primitive = map_primitive_state(&desc.primitive); mapped_desc.primitive(&mapped_primitive); - self.create_sendable(device.0.create_render_pipeline(&mapped_desc)) + self.create_identified(device.0.create_render_pipeline(&mapped_desc)) } fn device_create_compute_pipeline( @@ -1812,7 +1870,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { mapped_desc.label(label); } - self.create_sendable(device.0.create_compute_pipeline(&mapped_desc)) + self.create_identified(device.0.create_compute_pipeline(&mapped_desc)) } fn device_create_buffer( @@ -1826,7 +1884,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { mapped_desc.label(label); } - self.create_sendable(device.0.create_buffer(&mapped_desc)) + self.create_identified(device.0.create_buffer(&mapped_desc)) } fn device_create_texture( @@ -1845,7 +1903,7 @@ impl crate::Context for Context { mapped_desc.dimension(map_texture_dimension(desc.dimension)); mapped_desc.mip_level_count(desc.mip_level_count); mapped_desc.sample_count(desc.sample_count); - self.create_sendable(device.0.create_texture(&mapped_desc)) + self.create_identified(device.0.create_texture(&mapped_desc)) } fn device_create_sampler( @@ -1870,7 +1928,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { mapped_desc.label(label); } - self.create_sendable(device.0.create_sampler_with_descriptor(&mapped_desc)) + self.create_identified(device.0.create_sampler_with_descriptor(&mapped_desc)) } fn device_create_query_set( @@ -1887,7 +1945,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { mapped_desc.label(label); } - Sendable(device.0.create_query_set(&mapped_desc)) + self.create_identified(device.0.create_query_set(&mapped_desc)) } fn device_create_command_encoder( @@ -1899,7 +1957,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { mapped_desc.label(label); } - self.create_sendable( + Sendable( device .0 .create_command_encoder_with_descriptor(&mapped_desc), @@ -2033,7 +2091,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { mapped.label(label); } - self.create_sendable(texture.0.create_view_with_descriptor(&mapped)) + self.create_identified(texture.0.create_view_with_descriptor(&mapped)) } fn surface_drop(&self, _surface: &Self::SurfaceId) { @@ -2113,7 +2171,7 @@ impl crate::Context for Context { pipeline: &Self::ComputePipelineId, index: u32, ) -> Self::BindGroupLayoutId { - self.create_sendable(pipeline.0.get_bind_group_layout(index)) + self.create_identified(pipeline.0.get_bind_group_layout(index)) } fn render_pipeline_get_bind_group_layout( @@ -2121,7 +2179,7 @@ impl crate::Context for Context { pipeline: &Self::RenderPipelineId, index: u32, ) -> Self::BindGroupLayoutId { - self.create_sendable(pipeline.0.get_bind_group_layout(index)) + self.create_identified(pipeline.0.get_bind_group_layout(index)) } fn command_encoder_copy_buffer_to_buffer( @@ -2301,7 +2359,7 @@ impl crate::Context for Context { fn command_encoder_finish(&self, encoder: Self::CommandEncoderId) -> Self::CommandBufferId { let label = encoder.0.label(); - self.create_sendable(if label.is_empty() { + Sendable(if label.is_empty() { encoder.0.finish() } else { let mut mapped_desc = web_sys::GpuCommandBufferDescriptor::new(); @@ -2370,7 +2428,7 @@ impl crate::Context for Context { encoder: Self::RenderBundleEncoderId, desc: &crate::RenderBundleDescriptor, ) -> Self::RenderBundleId { - self.create_sendable(match desc.label { + self.create_identified(match desc.label { Some(label) => { let mut mapped_desc = web_sys::GpuRenderBundleDescriptor::new(); mapped_desc.label(label); From 67163bdc446b017c773e1883eacbb21ab9b0abb2 Mon Sep 17 00:00:00 2001 From: TheOnlyMrCat Date: Sat, 15 Oct 2022 16:02:05 +1100 Subject: [PATCH 5/7] Add `doc(cfg(...))` attributes to public items --- wgpu/src/lib.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 9257e67926..c846543de1 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -3781,6 +3781,7 @@ impl Surface { /// Opaque globally-unique identifier #[cfg(feature = "expose-ids")] +#[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))] #[repr(transparent)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Id(BackendId); @@ -3791,6 +3792,7 @@ impl Adapter { /// /// Calling this method multiple times on the same object will always return the same value. /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))] pub fn global_id(&self) -> Id { Id(self.id.global_id()) } @@ -3802,6 +3804,7 @@ impl Device { /// /// Calling this method multiple times on the same object will always return the same value. /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))] pub fn global_id(&self) -> Id { Id(self.id.global_id()) } @@ -3813,6 +3816,7 @@ impl Queue { /// /// Calling this method multiple times on the same object will always return the same value. /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))] pub fn global_id(&self) -> Id { Id(self.id.global_id()) } @@ -3824,6 +3828,7 @@ impl ShaderModule { /// /// Calling this method multiple times on the same object will always return the same value. /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))] pub fn global_id(&self) -> Id { Id(self.id.global_id()) } @@ -3835,6 +3840,7 @@ impl BindGroupLayout { /// /// Calling this method multiple times on the same object will always return the same value. /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))] pub fn global_id(&self) -> Id { Id(self.id.global_id()) } @@ -3846,6 +3852,7 @@ impl BindGroup { /// /// Calling this method multiple times on the same object will always return the same value. /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))] pub fn global_id(&self) -> Id { Id(self.id.global_id()) } @@ -3857,6 +3864,7 @@ impl TextureView { /// /// Calling this method multiple times on the same object will always return the same value. /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))] pub fn global_id(&self) -> Id { Id(self.id.global_id()) } @@ -3868,6 +3876,7 @@ impl Sampler { /// /// Calling this method multiple times on the same object will always return the same value. /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))] pub fn global_id(&self) -> Id { Id(self.id.global_id()) } @@ -3879,6 +3888,7 @@ impl Buffer { /// /// Calling this method multiple times on the same object will always return the same value. /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))] pub fn global_id(&self) -> Id { Id(self.id.global_id()) } @@ -3890,6 +3900,7 @@ impl Texture { /// /// Calling this method multiple times on the same object will always return the same value. /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))] pub fn global_id(&self) -> Id { Id(self.id.global_id()) } @@ -3901,6 +3912,7 @@ impl QuerySet { /// /// Calling this method multiple times on the same object will always return the same value. /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))] pub fn global_id(&self) -> Id { Id(self.id.global_id()) } @@ -3912,6 +3924,7 @@ impl PipelineLayout { /// /// Calling this method multiple times on the same object will always return the same value. /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))] pub fn global_id(&self) -> Id { Id(self.id.global_id()) } @@ -3923,6 +3936,7 @@ impl RenderPipeline { /// /// Calling this method multiple times on the same object will always return the same value. /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))] pub fn global_id(&self) -> Id { Id(self.id.global_id()) } @@ -3934,6 +3948,7 @@ impl ComputePipeline { /// /// Calling this method multiple times on the same object will always return the same value. /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))] pub fn global_id(&self) -> Id { Id(self.id.global_id()) } @@ -3945,6 +3960,7 @@ impl RenderBundle { /// /// Calling this method multiple times on the same object will always return the same value. /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))] pub fn global_id(&self) -> Id { Id(self.id.global_id()) } @@ -3956,6 +3972,7 @@ impl Surface { /// /// Calling this method multiple times on the same object will always return the same value. /// The returned value is guaranteed to be different for all resources created from the same `Instance`. + #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))] pub fn global_id(&self) -> Id { Id(self.id.global_id()) } From 9fbd0adece906644e58cc3da5de4a9d00d821a4f Mon Sep 17 00:00:00 2001 From: TheOnlyMrCat Date: Sun, 16 Oct 2022 17:56:41 +1100 Subject: [PATCH 6/7] Use global static for web identifiers --- wgpu/src/backend/web.rs | 159 +++++++++++----------------------------- 1 file changed, 42 insertions(+), 117 deletions(-) diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index 04fb3adafc..8c555a8fae 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -1,6 +1,8 @@ #![allow(clippy::type_complexity)] use js_sys::Promise; +#[cfg(feature = "expose-ids")] +use std::sync::atomic::{self, AtomicU64}; use std::{ cell::RefCell, fmt, @@ -44,10 +46,20 @@ impl crate::GlobalId for Identified { pub(crate) type Id = u64; -pub(crate) struct Context( - web_sys::Gpu, - #[cfg(feature = "expose-ids")] std::sync::atomic::AtomicU64, -); +#[cfg(feature = "expose-ids")] +static NEXT_ID: AtomicU64 = AtomicU64::new(0); + +#[cfg(not(feature = "expose-ids"))] +fn create_identified(value: T) -> Identified { + Identified(value) +} + +#[cfg(feature = "expose-ids")] +fn create_identified(value: T) -> Identified { + Identified(value, NEXT_ID.fetch_add(1, atomic::Ordering::Relaxed)) +} + +pub(crate) struct Context(web_sys::Gpu); unsafe impl Send for Context {} unsafe impl Sync for Context {} @@ -114,36 +126,6 @@ impl MakeSendFuture { unsafe impl Send for MakeSendFuture {} -pub(crate) struct MakeIdentifiedFuture { - future: F, - map: M, - id: u64, -} - -impl T, T> Future for MakeIdentifiedFuture { - type Output = T; - - fn poll(self: Pin<&mut Self>, cx: &mut task::Context) -> Poll { - // This is safe because we have no Drop implementation to violate the Pin requirements and - // do not provide any means of moving the inner future. - unsafe { - let this = self.get_unchecked_mut(); - match Pin::new_unchecked(&mut this.future).poll(cx) { - task::Poll::Ready(value) => task::Poll::Ready((this.map)(value, this.id)), - task::Poll::Pending => task::Poll::Pending, - } - } - } -} - -impl MakeIdentifiedFuture { - fn new(future: F, map: M, id: u64) -> Self { - Self { future, map, id } - } -} - -unsafe impl Send for MakeIdentifiedFuture {} - impl crate::ComputePassInner for ComputePass { fn set_pipeline(&mut self, pipeline: &Identified) { self.0.set_pipeline(&pipeline.0); @@ -963,29 +945,15 @@ fn map_map_mode(mode: crate::MapMode) -> u32 { type JsFutureResult = Result; -#[cfg(not(feature = "expose-ids"))] -fn create_identified(value: T, _id: u64) -> Identified { - Identified(value) -} - -#[cfg(feature = "expose-ids")] -fn create_identified(value: T, id: u64) -> Identified { - Identified(value, id) -} - -fn future_request_adapter( - result: JsFutureResult, - id: u64, -) -> Option> { +fn future_request_adapter(result: JsFutureResult) -> Option> { match result.and_then(wasm_bindgen::JsCast::dyn_into) { - Ok(adapter) => Some(create_identified(adapter, id)), + Ok(adapter) => Some(create_identified(adapter)), Err(_) => None, } } fn future_request_device( result: JsFutureResult, - id: u64, ) -> Result< ( Identified, @@ -998,10 +966,7 @@ fn future_request_device( let device_id = web_sys::GpuDevice::from(js_value); let queue_id = device_id.queue(); - ( - create_identified(device_id, id), - create_identified(queue_id, id + 1), - ) + (create_identified(device_id), create_identified(queue_id)) }) .map_err(|_| crate::RequestDeviceError) } @@ -1058,32 +1023,6 @@ where *rc_callback.borrow_mut() = Some((closure_success, closure_rejected, callback)); } -impl Context { - #[cfg(not(feature = "expose-ids"))] - fn create_identified(&self, item: T) -> Identified { - Identified(item) - } - - #[cfg(not(feature = "expose-ids"))] - fn allocate_id(&self, _count: u64) -> u64 { - 0 - } - - #[cfg(feature = "expose-ids")] - fn create_identified(&self, item: T) -> Identified { - Identified( - item, - self.1.fetch_add(1, std::sync::atomic::Ordering::Relaxed), - ) - } - - #[cfg(feature = "expose-ids")] - fn allocate_id(&self, count: u64) -> u64 { - self.1 - .fetch_add(count, std::sync::atomic::Ordering::Relaxed) - } -} - impl Context { pub fn instance_create_surface_from_canvas( &self, @@ -1093,7 +1032,7 @@ impl Context { Ok(Some(ctx)) => ctx.into(), _ => panic!("expected to get context from canvas"), }; - self.create_identified(context.into()) + create_identified(context.into()) } pub fn instance_create_surface_from_offscreen_canvas( @@ -1104,7 +1043,7 @@ impl Context { Ok(Some(ctx)) => ctx.into(), _ => panic!("expected to get context from canvas"), }; - self.create_identified(context.into()) + create_identified(context.into()) } pub fn queue_copy_external_image_to_texture( @@ -1171,21 +1110,17 @@ impl crate::Context for Context { type SurfaceOutputDetail = SurfaceOutputDetail; type SubmissionIndex = SubmissionIndex; - type RequestAdapterFuture = MakeIdentifiedFuture< + type RequestAdapterFuture = MakeSendFuture< wasm_bindgen_futures::JsFuture, - fn(JsFutureResult, u64) -> Option, + fn(JsFutureResult) -> Option, >; - type RequestDeviceFuture = MakeIdentifiedFuture< + type RequestDeviceFuture = MakeSendFuture< wasm_bindgen_futures::JsFuture, - fn( - JsFutureResult, - u64, - ) -> Result<(Self::DeviceId, Self::QueueId), crate::RequestDeviceError>, + fn(JsFutureResult) -> Result<(Self::DeviceId, Self::QueueId), crate::RequestDeviceError>, >; type PopErrorScopeFuture = MakeSendFuture Option>; - #[cfg(not(feature = "expose-ids"))] fn init(_backends: wgt::Backends) -> Self { let global: Global = js_sys::global().unchecked_into(); let gpu = if !global.window().is_undefined() { @@ -1203,14 +1138,6 @@ impl crate::Context for Context { Context(gpu) } - #[cfg(feature = "expose-ids")] - fn init(_backends: wgt::Backends) -> Self { - Context( - web_sys::window().unwrap().navigator().gpu(), - std::sync::atomic::AtomicU64::new(0), - ) - } - fn instance_create_surface( &self, _display_handle: raw_window_handle::RawDisplayHandle, @@ -1257,10 +1184,9 @@ impl crate::Context for Context { mapped_options.power_preference(mapped_power_preference); let adapter_promise = self.0.request_adapter_with_options(&mapped_options); - MakeIdentifiedFuture::new( + MakeSendFuture::new( wasm_bindgen_futures::JsFuture::from(adapter_promise), future_request_adapter, - self.allocate_id(1), ) } @@ -1329,10 +1255,9 @@ impl crate::Context for Context { let device_promise = adapter.0.request_device_with_descriptor(&mapped_desc); - MakeIdentifiedFuture::new( + MakeSendFuture::new( wasm_bindgen_futures::JsFuture::from(device_promise), future_request_device, - self.allocate_id(2), ) } @@ -1461,7 +1386,7 @@ impl crate::Context for Context { Self::SurfaceOutputDetail, ) { ( - Some(self.create_identified(surface.0.get_current_texture())), + Some(create_identified(surface.0.get_current_texture())), wgt::SurfaceStatus::Good, (), ) @@ -1585,7 +1510,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { descriptor.label(label); } - self.create_identified(device.0.create_shader_module(&descriptor)) + create_identified(device.0.create_shader_module(&descriptor)) } fn device_create_bind_group_layout( @@ -1683,7 +1608,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { mapped_desc.label(label); } - self.create_identified(device.0.create_bind_group_layout(&mapped_desc)) + create_identified(device.0.create_bind_group_layout(&mapped_desc)) } unsafe fn device_create_shader_module_spirv( @@ -1741,7 +1666,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { mapped_desc.label(label); } - self.create_identified(device.0.create_bind_group(&mapped_desc)) + create_identified(device.0.create_bind_group(&mapped_desc)) } fn device_create_pipeline_layout( @@ -1758,7 +1683,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { mapped_desc.label(label); } - self.create_identified(device.0.create_pipeline_layout(&mapped_desc)) + create_identified(device.0.create_pipeline_layout(&mapped_desc)) } fn device_create_render_pipeline( @@ -1849,7 +1774,7 @@ impl crate::Context for Context { let mapped_primitive = map_primitive_state(&desc.primitive); mapped_desc.primitive(&mapped_primitive); - self.create_identified(device.0.create_render_pipeline(&mapped_desc)) + create_identified(device.0.create_render_pipeline(&mapped_desc)) } fn device_create_compute_pipeline( @@ -1870,7 +1795,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { mapped_desc.label(label); } - self.create_identified(device.0.create_compute_pipeline(&mapped_desc)) + create_identified(device.0.create_compute_pipeline(&mapped_desc)) } fn device_create_buffer( @@ -1884,7 +1809,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { mapped_desc.label(label); } - self.create_identified(device.0.create_buffer(&mapped_desc)) + create_identified(device.0.create_buffer(&mapped_desc)) } fn device_create_texture( @@ -1903,7 +1828,7 @@ impl crate::Context for Context { mapped_desc.dimension(map_texture_dimension(desc.dimension)); mapped_desc.mip_level_count(desc.mip_level_count); mapped_desc.sample_count(desc.sample_count); - self.create_identified(device.0.create_texture(&mapped_desc)) + create_identified(device.0.create_texture(&mapped_desc)) } fn device_create_sampler( @@ -1928,7 +1853,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { mapped_desc.label(label); } - self.create_identified(device.0.create_sampler_with_descriptor(&mapped_desc)) + create_identified(device.0.create_sampler_with_descriptor(&mapped_desc)) } fn device_create_query_set( @@ -1945,7 +1870,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { mapped_desc.label(label); } - self.create_identified(device.0.create_query_set(&mapped_desc)) + create_identified(device.0.create_query_set(&mapped_desc)) } fn device_create_command_encoder( @@ -2091,7 +2016,7 @@ impl crate::Context for Context { if let Some(label) = desc.label { mapped.label(label); } - self.create_identified(texture.0.create_view_with_descriptor(&mapped)) + create_identified(texture.0.create_view_with_descriptor(&mapped)) } fn surface_drop(&self, _surface: &Self::SurfaceId) { @@ -2171,7 +2096,7 @@ impl crate::Context for Context { pipeline: &Self::ComputePipelineId, index: u32, ) -> Self::BindGroupLayoutId { - self.create_identified(pipeline.0.get_bind_group_layout(index)) + create_identified(pipeline.0.get_bind_group_layout(index)) } fn render_pipeline_get_bind_group_layout( @@ -2179,7 +2104,7 @@ impl crate::Context for Context { pipeline: &Self::RenderPipelineId, index: u32, ) -> Self::BindGroupLayoutId { - self.create_identified(pipeline.0.get_bind_group_layout(index)) + create_identified(pipeline.0.get_bind_group_layout(index)) } fn command_encoder_copy_buffer_to_buffer( @@ -2428,7 +2353,7 @@ impl crate::Context for Context { encoder: Self::RenderBundleEncoderId, desc: &crate::RenderBundleDescriptor, ) -> Self::RenderBundleId { - self.create_identified(match desc.label { + create_identified(match desc.label { Some(label) => { let mut mapped_desc = web_sys::GpuRenderBundleDescriptor::new(); mapped_desc.label(label); From d8b2b1c3c69745e13af1e22c32cffcf9cdf9f36a Mon Sep 17 00:00:00 2001 From: TheOnlyMrCat Date: Fri, 4 Nov 2022 05:49:35 +1100 Subject: [PATCH 7/7] Fully qualify atomics --- wgpu/src/backend/web.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index 8c555a8fae..38f2419a16 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -1,8 +1,6 @@ #![allow(clippy::type_complexity)] use js_sys::Promise; -#[cfg(feature = "expose-ids")] -use std::sync::atomic::{self, AtomicU64}; use std::{ cell::RefCell, fmt, @@ -47,7 +45,7 @@ impl crate::GlobalId for Identified { pub(crate) type Id = u64; #[cfg(feature = "expose-ids")] -static NEXT_ID: AtomicU64 = AtomicU64::new(0); +static NEXT_ID: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0); #[cfg(not(feature = "expose-ids"))] fn create_identified(value: T) -> Identified { @@ -56,7 +54,10 @@ fn create_identified(value: T) -> Identified { #[cfg(feature = "expose-ids")] fn create_identified(value: T) -> Identified { - Identified(value, NEXT_ID.fetch_add(1, atomic::Ordering::Relaxed)) + Identified( + value, + NEXT_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed), + ) } pub(crate) struct Context(web_sys::Gpu);