render_vulkan: Fixes

- Avoid create device for each physical device during support checking
- Avoid to select different queue family index and add support of creating multiple queues on same queue family
- Log select queue family index for each queue type
This commit is contained in:
Florian RICHER 2025-05-21 13:42:36 +02:00
parent 7951b05ab3
commit 18174e42e9
Signed by: florian.richer
GPG key ID: C73D37CBED7BFC77
2 changed files with 77 additions and 114 deletions

View file

@ -1,8 +1,9 @@
use std::sync::Arc;
use std::{collections::HashMap, 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::{
@ -86,22 +87,30 @@ fn pick_physical_device(world: &World, config: &VulkanConfig) -> Option<PickedDe
.get_resource::<VulkanInstance>()
.expect("Failed to get VulkanInstance during vulkan plugin initialization");
instance
let result = instance
.0
.enumerate_physical_devices()
.expect("Failed to enumerate physical devices")
.filter_map(|p| check_physical_device(world, &p, config))
.min_by_key(
|p| match p.device.physical_device().properties().device_type {
.filter_map(|p| check_physical_device_support(world, &p, config).and_then(|r| Some((p, r))))
.min_by_key(|(p, _)| match p.properties().device_type {
PhysicalDeviceType::DiscreteGpu => 0,
PhysicalDeviceType::IntegratedGpu => 1,
PhysicalDeviceType::VirtualGpu => 2,
PhysicalDeviceType::Cpu => 3,
PhysicalDeviceType::Other => 4,
_ => 5,
},
)
.take()
})
.take();
match result {
Some((p, (device_extensions, picked_queues_info))) => Some(create_device(
config,
&p,
device_extensions,
&picked_queues_info,
)),
None => None,
}
}
fn check_device_extensions_support(
@ -147,7 +156,7 @@ fn check_queues_support(
let mut transfer_queue_family_index: Option<u32> = None;
for (i, queue_family_property) in physical_device.queue_family_properties().iter().enumerate() {
if config.with_graphics_queue {
if config.with_graphics_queue && graphics_queue_family_index.is_none() {
let graphics_supported = queue_family_property
.queue_flags
.intersects(QueueFlags::GRAPHICS);
@ -169,7 +178,7 @@ fn check_queues_support(
}
}
if config.with_compute_queue {
if config.with_compute_queue && compute_queue_family_index.is_none() {
let compute_supported = queue_family_property
.queue_flags
.intersects(QueueFlags::COMPUTE);
@ -179,7 +188,7 @@ fn check_queues_support(
}
}
if config.with_transfer_queue {
if config.with_transfer_queue && transfer_queue_family_index.is_none() {
let transfer_supported = queue_family_property
.queue_flags
.intersects(QueueFlags::TRANSFER);
@ -193,7 +202,10 @@ fn check_queues_support(
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");
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;
@ -202,7 +214,10 @@ fn check_queues_support(
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");
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;
@ -211,7 +226,10 @@ fn check_queues_support(
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");
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;
@ -224,11 +242,11 @@ fn check_queues_support(
})
}
fn check_physical_device(
fn check_physical_device_support(
world: &World,
physical_device: &Arc<PhysicalDevice>,
config: &VulkanConfig,
) -> Option<PickedDevice> {
) -> Option<(DeviceExtensions, PickedQueuesInfo)> {
log::debug!("Checking physical device");
log::debug!("\tProperties");
log::debug!("\t\tName: {}", physical_device.properties().device_name);
@ -242,33 +260,54 @@ fn check_physical_device(
let device_extensions = check_device_extensions_support(physical_device, config)?;
let picked_queues_info = check_queues_support(world, physical_device, config)?;
let mut queue_create_infos = vec![];
Some((device_extensions, picked_queues_info))
}
fn create_device(
config: &VulkanConfig,
physical_device: &Arc<PhysicalDevice>,
device_extensions: DeviceExtensions,
picked_queues_info: &PickedQueuesInfo,
) -> PickedDevice {
let mut queue_create_infos = HashMap::<u32, QueueCreateInfo>::new();
if config.with_graphics_queue {
queue_create_infos.push(QueueCreateInfo {
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 {
queue_create_infos.push(QueueCreateInfo {
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 {
queue_create_infos.push(QueueCreateInfo {
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: queue_create_infos.values().cloned().collect(),
enabled_extensions: device_extensions,
enabled_features: config.device_features,
..Default::default()
@ -292,10 +331,10 @@ fn check_physical_device(
transfer_queue = queues.next();
}
Some(PickedDevice {
PickedDevice {
device,
graphics_queue,
compute_queue,
transfer_queue,
})
}
}

View file

@ -1,76 +0,0 @@
use std::{any::Any, sync::Arc};
use bevy_app::App;
use bevy_ecs::resource::Resource;
use engine_window::raw_handle::DisplayHandleWrapper;
use vulkano::{
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, PrimaryAutoCommandBuffer,
allocator::StandardCommandBufferAllocator,
},
descriptor_set::allocator::StandardDescriptorSetAllocator,
device::{Device, Queue},
instance::Instance,
memory::allocator::StandardMemoryAllocator,
swapchain::Surface,
};
use winit::raw_window_handle::{HasDisplayHandle, HasWindowHandle};
use super::utils;
#[derive(Resource)]
pub struct VulkanContext {
pub instance: Arc<Instance>,
pub device: Arc<Device>,
pub graphics_queue: Arc<Queue>,
pub memory_allocator: Arc<StandardMemoryAllocator>,
pub command_buffer_allocator: Arc<StandardCommandBufferAllocator>,
pub descriptor_set_allocator: Arc<StandardDescriptorSetAllocator>,
}
impl VulkanContext {
pub fn create_surface(
&self,
window: Arc<impl HasWindowHandle + HasDisplayHandle + Any + Send + Sync>,
) -> Arc<Surface> {
Surface::from_window(self.instance.clone(), window).unwrap()
}
pub fn create_render_builder(&self) -> AutoCommandBufferBuilder<PrimaryAutoCommandBuffer> {
AutoCommandBufferBuilder::primary(
self.command_buffer_allocator.clone(),
self.graphics_queue.queue_family_index(),
CommandBufferUsage::OneTimeSubmit,
)
.unwrap()
}
}
impl From<&App> for VulkanContext {
fn from(app: &App) -> Self {
let (device, mut queues) = utils::pick_graphics_device(&instance, &display_handle.0);
let graphics_queue = queues.next().unwrap();
let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone()));
let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new(
device.clone(),
Default::default(),
));
let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new(
device.clone(),
Default::default(),
));
Self {
instance: instance.clone(),
device,
graphics_queue,
memory_allocator,
command_buffer_allocator,
descriptor_set_allocator,
}
}
}