From 85bc9cd280a19b98079a8c807da552389e8d64a0 Mon Sep 17 00:00:00 2001 From: Rua Date: Sat, 29 Jul 2023 16:44:00 +0200 Subject: [PATCH 1/8] Improve debug messenger, remove second `Instance` constructor --- examples/src/bin/debug.rs | 65 ++++---- examples/src/bin/gl-interop.rs | 24 +-- vulkano-util/src/context.rs | 12 +- vulkano/src/instance/debug.rs | 278 ++++++++++++++++++++++++--------- vulkano/src/instance/mod.rs | 160 ++++++++----------- 5 files changed, 324 insertions(+), 215 deletions(-) diff --git a/examples/src/bin/debug.rs b/examples/src/bin/debug.rs index 2bdf4963a0..dadf51524f 100644 --- a/examples/src/bin/debug.rs +++ b/examples/src/bin/debug.rs @@ -7,7 +7,6 @@ // notice may not be copied, modified, or distributed except // according to those terms. -use std::sync::Arc; use vulkano::{ device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, @@ -15,7 +14,7 @@ use vulkano::{ instance::{ debug::{ DebugUtilsMessageSeverity, DebugUtilsMessageType, DebugUtilsMessenger, - DebugUtilsMessengerCreateInfo, + DebugUtilsMessengerCallback, DebugUtilsMessengerCreateInfo, }, Instance, InstanceCreateFlags, InstanceCreateInfo, InstanceExtensions, }, @@ -86,37 +85,41 @@ fn main() { message_type: DebugUtilsMessageType::GENERAL | DebugUtilsMessageType::VALIDATION | DebugUtilsMessageType::PERFORMANCE, - ..DebugUtilsMessengerCreateInfo::user_callback(Arc::new(|msg| { - let severity = if msg.severity.intersects(DebugUtilsMessageSeverity::ERROR) { - "error" - } else if msg.severity.intersects(DebugUtilsMessageSeverity::WARNING) { - "warning" - } else if msg.severity.intersects(DebugUtilsMessageSeverity::INFO) { - "information" - } else if msg.severity.intersects(DebugUtilsMessageSeverity::VERBOSE) { - "verbose" - } else { - panic!("no-impl"); - }; + ..DebugUtilsMessengerCreateInfo::user_callback(DebugUtilsMessengerCallback::new( + |message_severity, message_type, callback_data| { + let severity = if message_severity + .intersects(DebugUtilsMessageSeverity::ERROR) + { + "error" + } else if message_severity.intersects(DebugUtilsMessageSeverity::WARNING) { + "warning" + } else if message_severity.intersects(DebugUtilsMessageSeverity::INFO) { + "information" + } else if message_severity.intersects(DebugUtilsMessageSeverity::VERBOSE) { + "verbose" + } else { + panic!("no-impl"); + }; - let ty = if msg.ty.intersects(DebugUtilsMessageType::GENERAL) { - "general" - } else if msg.ty.intersects(DebugUtilsMessageType::VALIDATION) { - "validation" - } else if msg.ty.intersects(DebugUtilsMessageType::PERFORMANCE) { - "performance" - } else { - panic!("no-impl"); - }; + let ty = if message_type.intersects(DebugUtilsMessageType::GENERAL) { + "general" + } else if message_type.intersects(DebugUtilsMessageType::VALIDATION) { + "validation" + } else if message_type.intersects(DebugUtilsMessageType::PERFORMANCE) { + "performance" + } else { + panic!("no-impl"); + }; - println!( - "{} {} {}: {}", - msg.layer_prefix.unwrap_or("unknown"), - ty, - severity, - msg.description - ); - })) + println!( + "{} {} {}: {}", + callback_data.message_id_name.unwrap_or("unknown"), + ty, + severity, + callback_data.message + ); + }, + )) }, ) .ok() diff --git a/examples/src/bin/gl-interop.rs b/examples/src/bin/gl-interop.rs index c52af7c8f9..1dd9ae89d4 100644 --- a/examples/src/bin/gl-interop.rs +++ b/examples/src/bin/gl-interop.rs @@ -35,7 +35,9 @@ mod linux { Image, ImageCreateFlags, ImageCreateInfo, ImageType, ImageUsage, }, instance::{ - debug::{DebugUtilsMessenger, DebugUtilsMessengerCreateInfo}, + debug::{ + DebugUtilsMessenger, DebugUtilsMessengerCallback, DebugUtilsMessengerCreateInfo, + }, Instance, InstanceCreateFlags, InstanceCreateInfo, InstanceExtensions, }, memory::{ @@ -478,15 +480,17 @@ mod linux { let _debug_callback = unsafe { DebugUtilsMessenger::new( instance.clone(), - DebugUtilsMessengerCreateInfo::user_callback(Arc::new(|msg| { - println!( - "{} {:?} {:?}: {}", - msg.layer_prefix.unwrap_or("unknown"), - msg.ty, - msg.severity, - msg.description, - ); - })), + DebugUtilsMessengerCreateInfo::user_callback(DebugUtilsMessengerCallback::new( + |message_severity, message_type, callback_data| { + println!( + "{} {:?} {:?}: {}", + callback_data.message_id_name.unwrap_or("unknown"), + message_type, + message_severity, + callback_data.message, + ); + }, + )), ) .unwrap() }; diff --git a/vulkano-util/src/context.rs b/vulkano-util/src/context.rs index 00f439834b..80bbb73913 100644 --- a/vulkano-util/src/context.rs +++ b/vulkano-util/src/context.rs @@ -147,14 +147,10 @@ impl VulkanoContext { Instance::new(library, config.instance_create_info).expect("failed to create instance"); // Create debug callback - let _debug_utils_messenger = - config - .debug_create_info - .take() - .map(|dbg_create_info| unsafe { - DebugUtilsMessenger::new(instance.clone(), dbg_create_info) - .expect("failed to create debug callback") - }); + let _debug_utils_messenger = config.debug_create_info.take().map(|dbg_create_info| { + DebugUtilsMessenger::new(instance.clone(), dbg_create_info) + .expect("failed to create debug callback") + }); // Get prioritized device let physical_device = instance diff --git a/vulkano/src/instance/debug.rs b/vulkano/src/instance/debug.rs index 9a6aa789d6..c486c14835 100644 --- a/vulkano/src/instance/debug.rs +++ b/vulkano/src/instance/debug.rs @@ -23,12 +23,12 @@ //! # use vulkano::instance::Instance; //! # use std::sync::Arc; //! # let instance: Arc = return; -//! use vulkano::instance::debug::{DebugUtilsMessenger, DebugUtilsMessengerCreateInfo}; +//! use vulkano::instance::debug::{DebugUtilsMessenger, DebugUtilsMessengerCreateInfo, UserCallback}; //! //! let _callback = unsafe { //! DebugUtilsMessenger::new( //! instance, -//! DebugUtilsMessengerCreateInfo::user_callback(Arc::new(|msg| { +//! DebugUtilsMessengerCreateInfo::user_callback(UserCallback::new(|msg| { //! println!("Debug callback: {:?}", msg.description); //! })), //! ).ok() @@ -52,12 +52,11 @@ use std::{ fmt::{Debug, Error as FmtError, Formatter}, mem::MaybeUninit, panic::{catch_unwind, AssertUnwindSafe, RefUnwindSafe}, - ptr, + pin::Pin, + ptr, slice, sync::Arc, }; -pub type UserCallback = Arc) + RefUnwindSafe + Send + Sync>; - /// Registration of a callback called by validation layers. /// /// The callback can be called as long as this object is alive. @@ -65,26 +64,19 @@ pub type UserCallback = Arc) + RefUnwindSafe + Send + Sync>; pub struct DebugUtilsMessenger { handle: ash::vk::DebugUtilsMessengerEXT, instance: DebugWrapper>, - _user_callback: Box, + _user_callback: DebugUtilsMessengerCallback, } impl DebugUtilsMessenger { /// Initializes a debug callback. - /// - /// # 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( + #[inline] + pub fn new( instance: Arc, create_info: DebugUtilsMessengerCreateInfo, ) -> Result> { Self::validate_new(&instance, &create_info)?; - Ok(Self::new_unchecked(instance, create_info)?) + unsafe { Ok(Self::new_unchecked(instance, create_info)?) } } fn validate_new( @@ -119,16 +111,12 @@ impl DebugUtilsMessenger { _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 create_info_vk = ash::vk::DebugUtilsMessengerCreateInfoEXT { flags: ash::vk::DebugUtilsMessengerCreateFlagsEXT::empty(), 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 _, + p_user_data: user_callback.as_ptr() as *const c_void as *mut _, ..Default::default() }; @@ -183,44 +171,6 @@ impl Debug for DebugUtilsMessenger { } } -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 -} - /// Parameters to create a `DebugUtilsMessenger`. #[derive(Clone)] pub struct DebugUtilsMessengerCreateInfo { @@ -245,7 +195,7 @@ pub struct DebugUtilsMessengerCreateInfo { /// /// The callback is provided inside an `Arc` so that it can be shared across multiple /// messengers. - pub user_callback: UserCallback, + pub user_callback: DebugUtilsMessengerCallback, pub _ne: crate::NonExhaustive, } @@ -253,7 +203,7 @@ pub struct DebugUtilsMessengerCreateInfo { impl DebugUtilsMessengerCreateInfo { /// Returns a `DebugUtilsMessengerCreateInfo` with the specified `user_callback`. #[inline] - pub fn user_callback(user_callback: UserCallback) -> Self { + pub fn user_callback(user_callback: DebugUtilsMessengerCallback) -> Self { Self { message_severity: DebugUtilsMessageSeverity::ERROR | DebugUtilsMessageSeverity::WARNING, message_type: DebugUtilsMessageType::GENERAL, @@ -336,16 +286,198 @@ impl Debug for DebugUtilsMessengerCreateInfo { } } -/// 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, +/// The callback function for debug messages. +/// +/// This holds the provided closure inside an `Arc`, so it can be cloned cheaply. +#[derive(Clone)] +pub struct DebugUtilsMessengerCallback(Arc); + +type CallbackData = Pin< + Box< + dyn Fn( + DebugUtilsMessageSeverity, + DebugUtilsMessageType, + DebugUtilsMessengerCallbackData<'_>, + ) + RefUnwindSafe + + Send + + Sync, + >, +>; + +impl DebugUtilsMessengerCallback { + /// Returns a new `DebugUtilsMessengerCallback` wrapping the provided function. + /// + /// # Safety + /// + /// - `func` must not make any calls to the Vulkan API. + pub unsafe fn new( + func: impl Fn( + DebugUtilsMessageSeverity, + DebugUtilsMessageType, + DebugUtilsMessengerCallbackData<'_>, + ) + RefUnwindSafe + + Send + + Sync + + 'static, + ) -> Self { + Self(Arc::new(Box::pin(func))) + } + + pub(crate) fn as_ptr(&self) -> *const CallbackData { + self.0.as_ref() as _ + } +} + +pub(super) unsafe extern "system" fn trampoline( + message_severity_vk: ash::vk::DebugUtilsMessageSeverityFlagsEXT, + message_types_vk: ash::vk::DebugUtilsMessageTypeFlagsEXT, + callback_data_vk: *const ash::vk::DebugUtilsMessengerCallbackDataEXT, + user_data_vk: *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 ash::vk::DebugUtilsMessengerCallbackDataEXT { + s_type: _, + p_next: _, + flags: _, + p_message_id_name, + message_id_number, + p_message, + queue_label_count, + p_queue_labels, + cmd_buf_label_count, + p_cmd_buf_labels, + object_count, + p_objects, + } = *callback_data_vk; + + let callback_data = DebugUtilsMessengerCallbackData { + message_id_name: p_message_id_name + .as_ref() + .map(|p_message_id_name| CStr::from_ptr(p_message_id_name).to_str().unwrap()), + message_id_number, + message: CStr::from_ptr(p_message).to_str().unwrap(), + queue_labels: DebugUtilsMessengerCallbackLabelIter( + slice::from_raw_parts(p_queue_labels, queue_label_count as usize).iter(), + ), + cmd_buf_labels: DebugUtilsMessengerCallbackLabelIter( + slice::from_raw_parts(p_cmd_buf_labels, cmd_buf_label_count as usize).iter(), + ), + objects: DebugUtilsMessengerCallbackObjectNameInfoIter( + slice::from_raw_parts(p_objects, object_count as usize).iter(), + ), + }; + + let user_callback = &*(user_data_vk as *mut CallbackData as *const CallbackData); + + user_callback( + message_severity_vk.into(), + message_types_vk.into(), + callback_data, + ); + })); + + ash::vk::FALSE +} + +/// The data of a message received by the user callback. +#[non_exhaustive] +pub struct DebugUtilsMessengerCallbackData<'a> { + /// The particular message ID that is associated with the provided message. + /// + /// If the message is from a validation layer, then this may specify the part of the Vulkan + /// specification that was validated. + pub message_id_name: Option<&'a str>, + + /// The ID number of the message. + pub message_id_number: i32, + + /// The message detailing the conditions. + pub message: &'a str, + + /// Labels that were active in the current queue when the callback was triggered. + pub queue_labels: DebugUtilsMessengerCallbackLabelIter<'a>, + + /// Labels that were active in the current command buffer when the callback was triggered. + pub cmd_buf_labels: DebugUtilsMessengerCallbackLabelIter<'a>, + + /// Objects related to the message. + pub objects: DebugUtilsMessengerCallbackObjectNameInfoIter<'a>, +} + +/// The values of [`DebugUtilsLabel`], as returned to a messenger callback. +#[non_exhaustive] +pub struct DebugUtilsMessengerCallbackLabel<'a> { + /// The name of the label. + pub label_name: &'a str, + + /// An RGBA color value that is associated with the label, with values in the range `0.0..=1.0`. + pub color: &'a [f32; 4], +} + +#[derive(Clone, Debug)] +pub struct DebugUtilsMessengerCallbackLabelIter<'a>(slice::Iter<'a, ash::vk::DebugUtilsLabelEXT>); + +impl<'a> Iterator for DebugUtilsMessengerCallbackLabelIter<'a> { + type Item = DebugUtilsMessengerCallbackLabel<'a>; + + fn next(&mut self) -> Option { + self.0.next().map(|label| unsafe { + let &ash::vk::DebugUtilsLabelEXT { + s_type: _, + p_next: _, + p_label_name, + ref color, + } = label; + + DebugUtilsMessengerCallbackLabel { + label_name: CStr::from_ptr(p_label_name).to_str().unwrap(), + color, + } + }) + } +} + +/// An object that triggered a callback. +pub struct DebugUtilsMessengerCallbackObjectNameInfo<'a> { + /// The type of object. + pub object_type: ash::vk::ObjectType, + + /// The handle of the object. + pub object_handle: u64, + + /// The name of the object, if previously set. + pub object_name: Option<&'a str>, +} + +#[derive(Clone, Debug)] +pub struct DebugUtilsMessengerCallbackObjectNameInfoIter<'a>( + slice::Iter<'a, ash::vk::DebugUtilsObjectNameInfoEXT>, +); + +impl<'a> Iterator for DebugUtilsMessengerCallbackObjectNameInfoIter<'a> { + type Item = DebugUtilsMessengerCallbackObjectNameInfo<'a>; + + fn next(&mut self) -> Option { + self.0.next().map(|info| unsafe { + let &ash::vk::DebugUtilsObjectNameInfoEXT { + s_type: _, + p_next: _, + object_type, + object_handle, + p_object_name, + } = info; + + DebugUtilsMessengerCallbackObjectNameInfo { + object_type, + object_handle, + object_name: p_object_name + .as_ref() + .map(|p_object_name| CStr::from_ptr(p_object_name).to_str().unwrap()), + } + }) + } } vulkan_bitflags! { @@ -525,7 +657,9 @@ mod tests { message_type: DebugUtilsMessageType::GENERAL | DebugUtilsMessageType::VALIDATION | DebugUtilsMessageType::PERFORMANCE, - ..DebugUtilsMessengerCreateInfo::user_callback(Arc::new(|_| {})) + ..DebugUtilsMessengerCreateInfo::user_callback( + DebugUtilsMessengerCallback::new(|_, _, _| {}), + ) }, ) } diff --git a/vulkano/src/instance/mod.rs b/vulkano/src/instance/mod.rs index c702bfa2f5..28a9d5fb86 100644 --- a/vulkano/src/instance/mod.rs +++ b/vulkano/src/instance/mod.rs @@ -80,7 +80,8 @@ //! and must enable the appropriate features when creating the `Device` if you intend to use them. use self::debug::{ - DebugUtilsMessengerCreateInfo, UserCallback, ValidationFeatureDisable, ValidationFeatureEnable, + DebugUtilsMessengerCallback, DebugUtilsMessengerCreateInfo, ValidationFeatureDisable, + ValidationFeatureEnable, }; pub use self::layers::LayerProperties; use crate::{ @@ -275,7 +276,7 @@ pub struct Instance { enabled_layers: Vec, library: Arc, max_api_version: Version, - _user_callbacks: Vec>, + _user_callbacks: Vec, physical_devices: WeakArcOnceCache, physical_device_groups: RwLock<(bool, Vec)>, @@ -289,30 +290,8 @@ impl Instance { /// Creates a new `Instance`. #[inline] pub fn new( - library: Arc, - create_info: InstanceCreateInfo, - ) -> Result, Validated> { - unsafe { Self::with_debug_utils_messengers(library, create_info, []) } - } - - /// Creates a new `Instance` with debug messengers to use during the creation and destruction - /// of the instance. - /// - /// The debug messengers are not used at any other time, - /// [`DebugUtilsMessenger`](crate::instance::debug::DebugUtilsMessenger) should be used for - /// that. - /// - /// If `debug_utils_messengers` is not empty, the `ext_debug_utils` extension must be set in - /// `enabled_extensions`. - /// - /// # Safety - /// - /// - The `user_callback` of each element of `debug_utils_messengers` must not make any calls - /// to the Vulkan API. - pub unsafe fn with_debug_utils_messengers( library: Arc, mut create_info: InstanceCreateInfo, - debug_utils_messengers: impl IntoIterator, ) -> Result, Validated> { create_info.max_api_version.get_or_insert_with(|| { let api_version = library.api_version(); @@ -323,20 +302,14 @@ impl Instance { } }); - let debug_utils_messengers: SmallVec<[_; 4]> = debug_utils_messengers.into_iter().collect(); - Self::validate_new(&library, &create_info, &debug_utils_messengers)?; + Self::validate_new(&library, &create_info)?; - Ok(Self::with_debug_utils_messengers_unchecked( - library, - create_info, - debug_utils_messengers, - )?) + unsafe { Ok(Self::new_unchecked(library, create_info)?) } } fn validate_new( library: &VulkanLibrary, create_info: &InstanceCreateInfo, - debug_utils_messengers: &[DebugUtilsMessengerCreateInfo], ) -> Result<(), Box> { // VUID-vkCreateInstance-pCreateInfo-parameter create_info @@ -352,6 +325,7 @@ impl Instance { max_api_version, ref enabled_layers, ref enabled_extensions, + debug_utils_messengers: _, enabled_validation_features: _, disabled_validation_features: _, _ne, @@ -371,41 +345,13 @@ impl Instance { ..Default::default() })?; - if !debug_utils_messengers.is_empty() { - if !create_info.enabled_extensions.ext_debug_utils { - return Err(Box::new(ValidationError { - context: "debug_utils_messengers".into(), - problem: "is not empty".into(), - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ - Requires::InstanceExtension("ext_debug_utils"), - ])]), - vuids: &["VUID-VkInstanceCreateInfo-pNext-04926"], - })); - } - - for (index, messenger_create_info) in debug_utils_messengers.iter().enumerate() { - messenger_create_info - .validate_raw(api_version, enabled_extensions) - .map_err(|err| err.add_context(format!("debug_utils_messengers[{}]", index)))?; - } - } - Ok(()) } #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] pub unsafe fn new_unchecked( - library: Arc, - create_info: InstanceCreateInfo, - ) -> Result, VulkanError> { - Self::with_debug_utils_messengers_unchecked(library, create_info, []) - } - - #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] - pub unsafe fn with_debug_utils_messengers_unchecked( library: Arc, mut create_info: InstanceCreateInfo, - debug_utils_messengers: impl IntoIterator, ) -> Result, VulkanError> { create_info.max_api_version.get_or_insert_with(|| { let api_version = library.api_version(); @@ -436,6 +382,7 @@ impl Instance { max_api_version, ref enabled_layers, ref enabled_extensions, + ref debug_utils_messengers, ref enabled_validation_features, ref disabled_validation_features, _ne: _, @@ -531,32 +478,26 @@ impl Instance { create_info_vk.p_next = next as *const _ as *const _; } - let debug_utils_messengers = debug_utils_messengers.into_iter(); - let mut debug_utils_messenger_create_infos_vk = - Vec::with_capacity(debug_utils_messengers.size_hint().0); - let mut user_callbacks = Vec::with_capacity(debug_utils_messengers.size_hint().0); - - for create_info in debug_utils_messengers { - let DebugUtilsMessengerCreateInfo { - message_type, - message_severity, - user_callback, - _ne: _, - } = create_info; - - let user_callback = Box::new(user_callback); - let create_info = ash::vk::DebugUtilsMessengerCreateInfoEXT { - flags: ash::vk::DebugUtilsMessengerCreateFlagsEXT::empty(), - 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() - }; - - debug_utils_messenger_create_infos_vk.push(create_info); - user_callbacks.push(user_callback); - } + let mut debug_utils_messenger_create_infos_vk: Vec<_> = debug_utils_messengers + .iter() + .map(|create_info| { + let &DebugUtilsMessengerCreateInfo { + message_type, + message_severity, + ref user_callback, + _ne: _, + } = create_info; + + ash::vk::DebugUtilsMessengerCreateInfoEXT { + flags: ash::vk::DebugUtilsMessengerCreateFlagsEXT::empty(), + message_severity: message_severity.into(), + message_type: message_type.into(), + pfn_user_callback: Some(trampoline), + p_user_data: user_callback.as_ptr() as *const c_void as *mut _, + ..Default::default() + } + }) + .collect(); for i in 1..debug_utils_messenger_create_infos_vk.len() { debug_utils_messenger_create_infos_vk[i - 1].p_next = @@ -576,12 +517,7 @@ impl Instance { output.assume_init() }; - Ok(Self::from_handle( - library, - handle, - create_info, - user_callbacks, - )) + Ok(Self::from_handle(library, handle, create_info)) } /// Creates a new `Instance` from a raw object handle. @@ -594,7 +530,6 @@ impl Instance { library: Arc, handle: ash::vk::Instance, mut create_info: InstanceCreateInfo, - user_callbacks: Vec>, ) -> Arc { create_info.max_api_version.get_or_insert_with(|| { let api_version = library.api_version(); @@ -614,6 +549,7 @@ impl Instance { max_api_version, enabled_layers, enabled_extensions, + debug_utils_messengers, enabled_validation_features: _, disabled_validation_features: _, _ne: _, @@ -637,7 +573,10 @@ impl Instance { enabled_layers, library, max_api_version, - _user_callbacks: user_callbacks, + _user_callbacks: debug_utils_messengers + .into_iter() + .map(|m| m.user_callback) + .collect(), physical_devices: WeakArcOnceCache::new(), physical_device_groups: RwLock::new((false, Vec::new())), @@ -1012,6 +951,18 @@ pub struct InstanceCreateInfo { /// The default value is [`InstanceExtensions::empty()`]. pub enabled_extensions: InstanceExtensions, + /// Creation parameters for debug messengers, + /// to use during the creation and destruction of the instance. + /// + /// The debug messengers are not used at any other time, + /// [`DebugUtilsMessenger`](crate::instance::debug::DebugUtilsMessenger) should be used for + /// that. + /// + /// If this is not empty, the `ext_debug_utils` extension must be set in `enabled_extensions`. + /// + /// The default value is empty. + pub debug_utils_messengers: Vec, + /// Features of the validation layer to enable. /// /// If not empty, the @@ -1041,6 +992,7 @@ impl Default for InstanceCreateInfo { max_api_version: None, enabled_layers: Vec::new(), enabled_extensions: InstanceExtensions::empty(), + debug_utils_messengers: Vec::new(), enabled_validation_features: Vec::new(), disabled_validation_features: Vec::new(), _ne: crate::NonExhaustive(()), @@ -1079,6 +1031,7 @@ impl InstanceCreateInfo { max_api_version, enabled_layers: _, ref enabled_extensions, + ref debug_utils_messengers, ref enabled_validation_features, ref disabled_validation_features, _ne: _, @@ -1104,6 +1057,25 @@ impl InstanceCreateInfo { ..ValidationError::from_requirement(err) })?; + if !debug_utils_messengers.is_empty() { + if !enabled_extensions.ext_debug_utils { + return Err(Box::new(ValidationError { + context: "debug_utils_messengers".into(), + problem: "is not empty".into(), + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[ + Requires::InstanceExtension("ext_debug_utils"), + ])]), + vuids: &["VUID-VkInstanceCreateInfo-pNext-04926"], + })); + } + + for (index, messenger_create_info) in debug_utils_messengers.iter().enumerate() { + messenger_create_info + .validate_raw(api_version, enabled_extensions) + .map_err(|err| err.add_context(format!("debug_utils_messengers[{}]", index)))?; + } + } + if !enabled_validation_features.is_empty() { if !enabled_extensions.ext_validation_features { return Err(Box::new(ValidationError { From 876ac9b1e54c9277addebdc1c692686429707186 Mon Sep 17 00:00:00 2001 From: Rua Date: Sat, 29 Jul 2023 16:52:45 +0200 Subject: [PATCH 2/8] #2242 --- vulkano/src/device/mod.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/vulkano/src/device/mod.rs b/vulkano/src/device/mod.rs index a86f96cb1a..4ff8e6a18b 100644 --- a/vulkano/src/device/mod.rs +++ b/vulkano/src/device/mod.rs @@ -1663,6 +1663,16 @@ vulkan_bitflags! { pub unsafe trait DeviceOwned { /// Returns the device that owns `self`. fn device(&self) -> &Arc; + + /// Assigns a human-readable name to `object` for debugging purposes. + /// + /// If `object_name` is `None`, a previously set object name is removed. + fn set_debug_utils_object_name(&self, object_name: Option<&str>) -> Result<(), OomError> + where + Self: VulkanObject + Sized, + { + self.device().set_debug_utils_object_name(self, object_name) + } } unsafe impl DeviceOwned for T From 0cab409a2d0b209abac0c052d045f75cad8c5b40 Mon Sep 17 00:00:00 2001 From: Rua Date: Sat, 29 Jul 2023 17:14:41 +0200 Subject: [PATCH 3/8] Doctest fix --- vulkano/src/instance/debug.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/vulkano/src/instance/debug.rs b/vulkano/src/instance/debug.rs index c486c14835..96fa197abb 100644 --- a/vulkano/src/instance/debug.rs +++ b/vulkano/src/instance/debug.rs @@ -23,20 +23,20 @@ //! # use vulkano::instance::Instance; //! # use std::sync::Arc; //! # let instance: Arc = return; -//! use vulkano::instance::debug::{DebugUtilsMessenger, DebugUtilsMessengerCreateInfo, UserCallback}; +//! use vulkano::instance::debug::{DebugUtilsMessenger, DebugUtilsMessengerCallback, DebugUtilsMessengerCreateInfo}; //! //! let _callback = unsafe { //! DebugUtilsMessenger::new( //! instance, -//! DebugUtilsMessengerCreateInfo::user_callback(UserCallback::new(|msg| { -//! println!("Debug callback: {:?}", msg.description); -//! })), +//! DebugUtilsMessengerCreateInfo::user_callback( +//! DebugUtilsMessengerCallback::new(|message_severity, message_type, callback_data| { +//! println!("Debug callback: {:?}", callback_data.message); +//! }), +//! ), //! ).ok() //! }; //! ``` //! -//! 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 `DebugUtilsMessenger`'s constructor in a //! variable, it will be immediately destroyed and your callback will not work. @@ -192,9 +192,6 @@ pub struct DebugUtilsMessengerCreateInfo { /// /// 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: DebugUtilsMessengerCallback, pub _ne: crate::NonExhaustive, @@ -288,7 +285,8 @@ impl Debug for DebugUtilsMessengerCreateInfo { /// The callback function for debug messages. /// -/// This holds the provided closure inside an `Arc`, so it can be cloned cheaply. +/// The wrapper holds the provided closure inside an `Arc`, so it can be cloned cheaply. +/// This means it can be shared across multiple messengers. #[derive(Clone)] pub struct DebugUtilsMessengerCallback(Arc); From c1b580bcd77fcaad19a7b736567567a7f4b4d9d1 Mon Sep 17 00:00:00 2001 From: Rua Date: Sun, 30 Jul 2023 10:13:18 +0200 Subject: [PATCH 4/8] Take Arc out --- vulkano/src/instance/debug.rs | 18 +++++++----------- vulkano/src/instance/mod.rs | 2 +- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/vulkano/src/instance/debug.rs b/vulkano/src/instance/debug.rs index 96fa197abb..fe9c5966e3 100644 --- a/vulkano/src/instance/debug.rs +++ b/vulkano/src/instance/debug.rs @@ -64,7 +64,7 @@ use std::{ pub struct DebugUtilsMessenger { handle: ash::vk::DebugUtilsMessengerEXT, instance: DebugWrapper>, - _user_callback: DebugUtilsMessengerCallback, + _user_callback: Arc, } impl DebugUtilsMessenger { @@ -192,7 +192,7 @@ pub struct DebugUtilsMessengerCreateInfo { /// /// The closure must not make any calls to the Vulkan API. /// If the closure panics, the panic is caught and ignored. - pub user_callback: DebugUtilsMessengerCallback, + pub user_callback: Arc, pub _ne: crate::NonExhaustive, } @@ -200,7 +200,7 @@ pub struct DebugUtilsMessengerCreateInfo { impl DebugUtilsMessengerCreateInfo { /// Returns a `DebugUtilsMessengerCreateInfo` with the specified `user_callback`. #[inline] - pub fn user_callback(user_callback: DebugUtilsMessengerCallback) -> Self { + pub fn user_callback(user_callback: Arc) -> Self { Self { message_severity: DebugUtilsMessageSeverity::ERROR | DebugUtilsMessageSeverity::WARNING, message_type: DebugUtilsMessageType::GENERAL, @@ -284,11 +284,7 @@ impl Debug for DebugUtilsMessengerCreateInfo { } /// The callback function for debug messages. -/// -/// The wrapper holds the provided closure inside an `Arc`, so it can be cloned cheaply. -/// This means it can be shared across multiple messengers. -#[derive(Clone)] -pub struct DebugUtilsMessengerCallback(Arc); +pub struct DebugUtilsMessengerCallback(CallbackData); type CallbackData = Pin< Box< @@ -317,12 +313,12 @@ impl DebugUtilsMessengerCallback { + Send + Sync + 'static, - ) -> Self { - Self(Arc::new(Box::pin(func))) + ) -> Arc { + Arc::new(Self(Box::pin(func))) } pub(crate) fn as_ptr(&self) -> *const CallbackData { - self.0.as_ref() as _ + &self.0 as _ } } diff --git a/vulkano/src/instance/mod.rs b/vulkano/src/instance/mod.rs index 28a9d5fb86..72a07d4e71 100644 --- a/vulkano/src/instance/mod.rs +++ b/vulkano/src/instance/mod.rs @@ -276,7 +276,7 @@ pub struct Instance { enabled_layers: Vec, library: Arc, max_api_version: Version, - _user_callbacks: Vec, + _user_callbacks: Vec>, physical_devices: WeakArcOnceCache, physical_device_groups: RwLock<(bool, Vec)>, From 1b613a5570ed9ccd3f9f0c55b3a2d8744a0a9ce4 Mon Sep 17 00:00:00 2001 From: Rua Date: Sat, 5 Aug 2023 19:13:10 +0200 Subject: [PATCH 5/8] DeviceOwnedVulkanObject --- vulkano/src/device/mod.rs | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/vulkano/src/device/mod.rs b/vulkano/src/device/mod.rs index 4ff8e6a18b..8f378adb4a 100644 --- a/vulkano/src/device/mod.rs +++ b/vulkano/src/device/mod.rs @@ -1663,16 +1663,6 @@ vulkan_bitflags! { pub unsafe trait DeviceOwned { /// Returns the device that owns `self`. fn device(&self) -> &Arc; - - /// Assigns a human-readable name to `object` for debugging purposes. - /// - /// If `object_name` is `None`, a previously set object name is removed. - fn set_debug_utils_object_name(&self, object_name: Option<&str>) -> Result<(), OomError> - where - Self: VulkanObject + Sized, - { - self.device().set_debug_utils_object_name(self, object_name) - } } unsafe impl DeviceOwned for T @@ -1685,6 +1675,23 @@ where } } +/// Implemented on objects that implement both `DeviceOwned` and `VulkanObject`. +pub unsafe trait DeviceOwnedVulkanObject { + /// Assigns a human-readable name to `object` for debugging purposes. + /// + /// If `object_name` is `None`, a previously set object name is removed. + fn set_debug_utils_object_name(&self, object_name: Option<&str>) -> Result<(), OomError>; +} + +unsafe impl DeviceOwnedVulkanObject for T +where + T: DeviceOwned + VulkanObject, +{ + fn set_debug_utils_object_name(&self, object_name: Option<&str>) -> Result<(), OomError> { + self.device().set_debug_utils_object_name(self, object_name) + } +} + /// Same as [`DebugWrapper`], but also prints the device handle for disambiguation. /// /// [`DebugWrapper`]: crate:: DebugWrapper From 7abe7b4bf4babfb8a408c9ed1284117d83efe77c Mon Sep 17 00:00:00 2001 From: Rua Date: Sat, 5 Aug 2023 20:29:00 +0200 Subject: [PATCH 6/8] Update vulkano/src/device/mod.rs Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com> --- vulkano/src/device/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vulkano/src/device/mod.rs b/vulkano/src/device/mod.rs index 8f378adb4a..c32d15e343 100644 --- a/vulkano/src/device/mod.rs +++ b/vulkano/src/device/mod.rs @@ -1677,7 +1677,7 @@ where /// Implemented on objects that implement both `DeviceOwned` and `VulkanObject`. pub unsafe trait DeviceOwnedVulkanObject { - /// Assigns a human-readable name to `object` for debugging purposes. + /// Assigns a human-readable name to the object for debugging purposes. /// /// If `object_name` is `None`, a previously set object name is removed. fn set_debug_utils_object_name(&self, object_name: Option<&str>) -> Result<(), OomError>; From 5c195f39e09068b1c472eae07dbd6413bd2b5113 Mon Sep 17 00:00:00 2001 From: Rua Date: Sat, 5 Aug 2023 20:29:14 +0200 Subject: [PATCH 7/8] Update vulkano/src/instance/debug.rs Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com> --- vulkano/src/instance/debug.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vulkano/src/instance/debug.rs b/vulkano/src/instance/debug.rs index fe9c5966e3..bb1dc2fd24 100644 --- a/vulkano/src/instance/debug.rs +++ b/vulkano/src/instance/debug.rs @@ -23,7 +23,9 @@ //! # use vulkano::instance::Instance; //! # use std::sync::Arc; //! # let instance: Arc = return; -//! use vulkano::instance::debug::{DebugUtilsMessenger, DebugUtilsMessengerCallback, DebugUtilsMessengerCreateInfo}; +//! use vulkano::instance::debug::{ +//! DebugUtilsMessenger, DebugUtilsMessengerCallback, DebugUtilsMessengerCreateInfo, +//! }; //! //! let _callback = unsafe { //! DebugUtilsMessenger::new( From 07a8bea7d1d6fead9540e8b20686b6bab143f154 Mon Sep 17 00:00:00 2001 From: Rua Date: Sat, 5 Aug 2023 20:30:26 +0200 Subject: [PATCH 8/8] Fixes --- vulkano/src/instance/debug.rs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/vulkano/src/instance/debug.rs b/vulkano/src/instance/debug.rs index fe9c5966e3..d01c5c4098 100644 --- a/vulkano/src/instance/debug.rs +++ b/vulkano/src/instance/debug.rs @@ -52,7 +52,6 @@ use std::{ fmt::{Debug, Error as FmtError, Formatter}, mem::MaybeUninit, panic::{catch_unwind, AssertUnwindSafe, RefUnwindSafe}, - pin::Pin, ptr, slice, sync::Arc, }; @@ -286,16 +285,11 @@ impl Debug for DebugUtilsMessengerCreateInfo { /// The callback function for debug messages. pub struct DebugUtilsMessengerCallback(CallbackData); -type CallbackData = Pin< - Box< - dyn Fn( - DebugUtilsMessageSeverity, - DebugUtilsMessageType, - DebugUtilsMessengerCallbackData<'_>, - ) + RefUnwindSafe - + Send - + Sync, - >, +type CallbackData = Box< + dyn Fn(DebugUtilsMessageSeverity, DebugUtilsMessageType, DebugUtilsMessengerCallbackData<'_>) + + RefUnwindSafe + + Send + + Sync, >; impl DebugUtilsMessengerCallback { @@ -314,7 +308,7 @@ impl DebugUtilsMessengerCallback { + Sync + 'static, ) -> Arc { - Arc::new(Self(Box::pin(func))) + Arc::new(Self(Box::new(func))) } pub(crate) fn as_ptr(&self) -> *const CallbackData { @@ -434,6 +428,7 @@ impl<'a> Iterator for DebugUtilsMessengerCallbackLabelIter<'a> { } /// An object that triggered a callback. +#[non_exhaustive] pub struct DebugUtilsMessengerCallbackObjectNameInfo<'a> { /// The type of object. pub object_type: ash::vk::ObjectType,