diff --git a/crates/renderer/src/error.rs b/crates/renderer/src/error.rs index 923b351..6f44e31 100644 --- a/crates/renderer/src/error.rs +++ b/crates/renderer/src/error.rs @@ -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, } \ No newline at end of file diff --git a/crates/renderer/src/lib.rs b/crates/renderer/src/lib.rs index a9c5ac2..7b1da1c 100644 --- a/crates/renderer/src/lib.rs +++ b/crates/renderer/src/lib.rs @@ -16,6 +16,8 @@ pub struct Renderer { debug_utils: Option, /// 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 { + 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.