From eb3ebd036b353c54f40bbb30531a78827229903c Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Thu, 5 Dec 2024 01:36:31 -0500 Subject: [PATCH] Implement Clone on Api Types and Arc Dispatcher --- wgpu/src/api/adapter.rs | 2 +- wgpu/src/api/bind_group.rs | 2 +- wgpu/src/api/bind_group_layout.rs | 2 +- wgpu/src/api/blas.rs | 4 +- wgpu/src/api/buffer.rs | 5 +- wgpu/src/api/command_buffer.rs | 2 +- wgpu/src/api/compute_pipeline.rs | 2 +- wgpu/src/api/device.rs | 6 +- wgpu/src/api/instance.rs | 2 +- wgpu/src/api/pipeline_cache.rs | 2 +- wgpu/src/api/pipeline_layout.rs | 2 +- wgpu/src/api/query_set.rs | 2 +- wgpu/src/api/queue.rs | 2 +- wgpu/src/api/render_bundle.rs | 2 +- wgpu/src/api/render_pipeline.rs | 2 +- wgpu/src/api/sampler.rs | 2 +- wgpu/src/api/surface_texture.rs | 2 +- wgpu/src/api/texture.rs | 2 +- wgpu/src/api/texture_view.rs | 2 +- wgpu/src/api/tlas.rs | 2 +- wgpu/src/backend/wgpu_core.rs | 5 +- wgpu/src/dispatch.rs | 159 +++++++++++++++++++++++++----- 22 files changed, 162 insertions(+), 51 deletions(-) diff --git a/wgpu/src/api/adapter.rs b/wgpu/src/api/adapter.rs index 8fb5225bfe9..0b38c531034 100644 --- a/wgpu/src/api/adapter.rs +++ b/wgpu/src/api/adapter.rs @@ -13,7 +13,7 @@ use crate::*; /// Does not have to be kept alive. /// /// Corresponds to [WebGPU `GPUAdapter`](https://gpuweb.github.io/gpuweb/#gpu-adapter). -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Adapter { pub(crate) inner: dispatch::DispatchAdapter, } diff --git a/wgpu/src/api/bind_group.rs b/wgpu/src/api/bind_group.rs index 1cb73378554..dcec46542ed 100644 --- a/wgpu/src/api/bind_group.rs +++ b/wgpu/src/api/bind_group.rs @@ -8,7 +8,7 @@ use crate::*; /// [`ComputePass`] with [`ComputePass::set_bind_group`]. /// /// Corresponds to [WebGPU `GPUBindGroup`](https://gpuweb.github.io/gpuweb/#gpubindgroup). -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct BindGroup { pub(crate) inner: dispatch::DispatchBindGroup, } diff --git a/wgpu/src/api/bind_group_layout.rs b/wgpu/src/api/bind_group_layout.rs index 191752a2390..a55921ccc8b 100644 --- a/wgpu/src/api/bind_group_layout.rs +++ b/wgpu/src/api/bind_group_layout.rs @@ -11,7 +11,7 @@ use crate::*; /// /// Corresponds to [WebGPU `GPUBindGroupLayout`]( /// https://gpuweb.github.io/gpuweb/#gpubindgrouplayout). -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct BindGroupLayout { pub(crate) inner: dispatch::DispatchBindGroupLayout, } diff --git a/wgpu/src/api/blas.rs b/wgpu/src/api/blas.rs index b64c01ba8f8..56949fcbf7b 100644 --- a/wgpu/src/api/blas.rs +++ b/wgpu/src/api/blas.rs @@ -128,13 +128,13 @@ pub struct BlasBuildEntry<'a> { } static_assertions::assert_impl_all!(BlasBuildEntry<'_>: WasmNotSendSync); -#[derive(Debug)] +#[derive(Debug, Clone)] pub(crate) struct BlasShared { pub(crate) inner: dispatch::DispatchBlas, } static_assertions::assert_impl_all!(BlasShared: WasmNotSendSync); -#[derive(Debug)] +#[derive(Debug, Clone)] /// Bottom Level Acceleration Structure (BLAS). /// /// A BLAS is a device-specific raytracing acceleration structure that contains geometry data. diff --git a/wgpu/src/api/buffer.rs b/wgpu/src/api/buffer.rs index eacfd9ecc57..e4e3f1ab71c 100644 --- a/wgpu/src/api/buffer.rs +++ b/wgpu/src/api/buffer.rs @@ -1,6 +1,7 @@ use std::{ error, fmt, ops::{Bound, Deref, DerefMut, Range, RangeBounds}, + sync::Arc, }; use parking_lot::Mutex; @@ -167,10 +168,10 @@ use crate::*; /// [mac]: BufferDescriptor::mapped_at_creation /// [`MAP_READ`]: BufferUsages::MAP_READ /// [`MAP_WRITE`]: BufferUsages::MAP_WRITE -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Buffer { pub(crate) inner: dispatch::DispatchBuffer, - pub(crate) map_context: Mutex, + pub(crate) map_context: Arc>, pub(crate) size: wgt::BufferAddress, pub(crate) usage: BufferUsages, // Todo: missing map_state https://www.w3.org/TR/webgpu/#dom-gpubuffer-mapstate diff --git a/wgpu/src/api/command_buffer.rs b/wgpu/src/api/command_buffer.rs index e76ae2d5e9b..6022ad248d7 100644 --- a/wgpu/src/api/command_buffer.rs +++ b/wgpu/src/api/command_buffer.rs @@ -7,7 +7,7 @@ use crate::*; /// a [`CommandEncoder`] and then calling [`CommandEncoder::finish`]. /// /// Corresponds to [WebGPU `GPUCommandBuffer`](https://gpuweb.github.io/gpuweb/#command-buffer). -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct CommandBuffer { pub(crate) inner: Option, } diff --git a/wgpu/src/api/compute_pipeline.rs b/wgpu/src/api/compute_pipeline.rs index b1919301ccc..325f0ba1ff2 100644 --- a/wgpu/src/api/compute_pipeline.rs +++ b/wgpu/src/api/compute_pipeline.rs @@ -6,7 +6,7 @@ use crate::*; /// It can be created with [`Device::create_compute_pipeline`]. /// /// Corresponds to [WebGPU `GPUComputePipeline`](https://gpuweb.github.io/gpuweb/#compute-pipeline). -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ComputePipeline { pub(crate) inner: dispatch::DispatchComputePipeline, } diff --git a/wgpu/src/api/device.rs b/wgpu/src/api/device.rs index be2f2a908ba..ebdd443f853 100644 --- a/wgpu/src/api/device.rs +++ b/wgpu/src/api/device.rs @@ -14,7 +14,7 @@ use crate::*; /// A device may be requested from an adapter with [`Adapter::request_device`]. /// /// Corresponds to [WebGPU `GPUDevice`](https://gpuweb.github.io/gpuweb/#gpu-device). -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Device { pub(crate) inner: dispatch::DispatchDevice, } @@ -192,7 +192,7 @@ impl Device { Buffer { inner: buffer, - map_context: Mutex::new(map_context), + map_context: Arc::new(Mutex::new(map_context)), size: desc.size, usage: desc.usage, } @@ -273,7 +273,7 @@ impl Device { Buffer { inner: buffer.into(), - map_context: Mutex::new(map_context), + map_context: Arc::new(Mutex::new(map_context)), size: desc.size, usage: desc.usage, } diff --git a/wgpu/src/api/instance.rs b/wgpu/src/api/instance.rs index f03e348183e..12437cd34fe 100644 --- a/wgpu/src/api/instance.rs +++ b/wgpu/src/api/instance.rs @@ -12,7 +12,7 @@ use std::future::Future; /// Does not have to be kept alive. /// /// Corresponds to [WebGPU `GPU`](https://gpuweb.github.io/gpuweb/#gpu-interface). -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Instance { inner: dispatch::DispatchInstance, } diff --git a/wgpu/src/api/pipeline_cache.rs b/wgpu/src/api/pipeline_cache.rs index 4462a405eb3..e3c8d60886e 100644 --- a/wgpu/src/api/pipeline_cache.rs +++ b/wgpu/src/api/pipeline_cache.rs @@ -62,7 +62,7 @@ use crate::*; /// This type is unique to the Rust API of `wgpu`. /// /// [renaming]: std::fs::rename -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct PipelineCache { pub(crate) inner: dispatch::DispatchPipelineCache, } diff --git a/wgpu/src/api/pipeline_layout.rs b/wgpu/src/api/pipeline_layout.rs index 604dd78efd2..7baa91555c6 100644 --- a/wgpu/src/api/pipeline_layout.rs +++ b/wgpu/src/api/pipeline_layout.rs @@ -6,7 +6,7 @@ use crate::*; /// It can be created with [`Device::create_pipeline_layout`]. /// /// Corresponds to [WebGPU `GPUPipelineLayout`](https://gpuweb.github.io/gpuweb/#gpupipelinelayout). -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct PipelineLayout { pub(crate) inner: dispatch::DispatchPipelineLayout, } diff --git a/wgpu/src/api/query_set.rs b/wgpu/src/api/query_set.rs index a0d358ed4dc..24b5a028097 100644 --- a/wgpu/src/api/query_set.rs +++ b/wgpu/src/api/query_set.rs @@ -5,7 +5,7 @@ use crate::*; /// It can be created with [`Device::create_query_set`]. /// /// Corresponds to [WebGPU `GPUQuerySet`](https://gpuweb.github.io/gpuweb/#queryset). -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct QuerySet { pub(crate) inner: dispatch::DispatchQuerySet, } diff --git a/wgpu/src/api/queue.rs b/wgpu/src/api/queue.rs index 89f505d5727..73b09904056 100644 --- a/wgpu/src/api/queue.rs +++ b/wgpu/src/api/queue.rs @@ -9,7 +9,7 @@ use crate::*; /// It can be created along with a [`Device`] by calling [`Adapter::request_device`]. /// /// Corresponds to [WebGPU `GPUQueue`](https://gpuweb.github.io/gpuweb/#gpu-queue). -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Queue { pub(crate) inner: dispatch::DispatchQueue, } diff --git a/wgpu/src/api/render_bundle.rs b/wgpu/src/api/render_bundle.rs index 1d603eab6bb..95de9762078 100644 --- a/wgpu/src/api/render_bundle.rs +++ b/wgpu/src/api/render_bundle.rs @@ -9,7 +9,7 @@ use crate::*; /// using [`RenderPass::execute_bundles`]. /// /// Corresponds to [WebGPU `GPURenderBundle`](https://gpuweb.github.io/gpuweb/#render-bundle). -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct RenderBundle { pub(crate) inner: dispatch::DispatchRenderBundle, } diff --git a/wgpu/src/api/render_pipeline.rs b/wgpu/src/api/render_pipeline.rs index 71131e941e8..af23928cf9f 100644 --- a/wgpu/src/api/render_pipeline.rs +++ b/wgpu/src/api/render_pipeline.rs @@ -8,7 +8,7 @@ use crate::*; /// buffers and targets. It can be created with [`Device::create_render_pipeline`]. /// /// Corresponds to [WebGPU `GPURenderPipeline`](https://gpuweb.github.io/gpuweb/#render-pipeline). -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct RenderPipeline { pub(crate) inner: dispatch::DispatchRenderPipeline, } diff --git a/wgpu/src/api/sampler.rs b/wgpu/src/api/sampler.rs index 4c57819c990..49c988e85f0 100644 --- a/wgpu/src/api/sampler.rs +++ b/wgpu/src/api/sampler.rs @@ -9,7 +9,7 @@ use crate::*; /// It can be created with [`Device::create_sampler`]. /// /// Corresponds to [WebGPU `GPUSampler`](https://gpuweb.github.io/gpuweb/#sampler-interface). -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Sampler { pub(crate) inner: dispatch::DispatchSampler, } diff --git a/wgpu/src/api/surface_texture.rs b/wgpu/src/api/surface_texture.rs index ce4934e4a32..a988698e6ce 100644 --- a/wgpu/src/api/surface_texture.rs +++ b/wgpu/src/api/surface_texture.rs @@ -8,7 +8,7 @@ use crate::*; /// This type is unique to the Rust API of `wgpu`. In the WebGPU specification, /// the [`GPUCanvasContext`](https://gpuweb.github.io/gpuweb/#canvas-context) provides /// a texture without any additional information. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct SurfaceTexture { /// Accessible view of the frame. pub texture: Texture, diff --git a/wgpu/src/api/texture.rs b/wgpu/src/api/texture.rs index 3fdecd320bf..03044bdf15c 100644 --- a/wgpu/src/api/texture.rs +++ b/wgpu/src/api/texture.rs @@ -5,7 +5,7 @@ use crate::*; /// It can be created with [`Device::create_texture`]. /// /// Corresponds to [WebGPU `GPUTexture`](https://gpuweb.github.io/gpuweb/#texture-interface). -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Texture { pub(crate) inner: dispatch::DispatchTexture, pub(crate) descriptor: TextureDescriptor<'static>, diff --git a/wgpu/src/api/texture_view.rs b/wgpu/src/api/texture_view.rs index f255603bcbf..9b3a7d93860 100644 --- a/wgpu/src/api/texture_view.rs +++ b/wgpu/src/api/texture_view.rs @@ -6,7 +6,7 @@ use crate::*; /// [`RenderPipeline`] or [`BindGroup`]. /// /// Corresponds to [WebGPU `GPUTextureView`](https://gpuweb.github.io/gpuweb/#gputextureview). -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct TextureView { pub(crate) inner: dispatch::DispatchTextureView, } diff --git a/wgpu/src/api/tlas.rs b/wgpu/src/api/tlas.rs index 538f4e16c25..ec042f882a5 100644 --- a/wgpu/src/api/tlas.rs +++ b/wgpu/src/api/tlas.rs @@ -7,7 +7,7 @@ use wgt::WasmNotSendSync; pub type CreateTlasDescriptor<'a> = wgt::CreateTlasDescriptor>; static_assertions::assert_impl_all!(CreateTlasDescriptor<'_>: Send, Sync); -#[derive(Debug)] +#[derive(Debug, Clone)] /// Top Level Acceleration Structure (TLAS). /// /// A TLAS contains a series of [TLAS instances], which are a reference to diff --git a/wgpu/src/backend/wgpu_core.rs b/wgpu/src/backend/wgpu_core.rs index 41ef5821290..98c7d59bb1d 100644 --- a/wgpu/src/backend/wgpu_core.rs +++ b/wgpu/src/backend/wgpu_core.rs @@ -823,11 +823,12 @@ impl dispatch::InstanceInterface for ContextWgpuCore { }, }?; - Ok(dispatch::DispatchSurface::Core(CoreSurface { + Ok(CoreSurface { context: self.clone(), id, configured_device: Mutex::default(), - })) + } + .into()) } fn request_adapter( diff --git a/wgpu/src/dispatch.rs b/wgpu/src/dispatch.rs index 71826eb4292..36da51a4def 100644 --- a/wgpu/src/dispatch.rs +++ b/wgpu/src/dispatch.rs @@ -13,7 +13,7 @@ use crate::{WasmNotSend, WasmNotSendSync}; -use std::{any::Any, fmt::Debug, future::Future, hash::Hash, ops::Range, pin::Pin}; +use std::{any::Any, fmt::Debug, future::Future, hash::Hash, ops::Range, pin::Pin, sync::Arc}; use crate::backend; @@ -555,7 +555,138 @@ pub trait BufferMappedRangeInterface: CommonTraits { /// arguments. These are similarly free when there is only one backend. /// /// In the future, we may want a truly generic backend, which could be extended from this enum. -macro_rules! dispatch_types { +macro_rules! dispatch_arc_types { + ( + wgpu_core = $wgpu_core_context:ty; + webgpu = $webgpu_context:ty; + {$( + type $name:ident = InterfaceTypes::$subtype:ident: $trait:ident; + )*} + ) => { + $( + #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub enum $name { + #[cfg(wgpu_core)] + Core(Arc<<$wgpu_core_context as InterfaceTypes>::$subtype>), + #[cfg(webgpu)] + WebGPU(Arc<<$webgpu_context as InterfaceTypes>::$subtype>), + } + + impl $name { + #[cfg(wgpu_core)] + #[inline] + #[allow(unused)] + pub fn as_core(&self) -> &<$wgpu_core_context as InterfaceTypes>::$subtype { + match self { + Self::Core(value) => value, + _ => panic!(concat!(stringify!($name), " is not core")), + } + } + + #[cfg(wgpu_core)] + #[inline] + #[allow(unused)] + pub fn as_core_opt(&self) -> Option<&<$wgpu_core_context as InterfaceTypes>::$subtype> { + match self { + Self::Core(value) => Some(value), + _ => None, + } + } + + #[cfg(webgpu)] + #[inline] + #[allow(unused)] + pub fn as_webgpu(&self) -> &<$webgpu_context as InterfaceTypes>::$subtype { + match self { + Self::WebGPU(value) => value, + _ => panic!(concat!(stringify!($name), " is not webgpu")), + } + } + + #[cfg(webgpu)] + #[inline] + #[allow(unused)] + pub fn as_webgpu_opt(&self) -> Option<&<$webgpu_context as InterfaceTypes>::$subtype> { + match self { + Self::WebGPU(value) => Some(value), + _ => None, + } + } + } + + #[cfg(wgpu_core)] + impl From<<$wgpu_core_context as InterfaceTypes>::$subtype> for $name { + #[inline] + fn from(value: <$wgpu_core_context as InterfaceTypes>::$subtype) -> Self { + Self::Core(Arc::new(value)) + } + } + + #[cfg(webgpu)] + impl From<<$webgpu_context as InterfaceTypes>::$subtype> for $name { + #[inline] + fn from(value: <$webgpu_context as InterfaceTypes>::$subtype) -> Self { + Self::WebGPU(Arc::new(value)) + } + } + + impl std::ops::Deref for $name { + type Target = dyn $trait; + + #[inline] + fn deref(&self) -> &Self::Target { + match self { + #[cfg(wgpu_core)] + Self::Core(value) => &**value, + #[cfg(webgpu)] + Self::WebGPU(value) => &**value, + } + } + } + )* + }; +} + +dispatch_arc_types! { + wgpu_core = backend::ContextWgpuCore; + webgpu = backend::ContextWebGpu; + { + type DispatchInstance = InterfaceTypes::Instance: InstanceInterface; + type DispatchAdapter = InterfaceTypes::Adapter: AdapterInterface; + type DispatchDevice = InterfaceTypes::Device: DeviceInterface; + type DispatchQueue = InterfaceTypes::Queue: QueueInterface; + type DispatchShaderModule = InterfaceTypes::ShaderModule: ShaderModuleInterface; + type DispatchBindGroupLayout = InterfaceTypes::BindGroupLayout: BindGroupLayoutInterface; + type DispatchBindGroup = InterfaceTypes::BindGroup: BindGroupInterface; + type DispatchTextureView = InterfaceTypes::TextureView: TextureViewInterface; + type DispatchSampler = InterfaceTypes::Sampler: SamplerInterface; + type DispatchBuffer = InterfaceTypes::Buffer: BufferInterface; + type DispatchTexture = InterfaceTypes::Texture: TextureInterface; + type DispatchBlas = InterfaceTypes::Blas: BlasInterface; + type DispatchTlas = InterfaceTypes::Tlas: TlasInterface; + type DispatchQuerySet = InterfaceTypes::QuerySet: QuerySetInterface; + type DispatchPipelineLayout = InterfaceTypes::PipelineLayout: PipelineLayoutInterface; + type DispatchRenderPipeline = InterfaceTypes::RenderPipeline: RenderPipelineInterface; + type DispatchComputePipeline = InterfaceTypes::ComputePipeline: ComputePipelineInterface; + type DispatchPipelineCache = InterfaceTypes::PipelineCache: PipelineCacheInterface; + type DispatchCommandBuffer = InterfaceTypes::CommandBuffer: CommandBufferInterface; + type DispatchRenderBundle = InterfaceTypes::RenderBundle: RenderBundleInterface; + type DispatchSurface = InterfaceTypes::Surface: SurfaceInterface; + type DispatchSurfaceOutputDetail = InterfaceTypes::SurfaceOutputDetail: SurfaceOutputDetailInterface; + } +} + +/// Generates Dispatch types for each of the interfaces. Each type is a wrapper around the +/// wgpu_core and webgpu types, and derefs to the appropriate interface trait-object. +/// +/// When there is only one backend, deviritualization fires and all dispatches should turn into +/// direct calls. If there are multiple, some dispatching will occur. +/// +/// This also provides `as_*` methods so that the backend implementations can dereference other +/// arguments. These are similarly free when there is only one backend. +/// +/// In the future, we may want a truly generic backend, which could be extended from this enum. +macro_rules! dispatch_mut_types { ( wgpu_core = $wgpu_core_context:ty; webgpu = $webgpu_context:ty; @@ -699,36 +830,14 @@ macro_rules! dispatch_types { }; } -dispatch_types! { +dispatch_mut_types! { wgpu_core = backend::ContextWgpuCore; webgpu = backend::ContextWebGpu; { - type DispatchInstance = InterfaceTypes::Instance: InstanceInterface; - type DispatchAdapter = InterfaceTypes::Adapter: AdapterInterface; - type DispatchDevice = InterfaceTypes::Device: DeviceInterface; - type DispatchQueue = InterfaceTypes::Queue: QueueInterface; - type DispatchShaderModule = InterfaceTypes::ShaderModule: ShaderModuleInterface; - type DispatchBindGroupLayout = InterfaceTypes::BindGroupLayout: BindGroupLayoutInterface; - type DispatchBindGroup = InterfaceTypes::BindGroup: BindGroupInterface; - type DispatchTextureView = InterfaceTypes::TextureView: TextureViewInterface; - type DispatchSampler = InterfaceTypes::Sampler: SamplerInterface; - type DispatchBuffer = InterfaceTypes::Buffer: BufferInterface; - type DispatchTexture = InterfaceTypes::Texture: TextureInterface; - type DispatchBlas = InterfaceTypes::Blas: BlasInterface; - type DispatchTlas = InterfaceTypes::Tlas: TlasInterface; - type DispatchQuerySet = InterfaceTypes::QuerySet: QuerySetInterface; - type DispatchPipelineLayout = InterfaceTypes::PipelineLayout: PipelineLayoutInterface; - type DispatchRenderPipeline = InterfaceTypes::RenderPipeline: RenderPipelineInterface; - type DispatchComputePipeline = InterfaceTypes::ComputePipeline: ComputePipelineInterface; - type DispatchPipelineCache = InterfaceTypes::PipelineCache: PipelineCacheInterface; type DispatchCommandEncoder = InterfaceTypes::CommandEncoder: CommandEncoderInterface; type DispatchComputePass = InterfaceTypes::ComputePass: ComputePassInterface; type DispatchRenderPass = InterfaceTypes::RenderPass: RenderPassInterface; - type DispatchCommandBuffer = InterfaceTypes::CommandBuffer: CommandBufferInterface; type DispatchRenderBundleEncoder = InterfaceTypes::RenderBundleEncoder: RenderBundleEncoderInterface; - type DispatchRenderBundle = InterfaceTypes::RenderBundle: RenderBundleInterface; - type DispatchSurface = InterfaceTypes::Surface: SurfaceInterface; - type DispatchSurfaceOutputDetail = InterfaceTypes::SurfaceOutputDetail: SurfaceOutputDetailInterface; type DispatchQueueWriteBuffer = InterfaceTypes::QueueWriteBuffer: QueueWriteBufferInterface; type DispatchBufferMappedRange = InterfaceTypes::BufferMappedRange: BufferMappedRangeInterface; }