use crate::vulkan::utils::formatter::format_instance_layer; use crate::vulkan::utils::layers::{use_layers, LayersSelector}; use crate::vulkan::vk_surface::VkSurface; use crate::vulkan::{VkPhysicalDevice, LOG_TARGET}; use ash::khr::surface; use ash::prelude::VkResult; use ash::vk::QueueFlags; use ash::{vk, Entry, Instance}; use std::ffi::{c_char, CStr, CString}; use std::fmt::{Display, Formatter}; use winit::raw_window_handle::{HasDisplayHandle, HasWindowHandle}; pub struct VkInstance { entry: Entry, handle: Instance, } impl VkInstance { pub fn new( required_extensions: &Vec<*const c_char>, ) -> Self { let entry = Entry::linked(); log::debug!(target: LOG_TARGET, "Initializing Vulkan instance"); { let required_extensions = required_extensions .iter() .map(|str| unsafe { CStr::from_ptr(*str) }) .map(|cstr| cstr.to_string_lossy()) .collect::>(); log::debug!(target: LOG_TARGET, "Required instance extensions: {}", required_extensions.join(", ")); } // Layers let layers = use_layers( &entry, LayersSelector::SpecificLayers(vec![ "VK_LAYER_KHRONOS_validation", "VK_LAYER_MANGOHUD_overlay_x86_64", "VK_LAYER_NV_optimus" ]), ); { let layers = layers.iter() .map(|layer| layer.to_string_lossy()) .collect::>(); log::debug!(target: LOG_TARGET, "Selected debug layers : {}", layers.join(", ")) } let layers_raw = layers.iter().map(|s| s.as_ptr()).collect::>(); // App Info let app_name = CString::new("VulkanTriangle").unwrap(); let appinfo = vk::ApplicationInfo::default() .application_name(app_name.as_c_str()) .application_version(0) .engine_name(app_name.as_c_str()) .engine_version(0) .api_version(vk::make_api_version(0, 1, 0, 0)); let create_flags = if cfg!(any(target_os = "macos", target_os = "ios")) { vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR } else { vk::InstanceCreateFlags::default() }; // Instance Info let create_info = vk::InstanceCreateInfo::default() .application_info(&appinfo) .enabled_layer_names(&layers_raw) .enabled_extension_names(&required_extensions) .flags(create_flags); let instance: Instance = unsafe { entry .create_instance(&create_info, None) .expect("Instance creation error") }; log::debug!(target: LOG_TARGET, "Vulkan instance created"); Self { entry, handle: instance, } } pub fn get_physical_devices(&self) -> Vec { let physical_devices = unsafe { self.handle.enumerate_physical_devices() }; physical_devices .unwrap_or_default() .iter().map(|physical_device| VkPhysicalDevice::new(&self.handle, *physical_device)) .collect() } pub fn create_surface( &self, window: &crate::display::Window, ) -> anyhow::Result { let window_handle = window.handle() .ok_or_else(|| anyhow::anyhow!("Window handle is not available."))?; let surface_loader = surface::Instance::new(&self.entry, &self.handle); let surface = unsafe { ash_window::create_surface( &self.entry, &self.handle, window_handle.display_handle()?.as_raw(), window_handle.window_handle()?.as_raw(), None, )? }; log::debug!(target: LOG_TARGET, "Surface created"); Ok(VkSurface::new( surface_loader, surface, )) } pub fn create_device( &self, physical_device: &VkPhysicalDevice, create_info: &vk::DeviceCreateInfo, allocation_callbacks: Option<&vk::AllocationCallbacks>, ) -> VkResult { unsafe { self.handle.create_device(physical_device.handle, &create_info, allocation_callbacks) } } } impl Drop for VkInstance { fn drop(&mut self) { unsafe { self.handle.destroy_instance(None); } log::debug!(target: LOG_TARGET, "Vulkan instance destroyed"); } } impl Display for VkInstance { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { writeln!(f, "")?; let instance_layers = unsafe { self.entry.enumerate_instance_layer_properties().unwrap_or_default() }; writeln!(f, "Instance layers ({}) :", instance_layers.len())?; for instance_layer in &instance_layers { writeln!(f, "{}", format_instance_layer(instance_layer))?; } writeln!(f, "")?; let physical_devices = self.get_physical_devices(); writeln!(f, "Physical Devices ({}) :", physical_devices.len())?; for physical_device in physical_devices { writeln!(f, "{physical_device}")?; } writeln!(f, "")?; Ok(()) } }