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

Add support for ext_validation_features #2015

Merged
merged 2 commits into from
Oct 4, 2022
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
69 changes: 68 additions & 1 deletion vulkano/src/instance/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@
//!

use super::Instance;
use crate::{macros::vulkan_bitflags, RequirementNotMet, RequiresOneOf, VulkanError, VulkanObject};
use crate::{
macros::{vulkan_bitflags, vulkan_enum},
RequirementNotMet, RequiresOneOf, VulkanError, VulkanObject,
};
use std::{
error::Error,
ffi::{c_void, CStr},
Expand Down Expand Up @@ -428,6 +431,70 @@ impl Default for DebugUtilsLabel {
}
}

vulkan_enum! {
/// Features of the validation layer to enable.
ValidationFeatureEnable = ValidationFeatureEnableEXT(i32);

/// The validation layer will use shader programs running on the GPU to provide additional
/// validation.
///
/// This must not be used together with `DebugPrintf`.
GpuAssisted = GPU_ASSISTED,

/// The validation layer will reserve and use one descriptor set slot for its own use.
/// The limit reported by
/// [`max_bound_descriptor_sets`](crate::device::Properties::max_bound_descriptor_sets)
/// will be reduced by 1.
///
/// `GpuAssisted` must also be enabled.
GpuAssistedReserveBindingSlot = GPU_ASSISTED_RESERVE_BINDING_SLOT,

/// The validation layer will report recommendations that are not strictly errors,
/// but that may be considered good Vulkan practice.
BestPractices = BEST_PRACTICES,

/// The validation layer will process `debugPrintfEXT` operations in shaders, and send them
/// to the debug callback.
///
/// This must not be used together with `GpuAssisted`.
DebugPrintf = DEBUG_PRINTF,

/// The validation layer will report errors relating to synchronization, such as data races and
/// the use of synchronization primitives.
SynchronizationValidation = SYNCHRONIZATION_VALIDATION,
}

