Skip to content

Commit

Permalink
vulkan: Log validation messages during instance creation/destruction
Browse files Browse the repository at this point in the history
  • Loading branch information
exrook committed Oct 27, 2023
1 parent 4c5a817 commit 169fdfd
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 46 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ Bottom level categories:

For naga changelogs at or before v0.14.0. See [naga's changelog](naga/CHANGELOG.md).

### Changes

#### General

- Log vulkan validation layer messages during instance creation and destruction: By @exrook in [#4586](https://github.com/gfx-rs/wgpu/pull/4586)

## v0.18.0 (2023-10-25)

### Desktop OpenGL 3.3+ Support on Windows
Expand Down
144 changes: 98 additions & 46 deletions wgpu-hal/src/vulkan/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,17 @@ unsafe extern "system" fn debug_utils_messenger_callback(
vk::FALSE
}

impl super::DebugUtilsCreateInfo {
fn to_vk_create_info(&self) -> vk::DebugUtilsMessengerCreateInfoEXTBuilder<'_> {
let user_data_ptr: *const super::DebugUtilsMessengerUserData = &*self.callback_data;
vk::DebugUtilsMessengerCreateInfoEXT::builder()
.message_severity(self.severity)
.message_type(self.message_type)
.user_data(user_data_ptr as *mut _)
.pfn_user_callback(Some(debug_utils_messenger_callback))
}
}

impl super::Swapchain {
/// # Safety
///
Expand Down Expand Up @@ -295,50 +306,27 @@ impl super::Instance {
raw_instance: ash::Instance,
instance_api_version: u32,
android_sdk_version: u32,
debug_utils_user_data: Option<super::DebugUtilsMessengerUserData>,
debug_utils_create_info: Option<super::DebugUtilsCreateInfo>,
extensions: Vec<&'static CStr>,
flags: wgt::InstanceFlags,
has_nv_optimus: bool,
drop_guard: Option<crate::DropGuard>,
) -> Result<Self, crate::InstanceError> {
log::info!("Instance version: 0x{:x}", instance_api_version);

let debug_utils = if let Some(debug_callback_user_data) = debug_utils_user_data {
let debug_utils = if let Some(debug_utils_create_info) = debug_utils_create_info {
if extensions.contains(&ext::DebugUtils::name()) {
log::info!("Enabling debug utils");
// Move the callback data to the heap, to ensure it will never be
// moved.
let callback_data = Box::new(debug_callback_user_data);

let extension = ext::DebugUtils::new(&entry, &raw_instance);
// having ERROR unconditionally because Vk doesn't like empty flags
let mut severity = vk::DebugUtilsMessageSeverityFlagsEXT::ERROR;
if log::max_level() >= log::LevelFilter::Debug {
severity |= vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE;
}
if log::max_level() >= log::LevelFilter::Info {
severity |= vk::DebugUtilsMessageSeverityFlagsEXT::INFO;
}
if log::max_level() >= log::LevelFilter::Warn {
severity |= vk::DebugUtilsMessageSeverityFlagsEXT::WARNING;
}
let user_data_ptr: *const super::DebugUtilsMessengerUserData = &*callback_data;
let vk_info = vk::DebugUtilsMessengerCreateInfoEXT::builder()
.flags(vk::DebugUtilsMessengerCreateFlagsEXT::empty())
.message_severity(severity)
.message_type(
vk::DebugUtilsMessageTypeFlagsEXT::GENERAL
| vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION
| vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE,
)
.pfn_user_callback(Some(debug_utils_messenger_callback))
.user_data(user_data_ptr as *mut _);
let vk_info = debug_utils_create_info.to_vk_create_info();
let messenger =
unsafe { extension.create_debug_utils_messenger(&vk_info, None) }.unwrap();

Some(super::DebugUtils {
extension,
messenger,
callback_data,
callback_data: debug_utils_create_info.callback_data,
})
} else {
log::info!("Debug utils not enabled: extension not listed");
Expand Down Expand Up @@ -557,10 +545,12 @@ impl super::Instance {
impl Drop for super::InstanceShared {
fn drop(&mut self) {
unsafe {
if let Some(du) = self.debug_utils.take() {
// Keep du alive since destroy_instance may also log
let _du = self.debug_utils.take().map(|du| {
du.extension
.destroy_debug_utils_messenger(du.messenger, None);
}
du
});
if let Some(_drop_guard) = self.drop_guard.take() {
self.raw.destroy_instance(None);
}
Expand Down Expand Up @@ -610,7 +600,7 @@ impl crate::Instance<super::Api> for super::Instance {
},
);

let extensions = Self::desired_extensions(&entry, instance_api_version, desc.flags)?;
let mut extensions = Self::desired_extensions(&entry, instance_api_version, desc.flags)?;

let instance_layers = entry.enumerate_instance_layer_properties().map_err(|e| {
log::info!("enumerate_instance_layer_properties: {:?}", e);
Expand All @@ -637,22 +627,77 @@ impl crate::Instance<super::Api> for super::Instance {

let mut layers: Vec<&'static CStr> = Vec::new();

let mut validation_features = None;
// Request validation layer if asked.
let mut debug_callback_user_data = None;
if desc.flags.contains(wgt::InstanceFlags::VALIDATION) {
let mut debug_utils = None;
if desc.flags.intersects(wgt::InstanceFlags::VALIDATION) {
let validation_layer_name =
CStr::from_bytes_with_nul(b"VK_LAYER_KHRONOS_validation\0").unwrap();
if let Some(layer_properties) = find_layer(&instance_layers, validation_layer_name) {
layers.push(validation_layer_name);
debug_callback_user_data = Some(super::DebugUtilsMessengerUserData {
validation_layer_description: cstr_from_bytes_until_nul(
&layer_properties.description,
)
.unwrap()
.to_owned(),
validation_layer_spec_version: layer_properties.spec_version,
has_obs_layer,
});

if extensions.contains(&ext::DebugUtils::name()) {
// Put the callback data on the heap, to ensure it will never be
// moved.
let callback_data = Box::new(super::DebugUtilsMessengerUserData {
validation_layer_description: cstr_from_bytes_until_nul(
&layer_properties.description,
)
.unwrap()
.to_owned(),
validation_layer_spec_version: layer_properties.spec_version,
has_obs_layer,
});

// having ERROR unconditionally because Vk doesn't like empty flags
let mut severity = vk::DebugUtilsMessageSeverityFlagsEXT::ERROR;
if log::max_level() >= log::LevelFilter::Debug {
severity |= vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE;
}
if log::max_level() >= log::LevelFilter::Info {
severity |= vk::DebugUtilsMessageSeverityFlagsEXT::INFO;
}
if log::max_level() >= log::LevelFilter::Warn {
severity |= vk::DebugUtilsMessageSeverityFlagsEXT::WARNING;
}

let message_type = vk::DebugUtilsMessageTypeFlagsEXT::GENERAL
| vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION
| vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE;

let create_info = super::DebugUtilsCreateInfo {
severity,
message_type,
callback_data,
};

let vk_create_info = create_info.to_vk_create_info().build();

debug_utils = Some((create_info, vk_create_info));
}

let validation_extensions = entry
.enumerate_instance_extension_properties(Some(validation_layer_name))
.map_err(|e| {
crate::InstanceError::with_source(
String::from("enumerate_instance_extension_properties() failed for validation layer"),
e,
)
})?;

if desc.flags.contains(wgt::InstanceFlags::DEBUG)
&& validation_extensions.iter().any(|inst_ext| {
cstr_from_bytes_until_nul(&inst_ext.extension_name)
== Some(vk::ExtValidationFeaturesFn::name())
})
{
extensions.push(vk::ExtValidationFeaturesFn::name());
validation_features = Some(
vk::ValidationFeaturesEXT::builder().enabled_validation_features(&[
vk::ValidationFeatureEnableEXT::DEBUG_PRINTF,
]),
);
}
} else {
log::warn!(
"InstanceFlags::VALIDATION requested, but unable to find layer: {}",
Expand Down Expand Up @@ -691,23 +736,30 @@ impl crate::Instance<super::Api> for super::Instance {
if extensions.contains(&ash::vk::KhrPortabilityEnumerationFn::name()) {
flags |= vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR;
}

let vk_instance = {
let str_pointers = layers
.iter()
.chain(extensions.iter())
.map(|&s| {
.map(|&s: &&'static _| {
// Safe because `layers` and `extensions` entries have static lifetime.
s.as_ptr()
})
.collect::<Vec<_>>();

let create_info = vk::InstanceCreateInfo::builder()
let mut create_info = vk::InstanceCreateInfo::builder()
.flags(flags)
.application_info(&app_info)
.enabled_layer_names(&str_pointers[..layers.len()])
.enabled_extension_names(&str_pointers[layers.len()..]);

if let Some(validation_features) = validation_features.as_mut() {
create_info = create_info.push_next(validation_features);
}

if let Some(&mut (_, ref mut vk_create_info)) = debug_utils.as_mut() {
create_info = create_info.push_next(vk_create_info);
}

unsafe { entry.create_instance(&create_info, None) }.map_err(|e| {
crate::InstanceError::with_source(
String::from("Entry::create_instance() failed"),
Expand All @@ -722,7 +774,7 @@ impl crate::Instance<super::Api> for super::Instance {
vk_instance,
instance_api_version,
android_sdk_version,
debug_callback_user_data,
debug_utils.map(|(i, _)| i),
extensions,
desc.flags,
has_nv_optimus,
Expand Down
6 changes: 6 additions & 0 deletions wgpu-hal/src/vulkan/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ struct DebugUtils {
callback_data: Box<DebugUtilsMessengerUserData>,
}

pub struct DebugUtilsCreateInfo {
severity: vk::DebugUtilsMessageSeverityFlagsEXT,
message_type: vk::DebugUtilsMessageTypeFlagsEXT,
callback_data: Box<DebugUtilsMessengerUserData>,
}

/// User data needed by `instance::debug_utils_messenger_callback`.
///
/// When we create the [`vk::DebugUtilsMessengerEXT`], the `pUserData`
Expand Down

0 comments on commit 169fdfd

Please sign in to comment.