diff options
Diffstat (limited to 'third_party/rust/wgpu-hal/src/vulkan/instance.rs')
-rw-r--r-- | third_party/rust/wgpu-hal/src/vulkan/instance.rs | 183 |
1 files changed, 125 insertions, 58 deletions
diff --git a/third_party/rust/wgpu-hal/src/vulkan/instance.rs b/third_party/rust/wgpu-hal/src/vulkan/instance.rs index c4ef573461..771938b0b0 100644 --- a/third_party/rust/wgpu-hal/src/vulkan/instance.rs +++ b/third_party/rust/wgpu-hal/src/vulkan/instance.rs @@ -6,6 +6,7 @@ use std::{ thread, }; +use arrayvec::ArrayVec; use ash::{ extensions::{ext, khr}, vk, @@ -34,11 +35,13 @@ unsafe extern "system" fn debug_utils_messenger_callback( // the debug range start and end appear in different command buffers. let khronos_validation_layer = std::ffi::CStr::from_bytes_with_nul(b"Khronos Validation Layer\0").unwrap(); - if user_data.validation_layer_description.as_ref() == khronos_validation_layer - && user_data.validation_layer_spec_version >= vk::make_api_version(0, 1, 3, 240) - && user_data.validation_layer_spec_version <= vk::make_api_version(0, 1, 3, 250) - { - return vk::FALSE; + if let Some(layer_properties) = user_data.validation_layer_properties.as_ref() { + if layer_properties.layer_description.as_ref() == khronos_validation_layer + && layer_properties.layer_spec_version >= vk::make_api_version(0, 1, 3, 240) + && layer_properties.layer_spec_version <= vk::make_api_version(0, 1, 3, 250) + { + return vk::FALSE; + } } } @@ -211,6 +214,22 @@ impl super::Instance { &self.shared } + fn enumerate_instance_extension_properties( + entry: &ash::Entry, + layer_name: Option<&CStr>, + ) -> Result<Vec<vk::ExtensionProperties>, crate::InstanceError> { + let instance_extensions = { + profiling::scope!("vkEnumerateInstanceExtensionProperties"); + entry.enumerate_instance_extension_properties(layer_name) + }; + instance_extensions.map_err(|e| { + crate::InstanceError::with_source( + String::from("enumerate_instance_extension_properties() failed"), + e, + ) + }) + } + /// Return the instance extension names wgpu would like to enable. /// /// Return a vector of the names of instance extensions actually available @@ -229,16 +248,7 @@ impl super::Instance { _instance_api_version: u32, flags: wgt::InstanceFlags, ) -> Result<Vec<&'static CStr>, crate::InstanceError> { - let instance_extensions = { - profiling::scope!("vkEnumerateInstanceExtensionProperties"); - entry.enumerate_instance_extension_properties(None) - }; - let instance_extensions = instance_extensions.map_err(|e| { - crate::InstanceError::with_source( - String::from("enumerate_instance_extension_properties() failed"), - e, - ) - })?; + let instance_extensions = Self::enumerate_instance_extension_properties(entry, None)?; // Check our extensions against the available extensions let mut extensions: Vec<&'static CStr> = Vec::new(); @@ -643,6 +653,31 @@ impl crate::Instance<super::Api> for super::Instance { .find(|inst_layer| cstr_from_bytes_until_nul(&inst_layer.layer_name) == Some(name)) } + let validation_layer_name = + CStr::from_bytes_with_nul(b"VK_LAYER_KHRONOS_validation\0").unwrap(); + let validation_layer_properties = find_layer(&instance_layers, validation_layer_name); + + // Determine if VK_EXT_validation_features is available, so we can enable + // GPU assisted validation and synchronization validation. + let validation_features_are_enabled = if validation_layer_properties.is_some() { + // Get the all the instance extension properties. + let exts = + Self::enumerate_instance_extension_properties(&entry, Some(validation_layer_name))?; + // Convert all the names of the extensions into an iterator of CStrs. + let mut ext_names = exts + .iter() + .filter_map(|ext| cstr_from_bytes_until_nul(&ext.extension_name)); + // Find the validation features extension. + ext_names.any(|ext_name| ext_name == vk::ExtValidationFeaturesFn::name()) + } else { + false + }; + + let should_enable_gpu_based_validation = desc + .flags + .intersects(wgt::InstanceFlags::GPU_BASED_VALIDATION) + && validation_features_are_enabled; + let nv_optimus_layer = CStr::from_bytes_with_nul(b"VK_LAYER_NV_optimus\0").unwrap(); let has_nv_optimus = find_layer(&instance_layers, nv_optimus_layer).is_some(); @@ -651,52 +686,33 @@ impl crate::Instance<super::Api> for super::Instance { let mut layers: Vec<&'static CStr> = Vec::new(); + let has_debug_extension = extensions.contains(&ext::DebugUtils::name()); + let mut debug_user_data = has_debug_extension.then(|| { + // Put the callback data on the heap, to ensure it will never be + // moved. + Box::new(super::DebugUtilsMessengerUserData { + validation_layer_properties: None, + has_obs_layer, + }) + }); + // Request validation layer if asked. - 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) { + if desc.flags.intersects(wgt::InstanceFlags::VALIDATION) + || should_enable_gpu_based_validation + { + if let Some(layer_properties) = validation_layer_properties { layers.push(validation_layer_name); - 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)); + if let Some(debug_user_data) = debug_user_data.as_mut() { + debug_user_data.validation_layer_properties = + Some(super::ValidationLayerProperties { + layer_description: cstr_from_bytes_until_nul( + &layer_properties.description, + ) + .unwrap() + .to_owned(), + layer_spec_version: layer_properties.spec_version, + }); } } else { log::warn!( @@ -705,6 +721,35 @@ impl crate::Instance<super::Api> for super::Instance { ); } } + let mut debug_utils = if let Some(callback_data) = debug_user_data { + // 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(); + + Some((create_info, vk_create_info)) + } else { + None + }; #[cfg(target_os = "android")] let android_sdk_version = { @@ -756,6 +801,28 @@ impl crate::Instance<super::Api> for super::Instance { create_info = create_info.push_next(vk_create_info); } + // Enable explicit validation features if available + let mut validation_features; + let mut validation_feature_list: ArrayVec<_, 3>; + if validation_features_are_enabled { + validation_feature_list = ArrayVec::new(); + + // Always enable synchronization validation + validation_feature_list + .push(vk::ValidationFeatureEnableEXT::SYNCHRONIZATION_VALIDATION); + + // Only enable GPU assisted validation if requested. + if should_enable_gpu_based_validation { + validation_feature_list.push(vk::ValidationFeatureEnableEXT::GPU_ASSISTED); + validation_feature_list + .push(vk::ValidationFeatureEnableEXT::GPU_ASSISTED_RESERVE_BINDING_SLOT); + } + + validation_features = vk::ValidationFeaturesEXT::builder() + .enabled_validation_features(&validation_feature_list); + create_info = create_info.push_next(&mut validation_features); + } + unsafe { profiling::scope!("vkCreateInstance"); entry.create_instance(&create_info, None) |