use ash::vk; use std::ffi::CStr; pub struct QueueFamilyIndices { graphics_family: Option, } impl QueueFamilyIndices { pub fn is_complete(&self) -> bool { self.graphics_family.is_some() } pub fn graphics_family(&self) -> u32 { self.graphics_family.unwrap() } } pub(crate) fn pick_physical_device(instance: &ash::Instance) -> vk::PhysicalDevice { let physical_devices = unsafe { instance .enumerate_physical_devices() .expect("Failed to enumerate Physical Devices!") }; let mut result = None; for &physical_device in physical_devices.iter() { if is_physical_device_suitable(instance, physical_device) { if result.is_none() { result = Some(physical_device) } } } match result { None => panic!("Failed to find a suitable GPU!"), Some(physical_device) => physical_device, } } fn is_physical_device_suitable( instance: &ash::Instance, physical_device: vk::PhysicalDevice, ) -> bool { let device_properties = unsafe { instance.get_physical_device_properties(physical_device) }; let device_features = unsafe { instance.get_physical_device_features(physical_device) }; let device_queue_families = unsafe { instance.get_physical_device_queue_family_properties(physical_device) }; let device_type = match device_properties.device_type { vk::PhysicalDeviceType::CPU => "Cpu", vk::PhysicalDeviceType::INTEGRATED_GPU => "Integrated GPU", vk::PhysicalDeviceType::DISCRETE_GPU => "Discrete GPU", vk::PhysicalDeviceType::VIRTUAL_GPU => "Virtual GPU", vk::PhysicalDeviceType::OTHER => "Unknown", _ => panic!(), }; let device_name = unsafe { CStr::from_ptr(device_properties.device_name.as_ptr()) }; let device_name = device_name.to_string_lossy(); println!( "\tDevice Name: {}, id: {}, type: {}", device_name, device_properties.device_id, device_type ); println!("\tAPI Version: {}", device_properties.api_version); println!("\tSupport Queue Family: {}", device_queue_families.len()); println!("\t\tQueue Count | Graphics, Compute, Transfer, Sparse Binding"); for queue_family in device_queue_families.iter() { let is_graphics_support = if queue_family.queue_flags.contains(vk::QueueFlags::GRAPHICS) { "support" } else { "unsupport" }; let is_compute_support = if queue_family.queue_flags.contains(vk::QueueFlags::COMPUTE) { "support" } else { "unsupport" }; let is_transfer_support = if queue_family.queue_flags.contains(vk::QueueFlags::TRANSFER) { "support" } else { "unsupport" }; let is_sparse_support = if queue_family .queue_flags .contains(vk::QueueFlags::SPARSE_BINDING) { "support" } else { "unsupport" }; println!( "\t\t{}\t | {}, {}, {}, {}", queue_family.queue_count, is_graphics_support, is_compute_support, is_transfer_support, is_sparse_support ); } // there are plenty of features println!( "\tGeometry Shader support: {}", if device_features.geometry_shader == 1 { "support" } else { "unsupported" } ); let indices = find_queue_family(instance, physical_device); return indices.is_complete(); } pub fn find_queue_family( instance: &ash::Instance, physical_device: vk::PhysicalDevice, ) -> QueueFamilyIndices { let queue_families = unsafe { instance.get_physical_device_queue_family_properties(physical_device) }; let mut queue_family_indices = QueueFamilyIndices { graphics_family: None, }; let mut index = 0; for queue_family in queue_families.iter() { if queue_family.queue_count > 0 && queue_family.queue_flags.contains(vk::QueueFlags::GRAPHICS) { queue_family_indices.graphics_family = Some(index); } if queue_family_indices.is_complete() { break; } index += 1; } queue_family_indices }