diff options
Diffstat (limited to 'src/device/physical.rs')
-rw-r--r-- | src/device/physical.rs | 936 |
1 files changed, 936 insertions, 0 deletions
diff --git a/src/device/physical.rs b/src/device/physical.rs new file mode 100644 index 0000000..feaea4b --- /dev/null +++ b/src/device/physical.rs @@ -0,0 +1,936 @@ +// Copyright (c) 2021 The vulkano developers +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT +// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, +// at your option. All files in the project carrying such +// notice may not be copied, modified, or distributed except +// according to those terms. + +use crate::check_errors; +use crate::device::{DeviceExtensions, Features, FeaturesFfi, Properties, PropertiesFfi}; +use crate::instance::{Instance, InstanceCreationError}; +use crate::sync::PipelineStage; +use crate::DeviceSize; +use crate::Version; +use crate::VulkanObject; +use std::convert::TryFrom; +use std::ffi::CStr; +use std::fmt; +use std::hash::Hash; +use std::mem::MaybeUninit; +use std::ptr; +use std::sync::Arc; + +#[derive(Clone, Debug)] +pub(crate) struct PhysicalDeviceInfo { + handle: ash::vk::PhysicalDevice, + api_version: Version, + supported_extensions: DeviceExtensions, + required_extensions: DeviceExtensions, + supported_features: Features, + properties: Properties, + memory_properties: ash::vk::PhysicalDeviceMemoryProperties, + queue_families: Vec<ash::vk::QueueFamilyProperties>, +} + +pub(crate) fn init_physical_devices( + instance: &Instance, +) -> Result<Vec<PhysicalDeviceInfo>, InstanceCreationError> { + let fns = instance.fns(); + let instance_extensions = instance.enabled_extensions(); + + let handles: Vec<ash::vk::PhysicalDevice> = unsafe { + let mut num = 0; + check_errors(fns.v1_0.enumerate_physical_devices( + instance.internal_object(), + &mut num, + ptr::null_mut(), + ))?; + + let mut handles = Vec::with_capacity(num as usize); + check_errors(fns.v1_0.enumerate_physical_devices( + instance.internal_object(), + &mut num, + handles.as_mut_ptr(), + ))?; + handles.set_len(num as usize); + handles + }; + + let mut infos: Vec<PhysicalDeviceInfo> = handles + .into_iter() + .enumerate() + .map(|(index, handle)| -> Result<_, InstanceCreationError> { + let api_version = unsafe { + let mut output = MaybeUninit::uninit(); + fns.v1_0 + .get_physical_device_properties(handle, output.as_mut_ptr()); + let api_version = Version::try_from(output.assume_init().api_version).unwrap(); + std::cmp::min(instance.max_api_version(), api_version) + }; + + let extension_properties: Vec<ash::vk::ExtensionProperties> = unsafe { + let mut num = 0; + check_errors(fns.v1_0.enumerate_device_extension_properties( + handle, + ptr::null(), + &mut num, + ptr::null_mut(), + ))?; + + let mut properties = Vec::with_capacity(num as usize); + check_errors(fns.v1_0.enumerate_device_extension_properties( + handle, + ptr::null(), + &mut num, + properties.as_mut_ptr(), + ))?; + properties.set_len(num as usize); + properties + }; + + let supported_extensions = DeviceExtensions::from( + extension_properties + .iter() + .map(|property| unsafe { CStr::from_ptr(property.extension_name.as_ptr()) }), + ); + + let required_extensions = supported_extensions + .intersection(&DeviceExtensions::required_if_supported_extensions()); + + Ok(PhysicalDeviceInfo { + handle, + api_version, + supported_extensions, + required_extensions, + supported_features: Default::default(), + properties: Default::default(), + memory_properties: Default::default(), + queue_families: Default::default(), + }) + }) + .collect::<Result<_, _>>()?; + + // Getting the remaining infos. + // If possible, we use VK_KHR_get_physical_device_properties2. + if instance.api_version() >= Version::V1_1 + || instance_extensions.khr_get_physical_device_properties2 + { + init_physical_devices_inner2(instance, &mut infos) + } else { + init_physical_devices_inner(instance, &mut infos) + }; + + Ok(infos) +} + +/// Initialize all physical devices +fn init_physical_devices_inner(instance: &Instance, infos: &mut [PhysicalDeviceInfo]) { + let fns = instance.fns(); + + for info in infos.into_iter() { + info.supported_features = unsafe { + let mut output = FeaturesFfi::default(); + fns.v1_0 + .get_physical_device_features(info.handle, &mut output.head_as_mut().features); + Features::from(&output) + }; + + info.properties = unsafe { + let mut output = PropertiesFfi::default(); + output.make_chain( + info.api_version, + &info.supported_extensions, + instance.enabled_extensions(), + ); + fns.v1_0 + .get_physical_device_properties(info.handle, &mut output.head_as_mut().properties); + Properties::from(&output) + }; + + info.memory_properties = unsafe { + let mut output = MaybeUninit::uninit(); + fns.v1_0 + .get_physical_device_memory_properties(info.handle, output.as_mut_ptr()); + output.assume_init() + }; + + info.queue_families = unsafe { + let mut num = 0; + fns.v1_0.get_physical_device_queue_family_properties( + info.handle, + &mut num, + ptr::null_mut(), + ); + + let mut families = Vec::with_capacity(num as usize); + fns.v1_0.get_physical_device_queue_family_properties( + info.handle, + &mut num, + families.as_mut_ptr(), + ); + families.set_len(num as usize); + families + }; + } +} + +/// Initialize all physical devices, but use VK_KHR_get_physical_device_properties2 +/// TODO: Query extension-specific physical device properties, once a new instance extension is supported. +fn init_physical_devices_inner2(instance: &Instance, infos: &mut [PhysicalDeviceInfo]) { + let fns = instance.fns(); + + for info in infos.into_iter() { + info.supported_features = unsafe { + let mut output = FeaturesFfi::default(); + output.make_chain( + info.api_version, + &info.supported_extensions, + instance.enabled_extensions(), + ); + + if instance.api_version() >= Version::V1_1 { + fns.v1_1 + .get_physical_device_features2(info.handle, output.head_as_mut()); + } else { + fns.khr_get_physical_device_properties2 + .get_physical_device_features2_khr(info.handle, output.head_as_mut()); + } + + Features::from(&output) + }; + + info.properties = unsafe { + let mut output = PropertiesFfi::default(); + output.make_chain( + info.api_version, + &info.supported_extensions, + instance.enabled_extensions(), + ); + + if instance.api_version() >= Version::V1_1 { + fns.v1_1 + .get_physical_device_properties2(info.handle, output.head_as_mut()); + } else { + fns.khr_get_physical_device_properties2 + .get_physical_device_properties2_khr(info.handle, output.head_as_mut()); + } + + Properties::from(&output) + }; + + info.memory_properties = unsafe { + let mut output = ash::vk::PhysicalDeviceMemoryProperties2KHR::default(); + + if instance.api_version() >= Version::V1_1 { + fns.v1_1 + .get_physical_device_memory_properties2(info.handle, &mut output); + } else { + fns.khr_get_physical_device_properties2 + .get_physical_device_memory_properties2_khr(info.handle, &mut output); + } + + output.memory_properties + }; + + info.queue_families = unsafe { + let mut num = 0; + + if instance.api_version() >= Version::V1_1 { + fns.v1_1.get_physical_device_queue_family_properties2( + info.handle, + &mut num, + ptr::null_mut(), + ); + } else { + fns.khr_get_physical_device_properties2 + .get_physical_device_queue_family_properties2_khr( + info.handle, + &mut num, + ptr::null_mut(), + ); + } + + let mut families = vec![ash::vk::QueueFamilyProperties2::default(); num as usize]; + + if instance.api_version() >= Version::V1_1 { + fns.v1_1.get_physical_device_queue_family_properties2( + info.handle, + &mut num, + families.as_mut_ptr(), + ); + } else { + fns.khr_get_physical_device_properties2 + .get_physical_device_queue_family_properties2_khr( + info.handle, + &mut num, + families.as_mut_ptr(), + ); + } + + families + .into_iter() + .map(|family| family.queue_family_properties) + .collect() + }; + } +} + +/// Represents one of the available devices on this machine. +/// +/// This struct simply contains a pointer to an instance and a number representing the physical +/// device. You are therefore encouraged to pass this around by value instead of by reference. +/// +/// # Example +/// +/// ```no_run +/// # use vulkano::instance::Instance; +/// # use vulkano::instance::InstanceExtensions; +/// # use vulkano::Version; +/// use vulkano::device::physical::PhysicalDevice; +/// +/// # let instance = Instance::new(None, Version::V1_1, &InstanceExtensions::none(), None).unwrap(); +/// for physical_device in PhysicalDevice::enumerate(&instance) { +/// print_infos(physical_device); +/// } +/// +/// fn print_infos(dev: PhysicalDevice) { +/// println!("Name: {}", dev.properties().device_name); +/// } +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct PhysicalDevice<'a> { + instance: &'a Arc<Instance>, + index: usize, + info: &'a PhysicalDeviceInfo, +} + +impl<'a> PhysicalDevice<'a> { + /// Returns an iterator that enumerates the physical devices available. + /// + /// # Example + /// + /// ```no_run + /// # use vulkano::instance::Instance; + /// # use vulkano::instance::InstanceExtensions; + /// # use vulkano::Version; + /// use vulkano::device::physical::PhysicalDevice; + /// + /// # let instance = Instance::new(None, Version::V1_1, &InstanceExtensions::none(), None).unwrap(); + /// for physical_device in PhysicalDevice::enumerate(&instance) { + /// println!("Available device: {}", physical_device.properties().device_name); + /// } + /// ``` + #[inline] + pub fn enumerate( + instance: &'a Arc<Instance>, + ) -> impl ExactSizeIterator<Item = PhysicalDevice<'a>> { + instance + .physical_device_infos + .iter() + .enumerate() + .map(move |(index, info)| PhysicalDevice { + instance, + index, + info, + }) + } + + /// Returns a physical device from its index. Returns `None` if out of range. + /// + /// Indices range from 0 to the number of devices. + /// + /// # Example + /// + /// ```no_run + /// use vulkano::instance::Instance; + /// use vulkano::instance::InstanceExtensions; + /// use vulkano::device::physical::PhysicalDevice; + /// use vulkano::Version; + /// + /// let instance = Instance::new(None, Version::V1_1, &InstanceExtensions::none(), None).unwrap(); + /// let first_physical_device = PhysicalDevice::from_index(&instance, 0).unwrap(); + /// ``` + #[inline] + pub fn from_index(instance: &'a Arc<Instance>, index: usize) -> Option<PhysicalDevice<'a>> { + instance + .physical_device_infos + .get(index) + .map(|info| PhysicalDevice { + instance, + index, + info, + }) + } + + /// Returns the instance corresponding to this physical device. + /// + /// # Example + /// + /// ```no_run + /// use vulkano::device::physical::PhysicalDevice; + /// + /// fn do_something(physical_device: PhysicalDevice) { + /// let _loaded_extensions = physical_device.instance().enabled_extensions(); + /// // ... + /// } + /// ``` + #[inline] + pub fn instance(&self) -> &'a Arc<Instance> { + &self.instance + } + + /// Returns the index of the physical device in the physical devices list. + /// + /// This index never changes and can be used later to retrieve a `PhysicalDevice` from an + /// instance and an index. + #[inline] + pub fn index(&self) -> usize { + self.index + } + + /// Returns the version of Vulkan supported by this device. + /// + /// Unlike the `api_version` property, which is the version reported by the device directly, + /// this function returns the version the device can actually support, based on the instance's, + /// `max_api_version`. + #[inline] + pub fn api_version(&self) -> Version { + self.info.api_version + } + + /// Returns the extensions that are supported by this physical device. + #[inline] + pub fn supported_extensions(&self) -> &'a DeviceExtensions { + &self.info.supported_extensions + } + + /// Returns the extensions that must be enabled as a minimum when creating a `Device` from this + /// physical device. + pub fn required_extensions(&self) -> &'a DeviceExtensions { + &self.info.required_extensions + } + + /// Returns the properties reported by the device. + #[inline] + pub fn properties(&self) -> &'a Properties { + &self.info.properties + } + + /// Returns the features that are supported by this physical device. + #[inline] + pub fn supported_features(&self) -> &'a Features { + &self.info.supported_features + } + + /// Builds an iterator that enumerates all the memory types on this physical device. + #[inline] + pub fn memory_types(&self) -> impl ExactSizeIterator<Item = MemoryType<'a>> { + let physical_device = *self; + self.info.memory_properties.memory_types + [0..self.info.memory_properties.memory_type_count as usize] + .iter() + .enumerate() + .map(move |(id, info)| MemoryType { + physical_device, + id: id as u32, + info, + }) + } + + /// Returns the memory type with the given index, or `None` if out of range. + #[inline] + pub fn memory_type_by_id(&self, id: u32) -> Option<MemoryType<'a>> { + if id < self.info.memory_properties.memory_type_count { + Some(MemoryType { + physical_device: *self, + id, + info: &self.info.memory_properties.memory_types[id as usize], + }) + } else { + None + } + } + + /// Builds an iterator that enumerates all the memory heaps on this physical device. + #[inline] + pub fn memory_heaps(&self) -> impl ExactSizeIterator<Item = MemoryHeap<'a>> { + let physical_device = *self; + self.info.memory_properties.memory_heaps + [0..self.info.memory_properties.memory_heap_count as usize] + .iter() + .enumerate() + .map(move |(id, info)| MemoryHeap { + physical_device, + id: id as u32, + info, + }) + } + + /// Returns the memory heap with the given index, or `None` if out of range. + #[inline] + pub fn memory_heap_by_id(&self, id: u32) -> Option<MemoryHeap<'a>> { + if id < self.info.memory_properties.memory_heap_count { + Some(MemoryHeap { + physical_device: *self, + id, + info: &self.info.memory_properties.memory_heaps[id as usize], + }) + } else { + None + } + } + + /// Builds an iterator that enumerates all the queue families on this physical device. + #[inline] + pub fn queue_families(&self) -> impl ExactSizeIterator<Item = QueueFamily<'a>> { + let physical_device = *self; + self.info + .queue_families + .iter() + .enumerate() + .map(move |(id, properties)| QueueFamily { + physical_device, + id: id as u32, + properties, + }) + } + + /// Returns the queue family with the given index, or `None` if out of range. + #[inline] + pub fn queue_family_by_id(&self, id: u32) -> Option<QueueFamily<'a>> { + if (id as usize) < self.info.queue_families.len() { + Some(QueueFamily { + physical_device: *self, + id, + properties: &self.info.queue_families[id as usize], + }) + } else { + None + } + } +} + +unsafe impl<'a> VulkanObject for PhysicalDevice<'a> { + type Object = ash::vk::PhysicalDevice; + + #[inline] + fn internal_object(&self) -> ash::vk::PhysicalDevice { + self.info.handle + } +} + +/// Type of a physical device. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] +#[repr(i32)] +pub enum PhysicalDeviceType { + /// The device is an integrated GPU. + IntegratedGpu = ash::vk::PhysicalDeviceType::INTEGRATED_GPU.as_raw(), + /// The device is a discrete GPU. + DiscreteGpu = ash::vk::PhysicalDeviceType::DISCRETE_GPU.as_raw(), + /// The device is a virtual GPU. + VirtualGpu = ash::vk::PhysicalDeviceType::VIRTUAL_GPU.as_raw(), + /// The device is a CPU. + Cpu = ash::vk::PhysicalDeviceType::CPU.as_raw(), + /// The device is something else. + Other = ash::vk::PhysicalDeviceType::OTHER.as_raw(), +} + +/// VkPhysicalDeviceType::Other is represented as 0 +impl Default for PhysicalDeviceType { + fn default() -> Self { + PhysicalDeviceType::Other + } +} + +impl TryFrom<ash::vk::PhysicalDeviceType> for PhysicalDeviceType { + type Error = (); + + #[inline] + fn try_from(val: ash::vk::PhysicalDeviceType) -> Result<Self, Self::Error> { + match val { + ash::vk::PhysicalDeviceType::INTEGRATED_GPU => Ok(Self::IntegratedGpu), + ash::vk::PhysicalDeviceType::DISCRETE_GPU => Ok(Self::DiscreteGpu), + ash::vk::PhysicalDeviceType::VIRTUAL_GPU => Ok(Self::VirtualGpu), + ash::vk::PhysicalDeviceType::CPU => Ok(Self::Cpu), + ash::vk::PhysicalDeviceType::OTHER => Ok(Self::Other), + _ => Err(()), + } + } +} + +/// Represents a memory type in a physical device. +#[derive(Debug, Copy, Clone)] +pub struct MemoryType<'a> { + physical_device: PhysicalDevice<'a>, + id: u32, + info: &'a ash::vk::MemoryType, +} + +impl<'a> MemoryType<'a> { + /// Returns the physical device associated to this memory type. + #[inline] + pub fn physical_device(&self) -> PhysicalDevice<'a> { + self.physical_device + } + + /// Returns the identifier of this memory type within the physical device. + #[inline] + pub fn id(&self) -> u32 { + self.id + } + + /// Returns the heap that corresponds to this memory type. + #[inline] + pub fn heap(&self) -> MemoryHeap<'a> { + self.physical_device + .memory_heap_by_id(self.info.heap_index) + .unwrap() + } + + /// Returns true if the memory type is located on the device, which means that it's the most + /// efficient for GPU accesses. + #[inline] + pub fn is_device_local(&self) -> bool { + !(self.info.property_flags & ash::vk::MemoryPropertyFlags::DEVICE_LOCAL).is_empty() + } + + /// Returns true if the memory type can be accessed by the host. + #[inline] + pub fn is_host_visible(&self) -> bool { + !(self.info.property_flags & ash::vk::MemoryPropertyFlags::HOST_VISIBLE).is_empty() + } + + /// Returns true if modifications made by the host or the GPU on this memory type are + /// instantaneously visible to the other party. False means that changes have to be flushed. + /// + /// You don't need to worry about this, as this library handles that for you. + #[inline] + pub fn is_host_coherent(&self) -> bool { + !(self.info.property_flags & ash::vk::MemoryPropertyFlags::HOST_COHERENT).is_empty() + } + + /// Returns true if memory of this memory type is cached by the host. Host memory accesses to + /// cached memory is faster than for uncached memory. However you are not guaranteed that it + /// is coherent. + #[inline] + pub fn is_host_cached(&self) -> bool { + !(self.info.property_flags & ash::vk::MemoryPropertyFlags::HOST_CACHED).is_empty() + } + + /// Returns true if allocations made to this memory type is lazy. + /// + /// This means that no actual allocation is performed. Instead memory is automatically + /// allocated by the Vulkan implementation. + /// + /// Memory of this type can only be used on images created with a certain flag. Memory of this + /// type is never host-visible. + #[inline] + pub fn is_lazily_allocated(&self) -> bool { + !(self.info.property_flags & ash::vk::MemoryPropertyFlags::LAZILY_ALLOCATED).is_empty() + } +} + +/// Represents a memory heap in a physical device. +#[derive(Debug, Copy, Clone)] +pub struct MemoryHeap<'a> { + physical_device: PhysicalDevice<'a>, + id: u32, + info: &'a ash::vk::MemoryHeap, +} + +impl<'a> MemoryHeap<'a> { + /// Returns the physical device associated to this memory heap. + #[inline] + pub fn physical_device(&self) -> PhysicalDevice<'a> { + self.physical_device + } + + /// Returns the identifier of this memory heap within the physical device. + #[inline] + pub fn id(&self) -> u32 { + self.id + } + + /// Returns the size in bytes on this heap. + #[inline] + pub fn size(&self) -> DeviceSize { + self.info.size + } + + /// Returns true if the heap is local to the GPU. + #[inline] + pub fn is_device_local(&self) -> bool { + !(self.info.flags & ash::vk::MemoryHeapFlags::DEVICE_LOCAL).is_empty() + } + + /// Returns true if the heap is multi-instance enabled, that is allocation from such + /// heap will replicate to each physical-device's instance of heap. + #[inline] + pub fn is_multi_instance(&self) -> bool { + !(self.info.flags & ash::vk::MemoryHeapFlags::MULTI_INSTANCE).is_empty() + } +} + +/// Represents a queue family in a physical device. +/// +/// A queue family is group of one or multiple queues. All queues of one family have the same +/// characteristics. +#[derive(Debug, Copy, Clone)] +pub struct QueueFamily<'a> { + physical_device: PhysicalDevice<'a>, + id: u32, + properties: &'a ash::vk::QueueFamilyProperties, +} + +impl<'a> QueueFamily<'a> { + /// Returns the physical device associated to this queue family. + #[inline] + pub fn physical_device(&self) -> PhysicalDevice<'a> { + self.physical_device + } + + /// Returns the identifier of this queue family within the physical device. + #[inline] + pub fn id(&self) -> u32 { + self.id + } + + /// Returns the number of queues that belong to this family. + /// + /// Guaranteed to be at least 1 (or else that family wouldn't exist). + #[inline] + pub fn queues_count(&self) -> usize { + self.properties.queue_count as usize + } + + /// If timestamps are supported, returns the number of bits supported by timestamp operations. + /// The returned value will be in the range 36..64. + /// If timestamps are not supported, returns None. + #[inline] + pub fn timestamp_valid_bits(&self) -> Option<u32> { + let value = self.properties.timestamp_valid_bits; + if value == 0 { + None + } else { + Some(value) + } + } + + /// Returns the minimum granularity supported for image transfers in terms + /// of `[width, height, depth]` + #[inline] + pub fn min_image_transfer_granularity(&self) -> [u32; 3] { + let ref granularity = self.properties.min_image_transfer_granularity; + [granularity.width, granularity.height, granularity.depth] + } + + /// Returns `true` if queues of this family can execute graphics operations. + #[inline] + pub fn supports_graphics(&self) -> bool { + !(self.properties.queue_flags & ash::vk::QueueFlags::GRAPHICS).is_empty() + } + + /// Returns `true` if queues of this family can execute compute operations. + #[inline] + pub fn supports_compute(&self) -> bool { + !(self.properties.queue_flags & ash::vk::QueueFlags::COMPUTE).is_empty() + } + + /// Returns `true` if queues of this family can execute transfer operations. + /// > **Note**: While all queues that can perform graphics or compute operations can implicitly perform + /// > transfer operations, graphics & compute queues only optionally indicate support for tranfers. + /// > Many discrete cards will have one queue family that exclusively sets the VK_QUEUE_TRANSFER_BIT + /// > to indicate a special relationship with the DMA module and more efficient transfers. + #[inline] + pub fn explicitly_supports_transfers(&self) -> bool { + !(self.properties.queue_flags & ash::vk::QueueFlags::TRANSFER).is_empty() + } + + /// Returns `true` if queues of this family can execute sparse resources binding operations. + #[inline] + pub fn supports_sparse_binding(&self) -> bool { + !(self.properties.queue_flags & ash::vk::QueueFlags::SPARSE_BINDING).is_empty() + } + + /// Returns `true` if the queues of this family support a particular pipeline stage. + #[inline] + pub fn supports_stage(&self, stage: PipelineStage) -> bool { + !(self.properties.queue_flags & stage.required_queue_flags()).is_empty() + } +} + +impl<'a> PartialEq for QueueFamily<'a> { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + && self.physical_device.internal_object() == other.physical_device.internal_object() + } +} + +impl<'a> Eq for QueueFamily<'a> {} + +/// The version of the Vulkan conformance test that a driver is conformant against. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct ConformanceVersion { + pub major: u8, + pub minor: u8, + pub subminor: u8, + pub patch: u8, +} + +impl From<ash::vk::ConformanceVersion> for ConformanceVersion { + #[inline] + fn from(val: ash::vk::ConformanceVersion) -> Self { + ConformanceVersion { + major: val.major, + minor: val.minor, + subminor: val.subminor, + patch: val.patch, + } + } +} + +impl fmt::Debug for ConformanceVersion { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch) + } +} + +impl fmt::Display for ConformanceVersion { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self, formatter) + } +} + +/// An identifier for the driver of a physical device. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[repr(i32)] +pub enum DriverId { + AMDProprietary = ash::vk::DriverId::AMD_PROPRIETARY.as_raw(), + AMDOpenSource = ash::vk::DriverId::AMD_OPEN_SOURCE.as_raw(), + MesaRADV = ash::vk::DriverId::MESA_RADV.as_raw(), + NvidiaProprietary = ash::vk::DriverId::NVIDIA_PROPRIETARY.as_raw(), + IntelProprietaryWindows = ash::vk::DriverId::INTEL_PROPRIETARY_WINDOWS.as_raw(), + IntelOpenSourceMesa = ash::vk::DriverId::INTEL_OPEN_SOURCE_MESA.as_raw(), + ImaginationProprietary = ash::vk::DriverId::IMAGINATION_PROPRIETARY.as_raw(), + QualcommProprietary = ash::vk::DriverId::QUALCOMM_PROPRIETARY.as_raw(), + ARMProprietary = ash::vk::DriverId::ARM_PROPRIETARY.as_raw(), + GoogleSwiftshader = ash::vk::DriverId::GOOGLE_SWIFTSHADER.as_raw(), + GGPProprietary = ash::vk::DriverId::GGP_PROPRIETARY.as_raw(), + BroadcomProprietary = ash::vk::DriverId::BROADCOM_PROPRIETARY.as_raw(), + MesaLLVMpipe = ash::vk::DriverId::MESA_LLVMPIPE.as_raw(), + MoltenVK = ash::vk::DriverId::MOLTENVK.as_raw(), +} + +impl TryFrom<ash::vk::DriverId> for DriverId { + type Error = (); + + #[inline] + fn try_from(val: ash::vk::DriverId) -> Result<Self, Self::Error> { + match val { + ash::vk::DriverId::AMD_PROPRIETARY => Ok(Self::AMDProprietary), + ash::vk::DriverId::AMD_OPEN_SOURCE => Ok(Self::AMDOpenSource), + ash::vk::DriverId::MESA_RADV => Ok(Self::MesaRADV), + ash::vk::DriverId::NVIDIA_PROPRIETARY => Ok(Self::NvidiaProprietary), + ash::vk::DriverId::INTEL_PROPRIETARY_WINDOWS => Ok(Self::IntelProprietaryWindows), + ash::vk::DriverId::INTEL_OPEN_SOURCE_MESA => Ok(Self::IntelOpenSourceMesa), + ash::vk::DriverId::IMAGINATION_PROPRIETARY => Ok(Self::ImaginationProprietary), + ash::vk::DriverId::QUALCOMM_PROPRIETARY => Ok(Self::QualcommProprietary), + ash::vk::DriverId::ARM_PROPRIETARY => Ok(Self::ARMProprietary), + ash::vk::DriverId::GOOGLE_SWIFTSHADER => Ok(Self::GoogleSwiftshader), + ash::vk::DriverId::GGP_PROPRIETARY => Ok(Self::GGPProprietary), + ash::vk::DriverId::BROADCOM_PROPRIETARY => Ok(Self::BroadcomProprietary), + ash::vk::DriverId::MESA_LLVMPIPE => Ok(Self::MesaLLVMpipe), + ash::vk::DriverId::MOLTENVK => Ok(Self::MoltenVK), + _ => Err(()), + } + } +} + +/// Specifies which subgroup operations are supported. +#[derive(Clone, Copy, Debug)] +pub struct SubgroupFeatures { + pub basic: bool, + pub vote: bool, + pub arithmetic: bool, + pub ballot: bool, + pub shuffle: bool, + pub shuffle_relative: bool, + pub clustered: bool, + pub quad: bool, +} + +impl From<ash::vk::SubgroupFeatureFlags> for SubgroupFeatures { + #[inline] + fn from(val: ash::vk::SubgroupFeatureFlags) -> Self { + Self { + basic: val.intersects(ash::vk::SubgroupFeatureFlags::BASIC), + vote: val.intersects(ash::vk::SubgroupFeatureFlags::VOTE), + arithmetic: val.intersects(ash::vk::SubgroupFeatureFlags::ARITHMETIC), + ballot: val.intersects(ash::vk::SubgroupFeatureFlags::BALLOT), + shuffle: val.intersects(ash::vk::SubgroupFeatureFlags::SHUFFLE), + shuffle_relative: val.intersects(ash::vk::SubgroupFeatureFlags::SHUFFLE_RELATIVE), + clustered: val.intersects(ash::vk::SubgroupFeatureFlags::CLUSTERED), + quad: val.intersects(ash::vk::SubgroupFeatureFlags::QUAD), + } + } +} + +/// Specifies how the device clips single point primitives. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[repr(i32)] +pub enum PointClippingBehavior { + /// Points are clipped if they lie outside any clip plane, both those bounding the view volume + /// and user-defined clip planes. + AllClipPlanes = ash::vk::PointClippingBehavior::ALL_CLIP_PLANES.as_raw(), + /// Points are clipped only if they lie outside a user-defined clip plane. + UserClipPlanesOnly = ash::vk::PointClippingBehavior::USER_CLIP_PLANES_ONLY.as_raw(), +} + +impl TryFrom<ash::vk::PointClippingBehavior> for PointClippingBehavior { + type Error = (); + + #[inline] + fn try_from(val: ash::vk::PointClippingBehavior) -> Result<Self, Self::Error> { + match val { + ash::vk::PointClippingBehavior::ALL_CLIP_PLANES => Ok(Self::AllClipPlanes), + ash::vk::PointClippingBehavior::USER_CLIP_PLANES_ONLY => Ok(Self::UserClipPlanesOnly), + _ => Err(()), + } + } +} + +/// Specifies whether, and how, shader float controls can be set independently. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[repr(i32)] +pub enum ShaderFloatControlsIndependence { + Float32Only = ash::vk::ShaderFloatControlsIndependence::TYPE_32_ONLY.as_raw(), + All = ash::vk::ShaderFloatControlsIndependence::ALL.as_raw(), + None = ash::vk::ShaderFloatControlsIndependence::NONE.as_raw(), +} + +impl TryFrom<ash::vk::ShaderFloatControlsIndependence> for ShaderFloatControlsIndependence { + type Error = (); + + #[inline] + fn try_from(val: ash::vk::ShaderFloatControlsIndependence) -> Result<Self, Self::Error> { + match val { + ash::vk::ShaderFloatControlsIndependence::TYPE_32_ONLY => Ok(Self::Float32Only), + ash::vk::ShaderFloatControlsIndependence::ALL => Ok(Self::All), + ash::vk::ShaderFloatControlsIndependence::NONE => Ok(Self::None), + _ => Err(()), + } + } +} + +/// Specifies shader core properties. +#[derive(Clone, Copy, Debug)] +pub struct ShaderCoreProperties {} + +impl From<ash::vk::ShaderCorePropertiesFlagsAMD> for ShaderCoreProperties { + #[inline] + fn from(val: ash::vk::ShaderCorePropertiesFlagsAMD) -> Self { + Self {} + } +} |