diff options
Diffstat (limited to 'src/instance/debug.rs')
-rw-r--r-- | src/instance/debug.rs | 755 |
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); }); } } |