// SPDX-License-Identifier: AGPL-3.0-only use crate::error::RendererError; use ash::{Entry, Instance, ext, vk}; use std::ffi::{CStr, c_char}; use tracing::{debug, error, info, warn}; /// Creates a Vulkan instance and optionally a debug messenger. pub fn create_instance( entry: &Entry, required_extensions: &[*const c_char], ) -> Result< ( Instance, Option, vk::DebugUtilsMessengerEXT, ), RendererError, > { let mut extensions = required_extensions.to_vec(); let mut layers = Vec::new(); #[cfg(debug_assertions)] { extensions.push(ext::debug_utils::NAME.as_ptr()); layers.push(c"VK_LAYER_KHRONOS_validation".as_ptr()); } let app_info = vk::ApplicationInfo::default().api_version(vk::API_VERSION_1_3); let create_info = vk::InstanceCreateInfo::default() .application_info(&app_info) .enabled_extension_names(&extensions) .enabled_layer_names(&layers); let instance = unsafe { entry.create_instance(&create_info, None)? }; #[cfg(debug_assertions)] let (debug_utils, debug_messenger) = { let debug_info = vk::DebugUtilsMessengerCreateInfoEXT::default() .message_severity( vk::DebugUtilsMessageSeverityFlagsEXT::WARNING | vk::DebugUtilsMessageSeverityFlagsEXT::ERROR, ) .message_type( vk::DebugUtilsMessageTypeFlagsEXT::GENERAL | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE, ) .pfn_user_callback(Some(vulkan_debug_callback)); let utils = ext::debug_utils::Instance::new(entry, &instance); let messenger = unsafe { utils.create_debug_utils_messenger(&debug_info, None)? }; (Some(utils), messenger) }; #[cfg(not(debug_assertions))] let (debug_utils, debug_messenger) = (None, vk::DebugUtilsMessengerEXT::null()); Ok((instance, debug_utils, debug_messenger)) } /// The callback function invoked by Vulkan's validation layers. unsafe extern "system" fn vulkan_debug_callback( message_severity: vk::DebugUtilsMessageSeverityFlagsEXT, _message_type: vk::DebugUtilsMessageTypeFlagsEXT, p_callback_data: *const vk::DebugUtilsMessengerCallbackDataEXT<'_>, _user_data: *mut std::ffi::c_void, ) -> vk::Bool32 { let callback_data = unsafe { *p_callback_data }; let message = if callback_data.p_message.is_null() { "".into() } else { unsafe { CStr::from_ptr(callback_data.p_message).to_string_lossy() } }; match message_severity { vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE => debug!("{message}"), vk::DebugUtilsMessageSeverityFlagsEXT::INFO => info!("{message}"), vk::DebugUtilsMessageSeverityFlagsEXT::WARNING => warn!("{message}"), vk::DebugUtilsMessageSeverityFlagsEXT::ERROR => error!("{message}"), _ => info!("{message}"), } vk::FALSE }