macro_rules! vulkan_bitflags {
{
$(#[doc = $ty_doc:literal])*
$ty:ident
$( impl { $($impls:item)* } )?
= $ty_ffi:ident($repr:ty);
$(
$(#[doc = $flag_doc:literal])*
$flag_name:ident = $flag_name_ffi:ident,
)+
} => {
$(#[doc = $ty_doc])*
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct $ty($repr);
impl $ty {
$(
$(#[doc = $flag_doc])*
pub const $flag_name: Self = Self(ash::vk::$ty_ffi::$flag_name_ffi.as_raw());
)*
#[doc = concat!("Returns a `", stringify!($ty), "` with none of the flags set.")]
#[inline]
pub const fn empty() -> Self {
Self(0)
}
#[deprecated(since = "0.31.0", note = "use `empty` instead")]
#[doc = concat!("Returns a `", stringify!($ty), "` with none of the flags set.")]
#[inline]
pub const fn none() -> Self {
Self::empty()
}
#[doc = concat!("Returns a `", stringify!($ty), "` with all of the flags set.")]
#[inline]
pub const fn all() -> Self {
Self(Self::all_raw())
}
const fn all_raw() -> $repr {
0
$(
| ash::vk::$ty_ffi::$flag_name_ffi.as_raw()
)*
}
#[inline]
pub const fn is_empty(self) -> bool {
self.0 == 0
}
#[inline]
pub const fn intersects(self, #[allow(unused_variables)] other: Self) -> bool {
self.0 & other.0 != 0
}
#[inline]
pub const fn contains(self, #[allow(unused_variables)] other: Self) -> bool {
self.0 & other.0 == other.0
}
#[inline]
pub const fn union(self, #[allow(unused_variables)] other: Self) -> Self {
Self(self.0 | other.0)
}
#[inline]
pub const fn intersection(self, #[allow(unused_variables)] other: Self) -> Self {
Self(self.0 & other.0)
}
#[inline]
pub const fn difference(self, #[allow(unused_variables)] other: Self) -> Self {
Self(self.0 & !other.0)
}
#[inline]
pub const fn symmetric_difference(self, #[allow(unused_variables)] other: Self) -> Self {
Self(self.0 ^ other.0)
}
#[inline]
pub const fn complement(self) -> Self {
Self(!self.0 & Self::all_raw())
}
$( $($impls)* )?
}
impl Default for $ty {
#[inline]
fn default() -> Self {
Self::empty()
}
}
impl std::fmt::Debug for $ty {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
#[allow(unused_mut)]
let mut written = false;
$(
if self.intersects(Self::$flag_name) {
if written {
write!(f, " | ")?;
}
write!(f, stringify!($flag_name))?;
written = true;
}
)*
if !written {
write!(f, "empty()")?;
}
Ok(())
}
}
impl From<$ty> for ash::vk::$ty_ffi {
#[inline]
fn from(val: $ty) -> Self {
ash::vk::$ty_ffi::from_raw(val.0)
}
}
impl From<ash::vk::$ty_ffi> for $ty {
#[inline]
fn from(val: ash::vk::$ty_ffi) -> Self {
Self(val.as_raw() & Self::all_raw())
}
}
impl std::ops::BitAnd for $ty {
type Output = Self;
#[inline]
fn bitand(self, rhs: Self) -> Self {
self.intersection(rhs)
}
}
impl std::ops::BitAndAssign for $ty {
#[inline]
fn bitand_assign(&mut self, rhs: Self) {
*self = self.intersection(rhs);
}
}
impl std::ops::BitOr for $ty {
type Output = Self;
#[inline]
fn bitor(self, rhs: Self) -> Self {
self.union(rhs)
}
}
impl std::ops::BitOrAssign for $ty {
#[inline]
fn bitor_assign(&mut self, rhs: Self) {
*self = self.union(rhs);
}
}
impl std::ops::BitXor for $ty {
type Output = Self;
#[inline]
fn bitxor(self, rhs: Self) -> Self {
self.symmetric_difference(rhs)
}
}
impl std::ops::BitXorAssign for $ty {
#[inline]
fn bitxor_assign(&mut self, rhs: Self) {
*self = self.symmetric_difference(rhs);
}
}
impl std::ops::Sub for $ty {
type Output = Self;
#[inline]
fn sub(self, rhs: Self) -> Self {
self.difference(rhs)
}
}
impl std::ops::SubAssign for $ty {
#[inline]
fn sub_assign(&mut self, rhs: Self) {
*self = self.difference(rhs);
}
}
impl std::ops::Not for $ty {
type Output = Self;
#[inline]
fn not(self) -> Self {
self.complement()
}
}
};
{
#[non_exhaustive]
$(#[doc = $ty_doc:literal])*
$ty:ident
$( impl { $($impls:item)* } )?
= $ty_ffi:ident($repr:ty);
$(
$(#[doc = $flag_doc:literal])*
$flag_name:ident = $flag_name_ffi:ident
$(RequiresOneOf([
$(RequiresAllOf([
$(APIVersion($api_version:ident) $(,)?)?
$($(Feature($feature:ident)),+ $(,)?)?
$($(DeviceExtension($device_extension:ident)),+ $(,)?)?
$($(InstanceExtension($instance_extension:ident)),+ $(,)?)?
])),+ $(,)?
]))?
,
)*
} => {
$(#[doc = $ty_doc])*
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct $ty($repr);
impl $ty {
$(
$(#[doc = $flag_doc])*
pub const $flag_name: Self = Self(ash::vk::$ty_ffi::$flag_name_ffi.as_raw());
)*
#[doc = concat!("Returns a `", stringify!($ty), "` with none of the flags set.")]
#[inline]
pub const fn empty() -> Self {
Self(0)
}
#[deprecated(since = "0.31.0", note = "use `empty` instead")]
#[doc = concat!("Returns a `", stringify!($ty), "` with none of the flags set.")]
#[inline]
pub const fn none() -> Self {
Self::empty()
}
const fn all_raw() -> $repr {
0
$(
| ash::vk::$ty_ffi::$flag_name_ffi.as_raw()
)*
}
#[inline]
pub const fn count(self) -> u32 {
self.0.count_ones()
}
#[inline]
pub const fn is_empty(self) -> bool {
self.0 == 0
}
#[inline]
pub const fn intersects(self, #[allow(unused_variables)] other: Self) -> bool {
self.0 & other.0 != 0
}
#[inline]
pub const fn contains(self, #[allow(unused_variables)] other: Self) -> bool {
self.0 & other.0 == other.0
}
#[inline]
pub const fn union(self, #[allow(unused_variables)] other: Self) -> Self {
Self(self.0 | other.0)
}
#[inline]
pub const fn intersection(self, #[allow(unused_variables)] other: Self) -> Self {
Self(self.0 & other.0)
}
#[inline]
pub const fn difference(self, #[allow(unused_variables)] other: Self) -> Self {
Self(self.0 & !other.0)
}
#[inline]
pub const fn symmetric_difference(self, #[allow(unused_variables)] other: Self) -> Self {
Self(self.0 ^ other.0)
}
#[allow(dead_code)]
#[inline]
pub(crate) fn validate_device(
self,
device: &crate::device::Device,
) -> Result<(), Box<crate::ValidationError>> {
self.validate_device_raw(
device.api_version(),
device.enabled_features(),
device.enabled_extensions(),
device.instance().enabled_extensions(),
)
}
#[allow(dead_code)]
#[inline]
pub(crate) fn validate_physical_device(
self,
physical_device: &crate::device::physical::PhysicalDevice,
) -> Result<(), Box<crate::ValidationError>> {
self.validate_device_raw(
physical_device.api_version(),
physical_device.supported_features(),
physical_device.supported_extensions(),
physical_device.instance().enabled_extensions(),
)
}
#[allow(dead_code)]
pub(crate) fn validate_device_raw(
self,
#[allow(unused_variables)] device_api_version: crate::Version,
#[allow(unused_variables)] device_features: &crate::device::Features,
#[allow(unused_variables)] device_extensions: &crate::device::DeviceExtensions,
#[allow(unused_variables)] instance_extensions: &crate::instance::InstanceExtensions,
) -> Result<(), Box<crate::ValidationError>> {
$(
$(
if self.intersects(Self::$flag_name) && ![
$([
$(
device_api_version >= crate::Version::$api_version,
)?
$($(
device_features.$feature,
)+)?
$($(
device_extensions.$device_extension,
)+)?
$($(
instance_extensions.$instance_extension,
)+)?
].into_iter().all(|x| x)),*
].into_iter().any(|x| x) {
return Err(Box::new(crate::ValidationError {
problem: concat!("is `", stringify!($ty), "::", stringify!($flag_name), "`").into(),
requires_one_of: crate::RequiresOneOf(&[
$(crate::RequiresAllOf(&[
$(
crate::Requires::APIVersion(crate::Version::$api_version),
)?
$($(
crate::Requires::Feature(stringify!($feature)),
)+)?
$($(
crate::Requires::DeviceExtension(stringify!($device_extension)),
)+)?
$($(
crate::Requires::InstanceExtension(stringify!($instance_extension)),
)+)?
])),*
]),
..Default::default()
}));
}
)?
)*
Ok(())
}
#[allow(dead_code)]
#[inline]
pub(crate) fn validate_instance(
self,
instance: &crate::instance::Instance,
) -> Result<(), Box<crate::ValidationError>> {
self.validate_instance_raw(
instance.api_version(),
instance.enabled_extensions(),
)
}
#[allow(dead_code)]
pub(crate) fn validate_instance_raw(
self,
#[allow(unused_variables)] instance_api_version: crate::Version,
#[allow(unused_variables)] instance_extensions: &crate::instance::InstanceExtensions,
) -> Result<(), Box<crate::ValidationError>> {
$(
$(
if self.intersects(Self::$flag_name) && ![
$([
$(
instance_api_version >= crate::Version::$api_version,
)?
$($(
instance_extensions.$instance_extension,
)+)?
].into_iter().all(|x| x)),*
].into_iter().any(|x| x) {
return Err(Box::new(crate::ValidationError {
problem: concat!("is `", stringify!($ty), "::", stringify!($flag_name), "`").into(),
requires_one_of: crate::RequiresOneOf(&[
$(crate::RequiresAllOf(&[
$(
crate::Requires::APIVersion(crate::Version::$api_version),
)?
$($(
crate::Requires::InstanceExtension(stringify!($instance_extension)),
)+)?
])),*
]),
..Default::default()
}));
}
)?
)*
Ok(())
}
$( $($impls)* )?
}
impl Default for $ty {
#[inline]
fn default() -> Self {
Self::empty()
}
}
impl std::fmt::Debug for $ty {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
#[allow(unused_mut)]
let mut written = false;
$(
if self.intersects(Self::$flag_name) {
if written {
write!(f, " | ")?;
}
write!(f, stringify!($flag_name))?;
written = true;
}
)*
if !written {
write!(f, "empty()")?;
}
Ok(())
}
}
impl From<$ty> for ash::vk::$ty_ffi {
#[inline]
fn from(val: $ty) -> Self {
ash::vk::$ty_ffi::from_raw(val.0)
}
}
impl From<ash::vk::$ty_ffi> for $ty {
#[inline]
fn from(val: ash::vk::$ty_ffi) -> Self {
Self(val.as_raw() & Self::all_raw())
}
}
impl std::ops::BitAnd for $ty {
type Output = Self;
#[inline]
fn bitand(self, rhs: Self) -> Self {
self.intersection(rhs)
}
}
impl std::ops::BitAndAssign for $ty {
#[inline]
fn bitand_assign(&mut self, rhs: Self) {
*self = self.intersection(rhs);
}
}
impl std::ops::BitOr for $ty {
type Output = Self;
#[inline]
fn bitor(self, rhs: Self) -> Self {
self.union(rhs)
}
}
impl std::ops::BitOrAssign for $ty {
#[inline]
fn bitor_assign(&mut self, rhs: Self) {
*self = self.union(rhs);
}
}
impl std::ops::BitXor for $ty {
type Output = Self;
#[inline]
fn bitxor(self, rhs: Self) -> Self {
self.symmetric_difference(rhs)
}
}
impl std::ops::BitXorAssign for $ty {
#[inline]
fn bitxor_assign(&mut self, rhs: Self) {
*self = self.symmetric_difference(rhs);
}
}
impl std::ops::Sub for $ty {
type Output = Self;
#[inline]
fn sub(self, rhs: Self) -> Self {
self.difference(rhs)
}
}
impl std::ops::SubAssign for $ty {
#[inline]
fn sub_assign(&mut self, rhs: Self) {
*self = self.difference(rhs);
}
}
};
}
macro_rules! vulkan_enum {
{
$(#[doc = $ty_doc:literal])*
$ty:ident
$( impl { $($impls:item)* } )?
= $ty_ffi:ident($repr:ty);
$(
$(#[doc = $flag_doc:literal])*
$flag_name:ident = $flag_name_ffi:ident,
)+
} => {
$(#[doc = $ty_doc])*
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[repr($repr)]
pub enum $ty {
$(
$(#[doc = $flag_doc])*
$flag_name = ash::vk::$ty_ffi::$flag_name_ffi.as_raw(),
)+
}
impl $ty {
#[allow(dead_code)]
pub(crate) const COUNT: usize = [
$(ash::vk::$ty_ffi::$flag_name_ffi.as_raw()),+
].len();
$(
$($impls)*
)?
}
impl From<$ty> for ash::vk::$ty_ffi {
#[inline]
fn from(val: $ty) -> Self {
ash::vk::$ty_ffi::from_raw(val as $repr)
}
}
impl TryFrom<ash::vk::$ty_ffi> for $ty {
type Error = ();
#[inline]
fn try_from(val: ash::vk::$ty_ffi) -> Result<Self, Self::Error> {
Ok(match val {
$(
ash::vk::$ty_ffi::$flag_name_ffi => Self::$flag_name,
)+
_ => return Err(()),
})
}
}
};
{
#[non_exhaustive]
$(#[doc = $ty_doc:literal])*
$ty:ident
$( impl { $($impls:item)* } )?
= $ty_ffi:ident($repr:ty);
$(
$(#[doc = $flag_doc:literal])*
$flag_name:ident = $flag_name_ffi:ident
$(RequiresOneOf([
$(RequiresAllOf([
$(APIVersion($api_version:ident) $(,)?)?
$($(Feature($feature:ident)),+ $(,)?)?
$($(DeviceExtension($device_extension:ident)),+ $(,)?)?
$($(InstanceExtension($instance_extension:ident)),+ $(,)?)?
])),+ $(,)?
]))?
,
)+
} => {
$(#[doc = $ty_doc])*
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
#[repr($repr)]
pub enum $ty {
$(
$(#[doc = $flag_doc])*
$flag_name = ash::vk::$ty_ffi::$flag_name_ffi.as_raw(),
)+
}
impl $ty {
#[allow(dead_code)]
pub(crate) const COUNT: usize = [
$(ash::vk::$ty_ffi::$flag_name_ffi.as_raw()),+
].len();
#[allow(dead_code)]
#[inline]
pub(crate) fn validate_device(
self,
device: &crate::device::Device,
) -> Result<(), Box<crate::ValidationError>> {
self.validate_device_raw(
device.api_version(),
device.enabled_features(),
device.enabled_extensions(),
device.instance().enabled_extensions(),
)
}
#[allow(dead_code)]
#[inline]
pub(crate) fn validate_physical_device(
self,
physical_device: &crate::device::physical::PhysicalDevice,
) -> Result<(), Box<crate::ValidationError>> {
self.validate_device_raw(
physical_device.api_version(),
physical_device.supported_features(),
physical_device.supported_extensions(),
physical_device.instance().enabled_extensions(),
)
}
#[allow(dead_code)]
pub(crate) fn validate_device_raw(
self,
#[allow(unused_variables)] device_api_version: crate::Version,
#[allow(unused_variables)] device_features: &crate::device::Features,
#[allow(unused_variables)] device_extensions: &crate::device::DeviceExtensions,
#[allow(unused_variables)] instance_extensions: &crate::instance::InstanceExtensions,
) -> Result<(), Box<crate::ValidationError>> {
match self {
$(
$(
Self::$flag_name => {
if ![
$([
$(
device_api_version >= crate::Version::$api_version,
)?
$($(
device_features.$feature,
)+)?
$($(
device_extensions.$device_extension,
)+)?
$($(
instance_extensions.$instance_extension,
)+)?
].into_iter().all(|x| x)),*
].into_iter().any(|x| x) {
return Err(Box::new(crate::ValidationError {
problem: concat!("is `", stringify!($ty), "::", stringify!($flag_name), "`").into(),
requires_one_of: crate::RequiresOneOf(&[
$(crate::RequiresAllOf(&[
$(
crate::Requires::APIVersion(crate::Version::$api_version),
)?
$($(
crate::Requires::Feature(stringify!($feature)),
)+)?
$($(
crate::Requires::DeviceExtension(stringify!($device_extension)),
)+)?
$($(
crate::Requires::InstanceExtension(stringify!($instance_extension)),
)+)?
])),*
]),
..Default::default()
}));
}
},
)?
)+
_ => (),
}
Ok(())
}
#[allow(dead_code)]
#[inline]
pub(crate) fn validate_instance(
self,
instance: &crate::instance::Instance,
) -> Result<(), Box<crate::ValidationError>> {
self.validate_instance_raw(
instance.api_version(),
instance.enabled_extensions(),
)
}
#[allow(dead_code)]
pub(crate) fn validate_instance_raw(
self,
#[allow(unused_variables)] instance_api_version: crate::Version,
#[allow(unused_variables)] instance_extensions: &crate::instance::InstanceExtensions,
) -> Result<(), Box<crate::ValidationError>> {
match self {
$(
$(
Self::$flag_name => {
if ![
$([
$(
instance_api_version >= crate::Version::$api_version,
)?
$($(
instance_extensions.$instance_extension,
)+)?
].into_iter().all(|x| x)),*
].into_iter().any(|x| x) {
return Err(Box::new(crate::ValidationError {
problem: concat!("is `", stringify!($ty), "::", stringify!($flag_name), "`").into(),
requires_one_of: crate::RequiresOneOf(&[
$(crate::RequiresAllOf(&[
$(
crate::Requires::APIVersion(crate::Version::$api_version),
)?
$($(
crate::Requires::InstanceExtension(stringify!($instance_extension)),
)+)?
])),*
]),
..Default::default()
}));
}
},
)?
)+
_ => (),
}
Ok(())
}
$(
$($impls)*
)?
}
impl From<$ty> for ash::vk::$ty_ffi {
#[inline]
fn from(val: $ty) -> Self {
ash::vk::$ty_ffi::from_raw(val as $repr)
}
}
impl TryFrom<ash::vk::$ty_ffi> for $ty {
type Error = ();
#[inline]
fn try_from(val: ash::vk::$ty_ffi) -> Result<Self, Self::Error> {
Ok(match val {
$(
ash::vk::$ty_ffi::$flag_name_ffi => Self::$flag_name,
)+
_ => return Err(()),
})
}
}
};
}
macro_rules! vulkan_bitflags_enum {
{
#[non_exhaustive]
$(#[doc = $ty_bitflags_doc:literal])*
$ty_bitflags:ident
$( impl { $($impls_bitflags:item)* } )?
,
$(#[doc = $ty_enum_doc:literal])*
$ty_enum:ident
$( impl { $($impls_enum:item)* } )?
,
= $ty_ffi:ident($repr:ty);
$(
$(#[doc = $flag_doc:literal])*
$flag_name_bitflags:ident, $flag_name_enum:ident = $flag_name_ffi:ident
$(RequiresOneOf([
$(RequiresAllOf([
$(APIVersion($api_version:ident) $(,)?)?
$($(Feature($feature:ident)),+ $(,)?)?
$($(DeviceExtension($device_extension:ident)),+ $(,)?)?
$($(InstanceExtension($instance_extension:ident)),+ $(,)?)?
])),+ $(,)?
]))?
,
)*
} => {
crate::macros::vulkan_bitflags! {
#[non_exhaustive]
$(#[doc = $ty_bitflags_doc])*
$ty_bitflags
impl {
#[inline]
pub fn contains_enum(self, val: $ty_enum) -> bool {
self.intersects(val.into())
}
$( $($impls_bitflags)* )?
}
= $ty_ffi($repr);
$(
$(#[doc = $flag_doc])*
$flag_name_bitflags = $flag_name_ffi
$(RequiresOneOf([
$(RequiresAllOf([
$(APIVersion($api_version) ,)?
$($(Feature($feature)),+ ,)?
$($(DeviceExtension($device_extension)),+ ,)?
$($(InstanceExtension($instance_extension)),+ ,)?
])),+ ,
]))?
,
)*
}
crate::macros::vulkan_enum! {
#[non_exhaustive]
$(#[doc = $ty_enum_doc])*
$ty_enum
$( impl { $($impls_enum)* } )?
= $ty_ffi($repr);
$(
$(#[doc = $flag_doc])*
$flag_name_enum = $flag_name_ffi
$(RequiresOneOf([
$(RequiresAllOf([
$(APIVersion($api_version) ,)?
$($(Feature($feature)),+ ,)?
$($(DeviceExtension($device_extension)),+ ,)?
$($(InstanceExtension($instance_extension)),+ ,)?
])),+ ,
]))?
,
)*
}
impl From<$ty_enum> for $ty_bitflags {
#[inline]
fn from(val: $ty_enum) -> Self {
Self(val as $repr)
}
}
impl FromIterator<$ty_enum> for $ty_bitflags {
#[inline]
fn from_iter<T>(iter: T) -> Self where T: IntoIterator<Item = $ty_enum> {
iter.into_iter().map(|item| Self::from(item)).fold(Self::empty(), |r, i| r.union(i))
}
}
impl IntoIterator for $ty_bitflags {
type Item = $ty_enum;
type IntoIter = std::iter::Flatten<
std::array::IntoIter<
Option<Self::Item>,
{ $ty_bitflags::all_raw().count_ones() as usize },
>
>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
[
$(
self.intersects(Self::$flag_name_bitflags)
.then_some($ty_enum::$flag_name_enum),
)*
].into_iter().flatten()
}
}
}
}
macro_rules! impl_id_counter {
($type:ident $(< $($param:ident $(: $bound:ident $(+ $bounds:ident)* )?),+ >)?) => {
$crate::macros::impl_id_counter!(
@inner $type $(< $($param),+ >)?, $( $($param $(: $bound $(+ $bounds)* )?),+)?
);
};
($type:ident $(< $($param:ident $(: $bound:ident $(+ $bounds:ident)* )? + ?Sized),+ >)?) => {
$crate::macros::impl_id_counter!(
@inner $type $(< $($param),+ >)?, $( $($param $(: $bound $(+ $bounds)* )? + ?Sized),+)?
);
};
(@inner $type:ident $(< $($param:ident),+ >)?, $($bounds:tt)*) => {
impl< $($bounds)* > $type $(< $($param),+ >)? {
fn next_id() -> std::num::NonZeroU64 {
use std::{
num::NonZeroU64,
sync::atomic::{AtomicU64, Ordering},
};
static COUNTER: AtomicU64 = AtomicU64::new(1);
NonZeroU64::new(COUNTER.fetch_add(1, Ordering::Relaxed)).unwrap_or_else(|| {
eprintln!("an ID counter has overflown ...somehow");
std::process::abort();
})
}
#[allow(dead_code)]
pub(crate) fn id(&self) -> std::num::NonZeroU64 {
self.id
}
}
impl< $($bounds)* > PartialEq for $type $(< $($param),+ >)? {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl< $($bounds)* > Eq for $type $(< $($param),+ >)? {}
impl< $($bounds)* > std::hash::Hash for $type $(< $($param),+ >)? {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
};
}
macro_rules! try_opt {
($e:expr) => {
if let Some(val) = $e {
val
} else {
return None;
}
};
}
pub(crate) use {impl_id_counter, try_opt, vulkan_bitflags, vulkan_bitflags_enum, vulkan_enum};