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