1use {
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 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#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
57pub struct InstanceId {
58 #[cfg(not(feature = "no-slow-safety-checks"))]
60 pub id: u32,
61}
62
63impl InstanceId {
64 pub fn new() -> Self {
66 new_instance_id()
67 }
68}
69
70pub 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 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 pub fn id(&self) -> InstanceId {
97 self.id
98 }
99
100 pub fn raw(&self) -> &dyn Any {
102 &*self.instance
103 }
104
105 pub fn raw_mut(&mut self) -> &mut dyn Any {
107 &mut *self.instance
108 }
109
110 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 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#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
154pub struct DeviceId {
155 #[cfg(not(feature = "no-slow-safety-checks"))]
157 pub id: u32,
158
159 pub instance: InstanceId,
161}
162
163impl DeviceId {
164 pub fn new(instance: InstanceId) -> Self {
166 new_device_id(instance)
167 }
168}
169
170#[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 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 pub fn from_raw(device: B::Device, id: DeviceId) -> Self {
191 Device { id, device }
192 }
193
194 pub fn id(&self) -> DeviceId {
196 self.id
197 }
198
199 pub fn raw(&self) -> &B::Device {
201 &self.device
202 }
203
204 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#[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 pub fn device_id(&self) -> $crate::DeviceId {
235 ($getter)(self)
236 }
237
238 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 pub fn instance_id(&self) -> $crate::InstanceId {
245 self.device_id().instance
246 }
247
248 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#[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 pub fn instance_id(&self) -> $crate::InstanceId {
274 self.instance
275 }
276
277 pub fn assert_instance_owner(&self, instance: &Instance<B>) {
279 assert_eq!(self.instance_id(), instance.id());
280 }
281 }
282 };
283}