wgpu_core/
as_hal.rs

1use core::{mem::ManuallyDrop, ops::Deref};
2
3use alloc::sync::Arc;
4use hal::DynResource;
5
6use crate::{
7    global::Global,
8    id::{
9        AdapterId, BlasId, BufferId, CommandEncoderId, DeviceId, QueueId, SurfaceId, TextureId,
10        TextureViewId, TlasId,
11    },
12    lock::RankData,
13    resource::RawResourceAccess,
14    snatch::SnatchGuard,
15};
16
17/// A guard which holds alive a wgpu-core resource and dereferences to the Hal type.
18struct SimpleResourceGuard<Resource, HalType> {
19    _guard: Resource,
20    ptr: *const HalType,
21}
22
23impl<Resource, HalType> SimpleResourceGuard<Resource, HalType> {
24    /// Creates a new guard from a resource, using a callback to derive the Hal type.
25    pub fn new<C>(guard: Resource, callback: C) -> Option<Self>
26    where
27        C: Fn(&Resource) -> Option<&HalType>,
28    {
29        // Derive the hal type from the resource and coerce it to a pointer.
30        let ptr: *const HalType = callback(&guard)?;
31
32        Some(Self { _guard: guard, ptr })
33    }
34}
35
36impl<Resource, HalType> Deref for SimpleResourceGuard<Resource, HalType> {
37    type Target = HalType;
38
39    fn deref(&self) -> &Self::Target {
40        // SAFETY: The pointer is guaranteed to be valid as the original resource is
41        // still alive and this guard cannot be used with snatchable resources.
42        unsafe { &*self.ptr }
43    }
44}
45
46unsafe impl<Resource, HalType> Send for SimpleResourceGuard<Resource, HalType>
47where
48    Resource: Send,
49    HalType: Send,
50{
51}
52unsafe impl<Resource, HalType> Sync for SimpleResourceGuard<Resource, HalType>
53where
54    Resource: Sync,
55    HalType: Sync,
56{
57}
58
59/// A guard which holds alive a snatchable wgpu-core resource and dereferences to the Hal type.
60struct SnatchableResourceGuard<Resource, HalType>
61where
62    Resource: RawResourceAccess,
63{
64    resource: Arc<Resource>,
65    snatch_lock_rank_data: ManuallyDrop<RankData>,
66    ptr: *const HalType,
67}
68
69impl<Resource, HalType> SnatchableResourceGuard<Resource, HalType>
70where
71    Resource: RawResourceAccess,
72    HalType: 'static,
73{
74    /// Creates a new guard from a snatchable resource.
75    ///
76    /// Returns `None` if:
77    /// - The resource is not of the expected Hal type.
78    /// - The resource has been destroyed.
79    pub fn new(resource: Arc<Resource>) -> Option<Self> {
80        // Grab the snatchable lock.
81        let snatch_guard = resource.device().snatchable_lock.read();
82
83        // Get the raw resource and downcast it to the expected Hal type.
84        let underlying = resource
85            .raw(&snatch_guard)?
86            .as_any()
87            .downcast_ref::<HalType>()?;
88
89        // Cast the raw resource to a pointer to get rid of the lifetime
90        // connecting us to the snatch guard.
91        let ptr: *const HalType = underlying;
92
93        // SAFETY: At this point all panicking or divergance has already happened,
94        // so we can safely forget the snatch guard without causing the lock to be left open.
95        let snatch_lock_rank_data = SnatchGuard::forget(snatch_guard);
96
97        // SAFETY: We only construct this guard while the snatchable lock is held,
98        // as the `drop` implementation of this guard will unsafely release the lock.
99        Some(Self {
100            resource,
101            snatch_lock_rank_data: ManuallyDrop::new(snatch_lock_rank_data),
102            ptr,
103        })
104    }
105}
106
107impl<Resource, HalType> Deref for SnatchableResourceGuard<Resource, HalType>
108where
109    Resource: RawResourceAccess,
110{
111    type Target = HalType;
112
113    fn deref(&self) -> &Self::Target {
114        // SAFETY: The pointer is guaranteed to be valid as the original resource is
115        // still alive and the snatchable lock is still being held due to the forgotten
116        // snatch guard.
117        unsafe { &*self.ptr }
118    }
119}
120
121impl<Resource, HalType> Drop for SnatchableResourceGuard<Resource, HalType>
122where
123    Resource: RawResourceAccess,
124{
125    fn drop(&mut self) {
126        // SAFETY:
127        // - We are not going to access the rank data anymore.
128        let data = unsafe { ManuallyDrop::take(&mut self.snatch_lock_rank_data) };
129
130        // SAFETY:
131        // - The pointer is no longer going to be accessed.
132        // - The snatchable lock is being held because this type was not created
133        //   until after the snatchable lock was forgotten.
134        unsafe {
135            self.resource
136                .device()
137                .snatchable_lock
138                .force_unlock_read(data)
139        };
140    }
141}
142
143unsafe impl<Resource, HalType> Send for SnatchableResourceGuard<Resource, HalType>
144where
145    Resource: RawResourceAccess + Send,
146    HalType: Send,
147{
148}
149unsafe impl<Resource, HalType> Sync for SnatchableResourceGuard<Resource, HalType>
150where
151    Resource: RawResourceAccess + Sync,
152    HalType: Sync,
153{
154}
155
156impl crate::resource::Buffer {
157    /// # Safety
158    ///
159    /// - The raw buffer handle must not be manually destroyed
160    pub unsafe fn as_hal<A: hal::Api>(self: Arc<Self>) -> Option<impl Deref<Target = A::Buffer>> {
161        profiling::scope!("Buffer::as_hal");
162
163        SnatchableResourceGuard::new(self)
164    }
165}
166
167impl crate::resource::Texture {
168    /// # Safety
169    ///
170    /// - The raw texture handle must not be manually destroyed
171    pub unsafe fn as_hal<A: hal::Api>(self: Arc<Self>) -> Option<impl Deref<Target = A::Texture>> {
172        profiling::scope!("Texture::as_hal");
173
174        SnatchableResourceGuard::new(self)
175    }
176}
177
178impl crate::resource::TextureView {
179    /// # Safety
180    ///
181    /// - The raw texture view handle must not be manually destroyed
182    pub unsafe fn as_hal<A: hal::Api>(
183        self: Arc<Self>,
184    ) -> Option<impl Deref<Target = A::TextureView>> {
185        profiling::scope!("TextureView::as_hal");
186
187        SnatchableResourceGuard::new(self)
188    }
189}
190
191impl crate::instance::Adapter {
192    /// # Safety
193    ///
194    /// - The raw adapter handle must not be manually destroyed
195    pub unsafe fn as_hal<A: hal::Api>(self: Arc<Self>) -> Option<impl Deref<Target = A::Adapter>> {
196        profiling::scope!("Adapter::as_hal");
197
198        SimpleResourceGuard::new(self, move |adapter| {
199            adapter.raw.adapter.as_any().downcast_ref()
200        })
201    }
202}
203
204impl crate::device::Device {
205    /// # Safety
206    ///
207    /// - The raw device handle must not be manually destroyed
208    pub unsafe fn as_hal<A: hal::Api>(self: Arc<Self>) -> Option<impl Deref<Target = A::Device>> {
209        profiling::scope!("Device::as_hal");
210
211        SimpleResourceGuard::new(self, move |device| device.raw().as_any().downcast_ref())
212    }
213
214    /// # Safety
215    ///
216    /// - The raw fence handle must not be manually destroyed
217    pub unsafe fn fence_as_hal<A: hal::Api>(
218        self: Arc<Self>,
219    ) -> Option<impl Deref<Target = A::Fence>> {
220        profiling::scope!("Device::fence_as_hal");
221
222        SimpleResourceGuard::new(self, move |device| device.fence.as_any().downcast_ref())
223    }
224}
225
226impl crate::instance::Surface {
227    /// # Safety
228    ///
229    /// - The raw surface handle must not be manually destroyed
230    pub unsafe fn as_hal<A: hal::Api>(self: Arc<Self>) -> Option<impl Deref<Target = A::Surface>> {
231        profiling::scope!("Surface::as_hal");
232
233        SimpleResourceGuard::new(self, move |surface| {
234            surface.raw(A::VARIANT)?.as_any().downcast_ref()
235        })
236    }
237}
238
239impl crate::command::CommandEncoder {
240    /// Encode commands using the raw HAL command encoder.
241    ///
242    /// # Panics
243    ///
244    /// If the command encoder has already been used with the wgpu encoding API.
245    ///
246    /// # Safety
247    ///
248    /// - The raw command encoder handle must not be manually destroyed
249    pub unsafe fn as_hal_mut<A: hal::Api, F: FnOnce(Option<&mut A::CommandEncoder>) -> R, R>(
250        self: &Arc<Self>,
251        hal_command_encoder_callback: F,
252    ) -> R {
253        profiling::scope!("CommandEncoder::as_hal");
254
255        let mut cmd_buf_data = self.data.lock();
256        cmd_buf_data.record_as_hal_mut(|opt_cmd_buf| -> R {
257            hal_command_encoder_callback(opt_cmd_buf.and_then(|cmd_buf| {
258                cmd_buf
259                    .encoder
260                    .open()
261                    .ok()
262                    .and_then(|encoder| encoder.as_any_mut().downcast_mut())
263            }))
264        })
265    }
266}
267
268impl crate::device::queue::Queue {
269    /// # Safety
270    ///
271    /// - The raw queue handle must not be manually destroyed
272    pub unsafe fn as_hal<A: hal::Api>(self: Arc<Self>) -> Option<impl Deref<Target = A::Queue>> {
273        profiling::scope!("Queue::as_hal");
274
275        SimpleResourceGuard::new(self, move |queue| queue.raw().as_any().downcast_ref())
276    }
277}
278
279impl crate::resource::Blas {
280    /// # Safety
281    ///
282    /// - The raw blas handle must not be manually destroyed
283    pub unsafe fn as_hal<A: hal::Api>(
284        self: Arc<Self>,
285    ) -> Option<impl Deref<Target = A::AccelerationStructure>> {
286        profiling::scope!("Blas::as_hal");
287
288        SnatchableResourceGuard::new(self)
289    }
290}
291
292impl crate::resource::Tlas {
293    /// # Safety
294    ///
295    /// - The raw tlas handle must not be manually destroyed
296    pub unsafe fn as_hal<A: hal::Api>(
297        self: Arc<Self>,
298    ) -> Option<impl Deref<Target = A::AccelerationStructure>> {
299        profiling::scope!("Tlas::as_hal");
300
301        SnatchableResourceGuard::new(self)
302    }
303}
304
305impl Global {
306    /// # Safety
307    ///
308    /// - The raw buffer handle must not be manually destroyed
309    pub unsafe fn buffer_as_hal<A: hal::Api>(
310        &self,
311        id: BufferId,
312    ) -> Option<impl Deref<Target = A::Buffer>> {
313        let hub = &self.hub;
314
315        let buffer = hub.buffers.get(id);
316
317        unsafe { buffer.as_hal::<A>() }
318    }
319
320    /// # Safety
321    ///
322    /// - The raw texture handle must not be manually destroyed
323    pub unsafe fn texture_as_hal<A: hal::Api>(
324        &self,
325        id: TextureId,
326    ) -> Option<impl Deref<Target = A::Texture>> {
327        let hub = &self.hub;
328
329        let texture = hub.textures.get(id);
330
331        unsafe { texture.as_hal::<A>() }
332    }
333
334    /// # Safety
335    ///
336    /// - The raw texture view handle must not be manually destroyed
337    pub unsafe fn texture_view_as_hal<A: hal::Api>(
338        &self,
339        id: TextureViewId,
340    ) -> Option<impl Deref<Target = A::TextureView>> {
341        let hub = &self.hub;
342
343        let view = hub.texture_views.get(id);
344
345        unsafe { view.as_hal::<A>() }
346    }
347
348    /// # Safety
349    ///
350    /// - The raw adapter handle must not be manually destroyed
351    pub unsafe fn adapter_as_hal<A: hal::Api>(
352        &self,
353        id: AdapterId,
354    ) -> Option<impl Deref<Target = A::Adapter>> {
355        let hub = &self.hub;
356        let adapter = hub.adapters.get(id);
357
358        unsafe { adapter.as_hal::<A>() }
359    }
360
361    /// # Safety
362    ///
363    /// - The raw device handle must not be manually destroyed
364    pub unsafe fn device_as_hal<A: hal::Api>(
365        &self,
366        id: DeviceId,
367    ) -> Option<impl Deref<Target = A::Device>> {
368        let device = self.hub.devices.get(id);
369
370        unsafe { device.as_hal::<A>() }
371    }
372
373    /// # Safety
374    ///
375    /// - The raw fence handle must not be manually destroyed
376    pub unsafe fn device_fence_as_hal<A: hal::Api>(
377        &self,
378        id: DeviceId,
379    ) -> Option<impl Deref<Target = A::Fence>> {
380        let device = self.hub.devices.get(id);
381
382        unsafe { device.fence_as_hal::<A>() }
383    }
384
385    /// # Safety
386    ///
387    /// - The raw surface handle must not be manually destroyed
388    pub unsafe fn surface_as_hal<A: hal::Api>(
389        &self,
390        id: SurfaceId,
391    ) -> Option<impl Deref<Target = A::Surface>> {
392        let surface = self.surfaces.get(id);
393
394        unsafe { surface.as_hal::<A>() }
395    }
396
397    /// Encode commands using the raw HAL command encoder.
398    ///
399    /// # Panics
400    ///
401    /// If the command encoder has already been used with the wgpu encoding API.
402    ///
403    /// # Safety
404    ///
405    /// - The raw command encoder handle must not be manually destroyed
406    pub unsafe fn command_encoder_as_hal_mut<
407        A: hal::Api,
408        F: FnOnce(Option<&mut A::CommandEncoder>) -> R,
409        R,
410    >(
411        &self,
412        id: CommandEncoderId,
413        hal_command_encoder_callback: F,
414    ) -> R {
415        let hub = &self.hub;
416
417        let cmd_enc = hub.command_encoders.get(id);
418        unsafe { cmd_enc.as_hal_mut::<A, F, R>(hal_command_encoder_callback) }
419    }
420
421    /// # Safety
422    ///
423    /// - The raw queue handle must not be manually destroyed
424    pub unsafe fn queue_as_hal<A: hal::Api>(
425        &self,
426        id: QueueId,
427    ) -> Option<impl Deref<Target = A::Queue>> {
428        let queue = self.hub.queues.get(id);
429
430        unsafe { queue.as_hal::<A>() }
431    }
432
433    /// # Safety
434    ///
435    /// - The raw blas handle must not be manually destroyed
436    pub unsafe fn blas_as_hal<A: hal::Api>(
437        &self,
438        id: BlasId,
439    ) -> Option<impl Deref<Target = A::AccelerationStructure>> {
440        profiling::scope!("Blas::as_hal");
441
442        let hub = &self.hub;
443
444        let blas = hub.blas_s.get(id);
445
446        unsafe { blas.as_hal::<A>() }
447    }
448
449    /// # Safety
450    ///
451    /// - The raw tlas handle must not be manually destroyed
452    pub unsafe fn tlas_as_hal<A: hal::Api>(
453        &self,
454        id: TlasId,
455    ) -> Option<impl Deref<Target = A::AccelerationStructure>> {
456        profiling::scope!("Tlas::as_hal");
457
458        let hub = &self.hub;
459
460        let tlas = hub.tlas_s.get(id);
461
462        unsafe { tlas.as_hal::<A>() }
463    }
464}