summaryrefslogtreecommitdiffstats
path: root/third_party/rust/wgpu-hal/src/vulkan/instance.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/wgpu-hal/src/vulkan/instance.rs')
-rw-r--r--third_party/rust/wgpu-hal/src/vulkan/instance.rs183
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)