wgpu_core/
as_hal.rs

1use core::{mem::ManuallyDrop, ops::Deref};
2
3use alloc::sync::Arc;
4use hal::DynResource;
5
6use crate::{lock::RankData, resource::RawResourceAccess, snatch::SnatchGuard};
7
8/// A guard which holds alive a wgpu-core resource and dereferences to the Hal type.
9struct SimpleResourceGuard<Resource, HalType> {
10    _guard: Resource,
11    ptr: *const HalType,
12}
13
14impl<Resource, HalType> SimpleResourceGuard<Resource, HalType> {
15    /// Creates a new guard from a resource, using a callback to derive the Hal type.
16    pub fn new<C>(guard: Resource, callback: C) -> Option<Self>
17    where
18        C: Fn(&Resource) -> Option<&HalType>,
19    {
20        // Derive the hal type from the resource and coerce it to a pointer.
21        let ptr: *const HalType = callback(&guard)?;
22
23        Some(Self { _guard: guard, ptr })
24    }
25}
26
27impl<Resource, HalType> Deref for SimpleResourceGuard<Resource, HalType> {
28    type Target = HalType;
29
30    fn deref(&self) -> &Self::Target {
31        // SAFETY: The pointer is guaranteed to be valid as the original resource is
32        // still alive and this guard cannot be used with snatchable resources.
33        unsafe { &*self.ptr }
34    }
35}
36
37unsafe impl<Resource, HalType> Send for SimpleResourceGuard<Resource, HalType>
38where
39    Resource: Send,
40    HalType: Send,
41{
42}
43unsafe impl<Resource, HalType> Sync for SimpleResourceGuard<Resource, HalType>
44where
45    Resource: Sync,
46    HalType: Sync,
47{
48}
49
50/// A guard which holds alive a snatchable wgpu-core resource and dereferences to the Hal type.
51struct SnatchableResourceGuard<Resource, HalType>
52where
53    Resource: RawResourceAccess,
54{
55    resource: Arc<Resource>,
56    snatch_lock_rank_data: ManuallyDrop<RankData>,
57    ptr: *const HalType,
58}
59
60impl<Resource, HalType> SnatchableResourceGuard<Resource, HalType>
61where
62    Resource: RawResourceAccess,
63    HalType: 'static,
64{
65    /// Creates a new guard from a snatchable resource.
66    ///
67    /// Returns `None` if:
68    /// - The resource is not of the expected Hal type.
69    /// - The resource has been destroyed.
70    pub fn new(resource: Arc<Resource>) -> Option<Self> {
71        // Grab the snatchable lock.
72        let snatch_guard = resource.device().snatchable_lock.read();
73
74        // Get the raw resource and downcast it to the expected Hal type.
75        let underlying = resource
76            .raw(&snatch_guard)?
77            .as_any()
78            .downcast_ref::<HalType>()?;
79
80        // Cast the raw resource to a pointer to get rid of the lifetime
81        // connecting us to the snatch guard.
82        let ptr: *const HalType = underlying;
83
84        // SAFETY: At this point all panicking or divergance has already happened,
85        // so we can safely forget the snatch guard without causing the lock to be left open.
86        let snatch_lock_rank_data = SnatchGuard::forget(snatch_guard);
87
88        // SAFETY: We only construct this guard while the snatchable lock is held,
89        // as the `drop` implementation of this guard will unsafely release the lock.
90        Some(Self {
91            resource,
92            snatch_lock_rank_data: ManuallyDrop::new(snatch_lock_rank_data),
93            ptr,
94        })
95    }
96}
97
98impl<Resource, HalType> Deref for SnatchableResourceGuard<Resource, HalType>
99where
100    Resource: RawResourceAccess,
101{
102    type Target = HalType;
103
104    fn deref(&self) -> &Self::Target {
105        // SAFETY: The pointer is guaranteed to be valid as the original resource is
106        // still alive and the snatchable lock is still being held due to the forgotten
107        // snatch guard.
108        unsafe { &*self.ptr }
109    }
110}
111
112impl<Resource, HalType> Drop for SnatchableResourceGuard<Resource, HalType>
113where
114    Resource: RawResourceAccess,
115{
116    fn drop(&mut self) {
117        // SAFETY:
118        // - We are not going to access the rank data anymore.
119        let data = unsafe { ManuallyDrop::take(&mut self.snatch_lock_rank_data) };
120
121        // SAFETY:
122        // - The pointer is no longer going to be accessed.
123        // - The snatchable lock is being held because this type was not created
124        //   until after the snatchable lock was forgotten.
125        unsafe {
126            self.resource
127                .device()
128                .snatchable_lock
129                .force_unlock_read(data)
130        };
131    }
132}
133
134unsafe impl<Resource, HalType> Send for SnatchableResourceGuard<Resource, HalType>
135where
136    Resource: RawResourceAccess + Send,
137    HalType: Send,
138{
139}
140unsafe impl<Resource, HalType> Sync for SnatchableResourceGuard<Resource, HalType>
141where
142    Resource: RawResourceAccess + Sync,
143    HalType: Sync,
144{
145}
146
147impl crate::resource::Buffer {
148    /// # Safety
149    ///
150    /// - The raw buffer handle must not be manually destroyed
151    pub unsafe fn as_hal<A: hal::Api>(self: Arc<Self>) -> Option<impl Deref<Target = A::Buffer>> {
152        profiling::scope!("Buffer::as_hal");
153
154        SnatchableResourceGuard::new(self)
155    }
156}
157
158impl crate::resource::Texture {
159    /// # Safety
160    ///
161    /// - The raw texture handle must not be manually destroyed
162    pub unsafe fn as_hal<A: hal::Api>(self: Arc<Self>) -> Option<impl Deref<Target = A::Texture>> {
163        profiling::scope!("Texture::as_hal");
164
165        SnatchableResourceGuard::new(self)
166    }
167}
168
169impl crate::resource::TextureView {
170    /// # Safety
171    ///
172    /// - The raw texture view handle must not be manually destroyed
173    pub unsafe fn as_hal<A: hal::Api>(
174        self: Arc<Self>,
175    ) -> Option<impl Deref<Target = A::TextureView>> {
176        profiling::scope!("TextureView::as_hal");
177
178        SnatchableResourceGuard::new(self)
179    }
180}
181
182impl crate::instance::Adapter {
183    /// # Safety
184    ///
185    /// - The raw adapter handle must not be manually destroyed
186    pub unsafe fn as_hal<A: hal::Api>(self: Arc<Self>) -> Option<impl Deref<Target = A::Adapter>> {
187        profiling::scope!("Adapter::as_hal");
188
189        SimpleResourceGuard::new(self, move |adapter| {
190            adapter.raw.adapter.as_any().downcast_ref()
191        })
192    }
193}
194
195impl crate::device::Device {
196    /// # Safety
197    ///
198    /// - The raw device handle must not be manually destroyed
199    pub unsafe fn as_hal<A: hal::Api>(self: Arc<Self>) -> Option<impl Deref<Target = A::Device>> {
200        profiling::scope!("Device::as_hal");
201
202        SimpleResourceGuard::new(self, move |device| device.raw().as_any().downcast_ref())
203    }
204
205    /// # Safety
206    ///
207    /// - The raw fence handle must not be manually destroyed
208    pub unsafe fn fence_as_hal<A: hal::Api>(
209        self: Arc<Self>,
210    ) -> Option<impl Deref<Target = A::Fence>> {
211        profiling::scope!("Device::fence_as_hal");
212
213        SimpleResourceGuard::new(self, move |device| device.fence.as_any().downcast_ref())
214    }
215}
216
217impl crate::instance::Surface {
218    /// # Safety
219    ///
220    /// - The raw surface handle must not be manually destroyed
221    pub unsafe fn as_hal<A: hal::Api>(self: Arc<Self>) -> Option<impl Deref<Target = A::Surface>> {
222        profiling::scope!("Surface::as_hal");
223
224        SimpleResourceGuard::new(self, move |surface| {
225            surface.raw(A::VARIANT)?.as_any().downcast_ref()
226        })
227    }
228}
229
230impl crate::command::CommandEncoder {
231    /// Encode commands using the raw HAL command encoder.
232    ///
233    /// # Panics
234    ///
235    /// If the command encoder has already been used with the wgpu encoding API.
236    ///
237    /// # Safety
238    ///
239    /// - The raw command encoder handle must not be manually destroyed
240    pub unsafe fn as_hal_mut<A: hal::Api, F: FnOnce(Option<&mut A::CommandEncoder>) -> R, R>(
241        self: &Arc<Self>,
242        hal_command_encoder_callback: F,
243    ) -> R {
244        profiling::scope!("CommandEncoder::as_hal");
245
246        let mut cmd_buf_data = self.data.lock();
247        cmd_buf_data.record_as_hal_mut(|opt_cmd_buf| -> R {
248            hal_command_encoder_callback(opt_cmd_buf.and_then(|cmd_buf| {
249                cmd_buf
250                    .encoder
251                    .open()
252                    .ok()
253                    .and_then(|encoder| encoder.as_any_mut().downcast_mut())
254            }))
255        })
256    }
257}
258
259impl crate::device::queue::Queue {
260    /// # Safety
261    ///
262    /// - The raw queue handle must not be manually destroyed
263    pub unsafe fn as_hal<A: hal::Api>(self: Arc<Self>) -> Option<impl Deref<Target = A::Queue>> {
264        profiling::scope!("Queue::as_hal");
265
266        SimpleResourceGuard::new(self, move |queue| queue.raw().as_any().downcast_ref())
267    }
268}
269
270impl crate::resource::Blas {
271    /// # Safety
272    ///
273    /// - The raw blas handle must not be manually destroyed
274    pub unsafe fn as_hal<A: hal::Api>(
275        self: Arc<Self>,
276    ) -> Option<impl Deref<Target = A::AccelerationStructure>> {
277        profiling::scope!("Blas::as_hal");
278
279        SnatchableResourceGuard::new(self)
280    }
281}
282
283impl crate::resource::Tlas {
284    /// # Safety
285    ///
286    /// - The raw tlas handle must not be manually destroyed
287    pub unsafe fn as_hal<A: hal::Api>(
288        self: Arc<Self>,
289    ) -> Option<impl Deref<Target = A::AccelerationStructure>> {
290        profiling::scope!("Tlas::as_hal");
291
292        SnatchableResourceGuard::new(self)
293    }
294}