diff options
Diffstat (limited to 'src/device/properties.rs')
-rw-r--r-- | src/device/properties.rs | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/src/device/properties.rs b/src/device/properties.rs new file mode 100644 index 0000000..be1c36d --- /dev/null +++ b/src/device/properties.rs @@ -0,0 +1,316 @@ +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<T> 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<T> +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<ash::vk::$ty>, + )+ + } + + 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<F> +where + Self: Sized, +{ + fn from_vulkan(val: F) -> Option<Self>; +} + +impl FromVulkan<u8> for u8 { + #[inline] + fn from_vulkan(val: u8) -> Option<Self> { + Some(val) + } +} + +impl<const N: usize> FromVulkan<[u8; N]> for [u8; N] { + #[inline] + fn from_vulkan(val: [u8; N]) -> Option<Self> { + Some(val) + } +} + +impl FromVulkan<u32> for u32 { + #[inline] + fn from_vulkan(val: u32) -> Option<Self> { + Some(val) + } +} + +impl<const N: usize> FromVulkan<[u32; N]> for [u32; N] { + #[inline] + fn from_vulkan(val: [u32; N]) -> Option<Self> { + Some(val) + } +} + +impl FromVulkan<u64> for u64 { + #[inline] + fn from_vulkan(val: u64) -> Option<Self> { + Some(val) + } +} + +impl FromVulkan<usize> for usize { + #[inline] + fn from_vulkan(val: usize) -> Option<Self> { + Some(val) + } +} + +impl FromVulkan<i32> for i32 { + #[inline] + fn from_vulkan(val: i32) -> Option<Self> { + Some(val) + } +} + +impl FromVulkan<i64> for i64 { + #[inline] + fn from_vulkan(val: i64) -> Option<Self> { + Some(val) + } +} + +impl FromVulkan<f32> for f32 { + #[inline] + fn from_vulkan(val: f32) -> Option<Self> { + Some(val) + } +} + +impl<const N: usize> FromVulkan<[f32; N]> for [f32; N] { + #[inline] + fn from_vulkan(val: [f32; N]) -> Option<Self> { + Some(val) + } +} + +impl<const N: usize> FromVulkan<[std::os::raw::c_char; N]> for String { + #[inline] + fn from_vulkan(val: [i8; N]) -> Option<Self> { + Some(unsafe { CStr::from_ptr(val.as_ptr()).to_string_lossy().into_owned() }) + } +} + +impl FromVulkan<u32> for Version { + #[inline] + fn from_vulkan(val: u32) -> Option<Self> { + val.try_into().ok() + } +} + +impl FromVulkan<ash::vk::Bool32> for bool { + #[inline] + fn from_vulkan(val: ash::vk::Bool32) -> Option<Self> { + Some(val != 0) + } +} + +impl FromVulkan<ash::vk::ConformanceVersion> for ConformanceVersion { + #[inline] + fn from_vulkan(val: ash::vk::ConformanceVersion) -> Option<Self> { + Some(val.into()) + } +} + +impl FromVulkan<ash::vk::DriverId> for DriverId { + #[inline] + fn from_vulkan(val: ash::vk::DriverId) -> Option<Self> { + val.try_into().ok() + } +} + +impl FromVulkan<ash::vk::Extent2D> for [u32; 2] { + #[inline] + fn from_vulkan(val: ash::vk::Extent2D) -> Option<Self> { + Some([val.width, val.height]) + } +} + +impl FromVulkan<ash::vk::PhysicalDeviceType> for PhysicalDeviceType { + #[inline] + fn from_vulkan(val: ash::vk::PhysicalDeviceType) -> Option<Self> { + val.try_into().ok() + } +} + +impl FromVulkan<ash::vk::PointClippingBehavior> for PointClippingBehavior { + #[inline] + fn from_vulkan(val: ash::vk::PointClippingBehavior) -> Option<Self> { + val.try_into().ok() + } +} + +impl FromVulkan<ash::vk::ResolveModeFlags> for ResolveModes { + #[inline] + fn from_vulkan(val: ash::vk::ResolveModeFlags) -> Option<Self> { + Some(val.into()) + } +} + +impl FromVulkan<ash::vk::SampleCountFlags> for SampleCounts { + #[inline] + fn from_vulkan(val: ash::vk::SampleCountFlags) -> Option<Self> { + Some(val.into()) + } +} + +impl FromVulkan<ash::vk::SampleCountFlags> for SampleCount { + #[inline] + fn from_vulkan(val: ash::vk::SampleCountFlags) -> Option<Self> { + val.try_into().ok() + } +} + +impl FromVulkan<ash::vk::ShaderCorePropertiesFlagsAMD> for ShaderCoreProperties { + #[inline] + fn from_vulkan(val: ash::vk::ShaderCorePropertiesFlagsAMD) -> Option<Self> { + Some(val.into()) + } +} + +impl FromVulkan<ash::vk::ShaderFloatControlsIndependence> for ShaderFloatControlsIndependence { + #[inline] + fn from_vulkan(val: ash::vk::ShaderFloatControlsIndependence) -> Option<Self> { + val.try_into().ok() + } +} + +impl FromVulkan<ash::vk::ShaderStageFlags> for ShaderStages { + #[inline] + fn from_vulkan(val: ash::vk::ShaderStageFlags) -> Option<Self> { + Some(val.into()) + } +} + +impl FromVulkan<ash::vk::SubgroupFeatureFlags> for SubgroupFeatures { + #[inline] + fn from_vulkan(val: ash::vk::SubgroupFeatureFlags) -> Option<Self> { + Some(val.into()) + } +} |