use std::{collections::HashMap, sync::Arc}; use engine_window::raw_handle::DisplayHandleWrapper; use vulkano::device::{ QueueCreateInfo, QueueFamilyProperties, QueueFlags, physical::PhysicalDevice, }; #[derive(Debug)] pub enum VulkanQueueFamilyStatus { Unused, NotSupported, Supported(u32), } impl VulkanQueueFamilyStatus { pub fn can_be_set(&self) -> bool { match self { VulkanQueueFamilyStatus::NotSupported => true, _ => false, } } } /// Convert a boolean to a VulkanQueueFamilyStatus as default value impl From for VulkanQueueFamilyStatus { fn from(value: bool) -> Self { if value { VulkanQueueFamilyStatus::NotSupported } else { VulkanQueueFamilyStatus::Unused } } } /// Convert a DisplayHandleWrapper Option to a VulkanQueueFamilyStatus as default value impl From> for VulkanQueueFamilyStatus { fn from(value: Option<&DisplayHandleWrapper>) -> Self { if value.is_some() { VulkanQueueFamilyStatus::NotSupported } else { VulkanQueueFamilyStatus::Unused } } } #[derive(Debug)] pub struct VulkanQueueFamilyIndices { pub graphics_queue_family_index: VulkanQueueFamilyStatus, pub compute_queue_family_index: VulkanQueueFamilyStatus, pub transfer_queue_family_index: VulkanQueueFamilyStatus, } impl From for Vec<(VulkanQueueFamilyStatus, f32)> { fn from(indices: VulkanQueueFamilyIndices) -> Self { vec![ (indices.graphics_queue_family_index, 1.0), (indices.compute_queue_family_index, 0.5), (indices.transfer_queue_family_index, 0.5), ] } } impl From for Vec { fn from(indices: VulkanQueueFamilyIndices) -> Self { let mut queue_create_infos = HashMap::::new(); let statuses: Vec<(VulkanQueueFamilyStatus, f32)> = indices.into(); for (status, priority) in statuses.iter() { match status { VulkanQueueFamilyStatus::Supported(index) => { let entry = queue_create_infos.entry(*index).or_insert(QueueCreateInfo { queue_family_index: *index, queues: Vec::new(), ..Default::default() }); entry.queues.push(*priority); } _ => {} } } queue_create_infos .into_iter() .map(|(_, value)| value) .collect() } } /// Convert a VulkanQueuesQuery to a VulkanQueuesFamilyIndices as default value impl<'a> From<&'a VulkanQueuesQuery<'a>> for VulkanQueueFamilyIndices { fn from(query: &'a VulkanQueuesQuery<'a>) -> Self { VulkanQueueFamilyIndices { graphics_queue_family_index: query.with_graphics_queue.into(), compute_queue_family_index: query.with_compute_queue.into(), transfer_queue_family_index: query.with_transfer_queue.into(), } } } pub struct VulkanQueuesQuery<'a> { pub with_surface: Option<&'a DisplayHandleWrapper>, pub with_graphics_queue: bool, pub with_compute_queue: bool, pub with_transfer_queue: bool, } pub fn find_queues_family_indices( physical_device: &Arc, query: &VulkanQueuesQuery, ) -> VulkanQueueFamilyIndices { let mut indices: VulkanQueueFamilyIndices = query.into(); for (i, queue_family_properties) in physical_device.queue_family_properties().iter().enumerate() { let mut available_queue_count = queue_family_properties.queue_count; if indices.graphics_queue_family_index.can_be_set() && check_queue_support(queue_family_properties, QueueFlags::GRAPHICS) && available_queue_count > 0 { if query.with_surface.is_none() || check_presentation_support( physical_device, i as u32, &query.with_surface.as_ref().unwrap(), ) { indices.graphics_queue_family_index = VulkanQueueFamilyStatus::Supported(i as u32); available_queue_count -= 1; } } if indices.compute_queue_family_index.can_be_set() && check_queue_support(queue_family_properties, QueueFlags::COMPUTE) && available_queue_count > 0 { indices.compute_queue_family_index = VulkanQueueFamilyStatus::Supported(i as u32); available_queue_count -= 1; } if indices.transfer_queue_family_index.can_be_set() && check_queue_support(queue_family_properties, QueueFlags::TRANSFER) && available_queue_count > 0 { indices.transfer_queue_family_index = VulkanQueueFamilyStatus::Supported(i as u32); } if !indices.graphics_queue_family_index.can_be_set() && !indices.compute_queue_family_index.can_be_set() && !indices.transfer_queue_family_index.can_be_set() { break; } } return indices; } fn check_presentation_support( physical_device: &Arc, queue_family_index: u32, surface: &DisplayHandleWrapper, ) -> bool { physical_device .presentation_support(queue_family_index, &surface.0) .unwrap() } fn check_queue_support( queue_family_property: &QueueFamilyProperties, queue_flags: QueueFlags, ) -> bool { queue_family_property.queue_flags.intersects(queue_flags) }