use std::{ ffi::{CStr, CString}, sync::Arc, }; use ash::{Entry, ext, vk}; use raw_window_handle::RawDisplayHandle; use crate::{ device::{Extension, get_extensions, get_layers}, make_extension, }; pub struct DebugUtilsCreateInfo { pub severity: vk::DebugUtilsMessageSeverityFlagsEXT, pub message_type: vk::DebugUtilsMessageTypeFlagsEXT, } pub struct InstanceInner { pub raw: ash::Instance, pub entry: Entry, pub(crate) _debug_utils: DebugUtils, } #[derive(Clone)] pub struct Instance { pub(crate) inner: Arc, } impl core::fmt::Debug for Instance { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Instance") .field("raw", &self.inner.raw.handle()) .finish_non_exhaustive() } } pub struct InstanceDesc<'a> { pub app_name: Option<&'a str>, pub app_version: u32, pub instance_extensions: &'a [&'a CStr], pub layer_settings: &'a [vk::LayerSettingEXT<'a>], pub layers: &'a [&'a CStr], pub display_handle: Option, } impl Instance { pub fn new<'a>(desc: &InstanceDesc<'a>) -> crate::Result { let entry = unsafe { ash::Entry::load()? }; let app_name = desc .app_name .and_then(|name| CString::new(name).ok()) .unwrap_or(c"ShooterGame".to_owned()); let version = unsafe { entry.try_enumerate_instance_version()? }.unwrap_or(vk::API_VERSION_1_0); let app_info = vk::ApplicationInfo::default() .api_version(if version < vk::API_VERSION_1_1 { vk::API_VERSION_1_0 } else { // ash doesn't support 1.4 yet vk::API_VERSION_1_3 }) .application_name(&app_name) .application_version(desc.app_version) .engine_name(c"Bevy Engine") .engine_version(vk::make_api_version(0, 0, 1, 0)); let mut validation_info = vk::LayerSettingsCreateInfoEXT::default().settings(desc.layer_settings); let layers = match get_layers(&entry, desc.layers.to_vec()) { Ok(layers) => layers, Err((supported, unsupported)) => { tracing::error!( "Some requested layers were not supported by instance:\nSupported: {:?}\nUnsupported: {:?}", supported, unsupported ); supported } }; let mut requested_extensions = desc .instance_extensions .iter() .map(|name| Extension { name, version: 0 }) .collect::>(); requested_extensions.push(make_extension!(ext::debug_utils as 1)); #[cfg(debug_assertions)] requested_extensions.push(make_extension!(ext::layer_settings)); let (extensions, unsupported_extensions) = get_extensions(&entry, &layers, requested_extensions, desc.display_handle)?; if !unsupported_extensions.is_empty() { tracing::error!( "extensions were requested but not supported by instance: {:?}", unsupported_extensions ); } let layers = layers .iter() .map(|layer| layer.as_ptr()) .collect::>(); let extensions = extensions .iter() .map(|ext| ext.name.as_ptr()) .collect::>(); let create_info = vk::InstanceCreateInfo::default() .application_info(&app_info) .enabled_extension_names(&extensions) .enabled_layer_names(&layers) .push_next(&mut validation_info); tracing::debug!( "Creating instance:\napp_info: {app_info:#?}\ncreate_info: {create_info:#?}" ); let instance = unsafe { entry.create_instance(&create_info, None)? }; let debug_utils = { let debug_info = vk::DebugUtilsMessengerCreateInfoEXT::default() .message_severity( vk::DebugUtilsMessageSeverityFlagsEXT::ERROR | vk::DebugUtilsMessageSeverityFlagsEXT::WARNING | vk::DebugUtilsMessageSeverityFlagsEXT::INFO, ) .message_type( vk::DebugUtilsMessageTypeFlagsEXT::GENERAL | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE, ) .pfn_user_callback(Some(crate::debug::debug_callback)); let instance = ext::debug_utils::Instance::new(&entry, &instance); let messenger = unsafe { instance.create_debug_utils_messenger(&debug_info, None)? }; crate::DebugUtils { instance, messenger, } }; let instance = Arc::new(InstanceInner { raw: instance, _debug_utils: debug_utils, entry, }); Ok(Self { inner: instance }) } } pub(crate) struct DebugUtils { pub instance: ext::debug_utils::Instance, pub messenger: vk::DebugUtilsMessengerEXT, } impl Drop for DebugUtils { fn drop(&mut self) { unsafe { self.instance .destroy_debug_utils_messenger(self.messenger, None); } } }