wgpu_core/device/any_device.rs
1use wgt::Backend;
2
3use super::Device;
4/// The `AnyDevice` type: a pointer to a `Device<A>` for any backend `A`.
5use crate::hal_api::HalApi;
6
7use std::fmt;
8use std::mem::ManuallyDrop;
9use std::ptr::NonNull;
10use std::sync::Arc;
11
12struct AnyDeviceVtable {
13 // We oppurtunistically store the backend here, since we now it will be used
14 // with backend selection and it can be stored in static memory.
15 backend: Backend,
16 // Drop glue which knows how to drop the stored data.
17 drop: unsafe fn(*mut ()),
18}
19
20/// A pointer to a `Device<A>`, for any backend `A`.
21///
22/// Any `AnyDevice` is just like an `Arc<Device<A>>`, except that the `A` type
23/// parameter is erased. To access the `Device`, you must downcast to a
24/// particular backend with the \[`downcast_ref`\] or \[`downcast_clone`\]
25/// methods.
26pub struct AnyDevice {
27 data: NonNull<()>,
28 vtable: &'static AnyDeviceVtable,
29}
30
31impl AnyDevice {
32 /// Return an `AnyDevice` that holds an owning `Arc` pointer to `device`.
33 pub fn new<A: HalApi>(device: Arc<Device<A>>) -> AnyDevice {
34 unsafe fn drop_glue<A: HalApi>(ptr: *mut ()) {
35 // Drop the arc this instance is holding.
36 unsafe {
37 _ = Arc::from_raw(ptr.cast::<A::Device>());
38 }
39 }
40
41 // SAFETY: The pointer returned by Arc::into_raw is guaranteed to be
42 // non-null.
43 let data = unsafe { NonNull::new_unchecked(Arc::into_raw(device).cast_mut()) };
44
45 AnyDevice {
46 data: data.cast(),
47 vtable: &AnyDeviceVtable {
48 backend: A::VARIANT,
49 drop: drop_glue::<A>,
50 },
51 }
52 }
53
54 /// If `self` is an `Arc<Device<A>>`, return a reference to the
55 /// device.
56 pub fn downcast_ref<A: HalApi>(&self) -> Option<&Device<A>> {
57 if self.vtable.backend != A::VARIANT {
58 return None;
59 }
60
61 // SAFETY: We just checked the instance above implicitly by the backend
62 // that it was statically constructed through.
63 Some(unsafe { &*(self.data.as_ptr().cast::<Device<A>>()) })
64 }
65
66 /// If `self` is an `Arc<Device<A>>`, return a clone of that.
67 pub fn downcast_clone<A: HalApi>(&self) -> Option<Arc<Device<A>>> {
68 if self.vtable.backend != A::VARIANT {
69 return None;
70 }
71
72 // We need to prevent the destructor of the arc from running, since it
73 // refers to the instance held by this object. Dropping it would
74 // invalidate this object.
75 //
76 // SAFETY: We just checked the instance above implicitly by the backend
77 // that it was statically constructed through.
78 let this =
79 ManuallyDrop::new(unsafe { Arc::from_raw(self.data.as_ptr().cast::<Device<A>>()) });
80
81 // Cloning it increases the reference count, and we return a new arc
82 // instance.
83 Some((*this).clone())
84 }
85}
86
87impl Drop for AnyDevice {
88 fn drop(&mut self) {
89 unsafe { (self.vtable.drop)(self.data.as_ptr()) }
90 }
91}
92
93impl fmt::Debug for AnyDevice {
94 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95 write!(f, "AnyDevice<{}>", self.vtable.backend)
96 }
97}
98
99#[cfg(send_sync)]
100unsafe impl Send for AnyDevice {}
101#[cfg(send_sync)]
102unsafe impl Sync for AnyDevice {}