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 std::any::Any;
16
17use wgt::WasmNotSendSync;
18
19use crate::{
20    AccelerationStructureAABBs, AccelerationStructureEntries, AccelerationStructureInstances,
21    AccelerationStructureTriangleIndices, AccelerationStructureTriangleTransform,
22    AccelerationStructureTriangles, BufferBinding, ProgrammableStage, TextureBinding,
23};
24
25/// Base trait for all resources, allows downcasting via [`Any`].
26pub trait DynResource: Any + WasmNotSendSync + 'static {
27    fn as_any(&self) -> &dyn Any;
28    fn as_any_mut(&mut self) -> &mut dyn Any;
29}
30
31/// Utility macro for implementing `DynResource` for a list of types.
32macro_rules! impl_dyn_resource {
33    ($($type:ty),*) => {
34        $(
35            impl crate::DynResource for $type {
36                fn as_any(&self) -> &dyn ::std::any::Any {
37                    self
38                }
39
40                fn as_any_mut(&mut self) -> &mut dyn ::std::any::Any {
41                    self
42                }
43            }
44        )*
45    };
46}
47pub(crate) use impl_dyn_resource;
48
49/// Extension trait for `DynResource` used by implementations of various dynamic resource traits.
50trait DynResourceExt {
51    /// # Panics
52    ///
53    /// - Panics if `self` is not downcastable to `T`.
54    fn expect_downcast_ref<T: DynResource>(&self) -> &T;
55    /// # Panics
56    ///
57    /// - Panics if `self` is not downcastable to `T`.
58    fn expect_downcast_mut<T: DynResource>(&mut self) -> &mut T;
59
60    /// Unboxes a `Box<dyn DynResource>` to a concrete type.
61    ///
62    /// # Safety
63    ///
64    /// - `self` must be the correct concrete type.
65    unsafe fn unbox<T: DynResource + 'static>(self: Box<Self>) -> T;
66}
67
68impl<R: DynResource + ?Sized> DynResourceExt for R {
69    fn expect_downcast_ref<'a, T: DynResource>(&'a self) -> &'a T {
70        self.as_any()
71            .downcast_ref()
72            .expect("Resource doesn't have the expected backend type.")
73    }
74
75    fn expect_downcast_mut<'a, T: DynResource>(&'a mut self) -> &'a mut T {
76        self.as_any_mut()
77            .downcast_mut()
78            .expect("Resource doesn't have the expected backend type.")
79    }
80
81    unsafe fn unbox<T: DynResource + 'static>(self: Box<Self>) -> T {
82        debug_assert!(
83            <Self as Any>::type_id(self.as_ref()) == std::any::TypeId::of::<T>(),
84            "Resource doesn't have the expected type, expected {:?}, got {:?}",
85            std::any::TypeId::of::<T>(),
86            <Self as Any>::type_id(self.as_ref())
87        );
88
89        let casted_ptr = Box::into_raw(self).cast::<T>();
90        // SAFETY: This is adheres to the safety contract of `Box::from_raw` because:
91        //
92        // - We are casting the value of a previously `Box`ed value, which guarantees:
93        //   - `casted_ptr` is not null.
94        //   - `casted_ptr` is valid for reads and writes, though by itself this does not mean
95        //     valid reads and writes for `T` (read on for that).
96        // - We don't change the allocator.
97        // - The contract of `Box::from_raw` requires that an initialized and aligned `T` is stored
98        //   within `casted_ptr`.
99        *unsafe { Box::from_raw(casted_ptr) }
100    }
101}
102
103pub trait DynAccelerationStructure: DynResource + std::fmt::Debug {}
104pub trait DynBindGroup: DynResource + std::fmt::Debug {}
105pub trait DynBindGroupLayout: DynResource + std::fmt::Debug {}
106pub trait DynBuffer: DynResource + std::fmt::Debug {}
107pub trait DynCommandBuffer: DynResource + std::fmt::Debug {}
108pub trait DynComputePipeline: DynResource + std::fmt::Debug {}
109pub trait DynFence: DynResource + std::fmt::Debug {}
110pub trait DynPipelineCache: DynResource + std::fmt::Debug {}
111pub trait DynPipelineLayout: DynResource + std::fmt::Debug {}
112pub trait DynQuerySet: DynResource + std::fmt::Debug {}
113pub trait DynRenderPipeline: DynResource + std::fmt::Debug {}
114pub trait DynSampler: DynResource + std::fmt::Debug {}
115pub trait DynShaderModule: DynResource + std::fmt::Debug {}
116pub trait DynSurfaceTexture:
117    DynResource + std::borrow::Borrow<dyn DynTexture> + std::fmt::Debug
118{
119}
120pub trait DynTexture: DynResource + std::fmt::Debug {}
121pub trait DynTextureView: DynResource + std::fmt::Debug {}
122
123impl<'a> BufferBinding<'a, dyn DynBuffer> {
124    pub fn expect_downcast<B: DynBuffer>(self) -> BufferBinding<'a, B> {
125        BufferBinding {
126            buffer: self.buffer.expect_downcast_ref(),
127            offset: self.offset,
128            size: self.size,
129        }
130    }
131}
132
133impl<'a> TextureBinding<'a, dyn DynTextureView> {
134    pub fn expect_downcast<T: DynTextureView>(self) -> TextureBinding<'a, T> {
135        TextureBinding {
136            view: self.view.expect_downcast_ref(),
137            usage: self.usage,
138        }
139    }
140}
141
142impl<'a> ProgrammableStage<'a, dyn DynShaderModule> {
143    fn expect_downcast<T: DynShaderModule>(self) -> ProgrammableStage<'a, T> {
144        ProgrammableStage {
145            module: self.module.expect_downcast_ref(),
146            entry_point: self.entry_point,
147            constants: self.constants,
148            zero_initialize_workgroup_memory: self.zero_initialize_workgroup_memory,
149        }
150    }
151}
152
153impl<'a> AccelerationStructureEntries<'a, dyn DynBuffer> {
154    fn expect_downcast<B: DynBuffer>(&self) -> AccelerationStructureEntries<'a, B> {
155        match self {
156            AccelerationStructureEntries::Instances(instances) => {
157                AccelerationStructureEntries::Instances(AccelerationStructureInstances {
158                    buffer: instances.buffer.map(|b| b.expect_downcast_ref()),
159                    offset: instances.offset,
160                    count: instances.count,
161                })
162            }
163            AccelerationStructureEntries::Triangles(triangles) => {
164                AccelerationStructureEntries::Triangles(
165                    triangles
166                        .iter()
167                        .map(|t| AccelerationStructureTriangles {
168                            vertex_buffer: t.vertex_buffer.map(|b| b.expect_downcast_ref()),
169                            vertex_format: t.vertex_format,
170                            first_vertex: t.first_vertex,
171                            vertex_count: t.vertex_count,
172                            vertex_stride: t.vertex_stride,
173                            indices: t.indices.as_ref().map(|i| {
174                                AccelerationStructureTriangleIndices {
175                                    buffer: i.buffer.map(|b| b.expect_downcast_ref()),
176                                    format: i.format,
177                                    offset: i.offset,
178                                    count: i.count,
179                                }
180                            }),
181                            transform: t.transform.as_ref().map(|t| {
182                                AccelerationStructureTriangleTransform {
183                                    buffer: t.buffer.expect_downcast_ref(),
184                                    offset: t.offset,
185                                }
186                            }),
187                            flags: t.flags,
188                        })
189                        .collect(),
190                )
191            }
192            AccelerationStructureEntries::AABBs(entries) => AccelerationStructureEntries::AABBs(
193                entries
194                    .iter()
195                    .map(|e| AccelerationStructureAABBs {
196                        buffer: e.buffer.map(|b| b.expect_downcast_ref()),
197                        offset: e.offset,
198                        count: e.count,
199                        stride: e.stride,
200                        flags: e.flags,
201                    })
202                    .collect(),
203            ),
204        }
205    }
206}