vulkan_enum! {
/// Features of the validation layer to disable.
ValidationFeatureDisable = ValidationFeatureDisableEXT(i32);

/// All validation is disabled.
All = ALL,

/// Shader validation is disabled.
Shaders = SHADERS,

/// Thread safety validation is disabled.
ThreadSafety = THREAD_SAFETY,

/// Stateless parameter validation is disabled.
ApiParameters = API_PARAMETERS,

/// Object lifetime validation is disabled.
ObjectLifetimes = OBJECT_LIFETIMES,

/// Core validation checks are disabled.
///
/// This also disables shader validation and GPU-assisted validation.
CoreChecks = CORE_CHECKS,

/// Protection against duplicate non-dispatchable handles is disabled.
UniqueHandles = UNIQUE_HANDLES,

/// Results of shader validation will not be cached, and are validated from scratch each time.
ShaderValidationCache = SHADER_VALIDATION_CACHE,
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
76 changes: 72 additions & 4 deletions vulkano/src/instance/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@
//! Once you have chosen a physical device, you can create a `Device` object from it. See the
//! `device` module for more info.

use self::debug::{DebugUtilsMessengerCreateInfo, UserCallback};
use self::debug::{
DebugUtilsMessengerCreateInfo, UserCallback, ValidationFeatureDisable, ValidationFeatureEnable,
};
pub use self::{extensions::InstanceExtensions, layers::LayerProperties};
use crate::{
device::physical::PhysicalDevice, instance::debug::trampoline, OomError, RequiresOneOf,
Expand Down Expand Up @@ -294,6 +296,8 @@ impl Instance {
engine_version,
max_api_version,
enumerate_portability,
enabled_validation_features,
disabled_validation_features,
_ne: _,
} = create_info;

Expand Down Expand Up @@ -359,7 +363,18 @@ impl Instance {
..Default::default()
};

let mut create_info = ash::vk::InstanceCreateInfo {
let enable_validation_features_vk: SmallVec<[_; 5]> = enabled_validation_features
.iter()
.copied()
.map(Into::into)
.collect();
let disable_validation_features_vk: SmallVec<[_; 8]> = disabled_validation_features
.iter()
.copied()
.map(Into::into)
.collect();

let mut create_info_vk = ash::vk::InstanceCreateInfo {
flags,
p_application_info: &application_info,
enabled_layer_count: enabled_layers_ptrs.len() as u32,
Expand All @@ -368,6 +383,43 @@ impl Instance {
pp_enabled_extension_names: enabled_extensions_ptrs.as_ptr(),
..Default::default()
};
let mut validation_features_vk = None;

if !enabled_validation_features.is_empty() || !disabled_validation_features.is_empty() {
if !enabled_extensions.ext_validation_features {
return Err(InstanceCreationError::RequirementNotMet {
required_for: "`enabled_validation_features` or `disabled_validation_features` are not empty",
requires_one_of: RequiresOneOf {
instance_extensions: &["ext_validation_features"],
..Default::default()
},
});
}

// VUID-VkValidationFeaturesEXT-pEnabledValidationFeatures-02967
assert!(
!enabled_validation_features
.contains(&ValidationFeatureEnable::GpuAssistedReserveBindingSlot)
|| enabled_validation_features.contains(&ValidationFeatureEnable::GpuAssisted)
);

// VUID-VkValidationFeaturesEXT-pEnabledValidationFeatures-02968
assert!(
!(enabled_validation_features.contains(&ValidationFeatureEnable::DebugPrintf)
&& enabled_validation_features.contains(&ValidationFeatureEnable::GpuAssisted))
);

let next = validation_features_vk.insert(ash::vk::ValidationFeaturesEXT {
enabled_validation_feature_count: enable_validation_features_vk.len() as u32,
p_enabled_validation_features: enable_validation_features_vk.as_ptr(),
disabled_validation_feature_count: disable_validation_features_vk.len() as u32,
p_disabled_validation_features: disable_validation_features_vk.as_ptr(),
..Default::default()
});

next.p_next = create_info_vk.p_next;
create_info_vk.p_next = next as *const _ as *const _;
}

// Handle debug messengers
let debug_utils_messengers = debug_utils_messengers.into_iter();
Expand Down Expand Up @@ -429,14 +481,14 @@ impl Instance {
}

if let Some(info) = debug_utils_messenger_create_infos.first() {
create_info.p_next = info as *const _ as *const _;
create_info_vk.p_next = info as *const _ as *const _;
}

// Creating the Vulkan instance.
let handle = {
let mut output = MaybeUninit::uninit();
let fns = library.fns();
(fns.v1_0.create_instance)(&create_info, ptr::null(), output.as_mut_ptr())
(fns.v1_0.create_instance)(&create_info_vk, ptr::null(), output.as_mut_ptr())
.result()
.map_err(VulkanError::from)?;
output.assume_init()
Expand Down Expand Up @@ -675,6 +727,20 @@ pub struct InstanceCreateInfo {
/// extension will automatically be enabled.
pub enumerate_portability: bool,

/// Features of the validation layer to enable.
///
/// If not empty, the
/// [`ext_validation_features`](crate::instance::InstanceExtensions::ext_validation_features)
/// extension must be enabled on the instance.
pub enabled_validation_features: Vec<ValidationFeatureEnable>,

/// Features of the validation layer to disable.
///
/// If not empty, the
/// [`ext_validation_features`](crate::instance::InstanceExtensions::ext_validation_features)
/// extension must be enabled on the instance.
pub disabled_validation_features: Vec<ValidationFeatureDisable>,

pub _ne: crate::NonExhaustive,
}

Expand All @@ -690,6 +756,8 @@ impl Default for InstanceCreateInfo {
engine_version: Version::major_minor(0, 0),
max_api_version: None,
enumerate_portability: false,
enabled_validation_features: Vec::new(),
disabled_validation_features: Vec::new(),
_ne: crate::NonExhaustive(()),
}
}
Expand Down