macro_rules! vulkan_bitflags {
{
$(#[doc = $ty_doc:literal])*
$ty:ident = $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)]
pub struct $ty {
$(
$(#[doc = $flag_doc])*
pub $flag_name: bool,
)+
}
impl $ty {
#[doc = concat!("Returns a `", stringify!($ty), "` with none of the flags set.")]
#[inline]
pub const fn empty() -> Self {
Self {
$(
$flag_name: false,
)+
}
}
#[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 {
$(
$flag_name: true,
)+
}
}
#[inline]
pub const fn is_empty(&self) -> bool {
!(
$(
self.$flag_name
)||+
)
}
#[inline]
pub const fn intersects(&self, other: &Self) -> bool {
$(
(self.$flag_name && other.$flag_name)
)||+
}
#[inline]
pub const fn contains(&self, other: &Self) -> bool {
$(
(self.$flag_name || !other.$flag_name)
)&&+
}
#[inline]
pub const fn union(&self, other: &Self) -> Self {
Self {
$(
$flag_name: (self.$flag_name || other.$flag_name),
)+
}
}
#[inline]
pub const fn intersection(&self, other: &Self) -> Self {
Self {
$(
$flag_name: (self.$flag_name && other.$flag_name),
)+
}
}
#[inline]
pub const fn difference(&self, other: &Self) -> Self {
Self {
$(
$flag_name: (self.$flag_name && !other.$flag_name),
)+
}
}
#[inline]
pub const fn symmetric_difference(&self, other: &Self) -> Self {
Self {
$(
$flag_name: (self.$flag_name ^ other.$flag_name),
)+
}
}
#[inline]
pub const fn complement(&self) -> Self {
Self {
$(
$flag_name: !self.$flag_name,
)+
}
}
}
impl From<$ty> for ash::vk::$ty_ffi {
#[inline]
fn from(val: $ty) -> Self {
let mut result = ash::vk::$ty_ffi::empty();
$(
if val.$flag_name { result |= ash::vk::$ty_ffi::$flag_name_ffi }
)+
result
}
}
impl From<ash::vk::$ty_ffi> for $ty {
#[inline]
fn from(val: ash::vk::$ty_ffi) -> Self {
Self {
$(
$flag_name: val.intersects(ash::vk::$ty_ffi::$flag_name_ffi),
)+
}
}
}
impl Default for $ty {
#[inline]
fn default() -> Self {
Self {
$(
$flag_name: false,
)+
}
}
}
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()
}
}
};
{
$(#[doc = $ty_doc:literal])*
#[non_exhaustive]
$ty:ident = $ty_ffi:ident($repr:ty);
$(
$(#[doc = $flag_doc:literal])*
$flag_name:ident = $flag_name_ffi:ident
$({
$(api_version: $api_version:ident,)?
$(features: [$($feature:ident),+ $(,)?],)?
$(device_extensions: [$($device_extension:ident),+ $(,)?],)?
$(instance_extensions: [$($instance_extension:ident),+ $(,)?],)?
})?
,
)*
} => {
$(#[doc = $ty_doc])*
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct $ty {
$(
$(#[doc = $flag_doc])*
pub $flag_name: bool,
)*
pub _ne: crate::NonExhaustive,
}
impl $ty {
#[doc = concat!("Returns a `", stringify!($ty), "` with none of the flags set.")]
#[inline]
pub const fn empty() -> Self {
Self {
$(
$flag_name: false,
)*
_ne: crate::NonExhaustive(()),
}
}
#[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()
}
#[inline]
pub const fn is_empty(&self) -> bool {
!(
false
$(
|| self.$flag_name
)*
)
}
#[inline]
pub const fn intersects(&self, #[allow(unused_variables)] other: &Self) -> bool {
false
$(
|| (self.$flag_name && other.$flag_name)
)*
}
#[inline]
pub const fn contains(&self, #[allow(unused_variables)] other: &Self) -> bool {
true
$(
&& (self.$flag_name || !other.$flag_name)
)*
}
#[inline]
pub const fn union(&self, #[allow(unused_variables)] other: &Self) -> Self {
Self {
$(
$flag_name: (self.$flag_name || other.$flag_name),
)*
_ne: crate::NonExhaustive(()),
}
}
#[inline]
pub const fn intersection(&self, #[allow(unused_variables)] other: &Self) -> Self {
Self {
$(
$flag_name: (self.$flag_name && other.$flag_name),
)*
_ne: crate::NonExhaustive(()),
}
}
#[inline]
pub const fn difference(&self, #[allow(unused_variables)] other: &Self) -> Self {
Self {
$(
$flag_name: (self.$flag_name ^ other.$flag_name),
)*
_ne: crate::NonExhaustive(()),
}
}
#[inline]
pub const fn symmetric_difference(&self, #[allow(unused_variables)] other: &Self) -> Self {
Self {
$(
$flag_name: (self.$flag_name ^ other.$flag_name),
)*
_ne: crate::NonExhaustive(()),
}
}
#[allow(dead_code)]
pub(crate) fn validate_device(
self,
#[allow(unused_variables)] device: &crate::device::Device,
) -> Result<(), crate::RequirementNotMet> {
$(
$(
if self.$flag_name && ![
$(
device.api_version() >= crate::Version::$api_version,
)?
$($(
device.enabled_features().$feature,
)+)?
$($(
device.enabled_extensions().$device_extension,
)+)?
$($(
device.instance().enabled_extensions().$instance_extension,
)+)?
].into_iter().any(|x| x) {
return Err(crate::RequirementNotMet {
required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"),
requires_one_of: crate::RequiresOneOf {
$(api_version: Some(crate::Version::$api_version),)?
$(features: &[$(stringify!($feature)),+],)?
$(device_extensions: &[$(stringify!($device_extension)),+],)?
$(instance_extensions: &[$(stringify!($instance_extension)),+],)?
..Default::default()
},
});
}
)?
)*
Ok(())
}
#[allow(dead_code)]
pub(crate) fn validate_physical_device(
self,
#[allow(unused_variables)] physical_device: &crate::device::physical::PhysicalDevice,
) -> Result<(), crate::RequirementNotMet> {
$(
$(
if self.$flag_name && ![
$(
physical_device.api_version() >= crate::Version::$api_version,
)?
$($(
physical_device.supported_features().$feature,
)+)?
$($(
physical_device.supported_extensions().$device_extension,
)+)?
$($(
physical_device.instance().enabled_extensions().$instance_extension,
)+)?
].into_iter().any(|x| x) {
return Err(crate::RequirementNotMet {
required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"),
requires_one_of: crate::RequiresOneOf {
$(api_version: Some(crate::Version::$api_version),)?
$(features: &[$(stringify!($feature)),+],)?
$(device_extensions: &[$(stringify!($device_extension)),+],)?
$(instance_extensions: &[$(stringify!($instance_extension)),+],)?
..Default::default()
},
});
}
)?
)*
Ok(())
}
#[allow(dead_code)]
pub(crate) fn validate_instance(
self,
#[allow(unused_variables)] instance: &crate::instance::Instance,
) -> Result<(), crate::RequirementNotMet> {
$(
$(
if self.$flag_name && ![
$(
instance.api_version() >= crate::Version::$api_version,
)?
$($(
instance.enabled_extensions().$instance_extension,
)+)?
].into_iter().any(|x| x) {
return Err(crate::RequirementNotMet {
required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"),
requires_one_of: crate::RequiresOneOf {
$(api_version: Some(crate::Version::$api_version),)?
$(instance_extensions: &[$(stringify!($instance_extension)),+],)?
..Default::default()
},
});
}
)?
)*
Ok(())
}
}
impl From<$ty> for ash::vk::$ty_ffi {
#[inline]
fn from(#[allow(unused_variables)] val: $ty) -> Self {
#[allow(unused_mut)]
let mut result = ash::vk::$ty_ffi::empty();
$(
if val.$flag_name { result |= ash::vk::$ty_ffi::$flag_name_ffi }
)*
result
}
}
impl From<ash::vk::$ty_ffi> for $ty {
#[inline]
fn from(#[allow(unused_variables)] val: ash::vk::$ty_ffi) -> Self {
Self {
$(
$flag_name: val.intersects(ash::vk::$ty_ffi::$flag_name_ffi),
)*
_ne: crate::NonExhaustive(()),
}
}
}
impl Default for $ty {
#[inline]
fn default() -> Self {
Self {
$(
$flag_name: false,
)*
_ne: crate::NonExhaustive(()),
}
}
}
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 = $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 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(()),
})
}
}
};
{
$(#[doc = $ty_doc:literal])*
#[non_exhaustive]
$ty:ident = $ty_ffi:ident($repr:ty);
$(
$(#[doc = $flag_doc:literal])*
$flag_name:ident = $flag_name_ffi:ident
$({
$(api_version: $api_version:ident,)?
$(features: [$($feature:ident),+ $(,)?],)?
$(device_extensions: [$($device_extension:ident),+ $(,)?],)?
$(instance_extensions: [$($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) fn validate_device(
self,
#[allow(unused_variables)] device: &crate::device::Device,
) -> Result<(), crate::RequirementNotMet> {
match self {
$(
$(
Self::$flag_name => {
if ![
$(
device.api_version() >= crate::Version::$api_version,
)?
$($(
device.enabled_features().$feature,
)+)?
$($(
device.enabled_extensions().$device_extension,
)+)?
$($(
device.instance().enabled_extensions().$instance_extension,
)+)?
].into_iter().any(|x| x) {
return Err(crate::RequirementNotMet {
required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"),
requires_one_of: crate::RequiresOneOf {
$(api_version: Some(crate::Version::$api_version),)?
$(features: &[$(stringify!($feature)),+],)?
$(device_extensions: &[$(stringify!($device_extension)),+],)?
$(instance_extensions: &[$(stringify!($instance_extension)),+],)?
..Default::default()
},
});
}
},
)?
)+
_ => (),
}
Ok(())
}
#[allow(dead_code)]
pub(crate) fn validate_physical_device(
self,
#[allow(unused_variables)] physical_device: &crate::device::physical::PhysicalDevice,
) -> Result<(), crate::RequirementNotMet> {
match self {
$(
$(
Self::$flag_name => {
if ![
$(
physical_device.api_version() >= crate::Version::$api_version,
)?
$($(
physical_device.supported_features().$feature,
)+)?
$($(
physical_device.supported_extensions().$device_extension,
)+)?
$($(
physical_device.instance().enabled_extensions().$instance_extension,
)+)?
].into_iter().any(|x| x) {
return Err(crate::RequirementNotMet {
required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"),
requires_one_of: crate::RequiresOneOf {
$(api_version: Some(crate::Version::$api_version),)?
$(features: &[$(stringify!($feature)),+],)?
$(device_extensions: &[$(stringify!($device_extension)),+],)?
$(instance_extensions: &[$(stringify!($instance_extension)),+],)?
..Default::default()
},
});
}
},
)?
)+
_ => (),
}
Ok(())
}
#[allow(dead_code)]
pub(crate) fn validate_instance(
self,
#[allow(unused_variables)] instance: &crate::instance::Instance,
) -> Result<(), crate::RequirementNotMet> {
match self {
$(
$(
Self::$flag_name => {
if ![
$(
instance.api_version() >= crate::Version::$api_version,
)?
$($(
instance.enabled_extensions().$instance_extension,
)+)?
].into_iter().any(|x| x) {
return Err(crate::RequirementNotMet {
required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"),
requires_one_of: crate::RequiresOneOf {
$(api_version: Some(crate::Version::$api_version),)?
$(instance_extensions: &[$(stringify!($instance_extension)),+],)?
..Default::default()
},
});
}
},
)?
)+
_ => (),
}
Ok(())
}
}
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(()),
})
}
}
};
}
pub(crate) use {vulkan_bitflags, vulkan_enum};