rendy_util/
wrap.rs

1//! These are Vulkan Instance and Device wrappers that contain a unique ID
2//! This allows checking if any other Vulkan resource belongs to a specific
3//! Instance or Device. This is required to ensure we are making a safe
4//! call.
5
6use {
7    gfx_hal::Backend,
8    std::{any::Any, marker::PhantomData, ops::Deref},
9};
10
11#[cfg(not(feature = "no-slow-safety-checks"))]
12fn new_instance_id() -> InstanceId {
13    static INSTANCE_ID: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
14
15    let id = INSTANCE_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
16    assert!(
17        id < usize::max_value() && (id as u32) < u32::max_value(),
18        "Too many instances created"
19    );
20
21    if id == 0 {
22        // Warn once.
23        log::info!("Slow safety checks are enabled! You can disable them in production by enabling the 'no-slow-safety-checks' feature!");
24    }
25
26    InstanceId { id: id as u32 }
27}
28
29#[cfg(not(feature = "no-slow-safety-checks"))]
30fn new_device_id(instance: InstanceId) -> DeviceId {
31    static DEVICE_ID: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
32
33    let id = DEVICE_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
34    assert!(
35        id < usize::max_value() && (id as u32) < u32::max_value(),
36        "Too many devices created"
37    );
38
39    DeviceId {
40        id: id as u32,
41        instance,
42    }
43}
44
45#[cfg(feature = "no-slow-safety-checks")]
46fn new_instance_id() -> InstanceId {
47    InstanceId {}
48}
49
50#[cfg(feature = "no-slow-safety-checks")]
51fn new_device_id(instance: InstanceId) -> DeviceId {
52    DeviceId { instance }
53}
54
55/// Id of the hal instance.
56#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
57pub struct InstanceId {
58    /// Unique id.
59    #[cfg(not(feature = "no-slow-safety-checks"))]
60    pub id: u32,
61}
62
63impl InstanceId {
64    /// Create new instance id.
65    pub fn new() -> Self {
66        new_instance_id()
67    }
68}
69
70/// Raw instance wrapper with id.
71pub struct Instance<B: Backend> {
72    instance: Box<dyn Any + Send + Sync>,
73    id: InstanceId,
74    marker: PhantomData<B>,
75}
76
77impl<B> Instance<B>
78where
79    B: Backend,
80{
81    /// Wrap instance value.
82    pub fn new(instance: impl gfx_hal::Instance) -> Self {
83        Instance {
84            id: new_instance_id(),
85            instance: Box::new(instance),
86            marker: PhantomData,
87        }
88    }
89}
90
91impl<B> Instance<B>
92where
93    B: Backend,
94{
95    /// Get instance id.
96    pub fn id(&self) -> InstanceId {
97        self.id
98    }
99
100    /// Get reference to raw instance.
101    pub fn raw(&self) -> &dyn Any {
102        &*self.instance
103    }
104
105    /// Get mutable reference to raw instance.
106    pub fn raw_mut(&mut self) -> &mut dyn Any {
107        &mut *self.instance
108    }
109
110    /// Get reference to typed raw instance.
111    pub fn raw_typed<T>(&self) -> Option<&T>
112    where
113        T: gfx_hal::Instance,
114    {
115        if std::any::TypeId::of::<T::Backend>() == std::any::TypeId::of::<B>() {
116            Some(
117                self.instance
118                    .downcast_ref::<T>()
119                    .expect("Bad instance wrapper"),
120            )
121        } else {
122            None
123        }
124    }
125
126    /// Get mutable reference to typed raw instance.
127    pub fn raw_typed_mut<T>(&mut self) -> Option<&mut T>
128    where
129        T: gfx_hal::Instance,
130    {
131        if std::any::TypeId::of::<T::Backend>() == std::any::TypeId::of::<B>() {
132            Some(
133                self.instance
134                    .downcast_mut::<T>()
135                    .expect("Bad instance wrapper"),
136            )
137        } else {
138            None
139        }
140    }
141}
142
143impl<B> std::fmt::Debug for Instance<B>
144where
145    B: Backend,
146{
147    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
148        write!(fmt, "Instance {:?}", self.id)
149    }
150}
151
152/// Id of the instance.
153#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
154pub struct DeviceId {
155    /// Unique id.
156    #[cfg(not(feature = "no-slow-safety-checks"))]
157    pub id: u32,
158
159    /// Instance id.
160    pub instance: InstanceId,
161}
162
163impl DeviceId {
164    /// Create new device id.
165    pub fn new(instance: InstanceId) -> Self {
166        new_device_id(instance)
167    }
168}
169
170/// Raw device wrapper with id.
171#[derive(Debug)]
172pub struct Device<B: Backend> {
173    device: B::Device,
174    id: DeviceId,
175}
176
177impl<B> Device<B>
178where
179    B: Backend,
180{
181    /// Wrap device value.
182    pub fn new(device: B::Device, instance: &Instance<B>) -> Self {
183        Device {
184            id: new_device_id(instance.id),
185            device,
186        }
187    }
188
189    /// Wrap device value.
190    pub fn from_raw(device: B::Device, id: DeviceId) -> Self {
191        Device { id, device }
192    }
193
194    /// Get device id.
195    pub fn id(&self) -> DeviceId {
196        self.id
197    }
198
199    /// Get reference to raw device.
200    pub fn raw(&self) -> &B::Device {
201        &self.device
202    }
203
204    /// Get mutable reference to raw device.
205    pub fn raw_mut(&mut self) -> &mut B::Device {
206        &mut self.device
207    }
208}
209
210impl<B> Deref for Device<B>
211where
212    B: Backend,
213{
214    type Target = B::Device;
215
216    fn deref(&self) -> &B::Device {
217        self.raw()
218    }
219}
220
221/// Implement ownership checking for value with `device: DeviceId` field.
222#[macro_export]
223macro_rules! device_owned {
224    ($type:ident<B $(, $arg:ident $(: $(?$sized:ident)? $($bound:path)?)?)*> @ $getter:expr) => {
225        #[allow(unused_qualifications)]
226        impl<B $(, $arg)*> $type<B $(, $arg)*>
227        where
228            B: gfx_hal::Backend,
229            $(
230                $($arg: $(?$sized)* $($bound)?,)?
231            )*
232        {
233            /// Get owned id.
234            pub fn device_id(&self) -> $crate::DeviceId {
235                ($getter)(self)
236            }
237
238            /// Assert specified device is owner.
239            pub fn assert_device_owner(&self, device: &$crate::Device<B>) {
240                assert_eq!(self.device_id(), device.id(), "Resource is not owned by specified device");
241            }
242
243            /// Get owned id.
244            pub fn instance_id(&self) -> $crate::InstanceId {
245                self.device_id().instance
246            }
247
248            /// Assert specified instance is owner.
249            pub fn assert_instance_owner(&self, instance: &$crate::Instance<B>) {
250                assert_eq!(self.instance_id(), instance.id(), "Resource is not owned by specified instance");
251            }
252        }
253    };
254
255    ($type:ident<B $(, $arg:ident $(: $(?$sized:ident)? $($bound:path)?)?)*>) => {
256        device_owned!($type<B $(, $arg $(: $(?$sized)? $($bound)?)?)*> @ (|s: &Self| {s.device}));
257    };
258}
259
260/// Implement ownership checking for value with `instance: InstanceId` field.
261#[macro_export]
262macro_rules! instance_owned {
263    ($type:ident<B $(, $arg:ident $(: $(?$sized:ident)? $($bound:path)?)?)*>) => {
264        #[allow(unused_qualifications)]
265        impl<B $(, $arg)*> $type<B $(, $arg)*>
266        where
267            B: gfx_hal::Backend,
268            $(
269                $($arg: $(?$sized)? $($bound)?,)?
270            )*
271        {
272            /// Get owned id.
273            pub fn instance_id(&self) -> $crate::InstanceId {
274                self.instance
275            }
276
277            /// Assert specified instance is owner.
278            pub fn assert_instance_owner(&self, instance: &Instance<B>) {
279                assert_eq!(self.instance_id(), instance.id());
280            }
281        }
282    };
283}