aboutsummaryrefslogtreecommitdiff
path: root/src/instance/debug.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/instance/debug.rs')
-rw-r--r--src/instance/debug.rs755
1 files changed, 419 insertions, 336 deletions
diff --git a/src/instance/debug.rs b/src/instance/debug.rs
index 2bc0615..7e5a75e 100644
--- a/src/instance/debug.rs
+++ b/src/instance/debug.rs
@@ -7,9 +7,9 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-//! Debug callback called by intermediate layers or by the driver.
+//! Debug messenger called by intermediate layers or by the driver.
//!
-//! When working on an application, it is recommended to register a debug callback. For example if
+//! When working on an application, it is recommended to register a debug messenger. 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.
@@ -17,445 +17,528 @@
//! 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
+//! # Examples
//!
//! ```
//! # use vulkano::instance::Instance;
//! # use std::sync::Arc;
//! # let instance: Arc<Instance> = return;
-//! use vulkano::instance::debug::DebugCallback;
+//! use vulkano::instance::debug::{DebugUtilsMessenger, DebugUtilsMessengerCreateInfo};
//!
-//! let _callback = DebugCallback::errors_and_warnings(&instance, |msg| {
-//! println!("Debug callback: {:?}", msg.description);
-//! }).ok();
+//! let _callback = unsafe {
+//! DebugUtilsMessenger::new(
+//! instance,
+//! DebugUtilsMessengerCreateInfo::user_callback(Arc::new(|msg| {
+//! println!("Debug callback: {:?}", msg.description);
+//! })),
+//! ).ok()
+//! };
//! ```
//!
-//! The type of `msg` in the callback is [`Message`](struct.Message.html).
+//! The type of `msg` in the callback is [`Message`].
//!
//! 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
+//! be callable. If you don't store the return value of `DebugUtilsMessenger`'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;
+use super::Instance;
+use crate::{
+ macros::{vulkan_bitflags, vulkan_enum},
+ RequirementNotMet, RequiresOneOf, VulkanError, VulkanObject,
+};
+use std::{
+ error::Error,
+ ffi::{c_void, CStr},
+ fmt::{Debug, Display, Error as FmtError, Formatter},
+ mem::MaybeUninit,
+ panic::{catch_unwind, AssertUnwindSafe, RefUnwindSafe},
+ ptr,
+ sync::Arc,
+};
+
+pub(super) type UserCallback = Arc<dyn Fn(&Message<'_>) + RefUnwindSafe + Send + Sync>;
/// 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 {
+#[must_use = "The DebugUtilsMessenger object must be kept alive for as long as you want your callback to be called"]
+pub struct DebugUtilsMessenger {
+ handle: ash::vk::DebugUtilsMessengerEXT,
instance: Arc<Instance>,
- debug_report_callback: ash::vk::DebugUtilsMessengerEXT,
- user_callback: Box<Box<dyn Fn(&Message) + Send>>,
+ _user_callback: Box<UserCallback>,
}
-impl DebugCallback {
+impl DebugUtilsMessenger {
/// 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,
- {
+ /// # Panics
+ ///
+ /// - Panics if the `message_severity` or `message_type` members of `create_info` are empty.
+ ///
+ /// # Safety
+ ///
+ /// - `create_info.user_callback` must not make any calls to the Vulkan API.
+ pub unsafe fn new(
+ instance: Arc<Instance>,
+ mut create_info: DebugUtilsMessengerCreateInfo,
+ ) -> Result<Self, DebugUtilsMessengerCreationError> {
+ Self::validate_create(&instance, &mut create_info)?;
+ let (handle, user_callback) = Self::record_create(&instance, create_info)?;
+
+ Ok(DebugUtilsMessenger {
+ handle,
+ instance,
+ _user_callback: user_callback,
+ })
+ }
+
+ fn validate_create(
+ instance: &Instance,
+ create_info: &mut DebugUtilsMessengerCreateInfo,
+ ) -> Result<(), DebugUtilsMessengerCreationError> {
+ let &mut DebugUtilsMessengerCreateInfo {
+ message_type,
+ message_severity,
+ user_callback: _,
+ _ne: _,
+ } = create_info;
+
if !instance.enabled_extensions().ext_debug_utils {
- return Err(DebugCallbackCreationError::MissingExtension);
+ return Err(DebugUtilsMessengerCreationError::RequirementNotMet {
+ required_for: "`DebugUtilsMessenger::new`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["ext_debug_utils"],
+ ..Default::default()
+ },
+ });
}
- // 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,
- };
+ // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageSeverity-parameter
+ message_severity.validate_instance(instance)?;
- // 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);
- }));
+ // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageSeverity-requiredbitmask
+ assert!(!message_severity.is_empty());
- ash::vk::FALSE
- }
+ // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageType-parameter
+ message_type.validate_instance(instance)?;
- 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
- };
+ // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageType-requiredbitmask
+ assert!(!message_type.is_empty());
- 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
- };
+ // VUID-PFN_vkDebugUtilsMessengerCallbackEXT-None-04769
+ // Can't be checked, creation is unsafe.
+
+ Ok(())
+ }
+
+ unsafe fn record_create(
+ instance: &Instance,
+ create_info: DebugUtilsMessengerCreateInfo,
+ ) -> Result<
+ (ash::vk::DebugUtilsMessengerEXT, Box<UserCallback>),
+ DebugUtilsMessengerCreationError,
+ > {
+ let DebugUtilsMessengerCreateInfo {
+ message_severity,
+ message_type,
+ user_callback,
+ _ne: _,
+ } = create_info;
+
+ // 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(user_callback);
- let infos = ash::vk::DebugUtilsMessengerCreateInfoEXT {
+ let create_info = 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 _,
+ message_severity: message_severity.into(),
+ message_type: message_type.into(),
+ pfn_user_callback: Some(trampoline),
+ p_user_data: &*user_callback as &Arc<_> as *const Arc<_> as *const c_void as *mut _,
..Default::default()
};
let fns = instance.fns();
- let debug_report_callback = unsafe {
+ let handle = {
let mut output = MaybeUninit::uninit();
- check_errors(fns.ext_debug_utils.create_debug_utils_messenger_ext(
- instance.internal_object(),
- &infos,
+ (fns.ext_debug_utils.create_debug_utils_messenger_ext)(
+ instance.handle(),
+ &create_info,
ptr::null(),
output.as_mut_ptr(),
- ))?;
+ )
+ .result()
+ .map_err(VulkanError::from)?;
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,
- )
+ Ok((handle, user_callback))
}
}
-impl Drop for DebugCallback {
+impl Drop for DebugUtilsMessenger {
#[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,
+ (fns.ext_debug_utils.destroy_debug_utils_messenger_ext)(
+ self.instance.handle(),
+ self.handle,
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,
+impl Debug for DebugUtilsMessenger {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ let Self {
+ handle,
+ instance,
+ _user_callback: _,
+ } = self;
+
+ f.debug_struct("DebugUtilsMessenger")
+ .field("handle", handle)
+ .field("instance", instance)
+ .finish_non_exhaustive()
+ }
}
-/// 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,
+pub(super) unsafe extern "system" fn trampoline(
+ message_severity: ash::vk::DebugUtilsMessageSeverityFlagsEXT,
+ message_types: ash::vk::DebugUtilsMessageTypeFlagsEXT,
+ callback_data: *const ash::vk::DebugUtilsMessengerCallbackDataEXT,
+ user_data: *mut c_void,
+) -> ash::vk::Bool32 {
+ // Since we box the closure, the type system doesn't detect that the `UnwindSafe`
+ // bound is enforced. Therefore we enforce it manually.
+ let _ = catch_unwind(AssertUnwindSafe(move || {
+ let user_callback = user_data as *mut UserCallback as *const _;
+ let user_callback: &UserCallback = &*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: message_severity.into(),
+ ty: message_types.into(),
+ layer_prefix,
+ description,
+ };
+
+ user_callback(&message);
+ }));
+
+ ash::vk::FALSE
}
-impl MessageSeverity {
- /// Builds a `MessageSeverity` with all fields set to `false` expect `error`.
- #[inline]
- pub const fn errors() -> MessageSeverity {
- MessageSeverity {
- error: true,
- ..MessageSeverity::none()
- }
- }
+/// Error that can happen when creating a `DebugUtilsMessenger`.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum DebugUtilsMessengerCreationError {
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+}
- /// Builds a `MessageSeverity` with all fields set to `false` expect `warning`.
- #[inline]
- pub const fn warnings() -> MessageSeverity {
- MessageSeverity {
- warning: true,
- ..MessageSeverity::none()
+impl Error for DebugUtilsMessengerCreationError {}
+
+impl Display for DebugUtilsMessengerCreationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
}
}
+}
- /// Builds a `MessageSeverity` with all fields set to `false` expect `information`.
- #[inline]
- pub const fn information() -> MessageSeverity {
- MessageSeverity {
- information: true,
- ..MessageSeverity::none()
- }
+impl From<VulkanError> for DebugUtilsMessengerCreationError {
+ fn from(err: VulkanError) -> DebugUtilsMessengerCreationError {
+ panic!("unexpected error: {:?}", err)
}
+}
- /// Builds a `MessageSeverity` with all fields set to `false` expect `verbose`.
- #[inline]
- pub const fn verbose() -> MessageSeverity {
- MessageSeverity {
- verbose: true,
- ..MessageSeverity::none()
+impl From<RequirementNotMet> for DebugUtilsMessengerCreationError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
}
}
+}
- /// 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()
- }
- }
+/// Parameters to create a `DebugUtilsMessenger`.
+#[derive(Clone)]
+pub struct DebugUtilsMessengerCreateInfo {
+ /// The message severity types that the callback should be called for.
+ ///
+ /// The value must not be empty.
+ ///
+ /// The default value is `MessageSeverity::errors_and_warnings()`.
+ pub message_severity: DebugUtilsMessageSeverity,
- /// Builds a `MessageSeverity` with all fields set to `false`.
- #[inline]
- pub const fn none() -> MessageSeverity {
- MessageSeverity {
- error: false,
- warning: false,
- information: false,
- verbose: false,
- }
- }
+ /// The message types that the callback should be called for.
+ ///
+ /// The value must not be empty.
+ ///
+ /// The default value is `MessageType::general()`.
+ pub message_type: DebugUtilsMessageType,
+
+ /// The closure that should be called.
+ ///
+ /// The closure must not make any calls to the Vulkan API.
+ /// If the closure panics, the panic is caught and ignored.
+ ///
+ /// The callback is provided inside an `Arc` so that it can be shared across multiple
+ /// messengers.
+ pub user_callback: UserCallback,
- /// Builds a `MessageSeverity` with all fields set to `true`.
+ pub _ne: crate::NonExhaustive,
+}
+
+impl DebugUtilsMessengerCreateInfo {
+ /// Returns a `DebugUtilsMessengerCreateInfo` with the specified `user_callback`.
#[inline]
- pub const fn all() -> MessageSeverity {
- MessageSeverity {
- error: true,
- warning: true,
- information: true,
- verbose: true,
+ pub fn user_callback(user_callback: UserCallback) -> Self {
+ Self {
+ message_severity: DebugUtilsMessageSeverity::ERROR | DebugUtilsMessageSeverity::WARNING,
+ message_type: DebugUtilsMessageType::GENERAL,
+ user_callback,
+ _ne: crate::NonExhaustive(()),
}
}
}
-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,
- }
+impl Debug for DebugUtilsMessengerCreateInfo {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ let Self {
+ message_severity,
+ message_type,
+ user_callback: _,
+ _ne: _,
+ } = self;
+
+ f.debug_struct("DebugUtilsMessengerCreateInfo")
+ .field("message_severity", message_severity)
+ .field("message_type", message_type)
+ .finish_non_exhaustive()
}
}
-/// Type of message.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct MessageType {
+/// A message received by the callback.
+pub struct Message<'a> {
+ /// Severity of message.
+ pub severity: DebugUtilsMessageSeverity,
+ /// Type of message,
+ pub ty: DebugUtilsMessageType,
+ /// 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,
+}
+
+vulkan_bitflags! {
+ #[non_exhaustive]
+
+ /// Severity of message.
+ DebugUtilsMessageSeverity = DebugUtilsMessageSeverityFlagsEXT(u32);
+
+ /// An error that may cause undefined results, including an application crash.
+ ERROR = ERROR,
+
+ /// An unexpected use.
+ WARNING = WARNING,
+
+ /// An informational message that may be handy when debugging an application.
+ INFO = INFO,
+
+ /// Diagnostic information from the loader and layers.
+ VERBOSE = VERBOSE,
+}
+
+vulkan_bitflags! {
+ #[non_exhaustive]
+
+ /// Type of message.
+ DebugUtilsMessageType = DebugUtilsMessageTypeFlagsEXT(u32);
+
/// Specifies that some general event has occurred.
- pub general: bool,
+ GENERAL = GENERAL,
+
/// Specifies that something has occurred during validation against the vulkan specification
- pub validation: bool,
+ VALIDATION = VALIDATION,
+
/// Specifies a potentially non-optimal use of Vulkan
- pub performance: bool,
+ PERFORMANCE = PERFORMANCE,
}
-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,
- }
- }
+/// A label to associate with a span of work in a queue.
+///
+/// When debugging, labels can be useful to identify which queue, or where in a specific queue,
+/// something happened.
+#[derive(Clone, Debug)]
+pub struct DebugUtilsLabel {
+ /// The name of the label.
+ ///
+ /// The default value is empty.
+ pub label_name: String,
- /// Builds a `MessageType` with performance field set to `true`.
- #[inline]
- pub const fn performance() -> MessageType {
- MessageType {
- general: false,
- validation: false,
- performance: true,
- }
- }
+ /// An RGBA color value that is associated with the label, with values in the range `0.0..=1.0`.
+ ///
+ /// If set to `[0.0; 4]`, the value is ignored.
+ ///
+ /// The default value is `[0.0; 4]`.
+ pub color: [f32; 4],
- /// Builds a `MessageType` with all fields set to `true`.
- #[inline]
- pub const fn all() -> MessageType {
- MessageType {
- general: true,
- validation: true,
- performance: true,
- }
- }
+ pub _ne: crate::NonExhaustive,
+}
- /// Builds a `MessageType` with all fields set to `false`.
+impl Default for DebugUtilsLabel {
#[inline]
- pub const fn none() -> MessageType {
- MessageType {
- general: false,
- validation: false,
- performance: false,
+ fn default() -> Self {
+ Self {
+ label_name: String::new(),
+ color: [0.0; 4],
+ _ne: crate::NonExhaustive(()),
}
}
}
-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,
- }
- }
-}
+vulkan_enum! {
+ #[non_exhaustive]
-/// 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,
-}
+ /// Features of the validation layer to enable.
+ ValidationFeatureEnable = ValidationFeatureEnableEXT(i32);
-impl error::Error for DebugCallbackCreationError {}
+ /// The validation layer will use shader programs running on the GPU to provide additional
+ /// validation.
+ ///
+ /// This must not be used together with `DebugPrintf`.
+ GpuAssisted = GPU_ASSISTED,
-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"
- }
- }
- )
- }
+ /// The validation layer will reserve and use one descriptor set slot for its own use.
+ /// The limit reported by
+ /// [`max_bound_descriptor_sets`](crate::device::Properties::max_bound_descriptor_sets)
+ /// will be reduced by 1.
+ ///
+ /// `GpuAssisted` must also be enabled.
+ GpuAssistedReserveBindingSlot = GPU_ASSISTED_RESERVE_BINDING_SLOT,
+
+ /// The validation layer will report recommendations that are not strictly errors,
+ /// but that may be considered good Vulkan practice.
+ BestPractices = BEST_PRACTICES,
+
+ /// The validation layer will process `debugPrintfEXT` operations in shaders, and send them
+ /// to the debug callback.
+ ///
+ /// This must not be used together with `GpuAssisted`.
+ DebugPrintf = DEBUG_PRINTF,
+
+ /// The validation layer will report errors relating to synchronization, such as data races and
+ /// the use of synchronization primitives.
+ SynchronizationValidation = SYNCHRONIZATION_VALIDATION,
}
-impl From<Error> for DebugCallbackCreationError {
- #[inline]
- fn from(err: Error) -> DebugCallbackCreationError {
- panic!("unexpected error: {:?}", err)
- }
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// Features of the validation layer to disable.
+ ValidationFeatureDisable = ValidationFeatureDisableEXT(i32);
+
+ /// All validation is disabled.
+ All = ALL,
+
+ /// Shader validation is disabled.
+ Shaders = SHADERS,
+
+ /// Thread safety validation is disabled.
+ ThreadSafety = THREAD_SAFETY,
+
+ /// Stateless parameter validation is disabled.
+ ApiParameters = API_PARAMETERS,
+
+ /// Object lifetime validation is disabled.
+ ObjectLifetimes = OBJECT_LIFETIMES,
+
+ /// Core validation checks are disabled.
+ ///
+ /// This also disables shader validation and GPU-assisted validation.
+ CoreChecks = CORE_CHECKS,
+
+ /// Protection against duplicate non-dispatchable handles is disabled.
+ UniqueHandles = UNIQUE_HANDLES,
+
+ /// Results of shader validation will not be cached, and are validated from scratch each time.
+ ShaderValidationCache = SHADER_VALIDATION_CACHE,
}
#[cfg(test)]
mod tests {
use super::*;
+ use crate::{
+ instance::{InstanceCreateInfo, InstanceExtensions},
+ VulkanLibrary,
+ };
use std::thread;
+
#[test]
fn ensure_sendable() {
- // It's useful to be able to initialize a DebugCallback on one thread
+ // It's useful to be able to initialize a DebugUtilsMessenger 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, |_| {});
+ let instance = {
+ let library = match VulkanLibrary::new() {
+ Ok(x) => x,
+ Err(_) => return,
+ };
+
+ match Instance::new(
+ library,
+ InstanceCreateInfo {
+ enabled_extensions: InstanceExtensions {
+ ext_debug_utils: true,
+ ..InstanceExtensions::empty()
+ },
+ ..Default::default()
+ },
+ ) {
+ Ok(x) => x,
+ Err(_) => return,
+ }
+ };
+
+ let callback = unsafe {
+ DebugUtilsMessenger::new(
+ instance,
+ DebugUtilsMessengerCreateInfo {
+ message_severity: DebugUtilsMessageSeverity::ERROR,
+ message_type: DebugUtilsMessageType::GENERAL
+ | DebugUtilsMessageType::VALIDATION
+ | DebugUtilsMessageType::PERFORMANCE,
+ ..DebugUtilsMessengerCreateInfo::user_callback(Arc::new(|_| {}))
+ },
+ )
+ }
+ .unwrap();
thread::spawn(move || {
- let _ = callback;
+ drop(callback);
});
}
}