• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 callback called by intermediate layers or by the driver.
11 //!
12 //! When working on an application, it is recommended to register a debug callback. 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 //! # Example
21 //!
22 //! ```
23 //! # use vulkano::instance::Instance;
24 //! # use std::sync::Arc;
25 //! # let instance: Arc<Instance> = return;
26 //! use vulkano::instance::debug::DebugCallback;
27 //!
28 //! let _callback = DebugCallback::errors_and_warnings(&instance, |msg| {
29 //!     println!("Debug callback: {:?}", msg.description);
30 //! }).ok();
31 //! ```
32 //!
33 //! The type of `msg` in the callback is [`Message`](struct.Message.html).
34 //!
35 //! Note that you must keep the `_callback` object alive for as long as you want your callback to
36 //! be callable. If you don't store the return value of `DebugCallback`'s constructor in a
37 //! variable, it will be immediately destroyed and your callback will not work.
38 //!
39 
40 use crate::check_errors;
41 use crate::instance::Instance;
42 use crate::Error;
43 use crate::VulkanObject;
44 use std::error;
45 use std::ffi::CStr;
46 use std::fmt;
47 use std::mem::MaybeUninit;
48 use std::os::raw::c_void;
49 use std::panic;
50 use std::ptr;
51 use std::sync::Arc;
52 
53 /// Registration of a callback called by validation layers.
54 ///
55 /// The callback can be called as long as this object is alive.
56 #[must_use = "The DebugCallback object must be kept alive for as long as you want your callback \
57               to be called"]
58 pub struct DebugCallback {
59     instance: Arc<Instance>,
60     debug_report_callback: ash::vk::DebugUtilsMessengerEXT,
61     user_callback: Box<Box<dyn Fn(&Message) + Send>>,
62 }
63 
64 impl DebugCallback {
65     /// Initializes a debug callback.
66     ///
67     /// Panics generated by calling `user_callback` are ignored.
new<F>( instance: &Arc<Instance>, severity: MessageSeverity, ty: MessageType, user_callback: F, ) -> Result<DebugCallback, DebugCallbackCreationError> where F: Fn(&Message) + 'static + Send + panic::RefUnwindSafe,68     pub fn new<F>(
69         instance: &Arc<Instance>,
70         severity: MessageSeverity,
71         ty: MessageType,
72         user_callback: F,
73     ) -> Result<DebugCallback, DebugCallbackCreationError>
74     where
75         F: Fn(&Message) + 'static + Send + panic::RefUnwindSafe,
76     {
77         if !instance.enabled_extensions().ext_debug_utils {
78             return Err(DebugCallbackCreationError::MissingExtension);
79         }
80 
81         // Note that we need to double-box the callback, because a `*const Fn()` is a fat pointer
82         // that can't be cast to a `*const c_void`.
83         let user_callback = Box::new(Box::new(user_callback) as Box<_>);
84 
85         unsafe extern "system" fn callback(
86             severity: ash::vk::DebugUtilsMessageSeverityFlagsEXT,
87             ty: ash::vk::DebugUtilsMessageTypeFlagsEXT,
88             callback_data: *const ash::vk::DebugUtilsMessengerCallbackDataEXT,
89             user_data: *mut c_void,
90         ) -> ash::vk::Bool32 {
91             let user_callback = user_data as *mut Box<dyn Fn()> as *const _;
92             let user_callback: &Box<dyn Fn(&Message)> = &*user_callback;
93 
94             let layer_prefix = (*callback_data)
95                 .p_message_id_name
96                 .as_ref()
97                 .map(|msg_id_name| {
98                     CStr::from_ptr(msg_id_name)
99                         .to_str()
100                         .expect("debug callback message not utf-8")
101                 });
102 
103             let description = CStr::from_ptr((*callback_data).p_message)
104                 .to_str()
105                 .expect("debug callback message not utf-8");
106 
107             let message = Message {
108                 severity: MessageSeverity {
109                     information: !(severity & ash::vk::DebugUtilsMessageSeverityFlagsEXT::INFO)
110                         .is_empty(),
111                     warning: !(severity & ash::vk::DebugUtilsMessageSeverityFlagsEXT::WARNING)
112                         .is_empty(),
113                     error: !(severity & ash::vk::DebugUtilsMessageSeverityFlagsEXT::ERROR)
114                         .is_empty(),
115                     verbose: !(severity & ash::vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE)
116                         .is_empty(),
117                 },
118                 ty: MessageType {
119                     general: !(ty & ash::vk::DebugUtilsMessageTypeFlagsEXT::GENERAL).is_empty(),
120                     validation: !(ty & ash::vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION)
121                         .is_empty(),
122                     performance: !(ty & ash::vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE)
123                         .is_empty(),
124                 },
125                 layer_prefix,
126                 description,
127             };
128 
129             // Since we box the closure, the type system doesn't detect that the `UnwindSafe`
130             // bound is enforced. Therefore we enforce it manually.
131             let _ = panic::catch_unwind(panic::AssertUnwindSafe(move || {
132                 user_callback(&message);
133             }));
134 
135             ash::vk::FALSE
136         }
137 
138         let severity = {
139             let mut flags = ash::vk::DebugUtilsMessageSeverityFlagsEXT::empty();
140             if severity.information {
141                 flags |= ash::vk::DebugUtilsMessageSeverityFlagsEXT::INFO;
142             }
143             if severity.warning {
144                 flags |= ash::vk::DebugUtilsMessageSeverityFlagsEXT::WARNING;
145             }
146             if severity.error {
147                 flags |= ash::vk::DebugUtilsMessageSeverityFlagsEXT::ERROR;
148             }
149             if severity.verbose {
150                 flags |= ash::vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE;
151             }
152             flags
153         };
154 
155         let ty = {
156             let mut flags = ash::vk::DebugUtilsMessageTypeFlagsEXT::empty();
157             if ty.general {
158                 flags |= ash::vk::DebugUtilsMessageTypeFlagsEXT::GENERAL;
159             }
160             if ty.validation {
161                 flags |= ash::vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION;
162             }
163             if ty.performance {
164                 flags |= ash::vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE;
165             }
166             flags
167         };
168 
169         let infos = ash::vk::DebugUtilsMessengerCreateInfoEXT {
170             flags: ash::vk::DebugUtilsMessengerCreateFlagsEXT::empty(),
171             message_severity: severity,
172             message_type: ty,
173             pfn_user_callback: Some(callback),
174             p_user_data: &*user_callback as &Box<_> as *const Box<_> as *const c_void as *mut _,
175             ..Default::default()
176         };
177 
178         let fns = instance.fns();
179 
180         let debug_report_callback = unsafe {
181             let mut output = MaybeUninit::uninit();
182             check_errors(fns.ext_debug_utils.create_debug_utils_messenger_ext(
183                 instance.internal_object(),
184                 &infos,
185                 ptr::null(),
186                 output.as_mut_ptr(),
187             ))?;
188             output.assume_init()
189         };
190 
191         Ok(DebugCallback {
192             instance: instance.clone(),
193             debug_report_callback,
194             user_callback,
195         })
196     }
197 
198     /// Initializes a debug callback with errors and warnings.
199     ///
200     /// Shortcut for `new(instance, MessageTypes::errors_and_warnings(), user_callback)`.
201     #[inline]
errors_and_warnings<F>( instance: &Arc<Instance>, user_callback: F, ) -> Result<DebugCallback, DebugCallbackCreationError> where F: Fn(&Message) + Send + 'static + panic::RefUnwindSafe,202     pub fn errors_and_warnings<F>(
203         instance: &Arc<Instance>,
204         user_callback: F,
205     ) -> Result<DebugCallback, DebugCallbackCreationError>
206     where
207         F: Fn(&Message) + Send + 'static + panic::RefUnwindSafe,
208     {
209         DebugCallback::new(
210             instance,
211             MessageSeverity::errors_and_warnings(),
212             MessageType::general(),
213             user_callback,
214         )
215     }
216 }
217 
218 impl Drop for DebugCallback {
219     #[inline]
drop(&mut self)220     fn drop(&mut self) {
221         unsafe {
222             let fns = self.instance.fns();
223             fns.ext_debug_utils.destroy_debug_utils_messenger_ext(
224                 self.instance.internal_object(),
225                 self.debug_report_callback,
226                 ptr::null(),
227             );
228         }
229     }
230 }
231 
232 /// A message received by the callback.
233 pub struct Message<'a> {
234     /// Severity of message.
235     pub severity: MessageSeverity,
236     /// Type of message,
237     pub ty: MessageType,
238     /// Prefix of the layer that reported this message or `None` if unknown.
239     pub layer_prefix: Option<&'a str>,
240     /// Description of the message.
241     pub description: &'a str,
242 }
243 
244 /// Severity of message.
245 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
246 pub struct MessageSeverity {
247     /// An error that may cause undefined results, including an application crash.
248     pub error: bool,
249     /// An unexpected use.
250     pub warning: bool,
251     /// An informational message that may be handy when debugging an application.
252     pub information: bool,
253     /// Diagnostic information from the loader and layers.
254     pub verbose: bool,
255 }
256 
257 impl MessageSeverity {
258     /// Builds a `MessageSeverity` with all fields set to `false` expect `error`.
259     #[inline]
errors() -> MessageSeverity260     pub const fn errors() -> MessageSeverity {
261         MessageSeverity {
262             error: true,
263             ..MessageSeverity::none()
264         }
265     }
266 
267     /// Builds a `MessageSeverity` with all fields set to `false` expect `warning`.
268     #[inline]
warnings() -> MessageSeverity269     pub const fn warnings() -> MessageSeverity {
270         MessageSeverity {
271             warning: true,
272             ..MessageSeverity::none()
273         }
274     }
275 
276     /// Builds a `MessageSeverity` with all fields set to `false` expect `information`.
277     #[inline]
information() -> MessageSeverity278     pub const fn information() -> MessageSeverity {
279         MessageSeverity {
280             information: true,
281             ..MessageSeverity::none()
282         }
283     }
284 
285     /// Builds a `MessageSeverity` with all fields set to `false` expect `verbose`.
286     #[inline]
verbose() -> MessageSeverity287     pub const fn verbose() -> MessageSeverity {
288         MessageSeverity {
289             verbose: true,
290             ..MessageSeverity::none()
291         }
292     }
293 
294     /// Builds a `MessageSeverity` with all fields set to `false` expect `error`, `warning`
295     /// and `performance_warning`.
296     #[inline]
errors_and_warnings() -> MessageSeverity297     pub const fn errors_and_warnings() -> MessageSeverity {
298         MessageSeverity {
299             error: true,
300             warning: true,
301             ..MessageSeverity::none()
302         }
303     }
304 
305     /// Builds a `MessageSeverity` with all fields set to `false`.
306     #[inline]
none() -> MessageSeverity307     pub const fn none() -> MessageSeverity {
308         MessageSeverity {
309             error: false,
310             warning: false,
311             information: false,
312             verbose: false,
313         }
314     }
315 
316     /// Builds a `MessageSeverity` with all fields set to `true`.
317     #[inline]
all() -> MessageSeverity318     pub const fn all() -> MessageSeverity {
319         MessageSeverity {
320             error: true,
321             warning: true,
322             information: true,
323             verbose: true,
324         }
325     }
326 }
327 
328 impl std::ops::BitOr for MessageSeverity {
329     type Output = Self;
bitor(self, rhs: Self) -> Self::Output330     fn bitor(self, rhs: Self) -> Self::Output {
331         MessageSeverity {
332             error: self.error | rhs.error,
333             warning: self.warning | rhs.warning,
334             information: self.information | rhs.information,
335             verbose: self.verbose | rhs.verbose,
336         }
337     }
338 }
339 
340 /// Type of message.
341 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
342 pub struct MessageType {
343     /// Specifies that some general event has occurred.
344     pub general: bool,
345     /// Specifies that something has occurred during validation against the vulkan specification
346     pub validation: bool,
347     /// Specifies a potentially non-optimal use of Vulkan
348     pub performance: bool,
349 }
350 
351 impl MessageType {
352     /// Builds a `MessageType` with general field set to `true`.
353     #[inline]
general() -> MessageType354     pub const fn general() -> MessageType {
355         MessageType {
356             general: true,
357             validation: false,
358             performance: false,
359         }
360     }
361 
362     /// Builds a `MessageType` with validation field set to `true`.
363     #[inline]
validation() -> MessageType364     pub const fn validation() -> MessageType {
365         MessageType {
366             general: false,
367             validation: true,
368             performance: false,
369         }
370     }
371 
372     /// Builds a `MessageType` with performance field set to `true`.
373     #[inline]
performance() -> MessageType374     pub const fn performance() -> MessageType {
375         MessageType {
376             general: false,
377             validation: false,
378             performance: true,
379         }
380     }
381 
382     /// Builds a `MessageType` with all fields set to `true`.
383     #[inline]
all() -> MessageType384     pub const fn all() -> MessageType {
385         MessageType {
386             general: true,
387             validation: true,
388             performance: true,
389         }
390     }
391 
392     /// Builds a `MessageType` with all fields set to `false`.
393     #[inline]
none() -> MessageType394     pub const fn none() -> MessageType {
395         MessageType {
396             general: false,
397             validation: false,
398             performance: false,
399         }
400     }
401 }
402 
403 impl std::ops::BitOr for MessageType {
404     type Output = Self;
bitor(self, rhs: Self) -> Self::Output405     fn bitor(self, rhs: Self) -> Self::Output {
406         MessageType {
407             general: self.general | rhs.general,
408             validation: self.validation | rhs.validation,
409             performance: self.performance | rhs.performance,
410         }
411     }
412 }
413 
414 /// Error that can happen when creating a debug callback.
415 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
416 pub enum DebugCallbackCreationError {
417     /// The `EXT_debug_utils` extension was not enabled.
418     MissingExtension,
419 }
420 
421 impl error::Error for DebugCallbackCreationError {}
422 
423 impl fmt::Display for DebugCallbackCreationError {
424     #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>425     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
426         write!(
427             fmt,
428             "{}",
429             match *self {
430                 DebugCallbackCreationError::MissingExtension => {
431                     "the `EXT_debug_utils` extension was not enabled"
432                 }
433             }
434         )
435     }
436 }
437 
438 impl From<Error> for DebugCallbackCreationError {
439     #[inline]
from(err: Error) -> DebugCallbackCreationError440     fn from(err: Error) -> DebugCallbackCreationError {
441         panic!("unexpected error: {:?}", err)
442     }
443 }
444 
445 #[cfg(test)]
446 mod tests {
447     use super::*;
448     use std::thread;
449     #[test]
ensure_sendable()450     fn ensure_sendable() {
451         // It's useful to be able to initialize a DebugCallback on one thread
452         // and keep it alive on another thread.
453         let instance = instance!();
454         let severity = MessageSeverity::none();
455         let ty = MessageType::all();
456         let callback = DebugCallback::new(&instance, severity, ty, |_| {});
457         thread::spawn(move || {
458             let _ = callback;
459         });
460     }
461 }
462