use crate::raw::bindings::*;
use std::ffi::CStr;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DebugMessageSeverity(pub u32);
impl DebugMessageSeverity {
pub const VERBOSE: Self = Self(0x1);
pub const INFO: Self = Self(0x10);
pub const WARNING: Self = Self(0x100);
pub const ERROR: Self = Self(0x1000);
pub const ALL: Self = Self(Self::VERBOSE.0 | Self::INFO.0 | Self::WARNING.0 | Self::ERROR.0);
pub const WARNING_AND_ABOVE: Self = Self(Self::WARNING.0 | Self::ERROR.0);
pub const fn contains(self, other: Self) -> bool {
(self.0 & other.0) == other.0
}
pub fn label(self) -> &'static str {
if self.contains(Self::ERROR) {
"ERROR"
} else if self.contains(Self::WARNING) {
"WARN"
} else if self.contains(Self::INFO) {
"INFO"
} else if self.contains(Self::VERBOSE) {
"VERBOSE"
} else {
"?"
}
}
}
impl std::ops::BitOr for DebugMessageSeverity {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
Self(self.0 | rhs.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DebugMessageType(pub u32);
impl DebugMessageType {
pub const GENERAL: Self = Self(0x1);
pub const VALIDATION: Self = Self(0x2);
pub const PERFORMANCE: Self = Self(0x4);
pub const DEVICE_ADDRESS_BINDING: Self = Self(0x8);
pub const ALL: Self = Self(
Self::GENERAL.0 | Self::VALIDATION.0 | Self::PERFORMANCE.0 | Self::DEVICE_ADDRESS_BINDING.0,
);
pub const fn contains(self, other: Self) -> bool {
(self.0 & other.0) == other.0
}
pub fn label(self) -> &'static str {
if self.contains(Self::VALIDATION) {
"VALID"
} else if self.contains(Self::PERFORMANCE) {
"PERF"
} else if self.contains(Self::GENERAL) {
"GEN"
} else if self.contains(Self::DEVICE_ADDRESS_BINDING) {
"ADDR"
} else {
"?"
}
}
}
impl std::ops::BitOr for DebugMessageType {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
Self(self.0 | rhs.0)
}
}
pub struct DebugMessage<'a> {
pub severity: DebugMessageSeverity,
pub message_type: DebugMessageType,
pub message: &'a str,
pub message_id_name: Option<&'a str>,
pub message_id_number: i32,
}
pub type DebugCallback = dyn Fn(&DebugMessage<'_>) + Send + Sync + 'static;
pub fn default_callback() -> Box<DebugCallback> {
Box::new(|msg: &DebugMessage<'_>| {
if msg.severity.contains(DebugMessageSeverity::WARNING)
|| msg.severity.contains(DebugMessageSeverity::ERROR)
{
eprintln!(
"[VK {}/{}] {}",
msg.severity.label(),
msg.message_type.label(),
msg.message
);
}
})
}
pub(crate) type RealDebugCallbackFn = unsafe extern "system" fn(
severity: u32,
message_types: u32,
p_callback_data: *const VkDebugUtilsMessengerCallbackDataEXT,
p_user_data: *mut std::ffi::c_void,
) -> u32;
pub(crate) unsafe extern "system" fn trampoline(
severity: u32,
message_types: u32,
p_callback_data: *const VkDebugUtilsMessengerCallbackDataEXT,
p_user_data: *mut std::ffi::c_void,
) -> u32 {
if p_callback_data.is_null() || p_user_data.is_null() {
return 0;
}
let cb: &DebugCallback = unsafe { (*(p_user_data as *const Box<DebugCallback>)).as_ref() };
let data = unsafe { &*p_callback_data };
let message = if data.pMessage.is_null() {
""
} else {
unsafe { CStr::from_ptr(data.pMessage) }
.to_str()
.unwrap_or("<invalid utf-8>")
};
let message_id_name = if data.pMessageIdName.is_null() {
None
} else {
unsafe { CStr::from_ptr(data.pMessageIdName) }.to_str().ok()
};
let msg = DebugMessage {
severity: DebugMessageSeverity(severity),
message_type: DebugMessageType(message_types),
message,
message_id_name,
message_id_number: data.messageIdNumber,
};
cb(&msg);
0 }