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