Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable GPU-based validation for Vulkan #5046

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,12 @@ 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.
- When set, this flag implies `InstanceFlags::VALIDATION`.
- 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()
Expand Down
20 changes: 19 additions & 1 deletion examples/src/water/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -826,7 +826,25 @@ static TEST: crate::framework::ExampleTestParams = crate::framework::ExampleTest
height: 768,
optional_features: wgpu::Features::default(),
base_test_parameters: wgpu_test::TestParameters::default()
.downlevel_flags(wgpu::DownlevelFlags::READ_ONLY_DEPTH_STENCIL),
.downlevel_flags(wgpu::DownlevelFlags::READ_ONLY_DEPTH_STENCIL)
// To be fixed in <https://github.com/gfx-rs/wgpu/issues/5231>.
.expect_fail(wgpu_test::FailureCase {
backends: Some(wgpu::Backends::VULKAN),
reasons: vec![
wgpu_test::FailureReason::validation_error().with_message(concat!(
"vkCmdEndRenderPass: ",
"Hazard WRITE_AFTER_READ in subpass 0 for attachment 1 depth aspect ",
"during store with storeOp VK_ATTACHMENT_STORE_OP_STORE. ",
"Access info (",
"usage: SYNC_LATE_FRAGMENT_TESTS_DEPTH_STENCIL_ATTACHMENT_WRITE, ",
"prior_usage: SYNC_FRAGMENT_SHADER_SHADER_SAMPLED_READ, ",
"read_barriers: VkPipelineStageFlags2(0), ",
"command: vkCmdDraw"
)),
],
behavior: wgpu_test::FailureBehavior::AssertFailure,
..Default::default()
}),
comparisons: &[wgpu_test::ComparisonType::Mean(0.01)],
_phantom: std::marker::PhantomData::<Example>,
};
5 changes: 5 additions & 0 deletions tests/tests/shader/struct_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,11 @@ static UNIFORM_INPUT: GpuTestConfiguration = GpuTestConfiguration::new()
FailureCase::backend(wgpu::Backends::VULKAN)
.validation_error("a matrix with stride 8 not satisfying alignment to 16"),
)
.expect_fail(
FailureCase::backend(wgpu::Backends::VULKAN).validation_error(
"Failure to instrument shader. Proceeding with non-instrumented shader.",
),
)
.limits(Limits::downlevel_defaults()),
)
.run_async(|ctx| {
Expand Down
69 changes: 55 additions & 14 deletions wgpu-hal/src/vulkan/instance.rs
ErichDonGubler marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,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
Expand All @@ -229,16 +245,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();
Expand Down Expand Up @@ -643,6 +650,30 @@ 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);
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();

Expand All @@ -653,10 +684,10 @@ impl crate::Instance<super::Api> for super::Instance {

// 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()) {
Expand Down Expand Up @@ -756,6 +787,16 @@ impl crate::Instance<super::Api> 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)
Expand Down
6 changes: 4 additions & 2 deletions wgpu-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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. Implies [`Self::VALIDATION`]. Currently, this only changes
ErichDonGubler marked this conversation as resolved.
Show resolved Hide resolved
/// 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;
}
}
Expand Down
Loading