use std::error;
use std::ffi::CStr;
use std::fmt;
use std::mem;
use std::os::raw::{c_char, c_void};
use std::panic;
use std::ptr;
use std::sync::Arc;
use instance::Instance;
use Error;
use VulkanObject;
use check_errors;
use vk;
#[must_use = "The DebugCallback object must be kept alive for as long as you want your callback \
to be called"]
pub struct DebugCallback {
instance: Arc<Instance>,
debug_report_callback: vk::DebugReportCallbackEXT,
user_callback: Box<Box<dyn Fn(&Message)>>,
}
impl DebugCallback {
pub fn new<F>(instance: &Arc<Instance>, messages: MessageTypes, user_callback: F)
-> Result<DebugCallback, DebugCallbackCreationError>
where F: Fn(&Message) + 'static + Send + panic::RefUnwindSafe
{
if !instance.loaded_extensions().ext_debug_report {
return Err(DebugCallbackCreationError::MissingExtension);
}
let user_callback = Box::new(Box::new(user_callback) as Box<_>);
extern "system" fn callback(ty: vk::DebugReportFlagsEXT, _: vk::DebugReportObjectTypeEXT,
_: u64, _: usize, _: i32, layer_prefix: *const c_char,
description: *const c_char, user_data: *mut c_void)
-> u32 {
unsafe {
let user_callback = user_data as *mut Box<dyn Fn()> as *const _;
let user_callback: &Box<dyn Fn(&Message)> = &*user_callback;
let layer_prefix = CStr::from_ptr(layer_prefix)
.to_str()
.expect("debug callback message not utf-8");
let description = CStr::from_ptr(description)
.to_str()
.expect("debug callback message not utf-8");
let message = Message {
ty: MessageTypes {
information: (ty & vk::DEBUG_REPORT_INFORMATION_BIT_EXT) != 0,
warning: (ty & vk::DEBUG_REPORT_WARNING_BIT_EXT) != 0,
performance_warning: (ty & vk::DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) !=
0,
error: (ty & vk::DEBUG_REPORT_ERROR_BIT_EXT) != 0,
debug: (ty & vk::DEBUG_REPORT_DEBUG_BIT_EXT) != 0,
},
layer_prefix: layer_prefix,
description: description,
};
let _ = panic::catch_unwind(panic::AssertUnwindSafe(move || {
user_callback(&message);
}));
vk::FALSE
}
}
let flags = {
let mut flags = 0;
if messages.information {
flags |= vk::DEBUG_REPORT_INFORMATION_BIT_EXT;
}
if messages.warning {
flags |= vk::DEBUG_REPORT_WARNING_BIT_EXT;
}
if messages.performance_warning {
flags |= vk::DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
}
if messages.error {
flags |= vk::DEBUG_REPORT_ERROR_BIT_EXT;
}
if messages.debug {
flags |= vk::DEBUG_REPORT_DEBUG_BIT_EXT;
}
flags
};
let infos = vk::DebugReportCallbackCreateInfoEXT {
sType: vk::STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT,
pNext: ptr::null(),
flags: flags,
pfnCallback: callback,
pUserData: &*user_callback as &Box<_> as *const Box<_> as *const c_void as *mut _,
};
let vk = instance.pointers();
let debug_report_callback = unsafe {
let mut output = mem::uninitialized();
check_errors(vk.CreateDebugReportCallbackEXT(instance.internal_object(),
&infos,
ptr::null(),
&mut output))?;
output
};
Ok(DebugCallback {
instance: instance.clone(),
debug_report_callback: debug_report_callback,
user_callback: user_callback,
})
}
#[inline]
pub fn errors_and_warnings<F>(instance: &Arc<Instance>, user_callback: F)
-> Result<DebugCallback, DebugCallbackCreationError>
where F: Fn(&Message) + Send + 'static + panic::RefUnwindSafe
{
DebugCallback::new(instance, MessageTypes::errors_and_warnings(), user_callback)
}
}
impl Drop for DebugCallback {
#[inline]
fn drop(&mut self) {
unsafe {
let vk = self.instance.pointers();
vk.DestroyDebugReportCallbackEXT(self.instance.internal_object(),
self.debug_report_callback,
ptr::null());
}
}
}
pub struct Message<'a> {
pub ty: MessageTypes,
pub layer_prefix: &'a str,
pub description: &'a str,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct MessageTypes {
pub error: bool,
pub warning: bool,
pub performance_warning: bool,
pub information: bool,
pub debug: bool,
}
impl MessageTypes {
#[inline]
pub fn errors() -> MessageTypes {
MessageTypes {
error: true,
..MessageTypes::none()
}
}
#[inline]
pub fn errors_and_warnings() -> MessageTypes {
MessageTypes {
error: true,
warning: true,
performance_warning: true,
..MessageTypes::none()
}
}
#[inline]
pub fn none() -> MessageTypes {
MessageTypes {
error: false,
warning: false,
performance_warning: false,
information: false,
debug: false,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum DebugCallbackCreationError {
MissingExtension,
}
impl error::Error for DebugCallbackCreationError {
#[inline]
fn description(&self) -> &str {
match *self {
DebugCallbackCreationError::MissingExtension =>
"the `EXT_debug_report` extension was not enabled",
}
}
}
impl fmt::Display for DebugCallbackCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", error::Error::description(self))
}
}
impl From<Error> for DebugCallbackCreationError {
#[inline]
fn from(err: Error) -> DebugCallbackCreationError {
panic!("unexpected error: {:?}", err)
}
}