diff --git a/crates/engine_vulkan/src/utils/device.rs b/crates/engine_vulkan/src/device.rs similarity index 51% rename from crates/engine_vulkan/src/utils/device.rs rename to crates/engine_vulkan/src/device.rs index 38bf5fd..f20335f 100644 --- a/crates/engine_vulkan/src/utils/device.rs +++ b/crates/engine_vulkan/src/device.rs @@ -1,13 +1,12 @@ -use std::{collections::HashMap, sync::Arc}; +use std::sync::Arc; use bevy_ecs::world::World; use engine_window::raw_handle::DisplayHandleWrapper; use vulkano::{ - VulkanError, command_buffer::allocator::StandardCommandBufferAllocator, descriptor_set::allocator::StandardDescriptorSetAllocator, device::{ - Device, DeviceCreateInfo, DeviceExtensions, Queue, QueueCreateInfo, QueueFlags, + Device, DeviceCreateInfo, DeviceExtensions, Queue, physical::{PhysicalDevice, PhysicalDeviceType}, }, memory::allocator::StandardMemoryAllocator, @@ -16,6 +15,7 @@ use vulkano::{ use crate::{ VulkanCommandBufferAllocator, VulkanComputeQueue, VulkanConfig, VulkanDescriptorSetAllocator, VulkanDevice, VulkanGraphicsQueue, VulkanInstance, VulkanMemoryAllocator, VulkanTransferQueue, + queues::{VulkanQueueFamilyIndices, VulkanQueuesQuery, find_queues_family_indices}, }; pub fn create_and_insert_device(world: &mut World, config: &VulkanConfig) { @@ -101,12 +101,12 @@ fn pick_physical_device(world: &World, config: &VulkanConfig) -> Option 5, }) .take() - .and_then(|(p, (device_extensions, picked_queues_info))| { + .and_then(|(p, (device_extensions, queue_family_indices))| { Some(create_device( config, &p, device_extensions, - &picked_queues_info, + queue_family_indices, )) }) } @@ -138,121 +138,11 @@ fn check_device_extensions_support( } } -struct PickedQueuesInfo { - graphics_queue_family_index: Option, - compute_queue_family_index: Option, - transfer_queue_family_index: Option, -} - -fn check_queues_support( - world: &World, - physical_device: &Arc, - config: &VulkanConfig, -) -> Option { - let mut graphics_queue_family_index: Option = None; - let mut compute_queue_family_index: Option = None; - let mut transfer_queue_family_index: Option = None; - - for (i, queue_family_property) in physical_device.queue_family_properties().iter().enumerate() { - if config.with_graphics_queue && graphics_queue_family_index.is_none() { - let graphics_supported = queue_family_property - .queue_flags - .intersects(QueueFlags::GRAPHICS); - - let presentation_valid = if config.with_window_surface { - let display_handle = world - .get_resource::() - .expect("DisplayHandleWrapper must be added before VulkanPlugin"); - - physical_device - .presentation_support(i as u32, &display_handle.0) - .expect("Failed to check presentation support") - } else { - true - }; - - if graphics_supported && presentation_valid { - graphics_queue_family_index = Some(i as u32); - } - } - - if config.with_compute_queue && compute_queue_family_index.is_none() { - let compute_supported = queue_family_property - .queue_flags - .intersects(QueueFlags::COMPUTE); - - if compute_supported { - compute_queue_family_index = Some(i as u32); - } - } - - if config.with_transfer_queue && transfer_queue_family_index.is_none() { - let transfer_supported = queue_family_property - .queue_flags - .intersects(QueueFlags::TRANSFER); - - if transfer_supported { - transfer_queue_family_index = Some(i as u32); - } - } - - if (!config.with_graphics_queue || graphics_queue_family_index.is_some()) - && (!config.with_compute_queue || compute_queue_family_index.is_some()) - && (!config.with_transfer_queue || transfer_queue_family_index.is_some()) - { - // We found all required queues, no need to continue iterating - break; - } - } - - if !config.with_graphics_queue { - log::debug!("\t\t[SKIPPED] Graphics queue is not required"); - } else if graphics_queue_family_index.is_some() { - log::debug!( - "\t\t[OK] Graphics queue is supported (family index: {:?})", - graphics_queue_family_index - ); - } else { - log::debug!("\t\t[FAILED] Graphics queue is not supported"); - return None; - } - - if !config.with_compute_queue { - log::debug!("\t\t[SKIPPED] Compute queue is not required"); - } else if compute_queue_family_index.is_some() { - log::debug!( - "\t\t[OK] Compute queue is supported (family index: {:?})", - compute_queue_family_index - ); - } else { - log::debug!("\t\t[FAILED] Compute queue is not supported"); - return None; - } - - if !config.with_transfer_queue { - log::debug!("\t\t[SKIPPED] Transfer queue is not required"); - } else if transfer_queue_family_index.is_some() { - log::debug!( - "\t\t[OK] Transfer queue is supported (family index: {:?})", - transfer_queue_family_index - ); - } else { - log::debug!("\t\t[FAILED] Transfer queue is not supported"); - return None; - } - - Some(PickedQueuesInfo { - graphics_queue_family_index, - compute_queue_family_index, - transfer_queue_family_index, - }) -} - fn check_physical_device_support( world: &World, physical_device: &Arc, config: &VulkanConfig, -) -> Option<(DeviceExtensions, PickedQueuesInfo)> { +) -> Option<(DeviceExtensions, VulkanQueueFamilyIndices)> { log::debug!("Checking physical device"); log::debug!("\tProperties"); log::debug!("\t\tName: {}", physical_device.properties().device_name); @@ -264,56 +154,34 @@ fn check_physical_device_support( log::debug!("\tRequired supports checking report"); let device_extensions = check_device_extensions_support(physical_device, config)?; - let picked_queues_info = check_queues_support(world, physical_device, config)?; - Some((device_extensions, picked_queues_info)) + let display_handle = world + .get_resource::() + .expect("DisplayHandleWrapper must be added before VulkanPlugin"); + + let queue_support_query = VulkanQueuesQuery { + with_surface: Some(&display_handle), + with_graphics_queue: config.with_graphics_queue, + with_compute_queue: config.with_compute_queue, + with_transfer_queue: config.with_transfer_queue, + }; + + let queue_family_indices = find_queues_family_indices(physical_device, &queue_support_query); + log::debug!("\t\tQueue family indices: {:#?}", queue_family_indices); + + Some((device_extensions, queue_family_indices)) } fn create_device( config: &VulkanConfig, physical_device: &Arc, device_extensions: DeviceExtensions, - picked_queues_info: &PickedQueuesInfo, + queue_family_indices: VulkanQueueFamilyIndices, ) -> PickedDevice { - let mut queue_create_infos = HashMap::::new(); - - if config.with_graphics_queue { - let entry = queue_create_infos - .entry(picked_queues_info.graphics_queue_family_index.unwrap()) - .or_insert(QueueCreateInfo { - queue_family_index: picked_queues_info.graphics_queue_family_index.unwrap(), - ..Default::default() - }); - - entry.queues.push(1.0); - } - - if config.with_compute_queue { - let entry = queue_create_infos - .entry(picked_queues_info.compute_queue_family_index.unwrap()) - .or_insert(QueueCreateInfo { - queue_family_index: picked_queues_info.compute_queue_family_index.unwrap(), - ..Default::default() - }); - - entry.queues.push(1.0); - } - - if config.with_transfer_queue { - let entry = queue_create_infos - .entry(picked_queues_info.transfer_queue_family_index.unwrap()) - .or_insert(QueueCreateInfo { - queue_family_index: picked_queues_info.transfer_queue_family_index.unwrap(), - ..Default::default() - }); - - entry.queues.push(1.0); - } - let (device, mut queues) = Device::new( physical_device.clone(), DeviceCreateInfo { - queue_create_infos: queue_create_infos.values().cloned().collect(), + queue_create_infos: queue_family_indices.into(), enabled_extensions: device_extensions, enabled_features: config.device_features, ..Default::default() diff --git a/crates/engine_vulkan/src/utils/instance.rs b/crates/engine_vulkan/src/instance.rs similarity index 100% rename from crates/engine_vulkan/src/utils/instance.rs rename to crates/engine_vulkan/src/instance.rs diff --git a/crates/engine_vulkan/src/lib.rs b/crates/engine_vulkan/src/lib.rs index 4f5129b..38cb456 100644 --- a/crates/engine_vulkan/src/lib.rs +++ b/crates/engine_vulkan/src/lib.rs @@ -1,7 +1,7 @@ use std::sync::Arc; +use bevy_app::{App, Plugin}; use bevy_ecs::resource::Resource; -use utils::{device::create_and_insert_device, instance::create_and_insert_instance}; use vulkano::{ command_buffer::allocator::StandardCommandBufferAllocator, descriptor_set::allocator::StandardDescriptorSetAllocator, @@ -10,9 +10,11 @@ use vulkano::{ memory::allocator::StandardMemoryAllocator, }; -use bevy_app::{App, Plugin}; +mod device; +mod instance; +mod queues; -mod utils; +use crate::{device::create_and_insert_device, instance::create_and_insert_instance}; #[derive(Resource, Clone)] pub struct VulkanInstance(pub Arc); diff --git a/crates/engine_vulkan/src/queues.rs b/crates/engine_vulkan/src/queues.rs new file mode 100644 index 0000000..fc49dcc --- /dev/null +++ b/crates/engine_vulkan/src/queues.rs @@ -0,0 +1,174 @@ +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 present_queue_family_index: VulkanQueueFamilyStatus, + pub graphics_queue_family_index: VulkanQueueFamilyStatus, + pub compute_queue_family_index: VulkanQueueFamilyStatus, + pub transfer_queue_family_index: VulkanQueueFamilyStatus, +} + +impl From for Vec { + fn from(indices: VulkanQueueFamilyIndices) -> Self { + vec![ + indices.present_queue_family_index, + indices.graphics_queue_family_index, + indices.compute_queue_family_index, + indices.transfer_queue_family_index, + ] + } +} + +impl From for Vec { + fn from(indices: VulkanQueueFamilyIndices) -> Self { + let mut queue_create_infos = HashMap::::new(); + + let statuses: Vec = indices.into(); + + for status in statuses.iter() { + match status { + VulkanQueueFamilyStatus::Supported(index) => { + let entry = queue_create_infos.entry(*index).or_insert(QueueCreateInfo { + queue_family_index: *index, + ..Default::default() + }); + + entry.queues.push(1.0); + } + _ => {} + } + } + + 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 { + present_queue_family_index: query.with_surface.into(), + 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() + { + if indices.present_queue_family_index.can_be_set() + && check_presentation_support( + physical_device, + i as u32, + &query.with_surface.as_ref().unwrap(), + ) + { + indices.present_queue_family_index = VulkanQueueFamilyStatus::Supported(i as u32); + } + + if indices.graphics_queue_family_index.can_be_set() + && check_queue_support(queue_family_properties, QueueFlags::GRAPHICS) + { + indices.graphics_queue_family_index = VulkanQueueFamilyStatus::Supported(i as u32); + } + + if indices.compute_queue_family_index.can_be_set() + && check_queue_support(queue_family_properties, QueueFlags::COMPUTE) + { + indices.compute_queue_family_index = VulkanQueueFamilyStatus::Supported(i as u32); + } + + if indices.transfer_queue_family_index.can_be_set() + && check_queue_support(queue_family_properties, QueueFlags::TRANSFER) + { + indices.transfer_queue_family_index = VulkanQueueFamilyStatus::Supported(i as u32); + } + + if !indices.present_queue_family_index.can_be_set() + && !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) +} diff --git a/crates/engine_vulkan/src/utils/mod.rs b/crates/engine_vulkan/src/utils/mod.rs deleted file mode 100644 index 09e4b35..0000000 --- a/crates/engine_vulkan/src/utils/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod device; -pub mod instance;