rendy_core/
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    crate::hal::Backend,
8    std::ops::{Deref, DerefMut},
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: B::Instance,
73    id: InstanceId,
74}
75
76impl<B> Instance<B>
77where
78    B: Backend,
79{
80    /// Wrap instance value.
81    pub fn new(instance: B::Instance) -> Self {
82        Instance {
83            id: new_instance_id(),
84            instance,
85        }
86    }
87
88    /// Wrap instance value.
89    pub unsafe fn from_raw(instance: B::Instance, id: InstanceId) -> Self {
90        Instance { id, instance }
91    }
92
93    /// Get instance id.
94    pub fn id(&self) -> InstanceId {
95        self.id
96    }
97
98    /// Get reference to raw instance.
99    pub fn raw(&self) -> &B::Instance {
100        &self.instance
101    }
102
103    /// Get mutable reference to raw instance.
104    pub fn raw_mut(&mut self) -> &mut B::Instance {
105        &mut self.instance
106    }
107
108    /// Get inner raw instance
109    pub fn into_raw(self) -> B::Instance {
110        self.instance
111    }
112}
113
114impl<B> Deref for Instance<B>
115where
116    B: Backend,
117{
118    type Target = B::Instance;
119
120    fn deref(&self) -> &B::Instance {
121        self.raw()
122    }
123}
124
125impl<B> DerefMut for Instance<B>
126where
127    B: Backend,
128{
129    fn deref_mut(&mut self) -> &mut B::Instance {
130        self.raw_mut()
131    }
132}
133
134impl<B> std::fmt::Debug for Instance<B>
135where
136    B: Backend,
137{
138    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
139        write!(fmt, "Instance {:?}", self.id)
140    }
141}
142
143/// Id of the instance.
144#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
145pub struct DeviceId {
146    /// Unique id.
147    #[cfg(not(feature = "no-slow-safety-checks"))]
148    pub id: u32,
149
150    /// Instance id.
151    pub instance: InstanceId,
152}
153
154impl DeviceId {
155    /// Create new device id.
156    pub fn new(instance: InstanceId) -> Self {
157        new_device_id(instance)
158    }
159}
160
161/// Raw device wrapper with id.
162#[derive(Debug)]
163pub struct Device<B: Backend> {
164    device: B::Device,
165    id: DeviceId,
166}
167
168impl<B> Device<B>
169where
170    B: Backend,
171{
172    /// Wrap device value.
173    pub fn new(device: B::Device, instance: &Instance<B>) -> Self {
174        Device {
175            id: new_device_id(instance.id),
176            device,
177        }
178    }
179
180    /// Wrap device value.
181    pub fn from_raw(device: B::Device, id: DeviceId) -> Self {
182        Device { id, device }
183    }
184
185    /// Get device id.
186    pub fn id(&self) -> DeviceId {
187        self.id
188    }
189
190    /// Get reference to raw device.
191    pub fn raw(&self) -> &B::Device {
192        &self.device
193    }
194
195    /// Get mutable reference to raw device.
196    pub fn raw_mut(&mut self) -> &mut B::Device {
197        &mut self.device
198    }
199
200    /// Get inner raw device
201    pub fn into_raw(self) -> B::Device {
202        self.device
203    }
204}
205
206impl<B> Deref for Device<B>
207where
208    B: Backend,
209{
210    type Target = B::Device;
211
212    fn deref(&self) -> &B::Device {
213        self.raw()
214    }
215}
216
217/// Implement ownership checking for value with `device: DeviceId` field.
218#[macro_export]
219macro_rules! device_owned {
220    ($type:ident<B $(, $arg:ident $(: $(?$sized:ident)? $($bound:path)?)?)*> @ $getter:expr) => {
221        #[allow(unused_qualifications)]
222        impl<B $(, $arg)*> $type<B $(, $arg)*>
223        where
224            B: $crate::hal::Backend,
225            $(
226                $($arg: $(?$sized)* $($bound)?,)?
227            )*
228        {
229            /// Get owned id.
230            pub fn device_id(&self) -> $crate::DeviceId {
231                ($getter)(self)
232            }
233
234            /// Assert specified device is owner.
235            pub fn assert_device_owner(&self, device: &$crate::Device<B>) {
236                assert_eq!(self.device_id(), device.id(), "Resource is not owned by specified device");
237            }
238
239            /// Get owned id.
240            pub fn instance_id(&self) -> $crate::InstanceId {
241                self.device_id().instance
242            }
243
244            /// Assert specified instance is owner.
245            pub fn assert_instance_owner(&self, instance: &$crate::Instance<B>) {
246                assert_eq!(self.instance_id(), instance.id(), "Resource is not owned by specified instance");
247            }
248        }
249    };
250
251    ($type:ident<B $(, $arg:ident $(: $(?$sized:ident)? $($bound:path)?)?)*>) => {
252        device_owned!($type<B $(, $arg $(: $(?$sized)? $($bound)?)?)*> @ (|s: &Self| {s.device}));
253    };
254}
255
256/// Implement ownership checking for value with `instance: InstanceId` field.
257#[macro_export]
258macro_rules! instance_owned {
259    ($type:ident<B $(, $arg:ident $(: $(?$sized:ident)? $($bound:path)?)?)*>) => {
260        #[allow(unused_qualifications)]
261        impl<B $(, $arg)*> $type<B $(, $arg)*>
262        where
263            B: $crate::hal::Backend,
264            $(
265                $($arg: $(?$sized)? $($bound)?,)?
266            )*
267        {
268            /// Get owned id.
269            pub fn instance_id(&self) -> $crate::InstanceId {
270                self.instance
271            }
272
273            /// Assert specified instance is owner.
274            pub fn assert_instance_owner(&self, instance: &Instance<B>) {
275                assert_eq!(self.instance_id(), instance.id());
276            }
277        }
278    };
279}