From 6d69ebdfd16df51521a09072c24e7373110d9aa7 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Thu, 11 Jan 2024 14:09:12 -0500 Subject: [PATCH] feat(vulkan): enable GPU-based validation for Vulkan backend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If [`VK_LAYER_KHRONOS_validation`] is present, and it supports [`VK_EXT_validation_features`], we can configure it with another instance creation info. element of type [`VkValidationFeaturesEXT`] to enable GPU-based validation. Wire `InstanceFlags::GPU_BASED_VALIDATION` to do this in the Vulkan backend. It's even already finding issues in our `examples`! But…we'd like to handle those later. So, I've broken that out to [a separate issue][examples-fixups]. It is apparent from this and the [DX12 implementation of GPU-based validation] that we will need to communicate clearly to users that `InstanceFlags::GPU_BASED_VALIDATION` implies `InstanceFlags::VALIDATION`. Not all backends enforce this yet; I have [split out this work][follow-up for flag implication]. Note that `VK_EXT_validation_features` has been deprecated in favor of the more general layer configuration mechanism offered by [`VK_EXT_layer_settings`]. [DX12 implementation of GPU-based validation]: https://github.com/gfx-rs/wgpu/pull/5146 [`VK_EXT_layer_settings`]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_layer_settings.html [`VK_EXT_validation_features`]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_validation_features.html [`VK_LAYER_KHRONOS_validation`]:https://vulkan.lunarg.com/doc/sdk/1.3.275.0/linux/khronos_validation_layer.html [`VkValidationFeaturesEXT`]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkValidationFeaturesEXT.html [examples-fixups]: https://github.com/gfx-rs/wgpu/issues/5231 [follow-up for flag implication]: https://github.com/gfx-rs/wgpu/pull/5232 --- CHANGELOG.md | 4 ++-- wgpu-hal/src/vulkan/instance.rs | 34 ++++++++++++++++++++++++++++++++- wgpu-types/src/lib.rs | 6 ++++-- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3cae9dbb7d..83a64a5d9b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -89,11 +89,11 @@ Bottom level categories: - Eager release of GPU resources comes from device.trackers. By @bradwerth in [#5075](https://github.com/gfx-rs/wgpu/pull/5075) - `wgpu-types`'s `trace` and `replay` features have been replaced by the `serde` feature. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) - `wgpu-core`'s `serial-pass` feature has been removed. Use `serde` instead. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) -- Added `InstanceFlags::GPU_BASED_VALIDATION`, which enables GPU-based validation for shaders. This is currently only supported on the DX12 back end; other platforms ignore this flag, for now. +- Added `InstanceFlags::GPU_BASED_VALIDATION`, which enables GPU-based validation for shaders. This is currently only supported on the DX12 and Vulkan backends; other platforms ignore this flag, for now. - This has been added to the set of flags set by `InstanceFlags::debugging` and `InstanceFlags::from_build_config`. If you notice your graphics workloads running more slowly, this may be the culprit. - As with other instance flags, this flag can be changed in calls to `InstanceFlags::with_env` with the new `WGPU_GPU_BASED_VALIDATION` environment variable. - By @ErichDonGubler in [#5046](https://github.com/gfx-rs/wgpu/pull/5046). + By @ErichDonGubler in [#5146](https://github.com/gfx-rs/wgpu/pull/5146), [#5046](https://github.com/gfx-rs/wgpu/pull/5046). - `wgpu::Instance` can now report which `wgpu::Backends` are available based on the build configuration. By @wumpf [#5167](https://github.com/gfx-rs/wgpu/pull/5167) ```diff -wgpu::Instance::any_backend_feature_enabled() diff --git a/wgpu-hal/src/vulkan/instance.rs b/wgpu-hal/src/vulkan/instance.rs index 199ce511883..e6c651678cb 100644 --- a/wgpu-hal/src/vulkan/instance.rs +++ b/wgpu-hal/src/vulkan/instance.rs @@ -653,6 +653,26 @@ impl crate::Instance for super::Instance { 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); + let validation_features_are_enabled = || { + validation_layer_properties.is_some().then(|| { + let exts = Self::enumerate_instance_extension_properties( + &entry, + Some(validation_layer_name), + )?; + let mut ext_names = exts + .iter() + .filter_map(|ext| cstr_from_bytes_until_nul(&ext.extension_name)); + let found = + ext_names.any(|ext_name| ext_name == vk::ExtValidationFeaturesFn::name()); + Ok(found) + }) + }; + let should_enable_gpu_based_validation = desc + .flags + .intersects(wgt::InstanceFlags::GPU_BASED_VALIDATION) + && validation_features_are_enabled() + .transpose()? + .unwrap_or(false); 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(); @@ -664,7 +684,9 @@ impl crate::Instance for super::Instance { // Request validation layer if asked. let mut debug_utils = None; - if desc.flags.intersects(wgt::InstanceFlags::VALIDATION) { + 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); @@ -765,6 +787,16 @@ impl crate::Instance for super::Instance { create_info = create_info.push_next(vk_create_info); } + let mut gpu_assisted_validation = vk::ValidationFeaturesEXT::builder() + .enabled_validation_features(&[ + vk::ValidationFeatureEnableEXT::GPU_ASSISTED, + vk::ValidationFeatureEnableEXT::GPU_ASSISTED_RESERVE_BINDING_SLOT, + vk::ValidationFeatureEnableEXT::SYNCHRONIZATION_VALIDATION, + ]); + if should_enable_gpu_based_validation { + create_info = create_info.push_next(&mut gpu_assisted_validation); + } + unsafe { profiling::scope!("vkCreateInstance"); entry.create_instance(&create_info, None) diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 003cbb84736..0346e0b9161 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -904,13 +904,15 @@ bitflags::bitflags! { /// This mainly applies to a Vulkan driver's compliance version. If the major compliance version /// is `0`, then the driver is ignored. This flag allows that driver to be enabled for testing. const ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER = 1 << 3; - /// Enable GPU-based validation. Currently, this only changes behavior on the DX12 - /// backend. + /// Enable GPU-based validation. Currently, this only changes behavior on the DX12 and + /// Vulkan backends. /// /// Supported platforms: /// /// - D3D12; called ["GPU-based validation", or /// "GBV"](https://web.archive.org/web/20230206120404/https://learn.microsoft.com/en-us/windows/win32/direct3d12/using-d3d12-debug-layer-gpu-based-validation) + /// - Vulkan, via the `VK_LAYER_KHRONOS_validation` layer; called ["GPU-Assisted + /// Validation"](https://github.com/KhronosGroup/Vulkan-ValidationLayers/blob/e45aeb85079e0835694cb8f03e6681fd18ae72c9/docs/gpu_validation.md#gpu-assisted-validation) const GPU_BASED_VALIDATION = 1 << 4; } }