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:
parent
edcde4ffd1
commit
7034a24498
|
|
@ -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,
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Reference in a new issue