1 // Copyright (c) 2016 The vulkano developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
6 // at your option. All files in the project carrying such
7 // notice may not be copied, modified, or distributed except
8 // according to those terms.
9 
10 //! Debug messenger called by intermediate layers or by the driver.
11 //!
12 //! When working on an application, it is recommended to register a debug messenger. For example if
13 //! you enable the validation layers provided by the official Vulkan SDK, they will warn you about
14 //! invalid API usages or performance problems by calling this callback. The callback can also
15 //! be called by the driver or by whatever intermediate layer is activated.
16 //!
17 //! Note that the vulkano library can also emit messages to warn you about performance issues.
18 //! TODO: ^ that's not the case yet, need to choose whether we keep this idea
19 //!
20 //! # Examples
21 //!
22 //! ```
23 //! # use vulkano::instance::Instance;
24 //! # use std::sync::Arc;
25 //! # let instance: Arc<Instance> = return;
26 //! use vulkano::instance::debug::{DebugUtilsMessenger, DebugUtilsMessengerCreateInfo};
27 //!
28 //! let _callback = unsafe {
29 //!     DebugUtilsMessenger::new(
30 //!         instance,
31 //!         DebugUtilsMessengerCreateInfo::user_callback(Arc::new(|msg| {
32 //!             println!("Debug callback: {:?}", msg.description);
33 //!         })),
34 //!     ).ok()
35 //! };
36 //! ```
37 //!
38 //! The type of `msg` in the callback is [`Message`].
39 //!
40 //! Note that you must keep the `_callback` object alive for as long as you want your callback to
41 //! be callable. If you don't store the return value of `DebugUtilsMessenger`'s constructor in a
42 //! variable, it will be immediately destroyed and your callback will not work.
43 
44 use super::Instance;
45 use crate::{
46     macros::{vulkan_bitflags, vulkan_enum},
47     RequirementNotMet, RequiresOneOf, VulkanError, VulkanObject,
48 };
49 use std::{
50     error::Error,
51     ffi::{c_void, CStr},
52     fmt::{Debug, Display, Error as FmtError, Formatter},
53     mem::MaybeUninit,
54     panic::{catch_unwind, AssertUnwindSafe, RefUnwindSafe},
55     ptr,
56     sync::Arc,
57 };
58 
59 pub(super) type UserCallback = Arc<dyn Fn(&Message<'_>) + RefUnwindSafe + Send + Sync>;
60 
61 /// Registration of a callback called by validation layers.
62 ///
63 /// The callback can be called as long as this object is alive.
64 #[must_use = "The DebugUtilsMessenger object must be kept alive for as long as you want your callback to be called"]
65 pub struct DebugUtilsMessenger {
66     handle: ash::vk::DebugUtilsMessengerEXT,
67     instance: Arc<Instance>,
68     _user_callback: Box<UserCallback>,
69 }
70 
71 impl DebugUtilsMessenger {
72     /// Initializes a debug callback.
73     ///
74     /// # Panics
75     ///
76     /// - Panics if the `message_severity` or `message_type` members of `create_info` are empty.
77     ///
78     /// # Safety
79     ///
80     /// - `create_info.user_callback` must not make any calls to the Vulkan API.
new( instance: Arc<Instance>, mut create_info: DebugUtilsMessengerCreateInfo, ) -> Result<Self, DebugUtilsMessengerCreationError>81     pub unsafe fn new(
82         instance: Arc<Instance>,
83         mut create_info: DebugUtilsMessengerCreateInfo,
84     ) -> Result<Self, DebugUtilsMessengerCreationError> {
85         Self::validate_create(&instance, &mut create_info)?;
86         let (handle, user_callback) = Self::record_create(&instance, create_info)?;
87 
88         Ok(DebugUtilsMessenger {
89             handle,
90             instance,
91             _user_callback: user_callback,
92         })
93     }
94 
validate_create( instance: &Instance, create_info: &mut DebugUtilsMessengerCreateInfo, ) -> Result<(), DebugUtilsMessengerCreationError>95     fn validate_create(
96         instance: &Instance,
97         create_info: &mut DebugUtilsMessengerCreateInfo,
98     ) -> Result<(), DebugUtilsMessengerCreationError> {
99         let &mut DebugUtilsMessengerCreateInfo {
100             message_type,
101             message_severity,
102             user_callback: _,
103             _ne: _,
104         } = create_info;
105 
106         if !instance.enabled_extensions().ext_debug_utils {
107             return Err(DebugUtilsMessengerCreationError::RequirementNotMet {
108                 required_for: "`DebugUtilsMessenger::new`",
109                 requires_one_of: RequiresOneOf {
110                     instance_extensions: &["ext_debug_utils"],
111                     ..Default::default()
112                 },
113             });
114         }
115 
116         // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageSeverity-parameter
117         message_severity.validate_instance(instance)?;
118 
119         // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageSeverity-requiredbitmask
120         assert!(!message_severity.is_empty());
121 
122         // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageType-parameter
123         message_type.validate_instance(instance)?;
124 
125         // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageType-requiredbitmask
126         assert!(!message_type.is_empty());
127 
128         // VUID-PFN_vkDebugUtilsMessengerCallbackEXT-None-04769
129         // Can't be checked, creation is unsafe.
130 
131         Ok(())
132     }
133 
record_create( instance: &Instance, create_info: DebugUtilsMessengerCreateInfo, ) -> Result< (ash::vk::DebugUtilsMessengerEXT, Box<UserCallback>), DebugUtilsMessengerCreationError, >134     unsafe fn record_create(
135         instance: &Instance,
136         create_info: DebugUtilsMessengerCreateInfo,
137     ) -> Result<
138         (ash::vk::DebugUtilsMessengerEXT, Box<UserCallback>),
139         DebugUtilsMessengerCreationError,
140     > {
141         let DebugUtilsMessengerCreateInfo {
142             message_severity,
143             message_type,
144             user_callback,
145             _ne: _,
146         } = create_info;
147 
148         // Note that we need to double-box the callback, because a `*const Fn()` is a fat pointer
149         // that can't be cast to a `*const c_void`.
150         let user_callback = Box::new(user_callback);
151 
152         let create_info = ash::vk::DebugUtilsMessengerCreateInfoEXT {
153             flags: ash::vk::DebugUtilsMessengerCreateFlagsEXT::empty(),
154             message_severity: message_severity.into(),
155             message_type: message_type.into(),
156             pfn_user_callback: Some(trampoline),
157             p_user_data: &*user_callback as &Arc<_> as *const Arc<_> as *const c_void as *mut _,
158             ..Default::default()
159         };
160 
161         let fns = instance.fns();
162 
163         let handle = {
164             let mut output = MaybeUninit::uninit();
165             (fns.ext_debug_utils.create_debug_utils_messenger_ext)(
166                 instance.handle(),
167                 &create_info,
168                 ptr::null(),
169                 output.as_mut_ptr(),
170             )
171             .result()
172             .map_err(VulkanError::from)?;
173             output.assume_init()
174         };
175 
176         Ok((handle, user_callback))
177     }
178 }
179 
180 impl Drop for DebugUtilsMessenger {
181     #[inline]
drop(&mut self)182     fn drop(&mut self) {
183         unsafe {
184             let fns = self.instance.fns();
185             (fns.ext_debug_utils.destroy_debug_utils_messenger_ext)(
186                 self.instance.handle(),
187                 self.handle,
188                 ptr::null(),
189             );
190         }
191     }
192 }
193 
194 impl Debug for DebugUtilsMessenger {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>195     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
196         let Self {
197             handle,
198             instance,
199             _user_callback: _,
200         } = self;
201 
202         f.debug_struct("DebugUtilsMessenger")
203             .field("handle", handle)
204             .field("instance", instance)
205             .finish_non_exhaustive()
206     }
207 }
208 
trampoline( message_severity: ash::vk::DebugUtilsMessageSeverityFlagsEXT, message_types: ash::vk::DebugUtilsMessageTypeFlagsEXT, callback_data: *const ash::vk::DebugUtilsMessengerCallbackDataEXT, user_data: *mut c_void, ) -> ash::vk::Bool32209 pub(super) unsafe extern "system" fn trampoline(
210     message_severity: ash::vk::DebugUtilsMessageSeverityFlagsEXT,
211     message_types: ash::vk::DebugUtilsMessageTypeFlagsEXT,
212     callback_data: *const ash::vk::DebugUtilsMessengerCallbackDataEXT,
213     user_data: *mut c_void,
214 ) -> ash::vk::Bool32 {
215     // Since we box the closure, the type system doesn't detect that the `UnwindSafe`
216     // bound is enforced. Therefore we enforce it manually.
217     let _ = catch_unwind(AssertUnwindSafe(move || {
218         let user_callback = user_data as *mut UserCallback as *const _;
219         let user_callback: &UserCallback = &*user_callback;
220 
221         let layer_prefix = (*callback_data)
222             .p_message_id_name
223             .as_ref()
224             .map(|msg_id_name| {
225                 CStr::from_ptr(msg_id_name)
226                     .to_str()
227                     .expect("debug callback message not utf-8")
228             });
229 
230         let description = CStr::from_ptr((*callback_data).p_message)
231             .to_str()
232             .expect("debug callback message not utf-8");
233 
234         let message = Message {
235             severity: message_severity.into(),
236             ty: message_types.into(),
237             layer_prefix,
238             description,
239         };
240 
241         user_callback(&message);
242     }));
243 
244     ash::vk::FALSE
245 }
246 
247 /// Error that can happen when creating a `DebugUtilsMessenger`.
248 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
249 pub enum DebugUtilsMessengerCreationError {
250     RequirementNotMet {
251         required_for: &'static str,
252         requires_one_of: RequiresOneOf,
253     },
254 }
255 
256 impl Error for DebugUtilsMessengerCreationError {}
257 
258 impl Display for DebugUtilsMessengerCreationError {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>259     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
260         match self {
261             Self::RequirementNotMet {
262                 required_for,
263                 requires_one_of,
264             } => write!(
265                 f,
266                 "a requirement was not met for: {}; requires one of: {}",
267                 required_for, requires_one_of,
268             ),
269         }
270     }
271 }
272 
273 impl From<VulkanError> for DebugUtilsMessengerCreationError {
from(err: VulkanError) -> DebugUtilsMessengerCreationError274     fn from(err: VulkanError) -> DebugUtilsMessengerCreationError {
275         panic!("unexpected error: {:?}", err)
276     }
277 }
278 
279 impl From<RequirementNotMet> for DebugUtilsMessengerCreationError {
from(err: RequirementNotMet) -> Self280     fn from(err: RequirementNotMet) -> Self {
281         Self::RequirementNotMet {
282             required_for: err.required_for,
283             requires_one_of: err.requires_one_of,
284         }
285     }
286 }
287 
288 /// Parameters to create a `DebugUtilsMessenger`.
289 #[derive(Clone)]
290 pub struct DebugUtilsMessengerCreateInfo {
291     /// The message severity types that the callback should be called for.
292     ///
293     /// The value must not be empty.
294     ///
295     /// The default value is `MessageSeverity::errors_and_warnings()`.
296     pub message_severity: DebugUtilsMessageSeverity,
297 
298     /// The message types that the callback should be called for.
299     ///
300     /// The value must not be empty.
301     ///
302     /// The default value is `MessageType::general()`.
303     pub message_type: DebugUtilsMessageType,
304 
305     /// The closure that should be called.
306     ///
307     /// The closure must not make any calls to the Vulkan API.
308     /// If the closure panics, the panic is caught and ignored.
309     ///
310     /// The callback is provided inside an `Arc` so that it can be shared across multiple
311     /// messengers.
312     pub user_callback: UserCallback,
313 
314     pub _ne: crate::NonExhaustive,
315 }
316 
317 impl DebugUtilsMessengerCreateInfo {
318     /// Returns a `DebugUtilsMessengerCreateInfo` with the specified `user_callback`.
319     #[inline]
user_callback(user_callback: UserCallback) -> Self320     pub fn user_callback(user_callback: UserCallback) -> Self {
321         Self {
322             message_severity: DebugUtilsMessageSeverity::ERROR | DebugUtilsMessageSeverity::WARNING,
323             message_type: DebugUtilsMessageType::GENERAL,
324             user_callback,
325             _ne: crate::NonExhaustive(()),
326         }
327     }
328 }
329 
330 impl Debug for DebugUtilsMessengerCreateInfo {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>331     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
332         let Self {
333             message_severity,
334             message_type,
335             user_callback: _,
336             _ne: _,
337         } = self;
338 
339         f.debug_struct("DebugUtilsMessengerCreateInfo")
340             .field("message_severity", message_severity)
341             .field("message_type", message_type)
342             .finish_non_exhaustive()
343     }
344 }
345 
346 /// A message received by the callback.
347 pub struct Message<'a> {
348     /// Severity of message.
349     pub severity: DebugUtilsMessageSeverity,
350     /// Type of message,
351     pub ty: DebugUtilsMessageType,
352     /// Prefix of the layer that reported this message or `None` if unknown.
353     pub layer_prefix: Option<&'a str>,
354     /// Description of the message.
355     pub description: &'a str,
356 }
357 
358 vulkan_bitflags! {
359     #[non_exhaustive]
360 
361     /// Severity of message.
362     DebugUtilsMessageSeverity = DebugUtilsMessageSeverityFlagsEXT(u32);
363 
364     /// An error that may cause undefined results, including an application crash.
365     ERROR = ERROR,
366 
367     /// An unexpected use.
368     WARNING = WARNING,
369 
370     /// An informational message that may be handy when debugging an application.
371     INFO = INFO,
372 
373     /// Diagnostic information from the loader and layers.
374     VERBOSE = VERBOSE,
375 }
376 
377 vulkan_bitflags! {
378     #[non_exhaustive]
379 
380     /// Type of message.
381     DebugUtilsMessageType = DebugUtilsMessageTypeFlagsEXT(u32);
382 
383     /// Specifies that some general event has occurred.
384     GENERAL = GENERAL,
385 
386     /// Specifies that something has occurred during validation against the vulkan specification
387     VALIDATION = VALIDATION,
388 
389     /// Specifies a potentially non-optimal use of Vulkan
390     PERFORMANCE = PERFORMANCE,
391 }
392 
393 /// A label to associate with a span of work in a queue.
394 ///
395 /// When debugging, labels can be useful to identify which queue, or where in a specific queue,
396 /// something happened.
397 #[derive(Clone, Debug)]
398 pub struct DebugUtilsLabel {
399     /// The name of the label.
400     ///
401     /// The default value is empty.
402     pub label_name: String,
403 
404     /// An RGBA color value that is associated with the label, with values in the range `0.0..=1.0`.
405     ///
406     /// If set to `[0.0; 4]`, the value is ignored.
407     ///
408     /// The default value is `[0.0; 4]`.
409     pub color: [f32; 4],
410 
411     pub _ne: crate::NonExhaustive,
412 }
413 
414 impl Default for DebugUtilsLabel {
415     #[inline]
default() -> Self416     fn default() -> Self {
417         Self {
418             label_name: String::new(),
419             color: [0.0; 4],
420             _ne: crate::NonExhaustive(()),
421         }
422     }
423 }
424 
425 vulkan_enum! {
426     #[non_exhaustive]
427 
428     /// Features of the validation layer to enable.
429     ValidationFeatureEnable = ValidationFeatureEnableEXT(i32);
430 
431     /// The validation layer will use shader programs running on the GPU to provide additional
432     /// validation.
433     ///
434     /// This must not be used together with `DebugPrintf`.
435     GpuAssisted = GPU_ASSISTED,
436 
437     /// The validation layer will reserve and use one descriptor set slot for its own use.
438     /// The limit reported by
439     /// [`max_bound_descriptor_sets`](crate::device::Properties::max_bound_descriptor_sets)
440     /// will be reduced by 1.
441     ///
442     /// `GpuAssisted` must also be enabled.
443     GpuAssistedReserveBindingSlot = GPU_ASSISTED_RESERVE_BINDING_SLOT,
444 
445     /// The validation layer will report recommendations that are not strictly errors,
446     /// but that may be considered good Vulkan practice.
447     BestPractices = BEST_PRACTICES,
448 
449     /// The validation layer will process `debugPrintfEXT` operations in shaders, and send them
450     /// to the debug callback.
451     ///
452     /// This must not be used together with `GpuAssisted`.
453     DebugPrintf = DEBUG_PRINTF,
454 
455     /// The validation layer will report errors relating to synchronization, such as data races and
456     /// the use of synchronization primitives.
457     SynchronizationValidation = SYNCHRONIZATION_VALIDATION,
458 }
459 
460 vulkan_enum! {
461     #[non_exhaustive]
462 
463     /// Features of the validation layer to disable.
464     ValidationFeatureDisable = ValidationFeatureDisableEXT(i32);
465 
466     /// All validation is disabled.
467     All = ALL,
468 
469     /// Shader validation is disabled.
470     Shaders = SHADERS,
471 
472     /// Thread safety validation is disabled.
473     ThreadSafety = THREAD_SAFETY,
474 
475     /// Stateless parameter validation is disabled.
476     ApiParameters = API_PARAMETERS,
477 
478     /// Object lifetime validation is disabled.
479     ObjectLifetimes = OBJECT_LIFETIMES,
480 
481     /// Core validation checks are disabled.
482     ///
483     /// This also disables shader validation and GPU-assisted validation.
484     CoreChecks = CORE_CHECKS,
485 
486     /// Protection against duplicate non-dispatchable handles is disabled.
487     UniqueHandles = UNIQUE_HANDLES,
488 
489     /// Results of shader validation will not be cached, and are validated from scratch each time.
490     ShaderValidationCache = SHADER_VALIDATION_CACHE,
491 }
492 
493 #[cfg(test)]
494 mod tests {
495     use super::*;
496     use crate::{
497         instance::{InstanceCreateInfo, InstanceExtensions},
498         VulkanLibrary,
499     };
500     use std::thread;
501 
502     #[test]
ensure_sendable()503     fn ensure_sendable() {
504         // It's useful to be able to initialize a DebugUtilsMessenger on one thread
505         // and keep it alive on another thread.
506         let instance = {
507             let library = match VulkanLibrary::new() {
508                 Ok(x) => x,
509                 Err(_) => return,
510             };
511 
512             match Instance::new(
513                 library,
514                 InstanceCreateInfo {
515                     enabled_extensions: InstanceExtensions {
516                         ext_debug_utils: true,
517                         ..InstanceExtensions::empty()
518                     },
519                     ..Default::default()
520                 },
521             ) {
522                 Ok(x) => x,
523                 Err(_) => return,
524             }
525         };
526 
527         let callback = unsafe {
528             DebugUtilsMessenger::new(
529                 instance,
530                 DebugUtilsMessengerCreateInfo {
531                     message_severity: DebugUtilsMessageSeverity::ERROR,
532                     message_type: DebugUtilsMessageType::GENERAL
533                         | DebugUtilsMessageType::VALIDATION
534                         | DebugUtilsMessageType::PERFORMANCE,
535                     ..DebugUtilsMessengerCreateInfo::user_callback(Arc::new(|_| {}))
536                 },
537             )
538         }
539         .unwrap();
540         thread::spawn(move || {
541             drop(callback);
542         });
543     }
544 }
545