use crate::device::physical::{ ConformanceVersion, DriverId, PhysicalDeviceType, PointClippingBehavior, ShaderCoreProperties, ShaderFloatControlsIndependence, SubgroupFeatures, }; use crate::image::{SampleCount, SampleCounts}; use crate::pipeline::shader::ShaderStages; use crate::render_pass::ResolveModes; use crate::Version; use std::convert::TryInto; use std::ffi::CStr; /// this is a macro that outputs either T or Option depending on the 2nd argument macro_rules! property_type { ($ty:ty, true) => { $ty }; ($ty:ty, false) => { Option<$ty> }; } pub(crate) use property_type; /// this is a macro that executes the correct from_vulkan call depending on whether or not the type is Option macro_rules! property_from_vulkan { ($ty:ty, [$($ffi_struct:ident $(.$ffi_struct_field:ident)*),+], $ffi_field:ident, true, $properties:ident) => { std::array::IntoIter::new([ $($properties.$ffi_struct$(.$ffi_struct_field)*.$ffi_field),+ ]).next().and_then(|x| <$ty>::from_vulkan(x)).expect(concat!("expected good ", stringify!($ffi_field))) }; ($ty:ty, [$($ffi_struct:ident $(.$ffi_struct_field:ident)*),+], $ffi_field:ident, false, $properties:ident) => { std::array::IntoIter::new([ $($properties.$ffi_struct.map(|s| s$(.$ffi_struct_field)*.$ffi_field)),+ ]).flatten().next().and_then(|x| <$ty>::from_vulkan(x)) }; } pub(crate) use property_from_vulkan; macro_rules! properties { { $($member:ident => { doc: $doc:expr, ty: $ty:ty, ffi_name: $ffi_field:ident, ffi_members: [$($ffi_struct:ident $(.$ffi_struct_field:ident)*),+], required: $required:tt, },)* } => { /// Represents all the properties of a physical device. /// /// Depending on the highest version of Vulkan supported by the physical device, and the /// available extensions, not every property may be available. For that reason, properties /// are wrapped in an `Option`. #[derive(Clone, Debug, Default)] #[allow(missing_docs)] pub struct Properties { $( #[doc = $doc] pub $member: $crate::device::properties::property_type!($ty, $required), )* } impl From<&PropertiesFfi> for Properties { fn from(properties_ffi: &PropertiesFfi) -> Self { use crate::device::properties::FromVulkan; Properties { $( $member: crate::device::properties::property_from_vulkan!($ty, [ $($ffi_struct$(.$ffi_struct_field)*),+ ], $ffi_field, $required, properties_ffi), )* } } } }; } pub use crate::autogen::Properties; pub(crate) use properties; macro_rules! properties_ffi { { $api_version:ident, $device_extensions:ident, $instance_extensions:ident, $($member:ident => { ty: $ty:ident, provided_by: [$($provided_by:expr),+], conflicts: [$($conflicts:ident),*], },)+ } => { #[derive(Default)] pub(crate) struct PropertiesFfi { properties_vulkan10: ash::vk::PhysicalDeviceProperties2KHR, $( $member: Option, )+ } impl PropertiesFfi { pub(crate) fn make_chain( &mut self, $api_version: crate::Version, $device_extensions: &crate::device::DeviceExtensions, $instance_extensions: &crate::instance::InstanceExtensions, ) { self.properties_vulkan10 = Default::default(); let head = &mut self.properties_vulkan10; $( if std::array::IntoIter::new([$($provided_by),+]).any(|x| x) && std::array::IntoIter::new([$(self.$conflicts.is_none()),*]).all(|x| x) { self.$member = Some(Default::default()); let member = self.$member.as_mut().unwrap(); member.p_next = head.p_next; head.p_next = member as *mut _ as _; } )+ } pub(crate) fn head_as_ref(&self) -> &ash::vk::PhysicalDeviceProperties2KHR { &self.properties_vulkan10 } pub(crate) fn head_as_mut(&mut self) -> &mut ash::vk::PhysicalDeviceProperties2KHR { &mut self.properties_vulkan10 } } }; } pub(crate) use {crate::autogen::PropertiesFfi, properties_ffi}; // A bit of a hack... pub(crate) trait FromVulkan where Self: Sized, { fn from_vulkan(val: F) -> Option; } impl FromVulkan for u8 { #[inline] fn from_vulkan(val: u8) -> Option { Some(val) } } impl FromVulkan<[u8; N]> for [u8; N] { #[inline] fn from_vulkan(val: [u8; N]) -> Option { Some(val) } } impl FromVulkan for u32 { #[inline] fn from_vulkan(val: u32) -> Option { Some(val) } } impl FromVulkan<[u32; N]> for [u32; N] { #[inline] fn from_vulkan(val: [u32; N]) -> Option { Some(val) } } impl FromVulkan for u64 { #[inline] fn from_vulkan(val: u64) -> Option { Some(val) } } impl FromVulkan for usize { #[inline] fn from_vulkan(val: usize) -> Option { Some(val) } } impl FromVulkan for i32 { #[inline] fn from_vulkan(val: i32) -> Option { Some(val) } } impl FromVulkan for i64 { #[inline] fn from_vulkan(val: i64) -> Option { Some(val) } } impl FromVulkan for f32 { #[inline] fn from_vulkan(val: f32) -> Option { Some(val) } } impl FromVulkan<[f32; N]> for [f32; N] { #[inline] fn from_vulkan(val: [f32; N]) -> Option { Some(val) } } impl FromVulkan<[std::os::raw::c_char; N]> for String { #[inline] fn from_vulkan(val: [std::os::raw::c_char; N]) -> Option { Some(unsafe { CStr::from_ptr(val.as_ptr()).to_string_lossy().into_owned() }) } } impl FromVulkan for Version { #[inline] fn from_vulkan(val: u32) -> Option { val.try_into().ok() } } impl FromVulkan for bool { #[inline] fn from_vulkan(val: ash::vk::Bool32) -> Option { Some(val != 0) } } impl FromVulkan for ConformanceVersion { #[inline] fn from_vulkan(val: ash::vk::ConformanceVersion) -> Option { Some(val.into()) } } impl FromVulkan for DriverId { #[inline] fn from_vulkan(val: ash::vk::DriverId) -> Option { val.try_into().ok() } } impl FromVulkan for [u32; 2] { #[inline] fn from_vulkan(val: ash::vk::Extent2D) -> Option { Some([val.width, val.height]) } } impl FromVulkan for PhysicalDeviceType { #[inline] fn from_vulkan(val: ash::vk::PhysicalDeviceType) -> Option { val.try_into().ok() } } impl FromVulkan for PointClippingBehavior { #[inline] fn from_vulkan(val: ash::vk::PointClippingBehavior) -> Option { val.try_into().ok() } } impl FromVulkan for ResolveModes { #[inline] fn from_vulkan(val: ash::vk::ResolveModeFlags) -> Option { Some(val.into()) } } impl FromVulkan for SampleCounts { #[inline] fn from_vulkan(val: ash::vk::SampleCountFlags) -> Option { Some(val.into()) } } impl FromVulkan for SampleCount { #[inline] fn from_vulkan(val: ash::vk::SampleCountFlags) -> Option { val.try_into().ok() } } impl FromVulkan for ShaderCoreProperties { #[inline] fn from_vulkan(val: ash::vk::ShaderCorePropertiesFlagsAMD) -> Option { Some(val.into()) } } impl FromVulkan for ShaderFloatControlsIndependence { #[inline] fn from_vulkan(val: ash::vk::ShaderFloatControlsIndependence) -> Option { val.try_into().ok() } } impl FromVulkan for ShaderStages { #[inline] fn from_vulkan(val: ash::vk::ShaderStageFlags) -> Option { Some(val.into()) } } impl FromVulkan for SubgroupFeatures { #[inline] fn from_vulkan(val: ash::vk::SubgroupFeatureFlags) -> Option { Some(val.into()) } }