feat(renderer): wire vulkan debug messenger to tracing
Implemented the Vulkan debug callback to intercept internal driver warnings and validation layer errors, converting them into tracing logs. Resolved unused assignment and unsafe pointer 2024 edition warnings. Added doc comments for the Renderer and its initialization logic.
This commit is contained in:
parent
e20126fea5
commit
edcde4ffd1
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -1055,6 +1055,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"ash",
|
||||
"thiserror 2.0.18",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -6,3 +6,4 @@ edition = "2024"
|
|||
[dependencies]
|
||||
ash = "0.38.0"
|
||||
thiserror = "2.0.18"
|
||||
tracing = "0.1.44"
|
||||
|
|
|
|||
|
|
@ -1,13 +1,21 @@
|
|||
pub mod error;
|
||||
|
||||
use std::ffi::c_char;
|
||||
use ash::{Entry, Instance, vk};
|
||||
use std::ffi::{CStr, c_char};
|
||||
use ash::{Entry, Instance, ext, vk};
|
||||
use tracing::{debug, error, info, warn};
|
||||
|
||||
pub use error::RendererError;
|
||||
|
||||
/// The core renderer structure holding the Vulkan instance and debug resources.
|
||||
pub struct Renderer {
|
||||
/// The entry point to the Vulkan library.
|
||||
_entry: Entry,
|
||||
/// The Vulkan instance handle.
|
||||
instance: Instance,
|
||||
/// The debug utils instance, if enabled (debug builds only).
|
||||
debug_utils: Option<ext::debug_utils::Instance>,
|
||||
/// The debug messenger handle, if enabled (debug builds only).
|
||||
debug_messenger: vk::DebugUtilsMessengerEXT,
|
||||
}
|
||||
|
||||
impl Renderer {
|
||||
|
|
@ -16,12 +24,14 @@ impl Renderer {
|
|||
pub fn new(required_extensions: &[*const c_char]) -> Result<Self, RendererError> {
|
||||
let entry = unsafe { Entry::load() }?;
|
||||
|
||||
// Prepare extensions and layers
|
||||
let mut extensions: Vec<*const c_char> = required_extensions.to_vec();
|
||||
let mut layers: Vec<*const c_char> = Vec::new();
|
||||
|
||||
// Enable debug extensions and validation layers in debug builds
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
extensions.push(ash::ext::debug_utils::NAME.as_ptr());
|
||||
extensions.push(ext::debug_utils::NAME.as_ptr());
|
||||
layers.push(c"VK_LAYER_KHRONOS_validation".as_ptr());
|
||||
}
|
||||
|
||||
|
|
@ -33,11 +43,70 @@ impl Renderer {
|
|||
.enabled_extension_names(&extensions)
|
||||
.enabled_layer_names(&layers);
|
||||
|
||||
// Create the Vulkan instance
|
||||
let instance = unsafe { entry.create_instance(&create_info, None)? };
|
||||
|
||||
// Setup debug messenger for validation layer feedback
|
||||
#[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(Self {
|
||||
_entry: entry,
|
||||
instance,
|
||||
debug_utils,
|
||||
debug_messenger,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// The callback function invoked by Vulkan's validation layers.
|
||||
///
|
||||
/// This function translates Vulkan debug messages into `tracing` events.
|
||||
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 {
|
||||
// Safety: p_callback_data is guaranteed to be valid by the Vulkan spec
|
||||
let callback_data = unsafe { *p_callback_data };
|
||||
|
||||
// Convert raw C string to Rust string for logging
|
||||
let message = if callback_data.p_message.is_null() {
|
||||
"".into()
|
||||
} else {
|
||||
unsafe { CStr::from_ptr(callback_data.p_message).to_string_lossy() }
|
||||
};
|
||||
|
||||
// Route severity to matching tracing macro
|
||||
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}"),
|
||||
}
|
||||
|
||||
// TRUE aborts the Vulkan call that triggered the warning
|
||||
vk::FALSE
|
||||
}
|
||||
Loading…
Reference in a new issue