Skip to main content

wgpu_hal/dynamic/
mod.rs

1mod adapter;
2mod command;
3mod device;
4mod instance;
5mod queue;
6mod surface;
7
8pub use adapter::{DynAdapter, DynOpenDevice};
9pub use command::DynCommandEncoder;
10pub use device::DynDevice;
11pub use instance::{DynExposedAdapter, DynInstance};
12pub use queue::DynQueue;
13pub use surface::{DynAcquiredSurfaceTexture, DynSurface};
14
15use alloc::boxed::Box;
16use core::{
17    any::{Any, TypeId},
18    fmt,
19};
20
21use wgt::WasmNotSendSync;
22
23use crate::{
24    AccelerationStructureAABBs, AccelerationStructureEntries, AccelerationStructureInstances,
25    AccelerationStructureTriangleIndices, AccelerationStructureTriangleTransform,
26    AccelerationStructureTriangles, BufferBinding, ExternalTextureBinding, ProgrammableStage,
27    TextureBinding,
28};
29
30/// Base trait for all resources, allows downcasting via [`Any`].
31pub trait DynResource: Any + WasmNotSendSync + 'static {
32    fn as_any(&self) -> &dyn Any;
33    fn as_any_mut(&mut self) -> &mut dyn Any;
34}
35
36/// Utility macro for implementing `DynResource` for a list of types.
37macro_rules! impl_dyn_resource {
38    ($($type:ty),*) => {
39        $(
40            impl crate::DynResource for $type {
41                fn as_any(&self) -> &dyn ::core::any::Any {
42                    self
43                }
44
45                fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any {
46                    self
47                }
48            }
49        )*
50    };
51}
52pub(crate) use impl_dyn_resource;
53
54/// Extension trait for `DynResource` used by implementations of various dynamic resource traits.
55trait DynResourceExt {
56    /// # Panics
57    ///
58    /// - Panics if `self` is not downcastable to `T`.
59    fn expect_downcast_ref<T: DynResource>(&self) -> &T;
60
61    /// Unboxes a `Box<dyn DynResource>` to a concrete type.
62    ///
63    /// # Safety
64    ///
65    /// - `self` must be the correct concrete type.
66    unsafe fn unbox<T: DynResource + 'static>(self: Box<Self>) -> T;
67}
68
69impl<R: DynResource + ?Sized> DynResourceExt for R {
70    fn expect_downcast_ref<'a, T: DynResource>(&'a self) -> &'a T {
71        self.as_any()
72            .downcast_ref()
73            .expect("Resource doesn't have the expected backend type.")
74    }
75
76    unsafe fn unbox<T: DynResource + 'static>(self: Box<Self>) -> T {
77        debug_assert!(
78            <Self as Any>::type_id(self.as_ref()) == TypeId::of::<T>(),
79            "Resource doesn't have the expected type, expected {:?}, got {:?}",
80            TypeId::of::<T>(),
81            <Self as Any>::type_id(self.as_ref())
82        );
83
84        let casted_ptr = Box::into_raw(self).cast::<T>();
85        // SAFETY: This is adheres to the safety contract of `Box::from_raw` because:
86        //
87        // - We are casting the value of a previously `Box`ed value, which guarantees:
88        //   - `casted_ptr` is not null.
89        //   - `casted_ptr` is valid for reads and writes, though by itself this does not mean
90        //     valid reads and writes for `T` (read on for that).
91        // - We don't change the allocator.
92        // - The contract of `Box::from_raw` requires that an initialized and aligned `T` is stored
93        //   within `casted_ptr`.
94        *unsafe { Box::from_raw(casted_ptr) }
95    }
96}
97
98pub trait DynAccelerationStructure: DynResource + fmt::Debug {}
99pub trait DynBindGroup: DynResource + fmt::Debug {}
100pub trait DynBindGroupLayout: DynResource + fmt::Debug {}
101pub trait DynBuffer: DynResource + fmt::Debug {}
102pub trait DynCommandBuffer: DynResource + fmt::Debug {}
103pub trait DynComputePipeline: DynResource + fmt::Debug {}
104pub trait DynFence: DynResource + fmt::Debug {}
105pub trait DynPipelineCache: DynResource + fmt::Debug {}
106pub trait DynPipelineLayout: DynResource + fmt::Debug {}
107pub trait DynQuerySet: DynResource + fmt::Debug {}
108pub trait DynRenderPipeline: DynResource + fmt::Debug {}
109pub trait DynRayTracingPipeline: DynResource + fmt::Debug {}
110pub trait DynSampler: DynResource + fmt::Debug {}
111pub trait DynShaderModule: DynResource + fmt::Debug {}
112pub trait DynSurfaceTexture:
113    DynResource + core::borrow::Borrow<dyn DynTexture> + fmt::Debug
114{
115    /// Which of the surface's presentable images this texture is: the same
116    /// value each time the surface hands that image out again, until it is
117    /// configured anew. `None` where the backend cannot tell its images
118    /// apart.
119    fn image_id(&self) -> Option<u64> {
120        None
121    }
122
123    /// Whether no submission has waited for this texture's acquisition yet,
124    /// on a backend whose presentation waits for one.
125    fn awaits_acquire(&self) -> bool {
126        false
127    }
128}
129pub trait DynTexture: DynResource + fmt::Debug {}
130pub trait DynTextureView: DynResource + fmt::Debug {}
131
132impl<'a> BufferBinding<'a, dyn DynBuffer> {
133    pub fn expect_downcast<B: DynBuffer>(self) -> BufferBinding<'a, B> {
134        BufferBinding {
135            buffer: self.buffer.expect_downcast_ref(),
136            offset: self.offset,
137            size: self.size,
138        }
139    }
140}
141
142impl<'a> TextureBinding<'a, dyn DynTextureView> {
143    pub fn expect_downcast<T: DynTextureView>(self) -> TextureBinding<'a, T> {
144        TextureBinding {
145            view: self.view.expect_downcast_ref(),
146            usage: self.usage,
147        }
148    }
149}
150
151impl<'a> ExternalTextureBinding<'a, dyn DynBuffer, dyn DynTextureView> {
152    pub fn expect_downcast<B: DynBuffer, T: DynTextureView>(
153        self,
154    ) -> ExternalTextureBinding<'a, B, T> {
155        let planes = self.planes.map(|plane| plane.expect_downcast());
156        let params = self.params.expect_downcast();
157        ExternalTextureBinding { planes, params }
158    }
159}
160
161impl<'a> ProgrammableStage<'a, dyn DynShaderModule> {
162    fn expect_downcast<T: DynShaderModule>(self) -> ProgrammableStage<'a, T> {
163        ProgrammableStage {
164            module: self.module.expect_downcast_ref(),
165            entry_point: self.entry_point,
166            constants: self.constants,
167            zero_initialize_workgroup_memory: self.zero_initialize_workgroup_memory,
168        }
169    }
170}
171
172impl<'a> AccelerationStructureEntries<'a, dyn DynBuffer> {
173    fn expect_downcast<B: DynBuffer>(&self) -> AccelerationStructureEntries<'a, B> {
174        match self {
175            AccelerationStructureEntries::Instances(instances) => {
176                AccelerationStructureEntries::Instances(AccelerationStructureInstances {
177                    buffer: instances.buffer.map(|b| b.expect_downcast_ref()),
178                    offset: instances.offset,
179                    count: instances.count,
180                })
181            }
182            AccelerationStructureEntries::Triangles(triangles) => {
183                AccelerationStructureEntries::Triangles(
184                    triangles
185                        .iter()
186                        .map(|t| AccelerationStructureTriangles {
187                            vertex_buffer: t.vertex_buffer.map(|b| b.expect_downcast_ref()),
188                            vertex_format: t.vertex_format,
189                            first_vertex: t.first_vertex,
190                            vertex_count: t.vertex_count,
191                            vertex_stride: t.vertex_stride,
192                            indices: t.indices.as_ref().map(|i| {
193                                AccelerationStructureTriangleIndices {
194                                    buffer: i.buffer.map(|b| b.expect_downcast_ref()),
195                                    format: i.format,
196                                    offset: i.offset,
197                                    count: i.count,
198                                }
199                            }),
200                            transform: t.transform.as_ref().map(|t| {
201                                AccelerationStructureTriangleTransform {
202                                    buffer: t.buffer.expect_downcast_ref(),
203                                    offset: t.offset,
204                                }
205                            }),
206                            flags: t.flags,
207                        })
208                        .collect(),
209                )
210            }
211            AccelerationStructureEntries::AABBs(entries) => AccelerationStructureEntries::AABBs(
212                entries
213                    .iter()
214                    .map(|e| AccelerationStructureAABBs {
215                        buffer: e.buffer.map(|b| b.expect_downcast_ref()),
216                        offset: e.offset,
217                        count: e.count,
218                        stride: e.stride,
219                        flags: e.flags,
220                    })
221                    .collect(),
222            ),
223        }
224    }
225}