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