use ash::vk;
use ferroui_base::logging::{LogEventLevel, Logger};
use std::ffi::{c_void, CStr};
pub(crate) struct VulkanDebugLogger;
impl VulkanDebugLogger {
pub fn callback_ptr() -> vk::PFN_vkDebugUtilsMessengerCallbackEXT {
Some(write_log_event)
}
pub fn level_of(message_severity: vk::DebugUtilsMessageSeverityFlagsEXT) -> LogEventLevel {
if message_severity == vk::DebugUtilsMessageSeverityFlagsEXT::ERROR {
LogEventLevel::Error
} else if message_severity == vk::DebugUtilsMessageSeverityFlagsEXT::WARNING {
LogEventLevel::Warning
} else if message_severity == vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE {
LogEventLevel::Verbose
} else {
LogEventLevel::Information
}
}
}
unsafe extern "system" fn write_log_event(
message_severity: vk::DebugUtilsMessageSeverityFlagsEXT,
_message_types: vk::DebugUtilsMessageTypeFlagsEXT,
p_callback_data: *const vk::DebugUtilsMessengerCallbackDataEXT<'_>,
_p_user_data: *mut c_void,
) -> vk::Bool32 {
let level = VulkanDebugLogger::level_of(message_severity);
if let Some(logger) = Logger::try_get(level, "Vulkan") {
let msg = unsafe {
p_callback_data
.as_ref()
.filter(|data| !data.p_message.is_null())
.map(|data| CStr::from_ptr(data.p_message).to_string_lossy().into_owned())
}
.unwrap_or_default();
logger.log_with_values(None, "Vulkan: {0}", &[&msg]);
}
vk::FALSE
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_severity_maps_to_its_level() {
use vk::DebugUtilsMessageSeverityFlagsEXT as Severity;
assert_eq!(VulkanDebugLogger::level_of(Severity::ERROR), LogEventLevel::Error);
assert_eq!(VulkanDebugLogger::level_of(Severity::WARNING), LogEventLevel::Warning);
assert_eq!(VulkanDebugLogger::level_of(Severity::VERBOSE), LogEventLevel::Verbose);
assert_eq!(VulkanDebugLogger::level_of(Severity::INFO), LogEventLevel::Information);
assert_eq!(VulkanDebugLogger::level_of(Severity::ERROR | Severity::WARNING), LogEventLevel::Information);
assert_eq!(VulkanDebugLogger::level_of(Severity::empty()), LogEventLevel::Information);
}
#[test]
fn the_callback_lets_the_call_that_triggered_it_continue() {
let data = vk::DebugUtilsMessengerCallbackDataEXT::default().message(c"a message of a layer");
let callback = VulkanDebugLogger::callback_ptr().expect("the callback is a function");
let result = unsafe {
callback(
vk::DebugUtilsMessageSeverityFlagsEXT::WARNING,
vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION,
&data,
std::ptr::null_mut(),
)
};
assert_eq!(result, vk::FALSE);
let data = vk::DebugUtilsMessengerCallbackDataEXT::default();
let result = unsafe {
callback(
vk::DebugUtilsMessageSeverityFlagsEXT::ERROR,
vk::DebugUtilsMessageTypeFlagsEXT::GENERAL,
&data,
std::ptr::null_mut(),
)
};
assert_eq!(result, vk::FALSE);
}
}