use ash::{extensions::ext::DebugUtils, vk, Entry, Instance};
use log::{debug, error, warn};
use static_assertions::assert_impl_all;
use std::{
ffi::CStr,
os::raw::c_void,
pin::Pin,
sync::{
atomic::{AtomicUsize, Ordering},
Arc,
},
};
#[repr(C)]
pub struct DebugUtilsAndMessenger {
pub debug_utils: DebugUtils,
pub messenger: vk::DebugUtilsMessengerEXT,
pub debug_user_data: Pin<Arc<DebugUserData>>,
}
impl DebugUtilsAndMessenger {
pub fn new(
entry: &Entry, instance: &Instance, severity_flags: vk::DebugUtilsMessageSeverityFlagsEXT,
type_flags: vk::DebugUtilsMessageTypeFlagsEXT,
debug_user_data: Option<Pin<Arc<DebugUserData>>>,
) -> Self {
let debug_user_data = if let Some(debug_user_data) = debug_user_data {
debug_user_data
} else {
Arc::pin(DebugUserData::new())
};
let debug_user_data_ptr =
unsafe { Arc::into_raw(Pin::into_inner_unchecked(debug_user_data.clone())) as *mut c_void };
let debug_utils = DebugUtils::new(entry, instance);
let messenger_ci = vk::DebugUtilsMessengerCreateInfoEXT::builder()
.message_severity(severity_flags)
.message_type(type_flags)
.pfn_user_callback(Some(Self::debug_callback))
.user_data(debug_user_data_ptr)
.build();
let messenger = unsafe {
debug_utils
.create_debug_utils_messenger(&messenger_ci, None)
.expect("Could not create debug utils messenger")
};
DebugUtilsAndMessenger {
debug_utils,
messenger,
debug_user_data,
}
}
pub unsafe extern "system" fn debug_callback(
message_severity: vk::DebugUtilsMessageSeverityFlagsEXT,
_message_types: vk::DebugUtilsMessageTypeFlagsEXT,
p_callback_data: *const vk::DebugUtilsMessengerCallbackDataEXT, p_user_data: *mut c_void,
) -> u32 {
let user_data: Option<&mut DebugUserData> = if p_user_data.is_null() {
Some(&mut *(p_user_data as *mut DebugUserData))
} else {
None
};
if let Some(user_data) = user_data {
match message_severity {
vk::DebugUtilsMessageSeverityFlagsEXT::ERROR => {
user_data.error_count.fetch_add(1, Ordering::SeqCst);
}
vk::DebugUtilsMessageSeverityFlagsEXT::WARNING => {
user_data.warning_count.fetch_add(1, Ordering::SeqCst);
}
vk::DebugUtilsMessageSeverityFlagsEXT::INFO => {
user_data.info_count.fetch_add(1, Ordering::SeqCst);
}
_ => {}
}
}
let message = CStr::from_ptr((*p_callback_data).p_message as *const i8)
.to_str()
.unwrap();
match message_severity {
vk::DebugUtilsMessageSeverityFlagsEXT::ERROR => {
error!("Validation Error! {}", message);
}
vk::DebugUtilsMessageSeverityFlagsEXT::WARNING => {
warn!("Validation Warning! {}", message);
}
vk::DebugUtilsMessageSeverityFlagsEXT::INFO => {
debug!("Validation Info {}", message);
}
vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE => {
debug!("Validation Verbose {}", message);
}
_ => {}
}
vk::FALSE }
}
assert_impl_all!(DebugUserData: Sync);
#[repr(C)]
pub struct DebugUserData {
info_count: AtomicUsize,
warning_count: AtomicUsize,
error_count: AtomicUsize,
}
impl DebugUserData {
pub fn new() -> Self {
Self::default()
}
#[allow(dead_code)]
pub fn get_error_counts(&self) -> DebugUserDataCopy {
DebugUserDataCopy {
info_count: self.info_count.load(Ordering::SeqCst),
warning_count: self.warning_count.load(Ordering::SeqCst),
error_count: self.error_count.load(Ordering::SeqCst),
}
}
}
impl Default for DebugUserData {
fn default() -> Self {
Self {
info_count: AtomicUsize::new(0),
warning_count: AtomicUsize::new(0),
error_count: AtomicUsize::new(0),
}
}
}
#[derive(Debug)]
pub struct DebugUserDataCopy {
pub info_count: usize,
pub warning_count: usize,
pub error_count: usize,
}