diff options
Diffstat (limited to 'src/instance/debug.rs')
-rw-r--r-- | src/instance/debug.rs | 461 |
1 files changed, 0 insertions, 461 deletions
diff --git a/src/instance/debug.rs b/src/instance/debug.rs deleted file mode 100644 index 2bc0615..0000000 --- a/src/instance/debug.rs +++ /dev/null @@ -1,461 +0,0 @@ -// Copyright (c) 2016 The vulkano developers -// Licensed under the Apache License, Version 2.0 -// <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT -// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, -// at your option. All files in the project carrying such -// notice may not be copied, modified, or distributed except -// according to those terms. - -//! Debug callback called by intermediate layers or by the driver. -//! -//! When working on an application, it is recommended to register a debug callback. For example if -//! you enable the validation layers provided by the official Vulkan SDK, they will warn you about -//! invalid API usages or performance problems by calling this callback. The callback can also -//! be called by the driver or by whatever intermediate layer is activated. -//! -//! Note that the vulkano library can also emit messages to warn you about performance issues. -//! TODO: ^ that's not the case yet, need to choose whether we keep this idea -//! -//! # Example -//! -//! ``` -//! # use vulkano::instance::Instance; -//! # use std::sync::Arc; -//! # let instance: Arc<Instance> = return; -//! use vulkano::instance::debug::DebugCallback; -//! -//! let _callback = DebugCallback::errors_and_warnings(&instance, |msg| { -//! println!("Debug callback: {:?}", msg.description); -//! }).ok(); -//! ``` -//! -//! The type of `msg` in the callback is [`Message`](struct.Message.html). -//! -//! Note that you must keep the `_callback` object alive for as long as you want your callback to -//! be callable. If you don't store the return value of `DebugCallback`'s constructor in a -//! variable, it will be immediately destroyed and your callback will not work. -//! - -use crate::check_errors; -use crate::instance::Instance; -use crate::Error; -use crate::VulkanObject; -use std::error; -use std::ffi::CStr; -use std::fmt; -use std::mem::MaybeUninit; -use std::os::raw::c_void; -use std::panic; -use std::ptr; -use std::sync::Arc; - -/// Registration of a callback called by validation layers. -/// -/// The callback can be called as long as this object is alive. -#[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: ash::vk::DebugUtilsMessengerEXT, - user_callback: Box<Box<dyn Fn(&Message) + Send>>, -} - -impl DebugCallback { - /// Initializes a debug callback. - /// - /// Panics generated by calling `user_callback` are ignored. - pub fn new<F>( - instance: &Arc<Instance>, - severity: MessageSeverity, - ty: MessageType, - user_callback: F, - ) -> Result<DebugCallback, DebugCallbackCreationError> - where - F: Fn(&Message) + 'static + Send + panic::RefUnwindSafe, - { - if !instance.enabled_extensions().ext_debug_utils { - return Err(DebugCallbackCreationError::MissingExtension); - } - - // Note that we need to double-box the callback, because a `*const Fn()` is a fat pointer - // that can't be cast to a `*const c_void`. - let user_callback = Box::new(Box::new(user_callback) as Box<_>); - - unsafe extern "system" fn callback( - severity: ash::vk::DebugUtilsMessageSeverityFlagsEXT, - ty: ash::vk::DebugUtilsMessageTypeFlagsEXT, - callback_data: *const ash::vk::DebugUtilsMessengerCallbackDataEXT, - user_data: *mut c_void, - ) -> ash::vk::Bool32 { - let user_callback = user_data as *mut Box<dyn Fn()> as *const _; - let user_callback: &Box<dyn Fn(&Message)> = &*user_callback; - - let layer_prefix = (*callback_data) - .p_message_id_name - .as_ref() - .map(|msg_id_name| { - CStr::from_ptr(msg_id_name) - .to_str() - .expect("debug callback message not utf-8") - }); - - let description = CStr::from_ptr((*callback_data).p_message) - .to_str() - .expect("debug callback message not utf-8"); - - let message = Message { - severity: MessageSeverity { - information: !(severity & ash::vk::DebugUtilsMessageSeverityFlagsEXT::INFO) - .is_empty(), - warning: !(severity & ash::vk::DebugUtilsMessageSeverityFlagsEXT::WARNING) - .is_empty(), - error: !(severity & ash::vk::DebugUtilsMessageSeverityFlagsEXT::ERROR) - .is_empty(), - verbose: !(severity & ash::vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE) - .is_empty(), - }, - ty: MessageType { - general: !(ty & ash::vk::DebugUtilsMessageTypeFlagsEXT::GENERAL).is_empty(), - validation: !(ty & ash::vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION) - .is_empty(), - performance: !(ty & ash::vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE) - .is_empty(), - }, - layer_prefix, - description, - }; - - // Since we box the closure, the type system doesn't detect that the `UnwindSafe` - // bound is enforced. Therefore we enforce it manually. - let _ = panic::catch_unwind(panic::AssertUnwindSafe(move || { - user_callback(&message); - })); - - ash::vk::FALSE - } - - let severity = { - let mut flags = ash::vk::DebugUtilsMessageSeverityFlagsEXT::empty(); - if severity.information { - flags |= ash::vk::DebugUtilsMessageSeverityFlagsEXT::INFO; - } - if severity.warning { - flags |= ash::vk::DebugUtilsMessageSeverityFlagsEXT::WARNING; - } - if severity.error { - flags |= ash::vk::DebugUtilsMessageSeverityFlagsEXT::ERROR; - } - if severity.verbose { - flags |= ash::vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE; - } - flags - }; - - let ty = { - let mut flags = ash::vk::DebugUtilsMessageTypeFlagsEXT::empty(); - if ty.general { - flags |= ash::vk::DebugUtilsMessageTypeFlagsEXT::GENERAL; - } - if ty.validation { - flags |= ash::vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION; - } - if ty.performance { - flags |= ash::vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE; - } - flags - }; - - let infos = ash::vk::DebugUtilsMessengerCreateInfoEXT { - flags: ash::vk::DebugUtilsMessengerCreateFlagsEXT::empty(), - message_severity: severity, - message_type: ty, - pfn_user_callback: Some(callback), - p_user_data: &*user_callback as &Box<_> as *const Box<_> as *const c_void as *mut _, - ..Default::default() - }; - - let fns = instance.fns(); - - let debug_report_callback = unsafe { - let mut output = MaybeUninit::uninit(); - check_errors(fns.ext_debug_utils.create_debug_utils_messenger_ext( - instance.internal_object(), - &infos, - ptr::null(), - output.as_mut_ptr(), - ))?; - output.assume_init() - }; - - Ok(DebugCallback { - instance: instance.clone(), - debug_report_callback, - user_callback, - }) - } - - /// Initializes a debug callback with errors and warnings. - /// - /// Shortcut for `new(instance, MessageTypes::errors_and_warnings(), 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, - MessageSeverity::errors_and_warnings(), - MessageType::general(), - user_callback, - ) - } -} - -impl Drop for DebugCallback { - #[inline] - fn drop(&mut self) { - unsafe { - let fns = self.instance.fns(); - fns.ext_debug_utils.destroy_debug_utils_messenger_ext( - self.instance.internal_object(), - self.debug_report_callback, - ptr::null(), - ); - } - } -} - -/// A message received by the callback. -pub struct Message<'a> { - /// Severity of message. - pub severity: MessageSeverity, - /// Type of message, - pub ty: MessageType, - /// Prefix of the layer that reported this message or `None` if unknown. - pub layer_prefix: Option<&'a str>, - /// Description of the message. - pub description: &'a str, -} - -/// Severity of message. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct MessageSeverity { - /// An error that may cause undefined results, including an application crash. - pub error: bool, - /// An unexpected use. - pub warning: bool, - /// An informational message that may be handy when debugging an application. - pub information: bool, - /// Diagnostic information from the loader and layers. - pub verbose: bool, -} - -impl MessageSeverity { - /// Builds a `MessageSeverity` with all fields set to `false` expect `error`. - #[inline] - pub const fn errors() -> MessageSeverity { - MessageSeverity { - error: true, - ..MessageSeverity::none() - } - } - - /// Builds a `MessageSeverity` with all fields set to `false` expect `warning`. - #[inline] - pub const fn warnings() -> MessageSeverity { - MessageSeverity { - warning: true, - ..MessageSeverity::none() - } - } - - /// Builds a `MessageSeverity` with all fields set to `false` expect `information`. - #[inline] - pub const fn information() -> MessageSeverity { - MessageSeverity { - information: true, - ..MessageSeverity::none() - } - } - - /// Builds a `MessageSeverity` with all fields set to `false` expect `verbose`. - #[inline] - pub const fn verbose() -> MessageSeverity { - MessageSeverity { - verbose: true, - ..MessageSeverity::none() - } - } - - /// Builds a `MessageSeverity` with all fields set to `false` expect `error`, `warning` - /// and `performance_warning`. - #[inline] - pub const fn errors_and_warnings() -> MessageSeverity { - MessageSeverity { - error: true, - warning: true, - ..MessageSeverity::none() - } - } - - /// Builds a `MessageSeverity` with all fields set to `false`. - #[inline] - pub const fn none() -> MessageSeverity { - MessageSeverity { - error: false, - warning: false, - information: false, - verbose: false, - } - } - - /// Builds a `MessageSeverity` with all fields set to `true`. - #[inline] - pub const fn all() -> MessageSeverity { - MessageSeverity { - error: true, - warning: true, - information: true, - verbose: true, - } - } -} - -impl std::ops::BitOr for MessageSeverity { - type Output = Self; - fn bitor(self, rhs: Self) -> Self::Output { - MessageSeverity { - error: self.error | rhs.error, - warning: self.warning | rhs.warning, - information: self.information | rhs.information, - verbose: self.verbose | rhs.verbose, - } - } -} - -/// Type of message. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct MessageType { - /// Specifies that some general event has occurred. - pub general: bool, - /// Specifies that something has occurred during validation against the vulkan specification - pub validation: bool, - /// Specifies a potentially non-optimal use of Vulkan - pub performance: bool, -} - -impl MessageType { - /// Builds a `MessageType` with general field set to `true`. - #[inline] - pub const fn general() -> MessageType { - MessageType { - general: true, - validation: false, - performance: false, - } - } - - /// Builds a `MessageType` with validation field set to `true`. - #[inline] - pub const fn validation() -> MessageType { - MessageType { - general: false, - validation: true, - performance: false, - } - } - - /// Builds a `MessageType` with performance field set to `true`. - #[inline] - pub const fn performance() -> MessageType { - MessageType { - general: false, - validation: false, - performance: true, - } - } - - /// Builds a `MessageType` with all fields set to `true`. - #[inline] - pub const fn all() -> MessageType { - MessageType { - general: true, - validation: true, - performance: true, - } - } - - /// Builds a `MessageType` with all fields set to `false`. - #[inline] - pub const fn none() -> MessageType { - MessageType { - general: false, - validation: false, - performance: false, - } - } -} - -impl std::ops::BitOr for MessageType { - type Output = Self; - fn bitor(self, rhs: Self) -> Self::Output { - MessageType { - general: self.general | rhs.general, - validation: self.validation | rhs.validation, - performance: self.performance | rhs.performance, - } - } -} - -/// Error that can happen when creating a debug callback. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum DebugCallbackCreationError { - /// The `EXT_debug_utils` extension was not enabled. - MissingExtension, -} - -impl error::Error for DebugCallbackCreationError {} - -impl fmt::Display for DebugCallbackCreationError { - #[inline] - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!( - fmt, - "{}", - match *self { - DebugCallbackCreationError::MissingExtension => { - "the `EXT_debug_utils` extension was not enabled" - } - } - ) - } -} - -impl From<Error> for DebugCallbackCreationError { - #[inline] - fn from(err: Error) -> DebugCallbackCreationError { - panic!("unexpected error: {:?}", err) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::thread; - #[test] - fn ensure_sendable() { - // It's useful to be able to initialize a DebugCallback on one thread - // and keep it alive on another thread. - let instance = instance!(); - let severity = MessageSeverity::none(); - let ty = MessageType::all(); - let callback = DebugCallback::new(&instance, severity, ty, |_| {}); - thread::spawn(move || { - let _ = callback; - }); - } -} |