use {
gfx_hal::Backend,
std::{any::Any, marker::PhantomData, ops::Deref},
};
#[cfg(not(feature = "no-slow-safety-checks"))]
fn new_instance_id() -> InstanceId {
static INSTANCE_ID: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
let id = INSTANCE_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
assert!(
id < usize::max_value() && (id as u32) < u32::max_value(),
"Too many instances created"
);
if id == 0 {
log::info!("Slow safety checks are enabled! You can disable them in production by enabling the 'no-slow-safety-checks' feature!");
}
InstanceId { id: id as u32 }
}
#[cfg(not(feature = "no-slow-safety-checks"))]
fn new_device_id(instance: InstanceId) -> DeviceId {
static DEVICE_ID: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
let id = DEVICE_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
assert!(
id < usize::max_value() && (id as u32) < u32::max_value(),
"Too many devices created"
);
DeviceId {
id: id as u32,
instance,
}
}
#[cfg(feature = "no-slow-safety-checks")]
fn new_instance_id() -> InstanceId {
InstanceId {}
}
#[cfg(feature = "no-slow-safety-checks")]
fn new_device_id(instance: InstanceId) -> DeviceId {
DeviceId { instance }
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct InstanceId {
#[cfg(not(feature = "no-slow-safety-checks"))]
pub id: u32,
}
impl InstanceId {
pub fn new() -> Self {
new_instance_id()
}
}
pub struct Instance<B: Backend> {
instance: Box<dyn Any + Send + Sync>,
id: InstanceId,
marker: PhantomData<B>,
}
impl<B> Instance<B>
where
B: Backend,
{
pub fn new(instance: impl gfx_hal::Instance) -> Self {
Instance {
id: new_instance_id(),
instance: Box::new(instance),
marker: PhantomData,
}
}
}
impl<B> Instance<B>
where
B: Backend,
{
pub fn id(&self) -> InstanceId {
self.id
}
pub fn raw(&self) -> &dyn Any {
&*self.instance
}
pub fn raw_mut(&mut self) -> &mut dyn Any {
&mut *self.instance
}
pub fn raw_typed<T>(&self) -> Option<&T>
where
T: gfx_hal::Instance,
{
if std::any::TypeId::of::<T::Backend>() == std::any::TypeId::of::<B>() {
Some(
self.instance
.downcast_ref::<T>()
.expect("Bad instance wrapper"),
)
} else {
None
}
}
pub fn raw_typed_mut<T>(&mut self) -> Option<&mut T>
where
T: gfx_hal::Instance,
{
if std::any::TypeId::of::<T::Backend>() == std::any::TypeId::of::<B>() {
Some(
self.instance
.downcast_mut::<T>()
.expect("Bad instance wrapper"),
)
} else {
None
}
}
}
impl<B> std::fmt::Debug for Instance<B>
where
B: Backend,
{
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(fmt, "Instance {:?}", self.id)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct DeviceId {
#[cfg(not(feature = "no-slow-safety-checks"))]
pub id: u32,
pub instance: InstanceId,
}
impl DeviceId {
pub fn new(instance: InstanceId) -> Self {
new_device_id(instance)
}
}
#[derive(Debug)]
pub struct Device<B: Backend> {
device: B::Device,
id: DeviceId,
}
impl<B> Device<B>
where
B: Backend,
{
pub fn new(device: B::Device, instance: &Instance<B>) -> Self {
Device {
id: new_device_id(instance.id),
device,
}
}
pub fn from_raw(device: B::Device, id: DeviceId) -> Self {
Device { id, device }
}
pub fn id(&self) -> DeviceId {
self.id
}
pub fn raw(&self) -> &B::Device {
&self.device
}
pub fn raw_mut(&mut self) -> &mut B::Device {
&mut self.device
}
}
impl<B> Deref for Device<B>
where
B: Backend,
{
type Target = B::Device;
fn deref(&self) -> &B::Device {
self.raw()
}
}
#[macro_export]
macro_rules! device_owned {
($type:ident<B $(, $arg:ident $(: $(?$sized:ident)? $($bound:path)?)?)*> @ $getter:expr) => {
#[allow(unused_qualifications)]
impl<B $(, $arg)*> $type<B $(, $arg)*>
where
B: gfx_hal::Backend,
$(
$($arg: $(?$sized)* $($bound)?,)?
)*
{
pub fn device_id(&self) -> $crate::DeviceId {
($getter)(self)
}
pub fn assert_device_owner(&self, device: &$crate::Device<B>) {
assert_eq!(self.device_id(), device.id(), "Resource is not owned by specified device");
}
pub fn instance_id(&self) -> $crate::InstanceId {
self.device_id().instance
}
pub fn assert_instance_owner(&self, instance: &$crate::Instance<B>) {
assert_eq!(self.instance_id(), instance.id(), "Resource is not owned by specified instance");
}
}
};
($type:ident<B $(, $arg:ident $(: $(?$sized:ident)? $($bound:path)?)?)*>) => {
device_owned!($type<B $(, $arg $(: $(?$sized)? $($bound)?)?)*> @ (|s: &Self| {s.device}));
};
}
#[macro_export]
macro_rules! instance_owned {
($type:ident<B $(, $arg:ident $(: $(?$sized:ident)? $($bound:path)?)?)*>) => {
#[allow(unused_qualifications)]
impl<B $(, $arg)*> $type<B $(, $arg)*>
where
B: gfx_hal::Backend,
$(
$($arg: $(?$sized)? $($bound)?,)?
)*
{
pub fn instance_id(&self) -> $crate::InstanceId {
self.instance
}
pub fn assert_instance_owner(&self, instance: &Instance<B>) {
assert_eq!(self.instance_id(), instance.id());
}
}
};
}