feat(renderer): implement physical device selection

Added logic to enumerate and score physical devices, preferring discrete GPUs. Added NoSuitableGpu error variant and documentation for the selection process.
This commit is contained in:
Serkyo 2026-04-30 13:46:46 +02:00
parent edcde4ffd1
commit 7034a24498
2 changed files with 38 additions and 1 deletions

View file

@ -5,5 +5,7 @@ pub enum RendererError {
#[error("Failed to load Vulkan library")]
LoadFailed(#[from] ash::LoadingError),
#[error("Failed to create Vulkan instance")]
InstanceCreateFailed(#[from] ash::vk::Result)
InstanceCreateFailed(#[from] ash::vk::Result),
#[error("No suitable GPU found")]
NoSuitableGpu,
}

View file

@ -16,6 +16,8 @@ pub struct Renderer {
debug_utils: Option<ext::debug_utils::Instance>,
/// The debug messenger handle, if enabled (debug builds only).
debug_messenger: vk::DebugUtilsMessengerEXT,
/// The selected physical device (GPU).
physical_device: vk::PhysicalDevice,
}
impl Renderer {
@ -70,13 +72,46 @@ impl Renderer {
#[cfg(not(debug_assertions))]
let (debug_utils, debug_messenger) = (None, vk::DebugUtilsMessengerEXT::null());
let physical_device = Self::pick_physical_device(&instance)?;
Ok(Self {
_entry: entry,
instance,
debug_utils,
debug_messenger,
physical_device,
})
}
/// Selects the best physical device (GPU) available on the system.
///
/// This function filters for devices supporting graphics operations and scores
/// them based on their type, preferring discrete GPUs.
fn pick_physical_device(instance: &Instance) -> Result<vk::PhysicalDevice, RendererError> {
let devices = unsafe { instance.enumerate_physical_devices()? };
let selected = devices.into_iter()
.filter(|&device| {
// Check if the device has a queue family that supports graphics
let props = unsafe { instance.get_physical_device_queue_family_properties(device) };
props.iter().any(|p| p.queue_flags.contains(vk::QueueFlags::GRAPHICS))
})
.max_by_key(|&device| {
// Score the device based on its type
let props = unsafe { instance.get_physical_device_properties(device) };
match props.device_type {
vk::PhysicalDeviceType::DISCRETE_GPU => 1000,
vk::PhysicalDeviceType::INTEGRATED_GPU => 100,
_ => 1,
}
})
.ok_or(RendererError::NoSuitableGpu)?;
let props = unsafe { instance.get_physical_device_properties(selected) };
info!("Selected GPU: {:?}", unsafe { CStr::from_ptr(props.device_name.as_ptr()).to_string_lossy() });
Ok(selected)
}
}
/// The callback function invoked by Vulkan's validation layers.