Better validation and errors (#1966)

* Better validation and errors

* Small fix
This commit is contained in:
Rua 2022-09-10 05:41:52 +02:00 committed by GitHub
parent 896b49e92e
commit b06b29afd2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
84 changed files with 3242 additions and 2198 deletions

View File

@ -251,7 +251,9 @@ fn write_impls<'a>(
) -> impl Iterator<Item = TokenStream> + 'a {
let struct_ident = format_ident!("{}", struct_name);
(types_meta.partial_eq.then(|| {
(types_meta
.partial_eq
.then(|| {
let fields = rust_members
.iter()
.filter(|Member { is_dummy, .. }| !is_dummy)
@ -271,7 +273,8 @@ fn write_impls<'a>(
}
}
}
}).into_iter())
})
.into_iter())
.chain(types_meta.debug.then(|| {
let fields = rust_members
.iter()
@ -283,8 +286,8 @@ fn write_impls<'a>(
quote! {
impl std::fmt::Debug for #struct_ident {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
formatter
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
f
.debug_struct(#struct_name)
#( #fields )*
.finish()
@ -303,8 +306,8 @@ fn write_impls<'a>(
quote! {
impl std::fmt::Display for #struct_ident {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
formatter
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
f
.debug_struct(#struct_name)
#( #fields )*
.finish()
@ -323,7 +326,12 @@ fn write_impls<'a>(
}
}
}))
.chain(types_meta.impls.iter().map(move |i| quote!{ #i for #struct_ident {} }))
.chain(
types_meta
.impls
.iter()
.map(move |i| quote! { #i for #struct_ident {} }),
)
}
fn has_defined_layout(spirv: &Spirv, struct_id: Id) -> bool {

View File

@ -1,4 +1,10 @@
use std::{borrow::Borrow, error::Error, fmt, rc::Rc, sync::Arc};
use std::{
borrow::Borrow,
error::Error,
fmt::{Display, Error as FmtError, Formatter},
rc::Rc,
sync::Arc,
};
use vulkano::{
instance::{Instance, InstanceExtensions},
swapchain::{Surface, SurfaceCreationError},
@ -80,11 +86,11 @@ impl Error for CreationError {
}
}
impl fmt::Display for CreationError {
impl Display for CreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
fmt,
f,
"{}",
match *self {
CreationError::SurfaceCreationError(_) => "error while creating the surface",

View File

@ -105,7 +105,7 @@ fn device_extensions_output(members: &[ExtensionsMember]) -> TokenStream {
let requires_items = requires.iter().map(|require| {
let require_items = require.api_version.iter().map(|version| {
let version = format_ident!("V{}_{}", version.0, version.1);
quote! { api_version >= Version::#version }
quote! { api_version >= crate::Version::#version }
}).chain(require.instance_extensions.iter().map(|ext| {
quote! { instance_extensions.#ext }
})).chain(require.device_extensions.iter().map(|ext| {
@ -114,19 +114,20 @@ fn device_extensions_output(members: &[ExtensionsMember]) -> TokenStream {
let api_version_items = require.api_version.as_ref().map(|version| {
let version = format_ident!("V{}_{}", version.0, version.1);
quote! { Some(Version::#version) }
quote! { Some(crate::Version::#version) }
}).unwrap_or_else(|| quote!{ None });
let device_extensions_items = require.device_extensions.iter().map(|ext| ext.to_string());
let instance_extensions_items = require.instance_extensions.iter().map(|ext| ext.to_string());
quote! {
if !(#(#require_items)||*) {
return Err(ExtensionRestrictionError {
return Err(crate::device::ExtensionRestrictionError {
extension: #name_string,
restriction: ExtensionRestriction::Requires(OneOfRequirements {
restriction: crate::device::ExtensionRestriction::Requires(crate::RequiresOneOf {
api_version: #api_version_items,
device_extensions: &[#(#device_extensions_items),*],
instance_extensions: &[#(#instance_extensions_items),*],
..Default::default()
}),
})
}
@ -136,9 +137,9 @@ fn device_extensions_output(members: &[ExtensionsMember]) -> TokenStream {
let string = extension.to_string();
quote! {
if self.#extension {
return Err(ExtensionRestrictionError {
return Err(crate::device::ExtensionRestrictionError {
extension: #name_string,
restriction: ExtensionRestriction::ConflictsDeviceExtension(#string),
restriction: crate::device::ExtensionRestriction::ConflictsDeviceExtension(#string),
});
}
}
@ -146,9 +147,9 @@ fn device_extensions_output(members: &[ExtensionsMember]) -> TokenStream {
let required_if_supported = if *required_if_supported {
quote! {
if supported.#name {
return Err(ExtensionRestrictionError {
return Err(crate::device::ExtensionRestrictionError {
extension: #name_string,
restriction: ExtensionRestriction::RequiredIfSupported,
restriction: crate::device::ExtensionRestriction::RequiredIfSupported,
});
}
}
@ -159,9 +160,9 @@ fn device_extensions_output(members: &[ExtensionsMember]) -> TokenStream {
quote! {
if self.#name {
if !supported.#name {
return Err(ExtensionRestrictionError {
return Err(crate::device::ExtensionRestrictionError {
extension: #name_string,
restriction: ExtensionRestriction::NotSupported,
restriction: crate::device::ExtensionRestriction::NotSupported,
});
}
@ -181,9 +182,9 @@ fn device_extensions_output(members: &[ExtensionsMember]) -> TokenStream {
pub(super) fn check_requirements(
&self,
supported: &DeviceExtensions,
api_version: Version,
instance_extensions: &InstanceExtensions,
) -> Result<(), ExtensionRestrictionError> {
api_version: crate::Version,
instance_extensions: &crate::instance::InstanceExtensions,
) -> Result<(), crate::device::ExtensionRestrictionError> {
let device_extensions = self;
#(#check_requirements_items)*
Ok(())
@ -207,7 +208,7 @@ fn instance_extensions_output(members: &[ExtensionsMember]) -> TokenStream {
.iter()
.map(|version| {
let version = format_ident!("V{}_{}", version.0, version.1);
quote! { api_version >= Version::#version }
quote! { api_version >= crate::Version::#version }
})
.chain(require.instance_extensions.iter().map(|ext| {
quote! { instance_extensions.#ext }
@ -221,7 +222,7 @@ fn instance_extensions_output(members: &[ExtensionsMember]) -> TokenStream {
.as_ref()
.map(|version| {
let version = format_ident!("V{}_{}", version.0, version.1);
quote! { Some(Version::#version) }
quote! { Some(crate::Version::#version) }
})
.unwrap_or_else(|| quote! { None });
let device_extensions_items =
@ -233,12 +234,13 @@ fn instance_extensions_output(members: &[ExtensionsMember]) -> TokenStream {
quote! {
if !(#(#require_items)||*) {
return Err(ExtensionRestrictionError {
return Err(crate::instance::ExtensionRestrictionError {
extension: #name_string,
restriction: ExtensionRestriction::Requires(OneOfRequirements {
restriction: crate::instance::ExtensionRestriction::Requires(crate::RequiresOneOf {
api_version: #api_version_items,
device_extensions: &[#(#device_extensions_items),*],
instance_extensions: &[#(#instance_extensions_items),*],
..Default::default()
}),
})
}
@ -248,9 +250,9 @@ fn instance_extensions_output(members: &[ExtensionsMember]) -> TokenStream {
quote! {
if self.#name {
if !supported.#name {
return Err(ExtensionRestrictionError {
return Err(crate::instance::ExtensionRestrictionError {
extension: #name_string,
restriction: ExtensionRestriction::NotSupported,
restriction: crate::instance::ExtensionRestriction::NotSupported,
});
}
@ -267,8 +269,8 @@ fn instance_extensions_output(members: &[ExtensionsMember]) -> TokenStream {
pub(super) fn check_requirements(
&self,
supported: &InstanceExtensions,
api_version: Version,
) -> Result<(), ExtensionRestrictionError> {
api_version: crate::Version,
) -> Result<(), crate::instance::ExtensionRestrictionError> {
let instance_extensions = self;
#(#check_requirements_items)*
Ok(())
@ -348,7 +350,7 @@ fn extensions_common_output(struct_name: Ident, members: &[ExtensionsMember]) ->
let from_extensions_for_vec_cstring_items =
members.iter().map(|ExtensionsMember { name, raw, .. }| {
quote! {
if x.#name { data.push(CString::new(#raw).unwrap()); }
if x.#name { data.push(std::ffi::CString::new(#raw).unwrap()); }
}
});
@ -441,7 +443,7 @@ fn extensions_common_output(struct_name: Ident, members: &[ExtensionsMember]) ->
}
}
impl BitAnd for #struct_name {
impl std::ops::BitAnd for #struct_name {
type Output = #struct_name;
#[inline]
@ -450,14 +452,14 @@ fn extensions_common_output(struct_name: Ident, members: &[ExtensionsMember]) ->
}
}
impl BitAndAssign for #struct_name {
impl std::ops::BitAndAssign for #struct_name {
#[inline]
fn bitand_assign(&mut self, rhs: Self) {
*self = self.union(&rhs);
}
}
impl BitOr for #struct_name {
impl std::ops::BitOr for #struct_name {
type Output = #struct_name;
#[inline]
@ -466,14 +468,14 @@ fn extensions_common_output(struct_name: Ident, members: &[ExtensionsMember]) ->
}
}
impl BitOrAssign for #struct_name {
impl std::ops::BitOrAssign for #struct_name {
#[inline]
fn bitor_assign(&mut self, rhs: Self) {
*self = self.intersection(&rhs);
}
}
impl BitXor for #struct_name {
impl std::ops::BitXor for #struct_name {
type Output = #struct_name;
#[inline]
@ -482,14 +484,14 @@ fn extensions_common_output(struct_name: Ident, members: &[ExtensionsMember]) ->
}
}
impl BitXorAssign for #struct_name {
impl std::ops::BitXorAssign for #struct_name {
#[inline]
fn bitxor_assign(&mut self, rhs: Self) {
*self = self.symmetric_difference(&rhs);
}
}
impl Sub for #struct_name {
impl std::ops::Sub for #struct_name {
type Output = #struct_name;
#[inline]
@ -498,7 +500,7 @@ fn extensions_common_output(struct_name: Ident, members: &[ExtensionsMember]) ->
}
}
impl SubAssign for #struct_name {
impl std::ops::SubAssign for #struct_name {
#[inline]
fn sub_assign(&mut self, rhs: Self) {
*self = self.difference(&rhs);
@ -507,7 +509,7 @@ fn extensions_common_output(struct_name: Ident, members: &[ExtensionsMember]) ->
impl std::fmt::Debug for #struct_name {
#[allow(unused_assignments)]
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
write!(f, "[")?;
let mut first = true;
@ -517,7 +519,7 @@ fn extensions_common_output(struct_name: Ident, members: &[ExtensionsMember]) ->
}
}
impl<'a, I> From<I> for #struct_name where I: IntoIterator<Item = &'a CStr> {
impl<'a, I> From<I> for #struct_name where I: IntoIterator<Item = &'a std::ffi::CStr> {
fn from(names: I) -> Self {
let mut extensions = Self::empty();
for name in names {
@ -530,7 +532,7 @@ fn extensions_common_output(struct_name: Ident, members: &[ExtensionsMember]) ->
}
}
impl<'a> From<&'a #struct_name> for Vec<CString> {
impl<'a> From<&'a #struct_name> for Vec<std::ffi::CString> {
fn from(x: &'a #struct_name) -> Self {
let mut data = Self::new();
#(#from_extensions_for_vec_cstring_items)*

View File

@ -113,9 +113,9 @@ fn features_output(members: &[FeaturesMember]) -> TokenStream {
let string = feature.to_string();
quote! {
if !self.#feature {
return Err(FeatureRestrictionError {
return Err(crate::device::FeatureRestrictionError {
feature: #name_string,
restriction: FeatureRestriction::RequiresFeature(#string),
restriction: crate::device::FeatureRestriction::RequiresFeature(#string),
});
}
}
@ -124,9 +124,9 @@ fn features_output(members: &[FeaturesMember]) -> TokenStream {
let string = feature.to_string();
quote! {
if self.#feature {
return Err(FeatureRestrictionError {
return Err(crate::device::FeatureRestrictionError {
feature: #name_string,
restriction: FeatureRestriction::ConflictsFeature(#string),
restriction: crate::device::FeatureRestriction::ConflictsFeature(#string),
});
}
}
@ -135,10 +135,10 @@ fn features_output(members: &[FeaturesMember]) -> TokenStream {
required_by_extensions.iter().map(|(version, extension)| {
let string = extension.to_string();
quote! {
if extensions.#extension && api_version >= Version::#version {
return Err(FeatureRestrictionError {
if extensions.#extension && api_version >= crate::Version::#version {
return Err(crate::device::FeatureRestrictionError {
feature: #name_string,
restriction: FeatureRestriction::RequiredByExtension(#string),
restriction: crate::device::FeatureRestriction::RequiredByExtension(#string),
});
}
}
@ -146,9 +146,9 @@ fn features_output(members: &[FeaturesMember]) -> TokenStream {
quote! {
if self.#name {
if !supported.#name {
return Err(FeatureRestrictionError {
return Err(crate::device::FeatureRestrictionError {
feature: #name_string,
restriction: FeatureRestriction::NotSupported,
restriction: crate::device::FeatureRestriction::NotSupported,
});
}
@ -332,9 +332,9 @@ fn features_output(members: &[FeaturesMember]) -> TokenStream {
pub(super) fn check_requirements(
&self,
supported: &Features,
api_version: Version,
extensions: &DeviceExtensions,
) -> Result<(), FeatureRestrictionError> {
api_version: crate::Version,
extensions: &crate::device::DeviceExtensions,
) -> Result<(), crate::device::FeatureRestrictionError> {
#(#check_requirements_items)*
Ok(())
}
@ -420,7 +420,7 @@ fn features_output(members: &[FeaturesMember]) -> TokenStream {
}
}
impl BitAnd for Features {
impl std::ops::BitAnd for Features {
type Output = Features;
#[inline]
@ -429,14 +429,14 @@ fn features_output(members: &[FeaturesMember]) -> TokenStream {
}
}
impl BitAndAssign for Features {
impl std::ops::BitAndAssign for Features {
#[inline]
fn bitand_assign(&mut self, rhs: Self) {
*self = self.intersection(&rhs);
}
}
impl BitOr for Features {
impl std::ops::BitOr for Features {
type Output = Features;
#[inline]
@ -445,14 +445,14 @@ fn features_output(members: &[FeaturesMember]) -> TokenStream {
}
}
impl BitOrAssign for Features {
impl std::ops::BitOrAssign for Features {
#[inline]
fn bitor_assign(&mut self, rhs: Self) {
*self = self.union(&rhs);
}
}
impl BitXor for Features {
impl std::ops::BitXor for Features {
type Output = Features;
#[inline]
@ -461,14 +461,14 @@ fn features_output(members: &[FeaturesMember]) -> TokenStream {
}
}
impl BitXorAssign for Features {
impl std::ops::BitXorAssign for Features {
#[inline]
fn bitxor_assign(&mut self, rhs: Self) {
*self = self.symmetric_difference(&rhs);
}
}
impl Sub for Features {
impl std::ops::Sub for Features {
type Output = Features;
#[inline]
@ -477,7 +477,7 @@ fn features_output(members: &[FeaturesMember]) -> TokenStream {
}
}
impl SubAssign for Features {
impl std::ops::SubAssign for Features {
#[inline]
fn sub_assign(&mut self, rhs: Self) {
*self = self.difference(&rhs);
@ -486,7 +486,7 @@ fn features_output(members: &[FeaturesMember]) -> TokenStream {
impl std::fmt::Debug for Features {
#[allow(unused_assignments)]
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
fn fmt(&self, f: &mut std::fmt:: Formatter) -> Result<(), std::fmt::Error> {
write!(f, "[")?;
let mut first = true;
@ -698,9 +698,9 @@ fn features_ffi_output(members: &[FeaturesFfiMember]) -> TokenStream {
impl FeaturesFfi {
pub(crate) fn make_chain(
&mut self,
api_version: Version,
device_extensions: &DeviceExtensions,
_instance_extensions: &InstanceExtensions,
api_version: crate::Version,
device_extensions: &crate::device::DeviceExtensions,
_instance_extensions: &crate::instance::InstanceExtensions,
) {
self.features_vulkan10 = Default::default();
let head = &mut self.features_vulkan10;
@ -732,7 +732,7 @@ fn features_ffi_members<'a>(
.map(|provided_by| {
if let Some(version) = provided_by.strip_prefix("VK_VERSION_") {
let version = format_ident!("V{}", version);
quote! { api_version >= Version::#version }
quote! { api_version >= crate::Version::#version }
} else {
let member = format_ident!(
"{}_extensions",

View File

@ -90,7 +90,7 @@ fn fns_output(extension_members: &[FnsMember], fns_level: &str, doc: &str) -> To
impl std::fmt::Debug for #struct_name {
#[inline]
fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
fn fmt(&self, _f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
Ok(())
}
}

View File

@ -35,7 +35,7 @@ use crate::{
use smallvec::SmallVec;
use std::{
error::Error,
fmt,
fmt::{Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},
marker::PhantomData,
mem::size_of,
@ -572,13 +572,13 @@ pub enum ReadLockError {
impl Error for ReadLockError {}
impl fmt::Display for ReadLockError {
impl Display for ReadLockError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
fmt,
f,
"{}",
match *self {
match self {
ReadLockError::CpuWriteLocked => {
"the buffer is already locked for write mode by the CPU"
}
@ -601,13 +601,13 @@ pub enum WriteLockError {
impl Error for WriteLockError {}
impl fmt::Display for WriteLockError {
impl Display for WriteLockError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
fmt,
f,
"{}",
match *self {
match self {
WriteLockError::CpuLocked => "the buffer is already locked by the CPU",
WriteLockError::GpuLocked => "the buffer is already locked by the GPU",
}

View File

@ -37,10 +37,10 @@ use crate::{
sync::{NowFuture, Sharing},
DeviceSize,
};
use core::fmt;
use smallvec::SmallVec;
use std::{
error::Error,
fmt::{Display, Error as FmtError, Formatter},
fs::File,
hash::{Hash, Hasher},
marker::PhantomData,
@ -590,9 +590,9 @@ impl Error for DeviceLocalBufferCreationError {
}
}
impl fmt::Display for DeviceLocalBufferCreationError {
impl Display for DeviceLocalBufferCreationError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::DeviceMemoryAllocationError(err) => err.fmt(f),
Self::CommandBufferBeginError(err) => err.fmt(f),

View File

@ -30,18 +30,18 @@ use super::{
};
use crate::{
device::{Device, DeviceOwned},
macros::{vulkan_bitflags, ExtensionNotEnabled},
macros::vulkan_bitflags,
memory::{DeviceMemory, DeviceMemoryAllocationError, MemoryRequirements},
range_map::RangeMap,
sync::{AccessError, CurrentAccess, Sharing},
DeviceSize, OomError, Version, VulkanError, VulkanObject,
DeviceSize, OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
};
use ash::vk::Handle;
use parking_lot::{Mutex, MutexGuard};
use smallvec::SmallVec;
use std::{
error::Error,
fmt,
fmt::{Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},
mem::MaybeUninit,
ops::Range,
@ -86,7 +86,7 @@ impl UnsafeBuffer {
assert!(size != 0);
// VUID-VkBufferCreateInfo-usage-parameter
usage.validate(&device)?;
usage.validate_device(&device)?;
// VUID-VkBufferCreateInfo-usage-requiredbitmask
assert!(!usage.is_empty());
@ -97,25 +97,34 @@ impl UnsafeBuffer {
if let Some(sparse_level) = sparse {
// VUID-VkBufferCreateInfo-flags-00915
if !device.enabled_features().sparse_binding {
return Err(BufferCreationError::FeatureNotEnabled {
feature: "sparse_binding",
reason: "sparse was `Some`",
return Err(BufferCreationError::RequirementNotMet {
required_for: "`create_info.sparse` is `Some`",
requires_one_of: RequiresOneOf {
features: &["sparse_binding"],
..Default::default()
},
});
}
// VUID-VkBufferCreateInfo-flags-00916
if sparse_level.sparse_residency && !device.enabled_features().sparse_residency_buffer {
return Err(BufferCreationError::FeatureNotEnabled {
feature: "sparse_residency_buffer",
reason: "sparse was `Some` and `sparse_residency` was set",
return Err(BufferCreationError::RequirementNotMet {
required_for: "`create_info.sparse` is `Some(sparse_level)`, where `sparse_level.sparse_residency` is set",
requires_one_of: RequiresOneOf {
features: &["sparse_residency_buffer"],
..Default::default()
},
});
}
// VUID-VkBufferCreateInfo-flags-00917
if sparse_level.sparse_aliased && !device.enabled_features().sparse_residency_aliased {
return Err(BufferCreationError::FeatureNotEnabled {
feature: "sparse_residency_aliased",
reason: "sparse was `Some` and `sparse_aliased` was set",
return Err(BufferCreationError::RequirementNotMet {
required_for: "`create_info.sparse` is `Some(sparse_level)`, where `sparse_level.sparse_aliased` is set",
requires_one_of: RequiresOneOf {
features: &["sparse_residency_aliased"],
..Default::default()
},
});
}
@ -462,13 +471,9 @@ pub enum BufferCreationError {
/// Allocating memory failed.
AllocError(DeviceMemoryAllocationError),
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
},
FeatureNotEnabled {
feature: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// The specified size exceeded the value of the `max_buffer_size` limit.
@ -489,25 +494,25 @@ impl Error for BufferCreationError {
}
}
impl fmt::Display for BufferCreationError {
impl Display for BufferCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
Self::AllocError(_) => write!(fmt, "allocating memory failed"),
Self::ExtensionNotEnabled { extension, reason } => write!(
fmt,
"the extension {} must be enabled: {}",
extension, reason
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::AllocError(_) => write!(f, "allocating memory failed"),
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::FeatureNotEnabled { feature, reason } => {
write!(fmt, "the feature {} must be enabled: {}", feature, reason)
}
Self::MaxBufferSizeExceeded { .. } => write!(
fmt,
f,
"the specified size exceeded the value of the `max_buffer_size` limit"
),
Self::SharingInvalidQueueFamilyId { .. } => {
write!(fmt, "the sharing mode was set to `Concurrent`, but one of the specified queue family ids was not valid")
write!(f, "the sharing mode was set to `Concurrent`, but one of the specified queue family ids was not valid")
}
}
}
@ -535,12 +540,12 @@ impl From<VulkanError> for BufferCreationError {
}
}
impl From<ExtensionNotEnabled> for BufferCreationError {
impl From<RequirementNotMet> for BufferCreationError {
#[inline]
fn from(err: ExtensionNotEnabled) -> Self {
Self::ExtensionNotEnabled {
extension: err.extension,
reason: err.reason,
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}
@ -771,7 +776,10 @@ mod tests {
use super::{
BufferCreationError, BufferUsage, SparseLevel, UnsafeBuffer, UnsafeBufferCreateInfo,
};
use crate::device::{Device, DeviceOwned};
use crate::{
device::{Device, DeviceOwned},
RequiresOneOf,
};
#[test]
fn create() {
@ -810,10 +818,10 @@ mod tests {
..Default::default()
},
) {
Err(BufferCreationError::FeatureNotEnabled {
feature: "sparse_binding",
Err(BufferCreationError::RequirementNotMet {
requires_one_of: RequiresOneOf { features, .. },
..
}) => (),
}) if features.contains(&"sparse_binding") => (),
_ => panic!(),
}
}
@ -837,10 +845,10 @@ mod tests {
..Default::default()
},
) {
Err(BufferCreationError::FeatureNotEnabled {
feature: "sparse_residency_buffer",
Err(BufferCreationError::RequirementNotMet {
requires_one_of: RequiresOneOf { features, .. },
..
}) => (),
}) if features.contains(&"sparse_residency_buffer") => (),
_ => panic!(),
}
}
@ -864,10 +872,10 @@ mod tests {
..Default::default()
},
) {
Err(BufferCreationError::FeatureNotEnabled {
feature: "sparse_residency_aliased",
Err(BufferCreationError::RequirementNotMet {
requires_one_of: RequiresOneOf { features, .. },
..
}) => (),
}) if features.contains(&"sparse_residency_aliased") => (),
_ => panic!(),
}
}

View File

@ -8,10 +8,10 @@
// according to those terms.
use super::{sys::UnsafeBuffer, BufferContents, BufferSlice, BufferUsage};
use crate::{device::DeviceOwned, DeviceSize, SafeDeref, VulkanObject};
use crate::{device::DeviceOwned, DeviceSize, RequiresOneOf, SafeDeref, VulkanObject};
use std::{
error::Error,
fmt,
fmt::{Debug, Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},
num::NonZeroU64,
ops::Range,
@ -82,7 +82,13 @@ pub unsafe trait BufferAccess: DeviceOwned + Send + Sync {
// VUID-vkGetBufferDeviceAddress-bufferDeviceAddress-03324
if !device.enabled_features().buffer_device_address {
return Err(BufferDeviceAddressError::FeatureNotEnabled);
return Err(BufferDeviceAddressError::RequirementNotMet {
required_for: "`raw_device_address`",
requires_one_of: RequiresOneOf {
features: &["buffer_device_address"],
..Default::default()
},
});
}
// VUID-VkBufferDeviceAddressInfo-buffer-02601
@ -168,8 +174,8 @@ where
type Content = <T::Target as TypedBufferAccess>::Content;
}
impl fmt::Debug for dyn BufferAccess {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
impl Debug for dyn BufferAccess {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
f.debug_struct("dyn BufferAccess")
.field("inner", &self.inner())
.finish()
@ -196,24 +202,33 @@ impl Hash for dyn BufferAccess {
/// Error that can happen when querying the device address of a buffer.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BufferDeviceAddressError {
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
BufferMissingUsage,
FeatureNotEnabled,
}
impl Error for BufferDeviceAddressError {}
impl fmt::Display for BufferDeviceAddressError {
impl Display for BufferDeviceAddressError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::BufferMissingUsage => write!(
fmt,
f,
"the device address usage flag was not set on this buffer",
),
Self::FeatureNotEnabled => write!(
fmt,
"the buffer_device_address feature was not enabled on the device",
),
}
}
}

View File

@ -46,58 +46,58 @@ vulkan_bitflags! {
/// The buffer's device address can be retrieved.
shader_device_address = SHADER_DEVICE_ADDRESS {
api_version: V1_2,
extensions: [khr_buffer_device_address, ext_buffer_device_address],
device_extensions: [khr_buffer_device_address, ext_buffer_device_address],
},
/*
// TODO: document
video_decode_src = VIDEO_DECODE_SRC_KHR {
extensions: [khr_video_decode_queue],
device_extensions: [khr_video_decode_queue],
},
// TODO: document
video_decode_dst = VIDEO_DECODE_DST_KHR {
extensions: [khr_video_decode_queue],
device_extensions: [khr_video_decode_queue],
},
// TODO: document
transform_feedback_buffer = TRANSFORM_FEEDBACK_BUFFER_EXT {
extensions: [ext_transform_feedback],
device_extensions: [ext_transform_feedback],
},
// TODO: document
transform_feedback_counter_buffer = TRANSFORM_FEEDBACK_COUNTER_BUFFER_EXT {
extensions: [ext_transform_feedback],
device_extensions: [ext_transform_feedback],
},
// TODO: document
conditional_rendering = CONDITIONAL_RENDERING_EXT {
extensions: [ext_conditional_rendering],
device_extensions: [ext_conditional_rendering],
},
// TODO: document
acceleration_structure_build_input_read_only = ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_KHR {
extensions: [khr_acceleration_structure],
device_extensions: [khr_acceleration_structure],
},
// TODO: document
acceleration_structure_storage = ACCELERATION_STRUCTURE_STORAGE_KHR {
extensions: [khr_acceleration_structure],
device_extensions: [khr_acceleration_structure],
},
// TODO: document
shader_binding_table = SHADER_BINDING_TABLE_KHR {
extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
},
// TODO: document
video_encode_dst = VIDEO_ENCODE_DST_KHR {
extensions: [khr_video_encode_queue],
device_extensions: [khr_video_encode_queue],
},
// TODO: document
video_encode_src = VIDEO_ENCODE_SRC_KHR {
extensions: [khr_video_encode_queue],
device_extensions: [khr_video_encode_queue],
},
*/
}

View File

@ -50,7 +50,7 @@ use crate::{
};
use std::{
error::Error,
fmt,
fmt::{Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},
mem::MaybeUninit,
ops::Range,
@ -357,32 +357,32 @@ impl Error for BufferViewCreationError {
}
}
impl fmt::Display for BufferViewCreationError {
impl Display for BufferViewCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
BufferViewCreationError::OomError(_) => write!(
fmt,
f,
"out of memory when creating buffer view",
),
BufferViewCreationError::BufferMissingUsage => write!(
fmt,
f,
"the buffer was not created with one of the `storage_texel_buffer` or `uniform_texel_buffer` usages",
),
BufferViewCreationError::OffsetNotAligned { .. } => write!(
fmt,
f,
"the offset within the buffer is not a multiple of the required alignment",
),
BufferViewCreationError::RangeNotAligned { .. } => write!(
fmt,
f,
"the range within the buffer is not a multiple of the required alignment",
),
BufferViewCreationError::UnsupportedFormat => write!(
fmt,
f,
"the requested format is not supported for this usage",
),
BufferViewCreationError::MaxTexelBufferElementsExceeded => write!(
fmt,
f,
"the `max_texel_buffer_elements` limit has been exceeded",
),
}

View File

@ -24,11 +24,10 @@ use crate::{
device::{physical::QueueFamily, Device, DeviceOwned, Queue},
format::Format,
image::{sys::UnsafeImage, ImageAccess, ImageLayout, ImageSubresourceRange},
macros::ExtensionNotEnabled,
query::{QueryControlFlags, QueryType},
render_pass::{Framebuffer, Subpass},
sync::{AccessCheckError, AccessFlags, GpuFuture, PipelineMemoryAccess, PipelineStages},
DeviceSize, OomError,
DeviceSize, OomError, RequirementNotMet, RequiresOneOf,
};
use std::{
collections::HashMap,
@ -341,9 +340,12 @@ impl<L> AutoCommandBufferBuilder<L, StandardCommandPoolBuilder> {
// VUID-VkCommandBufferInheritanceRenderingInfo-multiview-06008
if view_mask != 0 && !device.enabled_features().multiview {
return Err(CommandBufferBeginError::FeatureNotEnabled {
feature: "multiview",
reason: "view_mask is not 0",
return Err(CommandBufferBeginError::RequirementNotMet {
required_for: "`inheritance_info.render_pass` is `CommandBufferInheritanceRenderPassType::BeginRendering`, where `view_mask` is not `0`",
requires_one_of: RequiresOneOf {
features: &["multiview"],
..Default::default()
},
});
}
@ -434,36 +436,46 @@ impl<L> AutoCommandBufferBuilder<L, StandardCommandPoolBuilder> {
if let Some(control_flags) = occlusion_query {
// VUID-VkCommandBufferInheritanceInfo-queryFlags-00057
control_flags.validate(device)?;
control_flags.validate_device(device)?;
// VUID-VkCommandBufferInheritanceInfo-occlusionQueryEnable-00056
// VUID-VkCommandBufferInheritanceInfo-queryFlags-02788
if !device.enabled_features().inherited_queries {
return Err(CommandBufferBeginError::FeatureNotEnabled {
feature: "inherited_queries",
reason: "occlusion queries were enabled",
return Err(CommandBufferBeginError::RequirementNotMet {
required_for: "`inheritance_info.occlusion_query` is `Some`",
requires_one_of: RequiresOneOf {
features: &["inherited_queries"],
..Default::default()
},
});
}
// VUID-vkBeginCommandBuffer-commandBuffer-00052
if control_flags.precise && !device.enabled_features().occlusion_query_precise {
return Err(CommandBufferBeginError::FeatureNotEnabled {
feature: "occlusion_query_precise",
reason: "occlusion_query.precise was set",
return Err(CommandBufferBeginError::RequirementNotMet {
required_for:
"`inheritance_info.occlusion_query` is `Some(control_flags)`, where `control_flags.precise` is set",
requires_one_of: RequiresOneOf {
features: &["occlusion_query_precise"],
..Default::default()
},
});
}
}
// VUID-VkCommandBufferInheritanceInfo-pipelineStatistics-02789
query_statistics_flags.validate(device)?;
query_statistics_flags.validate_device(device)?;
// VUID-VkCommandBufferInheritanceInfo-pipelineStatistics-00058
if query_statistics_flags.count() > 0
&& !device.enabled_features().pipeline_statistics_query
{
return Err(CommandBufferBeginError::FeatureNotEnabled {
feature: "pipeline_statistics_query",
reason: "one or more statistics flags were enabled",
return Err(CommandBufferBeginError::RequirementNotMet {
required_for: "`inheritance_info.query_statistics_flags` is not empty",
requires_one_of: RequiresOneOf {
features: &["pipeline_statistics_query"],
..Default::default()
},
});
}
} else {
@ -483,13 +495,9 @@ pub enum CommandBufferBeginError {
/// Not enough memory.
OomError(OomError),
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
},
FeatureNotEnabled {
feature: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// A color attachment has a format that does not support that usage.
@ -524,15 +532,17 @@ impl Error for CommandBufferBeginError {
impl Display for CommandBufferBeginError {
#[inline]
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
match self {
Self::OomError(_) => write!(f, "not enough memory available"),
Self::ExtensionNotEnabled { extension, reason } => {
write!(f, "the extension {} must be enabled: {}", extension, reason)
}
Self::FeatureNotEnabled { feature, reason } => {
write!(f, "the feature {} must be enabled: {}", feature, reason)
}
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::ColorAttachmentFormatUsageNotSupported { attachment_index } => write!(
f,
@ -568,12 +578,12 @@ impl From<OomError> for CommandBufferBeginError {
}
}
impl From<ExtensionNotEnabled> for CommandBufferBeginError {
impl From<RequirementNotMet> for CommandBufferBeginError {
#[inline]
fn from(err: ExtensionNotEnabled) -> Self {
Self::ExtensionNotEnabled {
extension: err.extension,
reason: err.reason,
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}

View File

@ -21,7 +21,6 @@ use crate::{
DescriptorWriteInfo, WriteDescriptorSet,
},
device::DeviceOwned,
macros::ExtensionNotEnabled,
pipeline::{
graphics::{
input_assembly::{Index, IndexType},
@ -31,12 +30,13 @@ use crate::{
ComputePipeline, GraphicsPipeline, PipelineBindPoint, PipelineLayout,
},
shader::ShaderStages,
DeviceSize, VulkanObject,
DeviceSize, RequirementNotMet, RequiresOneOf, VulkanObject,
};
use parking_lot::Mutex;
use smallvec::SmallVec;
use std::{
error, fmt,
error,
fmt::{Display, Error as FmtError, Formatter},
mem::{size_of, size_of_val},
ptr, slice,
sync::Arc,
@ -92,7 +92,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
descriptor_sets: &[DescriptorSetWithOffsets],
) -> Result<(), BindPushError> {
// VUID-vkCmdBindDescriptorSets-pipelineBindPoint-parameter
pipeline_bind_point.validate(self.device())?;
pipeline_bind_point.validate_device(self.device())?;
// VUID-vkCmdBindDescriptorSets-commandBuffer-cmdpool
// VUID-vkCmdBindDescriptorSets-pipelineBindPoint-00361
@ -186,9 +186,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
// VUID-vkCmdBindIndexBuffer-indexType-02765
if index_type == IndexType::U8 && !self.device().enabled_features().index_type_uint8 {
return Err(BindPushError::FeatureNotEnabled {
feature: "index_type_uint8",
reason: "index_buffer's index type was U8",
return Err(BindPushError::RequirementNotMet {
required_for: "`index_type` is `IndexType::U8`",
requires_one_of: RequiresOneOf {
features: &["index_type_uint8"],
..Default::default()
},
});
}
@ -535,14 +538,17 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
descriptor_writes: &[WriteDescriptorSet],
) -> Result<(), BindPushError> {
if !self.device().enabled_extensions().khr_push_descriptor {
return Err(BindPushError::ExtensionNotEnabled {
extension: "khr_push_descriptor",
reason: "called push_descriptor_set",
return Err(BindPushError::RequirementNotMet {
required_for: "`push_descriptor_set`",
requires_one_of: RequiresOneOf {
device_extensions: &["khr_push_descriptor"],
..Default::default()
},
});
}
// VUID-vkCmdPushDescriptorSetKHR-pipelineBindPoint-parameter
pipeline_bind_point.validate(self.device())?;
pipeline_bind_point.validate_device(self.device())?;
// VUID-vkCmdPushDescriptorSetKHR-commandBuffer-cmdpool
// VUID-vkCmdPushDescriptorSetKHR-pipelineBindPoint-00363
@ -1177,13 +1183,9 @@ impl UnsafeCommandBufferBuilderBindVertexBuffer {
enum BindPushError {
DescriptorSetUpdateError(DescriptorSetUpdateError),
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
},
FeatureNotEnabled {
feature: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// The element of `descriptor_sets` being bound to a slot is not compatible with the
@ -1242,20 +1244,19 @@ impl error::Error for BindPushError {
}
}
impl fmt::Display for BindPushError {
impl Display for BindPushError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::ExtensionNotEnabled { extension, reason } => write!(
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"the extension {} must be enabled: {}",
extension, reason
),
Self::FeatureNotEnabled { feature, reason } => write!(
f,
"the feature {} must be enabled: {}",
feature, reason,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::DescriptorSetUpdateError(_) => write!(
f,
"a DescriptorSetUpdateError",
@ -1318,12 +1319,12 @@ impl From<DescriptorSetUpdateError> for BindPushError {
}
}
impl From<ExtensionNotEnabled> for BindPushError {
impl From<RequirementNotMet> for BindPushError {
#[inline]
fn from(err: ExtensionNotEnabled) -> Self {
Self::ExtensionNotEnabled {
extension: err.extension,
reason: err.reason,
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}

View File

@ -15,8 +15,13 @@ use crate::{
},
device::DeviceOwned,
instance::debug::DebugUtilsLabel,
RequiresOneOf,
};
use std::{
error::Error,
ffi::CString,
fmt::{Display, Error as FmtError, Formatter},
};
use std::{error::Error, ffi::CString, fmt};
/// # Commands for debugging.
///
@ -49,9 +54,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
.enabled_extensions()
.ext_debug_utils
{
return Err(DebugUtilsError::ExtensionNotEnabled {
extension: "ext_debug_utils",
reason: "tried to record a debug utils command",
return Err(DebugUtilsError::RequirementNotMet {
required_for: "`begin_debug_utils_label`",
requires_one_of: RequiresOneOf {
instance_extensions: &["ext_debug_utils"],
..Default::default()
},
});
}
@ -86,9 +94,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
.enabled_extensions()
.ext_debug_utils
{
return Err(DebugUtilsError::ExtensionNotEnabled {
extension: "ext_debug_utils",
reason: "tried to record a debug utils command",
return Err(DebugUtilsError::RequirementNotMet {
required_for: "`end_debug_utils_label`",
requires_one_of: RequiresOneOf {
instance_extensions: &["ext_debug_utils"],
..Default::default()
},
});
}
@ -131,9 +142,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
.enabled_extensions()
.ext_debug_utils
{
return Err(DebugUtilsError::ExtensionNotEnabled {
extension: "ext_debug_utils",
reason: "tried to record a debug utils command",
return Err(DebugUtilsError::RequirementNotMet {
required_for: "`insert_debug_utils_label`",
requires_one_of: RequiresOneOf {
instance_extensions: &["ext_debug_utils"],
..Default::default()
},
});
}
@ -284,9 +298,9 @@ impl UnsafeCommandBufferBuilder {
/// Error that can happen when recording a debug utils command.
#[derive(Clone, Debug)]
pub enum DebugUtilsError {
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// The queue family doesn't allow this operation.
@ -295,13 +309,19 @@ pub enum DebugUtilsError {
impl Error for DebugUtilsError {}
impl fmt::Display for DebugUtilsError {
impl Display for DebugUtilsError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::ExtensionNotEnabled { extension, reason } => {
write!(f, "the extension {} must be enabled: {}", extension, reason)
}
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::NotSupportedByQueueFamily => {
write!(f, "the queue family doesn't allow this operation")
}

View File

@ -14,7 +14,6 @@ use crate::{
AutoCommandBufferBuilder,
},
device::DeviceOwned,
macros::ExtensionNotEnabled,
pipeline::{
graphics::{
color_blend::LogicOp,
@ -25,11 +24,15 @@ use crate::{
},
DynamicState,
},
Version,
RequirementNotMet, RequiresOneOf, Version,
};
use parking_lot::Mutex;
use smallvec::SmallVec;
use std::{error::Error, fmt, ops::RangeInclusive};
use std::{
error::Error,
fmt::{Display, Error as FmtError, Formatter},
ops::RangeInclusive,
};
/// # Commands to set dynamic state for pipelines.
///
@ -121,9 +124,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
// VUID-vkCmdSetColorWriteEnableEXT-None-04803
if !self.device().enabled_features().color_write_enable {
return Err(SetDynamicStateError::ExtensionNotEnabled {
extension: "color_write_enable",
reason: "called set_color_write_enable",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`set_color_write_enable`",
requires_one_of: RequiresOneOf {
device_extensions: &["ext_color_write_enable"],
..Default::default()
},
});
}
@ -171,7 +177,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
self.validate_pipeline_fixed_state(DynamicState::CullMode)?;
// VUID-vkCmdSetCullMode-cullMode-parameter
cull_mode.validate(self.device())?;
cull_mode.validate_device(self.device())?;
// VUID-vkCmdSetCullMode-commandBuffer-cmdpool
if !self.queue_family().supports_graphics() {
@ -182,9 +188,13 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
if !(self.device().api_version() >= Version::V1_3
|| self.device().enabled_features().extended_dynamic_state)
{
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "extended_dynamic_state",
reason: "called set_cull_mode",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`set_cull_mode`",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_3),
features: &["extended_dynamic_state"],
..Default::default()
},
});
}
@ -232,9 +242,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
// VUID-vkCmdSetDepthBias-depthBiasClamp-00790
if clamp != 0.0 && !self.device().enabled_features().depth_bias_clamp {
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "depth_bias_clamp",
reason: "clamp was not 0.0",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`clamp` is not `0.0`",
requires_one_of: RequiresOneOf {
features: &["depth_bias_clamp"],
..Default::default()
},
});
}
@ -273,9 +286,13 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
if !(self.device().api_version() >= Version::V1_3
|| self.device().enabled_features().extended_dynamic_state2)
{
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "extended_dynamic_state2",
reason: "called set_depth_bias_enable",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`set_depth_bias_enable`",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_3),
features: &["extended_dynamic_state2"],
..Default::default()
},
});
}
@ -321,9 +338,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
.ext_depth_range_unrestricted
&& !((0.0..=1.0).contains(bounds.start()) && (0.0..=1.0).contains(bounds.end()))
{
return Err(SetDynamicStateError::ExtensionNotEnabled {
extension: "ext_depth_range_unrestricted",
reason: "the start and end of bounds were not between 0.0 and 1.0 inclusive",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`bounds` is not between `0.0` and `1.0` inclusive",
requires_one_of: RequiresOneOf {
device_extensions: &["ext_depth_range_unrestricted"],
..Default::default()
},
});
}
@ -365,9 +385,13 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
if !(self.device().api_version() >= Version::V1_3
|| self.device().enabled_features().extended_dynamic_state)
{
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "extended_dynamic_state",
reason: "called set_depth_bounds_test_enable",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`set_depth_bounds_test_enable`",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_3),
features: &["extended_dynamic_state"],
..Default::default()
},
});
}
@ -401,7 +425,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
self.validate_pipeline_fixed_state(DynamicState::DepthCompareOp)?;
// VUID-vkCmdSetDepthCompareOp-depthCompareOp-parameter
compare_op.validate(self.device())?;
compare_op.validate_device(self.device())?;
// VUID-vkCmdSetDepthCompareOp-commandBuffer-cmdpool
if !self.queue_family().supports_graphics() {
@ -412,9 +436,13 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
if !(self.device().api_version() >= Version::V1_3
|| self.device().enabled_features().extended_dynamic_state)
{
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "extended_dynamic_state",
reason: "called set_depth_compare_op",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`set_depth_compare_op`",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_3),
features: &["extended_dynamic_state"],
..Default::default()
},
});
}
@ -453,9 +481,13 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
if !(self.device().api_version() >= Version::V1_3
|| self.device().enabled_features().extended_dynamic_state)
{
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "extended_dynamic_state",
reason: "called set_depth_test_enable",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`set_depth_test_enable`",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_3),
features: &["extended_dynamic_state"],
..Default::default()
},
});
}
@ -494,9 +526,13 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
if !(self.device().api_version() >= Version::V1_3
|| self.device().enabled_features().extended_dynamic_state)
{
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "extended_dynamic_state",
reason: "called set_depth_write_enable",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`set_depth_write_enable`",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_3),
features: &["extended_dynamic_state"],
..Default::default()
},
});
}
@ -544,9 +580,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
}
if self.device().enabled_extensions().ext_discard_rectangles {
return Err(SetDynamicStateError::ExtensionNotEnabled {
extension: "ext_discard_rectangles",
reason: "called set_discard_rectangle",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`set_discard_rectangle`",
requires_one_of: RequiresOneOf {
device_extensions: &["ext_discard_rectangles"],
..Default::default()
},
});
}
@ -597,7 +636,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
self.validate_pipeline_fixed_state(DynamicState::FrontFace)?;
// VUID-vkCmdSetFrontFace-frontFace-parameter
face.validate(self.device())?;
face.validate_device(self.device())?;
// VUID-vkCmdSetFrontFace-commandBuffer-cmdpool
if !self.queue_family().supports_graphics() {
@ -608,9 +647,13 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
if !(self.device().api_version() >= Version::V1_3
|| self.device().enabled_features().extended_dynamic_state)
{
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "extended_dynamic_state",
reason: "called set_front_face",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`set_front_face`",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_3),
features: &["extended_dynamic_state"],
..Default::default()
},
});
}
@ -650,9 +693,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
}
if !self.device().enabled_extensions().ext_line_rasterization {
return Err(SetDynamicStateError::ExtensionNotEnabled {
extension: "ext_line_rasterization",
reason: "called set_line_stipple",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`set_line_stipple`",
requires_one_of: RequiresOneOf {
device_extensions: &["ext_line_rasterization"],
..Default::default()
},
});
}
@ -692,9 +738,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
// VUID-vkCmdSetLineWidth-lineWidth-00788
if !self.device().enabled_features().wide_lines && line_width != 1.0 {
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "wide_lines",
reason: "line_width was not 1.0",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`line_width` is not `1.0`",
requires_one_of: RequiresOneOf {
features: &["wide_lines"],
..Default::default()
},
});
}
@ -725,7 +774,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
self.validate_pipeline_fixed_state(DynamicState::LogicOp)?;
// VUID-vkCmdSetLogicOpEXT-logicOp-parameter
logic_op.validate(self.device())?;
logic_op.validate_device(self.device())?;
// VUID-vkCmdSetLogicOpEXT-commandBuffer-cmdpool
if !self.queue_family().supports_graphics() {
@ -738,9 +787,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
.enabled_features()
.extended_dynamic_state2_logic_op
{
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "extended_dynamic_state2_logic_op",
reason: "called set_logic_op",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`set_logic_op`",
requires_one_of: RequiresOneOf {
features: &["extended_dynamic_state2_logic_op"],
..Default::default()
},
});
}
@ -785,9 +837,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
.enabled_features()
.extended_dynamic_state2_patch_control_points
{
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "extended_dynamic_state2_patch_control_points",
reason: "called set_patch_control_points",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`set_patch_control_points`",
requires_one_of: RequiresOneOf {
features: &["extended_dynamic_state2_patch_control_points"],
..Default::default()
},
});
}
@ -850,9 +905,13 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
if !(self.device().api_version() >= Version::V1_3
|| self.device().enabled_features().extended_dynamic_state2)
{
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "extended_dynamic_state2",
reason: "called set_primitive_restart_enable",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`set_primitive_restart_enable`",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_3),
features: &["extended_dynamic_state2"],
..Default::default()
},
});
}
@ -890,7 +949,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
self.validate_pipeline_fixed_state(DynamicState::PrimitiveTopology)?;
// VUID-vkCmdSetPrimitiveTopology-primitiveTopology-parameter
topology.validate(self.device())?;
topology.validate_device(self.device())?;
// VUID-vkCmdSetPrimitiveTopology-commandBuffer-cmdpool
if !self.queue_family().supports_graphics() {
@ -901,9 +960,13 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
if !(self.device().api_version() >= Version::V1_3
|| self.device().enabled_features().extended_dynamic_state)
{
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "extended_dynamic_state",
reason: "called set_primitive_topology",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`set_primitive_topology`",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_3),
features: &["extended_dynamic_state"],
..Default::default()
},
});
}
@ -917,9 +980,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
| PrimitiveTopology::TriangleStripWithAdjacency
)
{
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "geometry_shader",
reason: "topology was a WithAdjacency topology",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`topology` is `PrimitiveTopology::*WithAdjacency`",
requires_one_of: RequiresOneOf {
features: &["geometry_shader"],
..Default::default()
},
});
}
@ -927,9 +993,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
if !self.device().enabled_features().tessellation_shader
&& matches!(topology, PrimitiveTopology::PatchList)
{
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "tessellation_shader",
reason: "topology was PatchList",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`topology` is `PrimitiveTopology::PatchList`",
requires_one_of: RequiresOneOf {
features: &["tessellation_shader"],
..Default::default()
},
});
}
@ -971,9 +1040,13 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
if !(self.device().api_version() >= Version::V1_3
|| self.device().enabled_features().extended_dynamic_state2)
{
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "extended_dynamic_state2",
reason: "called set_rasterizer_discard_enable",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`set_rasterizer_discard_enable`",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_3),
features: &["extended_dynamic_state2"],
..Default::default()
},
});
}
@ -1029,17 +1102,23 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
if !self.device().enabled_features().multi_viewport {
// VUID-vkCmdSetScissor-firstScissor-00593
if first_scissor != 0 {
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "multi_viewport",
reason: "first_scissor was not 0",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`first_scissor` is not `0`",
requires_one_of: RequiresOneOf {
features: &["multi_viewport"],
..Default::default()
},
});
}
// VUID-vkCmdSetScissor-scissorCount-00594
if scissors.len() > 1 {
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "multi_viewport",
reason: "scissors contained more than one element",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`scissors.len()` is greater than `1`",
requires_one_of: RequiresOneOf {
features: &["multi_viewport"],
..Default::default()
},
});
}
}
@ -1090,9 +1169,13 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
if !(self.device().api_version() >= Version::V1_3
|| self.device().enabled_features().extended_dynamic_state)
{
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "extended_dynamic_state",
reason: "called set_scissor_with_count",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`set_scissor_with_count`",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_3),
features: &["extended_dynamic_state"],
..Default::default()
},
});
}
@ -1106,9 +1189,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
// VUID-vkCmdSetScissorWithCount-scissorCount-03398
if !self.device().enabled_features().multi_viewport && scissors.len() > 1 {
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "multi_viewport",
reason: "scissors contained more than one element",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`scissors.len()` is greater than `1`",
requires_one_of: RequiresOneOf {
features: &["multi_viewport"],
..Default::default()
},
});
}
@ -1144,7 +1230,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
self.validate_pipeline_fixed_state(DynamicState::StencilCompareMask)?;
// VUID-vkCmdSetStencilCompareMask-faceMask-parameter
faces.validate(self.device())?;
faces.validate_device(self.device())?;
// VUID-vkCmdSetStencilCompareMask-commandBuffer-cmdpool
if !self.queue_family().supports_graphics() {
@ -1194,19 +1280,19 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
self.validate_pipeline_fixed_state(DynamicState::StencilOp)?;
// VUID-vkCmdSetStencilOp-faceMask-parameter
faces.validate(self.device())?;
faces.validate_device(self.device())?;
// VUID-vkCmdSetStencilOp-failOp-parameter
fail_op.validate(self.device())?;
fail_op.validate_device(self.device())?;
// VUID-vkCmdSetStencilOp-passOp-parameter
pass_op.validate(self.device())?;
pass_op.validate_device(self.device())?;
// VUID-vkCmdSetStencilOp-depthFailOp-parameter
depth_fail_op.validate(self.device())?;
depth_fail_op.validate_device(self.device())?;
// VUID-vkCmdSetStencilOp-compareOp-parameter
compare_op.validate(self.device())?;
compare_op.validate_device(self.device())?;
// VUID-vkCmdSetStencilOp-commandBuffer-cmdpool
if !self.queue_family().supports_graphics() {
@ -1217,9 +1303,13 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
if !(self.device().api_version() >= Version::V1_3
|| self.device().enabled_features().extended_dynamic_state)
{
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "extended_dynamic_state",
reason: "called set_stencil_op",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`set_stencil_op`",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_3),
features: &["extended_dynamic_state"],
..Default::default()
},
});
}
@ -1251,7 +1341,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
self.validate_pipeline_fixed_state(DynamicState::StencilReference)?;
// VUID-vkCmdSetStencilReference-faceMask-parameter
faces.validate(self.device())?;
faces.validate_device(self.device())?;
// VUID-vkCmdSetStencilReference-commandBuffer-cmdpool
if !self.queue_family().supports_graphics() {
@ -1293,9 +1383,13 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
if !(self.device().api_version() >= Version::V1_3
|| self.device().enabled_features().extended_dynamic_state)
{
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "extended_dynamic_state",
reason: "called set_stencil_test_enable",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`set_stencil_test_enable`",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_3),
features: &["extended_dynamic_state"],
..Default::default()
},
});
}
@ -1327,7 +1421,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
self.validate_pipeline_fixed_state(DynamicState::StencilWriteMask)?;
// VUID-vkCmdSetStencilWriteMask-faceMask-parameter
faces.validate(self.device())?;
faces.validate_device(self.device())?;
// VUID-vkCmdSetStencilWriteMask-commandBuffer-cmdpool
if !self.queue_family().supports_graphics() {
@ -1387,17 +1481,23 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
if !self.device().enabled_features().multi_viewport {
// VUID-vkCmdSetViewport-firstViewport-01224
if first_viewport != 0 {
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "multi_viewport",
reason: "first_viewport was not 0",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`first_scissors` is not `0`",
requires_one_of: RequiresOneOf {
features: &["multi_viewport"],
..Default::default()
},
});
}
// VUID-vkCmdSetViewport-viewportCount-01225
if viewports.len() > 1 {
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "multi_viewport",
reason: "viewports contained more than one element",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`viewports.len()` is greater than `1`",
requires_one_of: RequiresOneOf {
features: &["multi_viewport"],
..Default::default()
},
});
}
}
@ -1448,9 +1548,13 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
if !(self.device().api_version() >= Version::V1_3
|| self.device().enabled_features().extended_dynamic_state)
{
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "extended_dynamic_state",
reason: "called set_viewport_with_count",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`set_viewport_with_count`",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_3),
features: &["extended_dynamic_state"],
..Default::default()
},
});
}
@ -1464,9 +1568,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
// VUID-vkCmdSetViewportWithCount-viewportCount-03395
if !self.device().enabled_features().multi_viewport && viewports.len() > 1 {
return Err(SetDynamicStateError::FeatureNotEnabled {
feature: "multi_viewport",
reason: "viewports contained more than one element",
return Err(SetDynamicStateError::RequirementNotMet {
required_for: "`viewports.len()` is greater than `1`",
requires_one_of: RequiresOneOf {
features: &["multi_viewport"],
..Default::default()
},
});
}
@ -2679,13 +2786,9 @@ impl UnsafeCommandBufferBuilder {
#[derive(Clone, Debug)]
#[allow(dead_code)]
enum SetDynamicStateError {
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
},
FeatureNotEnabled {
feature: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// The provided `factor` is not between 1 and 256 inclusive.
@ -2720,16 +2823,18 @@ enum SetDynamicStateError {
impl Error for SetDynamicStateError {}
impl fmt::Display for SetDynamicStateError {
impl Display for SetDynamicStateError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::ExtensionNotEnabled { extension, reason } => {
write!(f, "the extension {} must be enabled: {}", extension, reason)
}
Self::FeatureNotEnabled { feature, reason } => {
write!(f, "the feature {} must be enabled: {}", feature, reason,)
}
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::FactorOutOfRange => write!(
f,
@ -2767,12 +2872,12 @@ impl fmt::Display for SetDynamicStateError {
}
}
impl From<ExtensionNotEnabled> for SetDynamicStateError {
impl From<RequirementNotMet> for SetDynamicStateError {
#[inline]
fn from(err: ExtensionNotEnabled) -> Self {
Self::ExtensionNotEnabled {
extension: err.extension,
reason: err.reason,
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}

View File

@ -21,7 +21,7 @@ use crate::{
},
sampler::Filter,
sync::{AccessFlags, PipelineMemoryAccess, PipelineStages},
Version, VulkanObject,
RequiresOneOf, Version, VulkanObject,
};
use smallvec::{smallvec, SmallVec};
use std::{
@ -102,13 +102,13 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
} = blit_image_info;
// VUID-VkBlitImageInfo2-srcImageLayout-parameter
src_image_layout.validate(device)?;
src_image_layout.validate_device(device)?;
// VUID-VkBlitImageInfo2-dstImageLayout-parameter
dst_image_layout.validate(device)?;
dst_image_layout.validate_device(device)?;
// VUID-VkBlitImageInfo2-filter-parameter
filter.validate(device)?;
filter.validate_device(device)?;
let src_image_inner = src_image.inner();
let dst_image_inner = dst_image.inner();
@ -328,7 +328,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
}
// VUID-VkImageSubresourceLayers-aspectMask-parameter
subresource.aspects.validate(device)?;
subresource.aspects.validate_device(device)?;
// VUID-VkImageSubresourceLayers-aspectMask-requiredbitmask
assert!(!subresource.aspects.is_empty());
@ -600,7 +600,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
} = clear_info;
// VUID-vkCmdClearColorImage-imageLayout-parameter
image_layout.validate(device)?;
image_layout.validate_device(device)?;
// VUID-vkCmdClearColorImage-commonparent
assert_eq!(device, image.device());
@ -662,7 +662,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
for (region_index, subresource_range) in regions.iter().enumerate() {
// VUID-VkImageSubresourceRange-aspectMask-parameter
subresource_range.aspects.validate(device)?;
subresource_range.aspects.validate_device(device)?;
// VUID-VkImageSubresourceRange-aspectMask-requiredbitmask
assert!(!subresource_range.aspects.is_empty());
@ -748,7 +748,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
} = clear_info;
// VUID-vkCmdClearDepthStencilImage-imageLayout-parameter
image_layout.validate(device)?;
image_layout.validate_device(device)?;
// VUID-vkCmdClearDepthStencilImage-commonparent
assert_eq!(device, image.device());
@ -799,15 +799,19 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
if !device.enabled_extensions().ext_depth_range_unrestricted
&& !(0.0..=1.0).contains(&clear_value.depth)
{
return Err(CopyError::ExtensionNotEnabled {
extension: "ext_depth_range_unrestricted",
reason: "clear_value.depth was not between 0.0 and 1.0 inclusive",
return Err(CopyError::RequirementNotMet {
required_for:
"`clear_info.clear_value.depth` is not between `0.0` and `1.0` inclusive",
requires_one_of: RequiresOneOf {
device_extensions: &["ext_depth_range_unrestricted"],
..Default::default()
},
});
}
for (region_index, subresource_range) in regions.iter().enumerate() {
// VUID-VkImageSubresourceRange-aspectMask-parameter
subresource_range.aspects.validate(device)?;
subresource_range.aspects.validate_device(device)?;
// VUID-VkImageSubresourceRange-aspectMask-requiredbitmask
assert!(!subresource_range.aspects.is_empty());
@ -901,10 +905,10 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
} = resolve_image_info;
// VUID-VkResolveImageInfo2-srcImageLayout-parameter
src_image_layout.validate(device)?;
src_image_layout.validate_device(device)?;
// VUID-VkResolveImageInfo2-dstImageLayout-parameter
dst_image_layout.validate(device)?;
dst_image_layout.validate_device(device)?;
// VUID-VkResolveImageInfo2-commonparent
assert_eq!(device, src_image.device());
@ -1028,7 +1032,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
}
// VUID-VkImageSubresourceLayers-aspectMask-parameter
subresource.aspects.validate(device)?;
subresource.aspects.validate_device(device)?;
// VUID-VkImageSubresourceLayers-aspectMask-requiredbitmask
// VUID-VkImageResolve2-aspectMask-00266

View File

@ -22,19 +22,21 @@ use super::synced::SyncCommandBufferBuilderError;
use crate::{
format::Format,
image::{ImageAspects, ImageLayout, SampleCount, SampleCounts},
macros::ExtensionNotEnabled,
DeviceSize,
DeviceSize, RequirementNotMet, RequiresOneOf,
};
use std::{
error::Error,
fmt::{Display, Error as FmtError, Formatter},
};
use std::{error::Error, fmt};
/// Error that can happen when recording a copy command.
#[derive(Clone, Debug)]
pub enum CopyError {
SyncCommandBufferBuilderError(SyncCommandBufferBuilderError),
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// Operation forbidden inside of a render pass.
@ -282,16 +284,21 @@ impl Error for CopyError {
}
}
impl fmt::Display for CopyError {
impl Display for CopyError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::SyncCommandBufferBuilderError(_) => write!(f, "a SyncCommandBufferBuilderError"),
Self::ExtensionNotEnabled { extension, reason } => write!(
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"the extension {} must be enabled: {}",
extension, reason
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::ForbiddenInsideRenderPass => {
write!(f, "operation forbidden inside of a render pass")
}
@ -585,12 +592,12 @@ impl From<SyncCommandBufferBuilderError> for CopyError {
}
}
impl From<ExtensionNotEnabled> for CopyError {
impl From<RequirementNotMet> for CopyError {
#[inline]
fn from(err: ExtensionNotEnabled) -> Self {
Self::ExtensionNotEnabled {
extension: err.extension,
reason: err.reason,
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}
@ -602,9 +609,9 @@ pub enum CopyErrorResource {
Destination,
}
impl fmt::Display for CopyErrorResource {
impl Display for CopyErrorResource {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::Source => write!(f, "source"),
Self::Destination => write!(f, "destination"),

View File

@ -34,9 +34,17 @@ use crate::{
sampler::{Sampler, SamplerImageViewIncompatibleError},
shader::{DescriptorRequirements, ShaderScalarType, ShaderStage},
sync::{AccessFlags, PipelineMemoryAccess, PipelineStages},
DeviceSize, VulkanObject,
DeviceSize, RequiresOneOf, VulkanObject,
};
use std::{
borrow::Cow,
cmp::min,
error::Error,
fmt::{Display, Error as FmtError, Formatter},
mem::size_of,
ops::Range,
sync::Arc,
};
use std::{borrow::Cow, cmp::min, error::Error, fmt, mem::size_of, ops::Range, sync::Arc};
/// # Commands to execute a bound pipeline.
///
@ -286,9 +294,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
// VUID-vkCmdDrawIndirect-drawCount-02718
if draw_count > 1 && !self.device().enabled_features().multi_draw_indirect {
return Err(PipelineExecutionError::FeatureNotEnabled {
feature: "multi_draw_indirect",
reason: "draw_count was greater than 1",
return Err(PipelineExecutionError::RequirementNotMet {
required_for: "`draw_count` is greater than `1`",
requires_one_of: RequiresOneOf {
features: &["multi_draw_indirect"],
..Default::default()
},
});
}
@ -475,9 +486,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
// VUID-vkCmdDrawIndexedIndirect-drawCount-02718
if draw_count > 1 && !self.device().enabled_features().multi_draw_indirect {
return Err(PipelineExecutionError::FeatureNotEnabled {
feature: "multi_draw_indirect",
reason: "draw_count was greater than 1",
return Err(PipelineExecutionError::RequirementNotMet {
required_for: "`draw_count` is greater than `1`",
requires_one_of: RequiresOneOf {
features: &["multi_draw_indirect"],
..Default::default()
},
});
}
@ -1093,9 +1107,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
| PrimitiveTopology::TriangleListWithAdjacency => {
// VUID?
if !device.enabled_features().primitive_topology_list_restart {
return Err(PipelineExecutionError::FeatureNotEnabled {
feature: "primitive_topology_list_restart",
reason: "the PrimitiveRestartEnable dynamic state was true in combination with a List PrimitiveTopology",
return Err(PipelineExecutionError::RequirementNotMet {
required_for: "The bound pipeline sets `DynamicState::PrimitiveRestartEnable` and the current primitive topology is `PrimitiveTopology::*List`",
requires_one_of: RequiresOneOf {
features: &["primitive_topology_list_restart"],
..Default::default()
},
});
}
}
@ -1105,9 +1122,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
.enabled_features()
.primitive_topology_patch_list_restart
{
return Err(PipelineExecutionError::FeatureNotEnabled {
feature: "primitive_topology_patch_list_restart",
reason: "the PrimitiveRestartEnable dynamic state was true in combination with PrimitiveTopology::PatchList",
return Err(PipelineExecutionError::RequirementNotMet {
required_for: "The bound pipeline sets `DynamicState::PrimitiveRestartEnable` and the current primitive topology is `PrimitiveTopology::PatchList`",
requires_one_of: RequiresOneOf {
features: &["primitive_topology_patch_list_restart"],
..Default::default()
},
});
}
}
@ -2241,9 +2261,9 @@ impl UnsafeCommandBufferBuilder {
pub enum PipelineExecutionError {
SyncCommandBufferBuilderError(SyncCommandBufferBuilderError),
FeatureNotEnabled {
feature: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// The resource bound to a descriptor set binding at a particular index is not compatible
@ -2430,15 +2450,20 @@ impl Error for PipelineExecutionError {
}
}
impl fmt::Display for PipelineExecutionError {
impl Display for PipelineExecutionError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::SyncCommandBufferBuilderError(_) => write!(f, "a SyncCommandBufferBuilderError"),
Self::FeatureNotEnabled { feature, reason } => {
write!(f, "the feature {} must be enabled: {}", feature, reason)
}
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::DescriptorResourceInvalid { set_num, binding_num, index, .. } => write!(
f,
@ -2689,9 +2714,9 @@ impl Error for DescriptorResourceInvalidError {
}
}
impl fmt::Display for DescriptorResourceInvalidError {
impl Display for DescriptorResourceInvalidError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::ImageViewFormatMismatch { provided, required } => write!(
f,

View File

@ -16,15 +16,20 @@ use crate::{
AutoCommandBufferBuilder,
},
device::{physical::QueueFamily, DeviceOwned},
macros::ExtensionNotEnabled,
query::{
QueriesRange, Query, QueryControlFlags, QueryPool, QueryResultElement, QueryResultFlags,
QueryType,
},
sync::{AccessFlags, PipelineMemoryAccess, PipelineStage, PipelineStages},
DeviceSize, VulkanObject,
DeviceSize, RequirementNotMet, RequiresOneOf, VulkanObject,
};
use std::{
error::Error,
fmt::{Display, Error as FmtError, Formatter},
mem::size_of,
ops::Range,
sync::Arc,
};
use std::{error::Error, fmt, mem::size_of, ops::Range, sync::Arc};
/// # Commands related to queries.
impl<L, P> AutoCommandBufferBuilder<L, P> {
@ -74,7 +79,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
let device = self.device();
// VUID-vkCmdBeginQuery-flags-parameter
flags.validate(device)?;
flags.validate_device(device)?;
// VUID-vkCmdBeginQuery-commonparent
assert_eq!(device, query_pool.device());
@ -92,9 +97,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
// VUID-vkCmdBeginQuery-queryType-00800
if flags.precise && !device.enabled_features().occlusion_query_precise {
return Err(QueryError::FeatureNotEnabled {
feature: "occlusion_query_precise",
reason: "flags.precise was enabled",
return Err(QueryError::RequirementNotMet {
required_for: "`flags.precise` is set",
requires_one_of: RequiresOneOf {
features: &["occlusion_query_precise"],
..Default::default()
},
});
}
}
@ -237,9 +245,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
PipelineStage::GeometryShader => {
// VUID-vkCmdWriteTimestamp-pipelineStage-04075
if !device.enabled_features().geometry_shader {
return Err(QueryError::FeatureNotEnabled {
feature: "geometry_shader",
reason: "stage was GeometryShader",
return Err(QueryError::RequirementNotMet {
required_for: "`stage` is `PipelineStage::GeometryShader`",
requires_one_of: RequiresOneOf {
features: &["geometry_shadere"],
..Default::default()
},
});
}
}
@ -247,10 +258,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
| PipelineStage::TessellationEvaluationShader => {
// VUID-vkCmdWriteTimestamp-pipelineStage-04076
if !device.enabled_features().tessellation_shader {
return Err(QueryError::FeatureNotEnabled {
feature: "tessellation_shader",
reason:
"stage was TessellationControlShader or TessellationEvaluationShader",
return Err(QueryError::RequirementNotMet {
required_for: "`stage` is `PipelineStage::TessellationControlShader` or `PipelineStage::TessellationEvaluationShader`",
requires_one_of: RequiresOneOf {
features: &["tessellation_shader"],
..Default::default()
},
});
}
}
@ -723,13 +736,9 @@ impl UnsafeCommandBufferBuilder {
pub enum QueryError {
SyncCommandBufferBuilderError(SyncCommandBufferBuilderError),
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
},
FeatureNotEnabled {
feature: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// The buffer is too small for the copy operation.
@ -777,24 +786,22 @@ pub enum QueryError {
impl Error for QueryError {}
impl fmt::Display for QueryError {
impl Display for QueryError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
Self::SyncCommandBufferBuilderError(_) => write!(
f,
"a SyncCommandBufferBuilderError",
),
Self::ExtensionNotEnabled { extension, reason } => write!(
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"the extension {} must be enabled: {}",
extension, reason
),
Self::FeatureNotEnabled { feature, reason } => write!(
f,
"the feature {} must be enabled: {}",
feature, reason,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::BufferTooSmall { .. } => {
@ -842,12 +849,12 @@ impl From<SyncCommandBufferBuilderError> for QueryError {
}
}
impl From<ExtensionNotEnabled> for QueryError {
impl From<RequirementNotMet> for QueryError {
#[inline]
fn from(err: ExtensionNotEnabled) -> Self {
Self::ExtensionNotEnabled {
extension: err.extension,
reason: err.reason,
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}

View File

@ -21,16 +21,21 @@ use crate::{
device::DeviceOwned,
format::{ClearColorValue, ClearValue, Format, NumericType},
image::{ImageLayout, ImageViewAbstract, SampleCount},
macros::ExtensionNotEnabled,
render_pass::{
AttachmentDescription, Framebuffer, LoadOp, RenderPass, ResolveMode, StoreOp,
SubpassDescription,
},
sync::{AccessFlags, PipelineMemoryAccess, PipelineStages},
Version, VulkanObject,
RequirementNotMet, RequiresOneOf, Version, VulkanObject,
};
use smallvec::SmallVec;
use std::{cmp::min, error::Error, fmt, ops::Range, sync::Arc};
use std::{
cmp::min,
error::Error,
fmt::{Display, Error as FmtError, Formatter},
ops::Range,
sync::Arc,
};
/// # Commands for render passes.
///
@ -94,7 +99,7 @@ where
let device = self.device();
// VUID-VkSubpassBeginInfo-contents-parameter
contents.validate(device)?;
contents.validate_device(device)?;
// VUID-vkCmdBeginRenderPass2-commandBuffer-cmdpool
if !self.queue_family().supports_graphics() {
@ -420,7 +425,7 @@ where
let device = self.device();
// VUID-VkSubpassBeginInfo-contents-parameter
contents.validate(device)?;
contents.validate_device(device)?;
// VUID-vkCmdNextSubpass2-renderpass
let render_pass_state = self
@ -661,9 +666,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
// VUID-vkCmdBeginRendering-dynamicRendering-06446
if !device.enabled_features().dynamic_rendering {
return Err(RenderPassError::FeatureNotEnabled {
feature: "dynamic_rendering",
reason: "called begin_rendering",
return Err(RenderPassError::RequirementNotMet {
required_for: "`begin_rendering`",
requires_one_of: RequiresOneOf {
features: &["dynamic_rendering"],
..Default::default()
},
});
}
@ -690,7 +698,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
} = rendering_info;
// VUID-VkRenderingInfo-flags-parameter
contents.validate(device)?;
contents.validate_device(device)?;
// VUID-vkCmdBeginRendering-commandBuffer-06068
if self.inheritance_info.is_some() && contents == SubpassContents::SecondaryCommandBuffers {
@ -704,9 +712,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
// VUID-VkRenderingInfo-multiview-06127
if view_mask != 0 && !device.enabled_features().multiview {
return Err(RenderPassError::FeatureNotEnabled {
feature: "multiview",
reason: "view_mask is not 0",
return Err(RenderPassError::RequirementNotMet {
required_for: "`rendering_info.viewmask` is not `0`",
requires_one_of: RequiresOneOf {
features: &["multiview"],
..Default::default()
},
});
}
@ -752,13 +763,13 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
} = attachment_info;
// VUID-VkRenderingAttachmentInfo-imageLayout-parameter
image_layout.validate(device)?;
image_layout.validate_device(device)?;
// VUID-VkRenderingAttachmentInfo-loadOp-parameter
load_op.validate(device)?;
load_op.validate_device(device)?;
// VUID-VkRenderingAttachmentInfo-storeOp-parameter
store_op.validate(device)?;
store_op.validate_device(device)?;
// VUID-VkRenderingInfo-colorAttachmentCount-06087
if !image_view.usage().color_attachment {
@ -812,10 +823,10 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
} = resolve_info;
// VUID-VkRenderingAttachmentInfo-resolveImageLayout-parameter
resolve_image_layout.validate(device)?;
resolve_image_layout.validate_device(device)?;
// VUID-VkRenderingAttachmentInfo-resolveMode-parameter
mode.validate(device)?;
mode.validate_device(device)?;
let resolve_image = resolve_image_view.image();
@ -901,13 +912,13 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
} = attachment_info;
// VUID-VkRenderingAttachmentInfo-imageLayout-parameter
image_layout.validate(device)?;
image_layout.validate_device(device)?;
// VUID-VkRenderingAttachmentInfo-loadOp-parameter
load_op.validate(device)?;
load_op.validate_device(device)?;
// VUID-VkRenderingAttachmentInfo-storeOp-parameter
store_op.validate(device)?;
store_op.validate_device(device)?;
let image_aspects = image_view.format().unwrap().aspects();
@ -965,10 +976,10 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
} = resolve_info;
// VUID-VkRenderingAttachmentInfo-resolveImageLayout-parameter
resolve_image_layout.validate(device)?;
resolve_image_layout.validate_device(device)?;
// VUID-VkRenderingAttachmentInfo-resolveMode-parameter
mode.validate(device)?;
mode.validate_device(device)?;
// VUID-VkRenderingInfo-pDepthAttachment-06102
if !properties
@ -1026,13 +1037,13 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
} = attachment_info;
// VUID-VkRenderingAttachmentInfo-imageLayout-parameter
image_layout.validate(device)?;
image_layout.validate_device(device)?;
// VUID-VkRenderingAttachmentInfo-loadOp-parameter
load_op.validate(device)?;
load_op.validate_device(device)?;
// VUID-VkRenderingAttachmentInfo-storeOp-parameter
store_op.validate(device)?;
store_op.validate_device(device)?;
let image_aspects = image_view.format().unwrap().aspects();
@ -1090,10 +1101,10 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
} = resolve_info;
// VUID-VkRenderingAttachmentInfo-resolveImageLayout-parameter
resolve_image_layout.validate(device)?;
resolve_image_layout.validate_device(device)?;
// VUID-VkRenderingAttachmentInfo-resolveMode-parameter
mode.validate(device)?;
mode.validate_device(device)?;
// VUID-VkRenderingInfo-pStencilAttachment-06103
if !properties
@ -2528,13 +2539,9 @@ pub struct ClearRect {
pub enum RenderPassError {
SyncCommandBufferBuilderError(SyncCommandBufferBuilderError),
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
},
FeatureNotEnabled {
feature: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// A framebuffer image did not have the required usage enabled.
@ -2789,20 +2796,20 @@ impl Error for RenderPassError {
}
}
impl fmt::Display for RenderPassError {
impl Display for RenderPassError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::SyncCommandBufferBuilderError(_) => write!(f, "a SyncCommandBufferBuilderError"),
Self::ExtensionNotEnabled { extension, reason } => write!(
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"the extension {} must be enabled: {}",
extension, reason
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::FeatureNotEnabled { feature, reason } => {
write!(f, "the feature {} must be enabled: {}", feature, reason)
}
Self::AttachmentImageMissingUsage { attachment_index, usage } => write!(
f,
@ -3093,12 +3100,12 @@ impl From<SyncCommandBufferBuilderError> for RenderPassError {
}
}
impl From<ExtensionNotEnabled> for RenderPassError {
impl From<RequirementNotMet> for RenderPassError {
#[inline]
fn from(err: ExtensionNotEnabled) -> Self {
Self::ExtensionNotEnabled {
extension: err.extension,
reason: err.reason,
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}

View File

@ -20,10 +20,13 @@ use crate::{
format::Format,
image::SampleCount,
query::{QueryControlFlags, QueryPipelineStatisticFlags, QueryType},
SafeDeref, VulkanObject,
RequiresOneOf, SafeDeref, VulkanObject,
};
use smallvec::SmallVec;
use std::{error::Error, fmt};
use std::{
error::Error,
fmt::{Display, Error as FmtError, Formatter},
};
/// # Commands to execute a secondary command buffer inside a primary command buffer.
///
@ -317,9 +320,12 @@ where
// VUID-vkCmdExecuteCommands-commandBuffer-00101
if !self.query_state.is_empty() && !self.device().enabled_features().inherited_queries {
return Err(ExecuteCommandsError::FeatureNotEnabled {
feature: "inherited_queries",
reason: "a query was active when calling execute_commands",
return Err(ExecuteCommandsError::RequirementNotMet {
required_for: "`execute_commands` when a query is active",
requires_one_of: RequiresOneOf {
features: &["inherited_queries"],
..Default::default()
},
});
}
@ -557,9 +563,9 @@ impl UnsafeCommandBufferBuilderExecuteCommands {
pub enum ExecuteCommandsError {
SyncCommandBufferBuilderError(SyncCommandBufferBuilderError),
FeatureNotEnabled {
feature: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// Operation forbidden inside a render subpass with the specified contents.
@ -701,15 +707,20 @@ impl Error for ExecuteCommandsError {
}
}
impl fmt::Display for ExecuteCommandsError {
impl Display for ExecuteCommandsError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::SyncCommandBufferBuilderError(_) => write!(f, "a SyncCommandBufferBuilderError"),
Self::FeatureNotEnabled { feature, reason } => {
write!(f, "the feature {} must be enabled: {}", feature, reason)
}
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::ForbiddenWithSubpassContents { contents: subpass_contents } => write!(
f,

View File

@ -229,10 +229,10 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
} = copy_image_info;
// VUID-VkCopyImageInfo2-srcImageLayout-parameter
src_image_layout.validate(device)?;
src_image_layout.validate_device(device)?;
// VUID-VkCopyImageInfo2-dstImageLayout-parameter
dst_image_layout.validate(device)?;
dst_image_layout.validate_device(device)?;
// VUID-VkCopyImageInfo2-commonparent
assert_eq!(device, src_image.device());
@ -404,7 +404,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
}
// VUID-VkImageSubresourceLayers-aspectMask-parameter
subresource.aspects.validate(device)?;
subresource.aspects.validate_device(device)?;
// VUID-VkImageSubresourceLayers-aspectMask-requiredbitmask
assert!(!subresource.aspects.is_empty());
@ -878,7 +878,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
} = copy_buffer_to_image_info;
// VUID-VkCopyBufferToImageInfo2-dstImageLayout-parameter
dst_image_layout.validate(device)?;
dst_image_layout.validate_device(device)?;
// VUID-VkCopyBufferToImageInfo2-commonparent
assert_eq!(device, src_buffer.device());
@ -1307,7 +1307,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
} = copy_image_to_buffer_info;
// VUID-VkCopyImageToBufferInfo2-srcImageLayout-parameter
src_image_layout.validate(device)?;
src_image_layout.validate_device(device)?;
// VUID-VkCopyImageToBufferInfo2-commonparent
assert_eq!(device, dst_buffer.device());

View File

@ -10,12 +10,12 @@
use crate::{
command_buffer::CommandBufferLevel,
device::{physical::QueueFamily, Device, DeviceOwned},
OomError, Version, VulkanError, VulkanObject,
OomError, RequiresOneOf, Version, VulkanError, VulkanObject,
};
use smallvec::SmallVec;
use std::{
error::Error,
fmt,
fmt::{Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},
marker::PhantomData,
mem::MaybeUninit,
@ -275,7 +275,14 @@ impl UnsafeCommandPool {
if !(self.device.api_version() >= Version::V1_1
|| self.device.enabled_extensions().khr_maintenance1)
{
return Err(CommandPoolTrimError::Maintenance1ExtensionNotEnabled);
return Err(CommandPoolTrimError::RequirementNotMet {
required_for: "`trim`",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_1),
device_extensions: &["khr_maintenance1"],
..Default::default()
},
});
}
unsafe {
@ -380,16 +387,16 @@ impl Error for UnsafeCommandPoolCreationError {
}
}
impl fmt::Display for UnsafeCommandPoolCreationError {
impl Display for UnsafeCommandPoolCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
Self::OomError(_) => write!(fmt, "not enough memory",),
Self::OomError(_) => write!(f, "not enough memory",),
Self::QueueFamilyIndexOutOfRange {
queue_family_index,
queue_family_count,
} => write!(
fmt,
f,
"the provided `queue_family_index` ({}) was not less than the number of queue families in the physical device ({})",
queue_family_index, queue_family_count,
),
@ -521,25 +528,28 @@ impl Hash for UnsafeCommandPoolAlloc {
/// Error that can happen when trimming command pools.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum CommandPoolTrimError {
/// The `KHR_maintenance1` extension was not enabled.
Maintenance1ExtensionNotEnabled,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
}
impl Error for CommandPoolTrimError {}
impl fmt::Display for CommandPoolTrimError {
impl Display for CommandPoolTrimError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(
fmt,
"{}",
match *self {
CommandPoolTrimError::Maintenance1ExtensionNotEnabled => {
"the `KHR_maintenance1` extension was not enabled"
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
}
}
)
}
}
impl From<VulkanError> for CommandPoolTrimError {
@ -557,7 +567,7 @@ mod tests {
};
use crate::{
command_buffer::{pool::sys::CommandBufferAllocateInfo, CommandBufferLevel},
Version,
RequiresOneOf, Version,
};
#[test]
@ -617,14 +627,24 @@ mod tests {
if device.api_version() >= Version::V1_1 {
if matches!(
pool.trim(),
Err(CommandPoolTrimError::Maintenance1ExtensionNotEnabled)
Err(CommandPoolTrimError::RequirementNotMet {
requires_one_of: RequiresOneOf {
device_extensions,
..
}, ..
}) if device_extensions.contains(&"khr_maintenance1")
) {
panic!()
}
} else {
if !matches!(
pool.trim(),
Err(CommandPoolTrimError::Maintenance1ExtensionNotEnabled)
Err(CommandPoolTrimError::RequirementNotMet {
requires_one_of: RequiresOneOf {
device_extensions,
..
}, ..
}) if device_extensions.contains(&"khr_maintenance1")
) {
panic!()
}

View File

@ -16,7 +16,11 @@ use crate::{
DeviceSize, OomError, SynchronizedVulkanObject, VulkanError, VulkanObject,
};
use smallvec::SmallVec;
use std::{error::Error, fmt, marker::PhantomData};
use std::{
error::Error,
fmt::{Debug, Display, Error as FmtError, Formatter},
marker::PhantomData,
};
// TODO: correctly implement Debug on all the structs of this module
@ -246,10 +250,10 @@ impl<'a> SubmitBindSparseBuilder<'a> {
}
}
impl<'a> fmt::Debug for SubmitBindSparseBuilder<'a> {
impl<'a> Debug for SubmitBindSparseBuilder<'a> {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "<Bind sparse operation>")
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(f, "<Bind sparse operation>")
}
}
@ -480,11 +484,11 @@ impl Error for SubmitBindSparseError {
}
}
impl fmt::Display for SubmitBindSparseError {
impl Display for SubmitBindSparseError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
fmt,
f,
"{}",
match *self {
SubmitBindSparseError::OomError(_) => "not enough memory",

View File

@ -14,7 +14,12 @@ use crate::{
OomError, SynchronizedVulkanObject, VulkanError, VulkanObject,
};
use smallvec::SmallVec;
use std::{error::Error, fmt, marker::PhantomData, ptr};
use std::{
error::Error,
fmt::{Debug, Display, Error as FmtError, Formatter},
marker::PhantomData,
ptr,
};
/// Prototype for a submission that presents a swapchain on the screen.
// TODO: example here
@ -181,9 +186,9 @@ impl<'a> SubmitPresentBuilder<'a> {
}
}
impl<'a> fmt::Debug for SubmitPresentBuilder<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fmt.debug_struct("SubmitPresentBuilder")
impl<'a> Debug for SubmitPresentBuilder<'a> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
f.debug_struct("SubmitPresentBuilder")
.field("wait_semaphores", &self.wait_semaphores)
.field("swapchains", &self.swapchains)
.field("image_indices", &self.image_indices)
@ -223,11 +228,11 @@ impl Error for SubmitPresentError {
}
}
impl fmt::Display for SubmitPresentError {
impl Display for SubmitPresentError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
fmt,
f,
"{}",
match *self {
SubmitPresentError::OomError(_) => "not enough memory",

View File

@ -14,7 +14,11 @@ use crate::{
OomError, SynchronizedVulkanObject, VulkanError, VulkanObject,
};
use smallvec::SmallVec;
use std::{error::Error, fmt, marker::PhantomData};
use std::{
error::Error,
fmt::{Display, Error as FmtError, Formatter},
marker::PhantomData,
};
/// Prototype for a submission that executes command buffers.
// TODO: example here
@ -261,11 +265,11 @@ impl Error for SubmitCommandBufferError {
}
}
impl fmt::Display for SubmitCommandBufferError {
impl Display for SubmitCommandBufferError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
fmt,
f,
"{}",
match *self {
SubmitCommandBufferError::OomError(_) => "not enough memory",

View File

@ -48,7 +48,7 @@ use std::{
borrow::Cow,
collections::{hash_map::Entry, HashMap},
error::Error,
fmt,
fmt::{Debug, Display, Error as FmtError, Formatter},
ops::{Range, RangeInclusive},
sync::Arc,
};
@ -59,9 +59,6 @@ use std::{
/// for `pipeline_layout` which is automatically handled. This wrapper automatically builds
/// pipeline barriers, keeps used resources alive and implements the `CommandBuffer` trait.
///
/// Since the implementation needs to cache commands in a `Vec`, most methods have additional
/// `Send + Sync + 'static` trait requirements on their generics.
///
/// If this builder finds out that a command isn't valid because of synchronization reasons (eg.
/// trying to copy from a buffer to an image which share the same memory), then an error is
/// returned.
@ -863,10 +860,10 @@ unsafe impl DeviceOwned for SyncCommandBufferBuilder {
}
}
impl fmt::Debug for SyncCommandBufferBuilder {
impl Debug for SyncCommandBufferBuilder {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.inner, f)
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
Debug::fmt(&self.inner, f)
}
}
@ -886,12 +883,12 @@ pub enum SyncCommandBufferBuilderError {
impl Error for SyncCommandBufferBuilderError {}
impl fmt::Display for SyncCommandBufferBuilderError {
impl Display for SyncCommandBufferBuilderError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
SyncCommandBufferBuilderError::Conflict { .. } => write!(fmt, "unsolvable conflict"),
SyncCommandBufferBuilderError::ExecError(err) => err.fmt(fmt),
SyncCommandBufferBuilderError::Conflict { .. } => write!(f, "unsolvable conflict"),
SyncCommandBufferBuilderError::ExecError(err) => Display::fmt(err, f),
}
}
}

View File

@ -84,7 +84,13 @@ use crate::{
},
DeviceSize,
};
use std::{borrow::Cow, collections::HashMap, ops::Range, sync::Arc};
use std::{
borrow::Cow,
collections::HashMap,
fmt::{Debug, Error as FmtError, Formatter},
ops::Range,
sync::Arc,
};
mod builder;
@ -513,8 +519,8 @@ pub(super) trait Command: Send + Sync {
unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder);
}
impl std::fmt::Debug for dyn Command {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl Debug for dyn Command {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
f.write_str(self.name())
}
}

View File

@ -26,7 +26,7 @@ use parking_lot::Mutex;
use std::{
borrow::Cow,
error::Error,
fmt,
fmt::{Display, Error as FmtError, Formatter},
ops::Range,
sync::{
atomic::{AtomicBool, Ordering},
@ -540,11 +540,11 @@ impl Error for CommandBufferExecError {
}
}
impl fmt::Display for CommandBufferExecError {
impl Display for CommandBufferExecError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
fmt,
f,
"{}",
match *self {
CommandBufferExecError::AccessError { .. } =>

View File

@ -13,15 +13,15 @@
use crate::{
device::{Device, DeviceOwned},
macros::{vulkan_enum, ExtensionNotEnabled},
macros::vulkan_enum,
sampler::Sampler,
shader::{DescriptorRequirements, ShaderStages},
OomError, Version, VulkanError, VulkanObject,
OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
};
use std::{
collections::{BTreeMap, HashMap},
error::Error,
fmt,
fmt::{Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},
mem::MaybeUninit,
ptr,
@ -115,9 +115,12 @@ impl DescriptorSetLayout {
if push_descriptor {
if !device.enabled_extensions().khr_push_descriptor {
return Err(DescriptorSetLayoutCreationError::ExtensionNotEnabled {
extension: "khr_push_descriptor",
reason: "description was set to be a push descriptor",
return Err(DescriptorSetLayoutCreationError::RequirementNotMet {
required_for: "`create_info.push_descriptor` is set",
requires_one_of: RequiresOneOf {
device_extensions: &["khr_push_descriptor"],
..Default::default()
},
});
}
}
@ -135,11 +138,11 @@ impl DescriptorSetLayout {
} = binding;
// VUID-VkDescriptorSetLayoutBinding-descriptorType-parameter
descriptor_type.validate(device)?;
descriptor_type.validate_device(device)?;
if descriptor_count != 0 {
// VUID-VkDescriptorSetLayoutBinding-descriptorCount-00283
stages.validate(device)?;
stages.validate_device(device)?;
*descriptor_counts.entry(descriptor_type).or_default() += descriptor_count;
}
@ -213,9 +216,12 @@ impl DescriptorSetLayout {
.enabled_features()
.descriptor_binding_variable_descriptor_count
{
return Err(DescriptorSetLayoutCreationError::FeatureNotEnabled {
feature: "descriptor_binding_variable_descriptor_count",
reason: "binding has a variable count",
return Err(DescriptorSetLayoutCreationError::RequirementNotMet {
required_for: "`create_info.bindings` has an element where `variable_descriptor_count` is set",
requires_one_of: RequiresOneOf {
features: &["descriptor_binding_variable_descriptor_count"],
..Default::default()
},
});
}
@ -465,13 +471,9 @@ pub enum DescriptorSetLayoutCreationError {
/// Out of Memory.
OomError(OomError),
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
},
FeatureNotEnabled {
feature: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// A binding includes immutable samplers but their number differs from `descriptor_count`.
@ -514,28 +516,30 @@ impl From<VulkanError> for DescriptorSetLayoutCreationError {
impl Error for DescriptorSetLayoutCreationError {}
impl std::fmt::Display for DescriptorSetLayoutCreationError {
impl Display for DescriptorSetLayoutCreationError {
#[inline]
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
Self::OomError(_) => {
write!(fmt, "out of memory")
write!(f, "out of memory")
}
Self::ExtensionNotEnabled { extension, reason } => write!(
fmt,
"the extension {} must be enabled: {}",
extension, reason
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::FeatureNotEnabled { feature, reason } => {
write!(fmt, "the feature {} must be enabled: {}", feature, reason)
}
Self::ImmutableSamplersCountMismatch { binding_num, sampler_count, descriptor_count } => write!(
fmt,
f,
"binding {} includes immutable samplers but their number ({}) differs from `descriptor_count` ({})",
binding_num, sampler_count, descriptor_count,
),
Self::ImmutableSamplersDescriptorTypeIncompatible { binding_num } => write!(
fmt,
f,
"binding {} includes immutable samplers but it has an incompatible `descriptor_type`",
binding_num,
),
@ -543,27 +547,27 @@ impl std::fmt::Display for DescriptorSetLayoutCreationError {
provided,
max_supported,
} => write!(
fmt,
f,
"more descriptors were provided in all bindings ({}) than the `max_push_descriptors` limit ({})",
provided, max_supported,
),
Self::PushDescriptorDescriptorTypeIncompatible { binding_num } => write!(
fmt,
f,
"`push_descriptor` is enabled, but binding {} has an incompatible `descriptor_type`",
binding_num,
),
Self::PushDescriptorVariableDescriptorCount { binding_num } => write!(
fmt,
f,
"`push_descriptor` is enabled, but binding {} has `variable_descriptor_count` enabled",
binding_num,
),
Self::VariableDescriptorCountBindingNotHighest { binding_num, highest_binding_num } => write!(
fmt,
f,
"binding {} has `variable_descriptor_count` enabled, but it is not the highest-numbered binding ({})",
binding_num, highest_binding_num,
),
Self::VariableDescriptorCountDescriptorTypeIncompatible { binding_num } => write!(
fmt,
f,
"binding {} has `variable_descriptor_count` enabled, but it has an incompatible `descriptor_type`",
binding_num,
),
@ -571,12 +575,12 @@ impl std::fmt::Display for DescriptorSetLayoutCreationError {
}
}
impl From<ExtensionNotEnabled> for DescriptorSetLayoutCreationError {
impl From<RequirementNotMet> for DescriptorSetLayoutCreationError {
#[inline]
fn from(err: ExtensionNotEnabled) -> Self {
Self::ExtensionNotEnabled {
extension: err.extension,
reason: err.reason,
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}
@ -792,22 +796,22 @@ pub enum DescriptorRequirementsNotMet {
impl Error for DescriptorRequirementsNotMet {}
impl fmt::Display for DescriptorRequirementsNotMet {
impl Display for DescriptorRequirementsNotMet {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::DescriptorType { required, obtained } => write!(
fmt,
f,
"the descriptor's type ({:?}) is not one of those required ({:?})",
obtained, required
),
Self::DescriptorCount { required, obtained } => write!(
fmt,
f,
"the descriptor count ({}) is less than what is required ({})",
obtained, required
),
Self::ShaderStages { .. } => write!(
fmt,
f,
"the descriptor's shader stages do not contain the stages that are required",
),
}
@ -863,22 +867,22 @@ vulkan_enum! {
// TODO: document
InlineUniformBlock = INLINE_UNIFORM_BLOCK {
api_version: V1_3,
extensions: [ext_inline_uniform_block],
device_extensions: [ext_inline_uniform_block],
},
// TODO: document
AccelerationStructure = ACCELERATION_STRUCTURE_KHR {
extensions: [khr_acceleration_structure],
device_extensions: [khr_acceleration_structure],
},
// TODO: document
AccelerationStructureNV = ACCELERATION_STRUCTURE_NV {
extensions: [nv_ray_tracing],
device_extensions: [nv_ray_tracing],
},
// TODO: document
Mutable = MUTABLE_VALVE {
extensions: [valve_mutable_descriptor_type],
device_extensions: [valve_mutable_descriptor_type],
},
*/
}

View File

@ -93,6 +93,7 @@ use smallvec::{smallvec, SmallVec};
use std::{
collections::HashMap,
error::Error,
fmt::{Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},
ptr,
sync::Arc,
@ -504,9 +505,9 @@ impl Error for DescriptorSetCreationError {
}
}
impl std::fmt::Display for DescriptorSetCreationError {
impl Display for DescriptorSetCreationError {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::DescriptorSetUpdateError(_) => {
write!(f, "an error occurred while updating the descriptor set")

View File

@ -19,7 +19,7 @@ use smallvec::SmallVec;
use std::{
collections::HashMap,
error::Error,
fmt,
fmt::{Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},
mem::MaybeUninit,
ptr,
@ -426,11 +426,11 @@ pub enum DescriptorPoolAllocError {
impl Error for DescriptorPoolAllocError {}
impl fmt::Display for DescriptorPoolAllocError {
impl Display for DescriptorPoolAllocError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
fmt,
f,
"{}",
match *self {
DescriptorPoolAllocError::OutOfHostMemory => "no memory available on the host",

View File

@ -18,7 +18,10 @@ use crate::{
VulkanObject,
};
use smallvec::SmallVec;
use std::{fmt, ptr};
use std::{
fmt::{Debug, Error as FmtError, Formatter},
ptr,
};
/// Low-level descriptor set.
///
@ -114,8 +117,8 @@ unsafe impl VulkanObject for UnsafeDescriptorSet {
}
}
impl fmt::Debug for UnsafeDescriptorSet {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "<Vulkan descriptor set {:?}>", self.handle)
impl Debug for UnsafeDescriptorSet {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(f, "<Vulkan descriptor set {:?}>", self.handle)
}
}

View File

@ -16,7 +16,12 @@ use crate::{
DeviceSize, VulkanObject,
};
use smallvec::SmallVec;
use std::{error::Error, ptr, sync::Arc};
use std::{
error::Error,
fmt::{Display, Error as FmtError, Formatter},
ptr,
sync::Arc,
};
/// Represents a single write operation to the binding of a descriptor set.
///
@ -943,56 +948,56 @@ impl Error for DescriptorSetUpdateError {
}
}
impl std::fmt::Display for DescriptorSetUpdateError {
impl Display for DescriptorSetUpdateError {
#[inline]
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::ArrayIndexOutOfBounds {
binding,
available_count,
written_count,
} => write!(
fmt,
f,
"tried to write up to element {} to binding {}, but only {} descriptors are available",
written_count, binding, available_count,
),
Self::ImageView2dFrom3d { binding, index } => write!(
fmt,
f,
"tried to write an image view to binding {} index {} with a 2D type and a 3D underlying image",
binding, index,
),
Self::ImageViewDepthAndStencil { binding, index } => write!(
fmt,
f,
"tried to write an image view to binding {} index {} that has both the `depth` and `stencil` aspects",
binding, index,
),
Self::ImageViewHasSamplerYcbcrConversion { binding, index } => write!(
fmt,
f,
"tried to write an image view to binding {} index {} with an attached sampler YCbCr conversion to binding that does not support it",
binding, index,
),
Self::ImageViewIsArrayed { binding, index } => write!(
fmt,
f,
"tried to write an image view of an arrayed type to binding {} index {}, but this binding has a descriptor type that does not support arrayed image views",
binding, index,
),
Self::ImageViewIncompatibleSampler { binding, index, .. } => write!(
fmt,
f,
"tried to write an image view to binding {} index {}, that was not compatible with the sampler that was provided as part of the update or immutably in the layout",
binding, index,
),
Self::ImageViewNotIdentitySwizzled { binding, index } => write!(
fmt,
f,
"tried to write an image view with non-identity swizzling to binding {} index {}, but this binding has a descriptor type that requires it to be identity swizzled",
binding, index,
),
Self::IncompatibleDescriptorType { binding } => write!(
fmt,
f,
"tried to write a resource to binding {} whose type was not compatible with the descriptor type",
binding,
),
Self::InvalidBinding { binding } => write!(
fmt,
f,
"tried to write to a nonexistent binding {}",
binding,
),
@ -1001,17 +1006,17 @@ impl std::fmt::Display for DescriptorSetUpdateError {
index,
usage,
} => write!(
fmt,
f,
"tried to write a resource to binding {} index {} that did not have the required usage {} enabled",
binding, index, usage,
),
Self::SamplerHasSamplerYcbcrConversion { binding, index } => write!(
fmt,
f,
"tried to write a sampler to binding {} index {} that has an attached sampler YCbCr conversion",
binding, index,
),
Self::SamplerIsImmutable { binding } => write!(
fmt,
f,
"tried to write a sampler to binding {}, which already contains immutable samplers in the descriptor set layout",
binding,
),

View File

@ -7,13 +7,7 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
pub use crate::extensions::{ExtensionRestriction, ExtensionRestrictionError, OneOfRequirements};
use crate::{instance::InstanceExtensions, Version};
use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Sub, SubAssign};
use std::{
ffi::{CStr, CString},
fmt::Formatter,
};
pub use crate::extensions::{ExtensionRestriction, ExtensionRestrictionError};
// Generated by build.rs
include!(concat!(env!("OUT_DIR"), "/device_extensions.rs"));

View File

@ -7,10 +7,10 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::{device::DeviceExtensions, instance::InstanceExtensions, Version};
use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Sub, SubAssign};
use std::fmt::Display;
use std::{error::Error, fmt, fmt::Formatter};
use std::{
error::Error,
fmt::{Display, Error as FmtError, Formatter},
};
// Generated by build.rs
include!(concat!(env!("OUT_DIR"), "/features.rs"));
@ -28,9 +28,9 @@ impl Error for FeatureRestrictionError {}
impl Display for FeatureRestrictionError {
#[inline]
fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
fmt,
f,
"a restriction for the feature {} was not met: {}",
self.feature, self.restriction,
)
@ -51,19 +51,19 @@ pub enum FeatureRestriction {
impl Display for FeatureRestriction {
#[inline]
fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
FeatureRestriction::NotSupported => {
write!(fmt, "not supported by the physical device")
write!(f, "not supported by the physical device")
}
FeatureRestriction::RequiresFeature(feat) => {
write!(fmt, "requires feature {} to be enabled", feat)
write!(f, "requires feature {} to be enabled", feat)
}
FeatureRestriction::ConflictsFeature(feat) => {
write!(fmt, "requires feature {} to be disabled", feat)
write!(f, "requires feature {} to be disabled", feat)
}
FeatureRestriction::RequiredByExtension(ext) => {
write!(fmt, "required to be enabled by extension {}", ext)
write!(f, "required to be enabled by extension {}", ext)
}
}
}

View File

@ -106,9 +106,9 @@ use crate::{
command_buffer::pool::StandardCommandPool,
descriptor_set::pool::StandardDescriptorPool,
instance::{debug::DebugUtilsLabel, Instance},
macros::ExtensionNotEnabled,
memory::{pool::StandardMemoryPool, ExternalMemoryHandleType},
OomError, SynchronizedVulkanObject, Version, VulkanError, VulkanObject,
OomError, RequirementNotMet, RequiresOneOf, SynchronizedVulkanObject, Version, VulkanError,
VulkanObject,
};
pub use crate::{
device::extensions::DeviceExtensions,
@ -124,7 +124,7 @@ use std::{
collections::{hash_map::Entry, HashMap},
error::Error,
ffi::CString,
fmt,
fmt::{Display, Error as FmtError, Formatter},
fs::File,
hash::{Hash, Hasher},
mem::MaybeUninit,
@ -633,7 +633,7 @@ impl Device {
use std::os::unix::io::IntoRawFd;
// VUID-vkGetMemoryFdPropertiesKHR-handleType-parameter
handle_type.validate(self)?;
handle_type.validate_device(self)?;
// VUID-vkGetMemoryFdPropertiesKHR-handleType-00674
if handle_type == ExternalMemoryHandleType::OpaqueFd {
@ -766,44 +766,44 @@ pub enum DeviceCreationError {
impl Error for DeviceCreationError {}
impl fmt::Display for DeviceCreationError {
impl Display for DeviceCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
Self::InitializationFailed => {
write!(
fmt,
f,
"failed to create the device for an implementation-specific reason"
)
}
Self::OutOfHostMemory => write!(fmt, "no memory available on the host"),
Self::OutOfHostMemory => write!(f, "no memory available on the host"),
Self::OutOfDeviceMemory => {
write!(fmt, "no memory available on the graphical device")
write!(f, "no memory available on the graphical device")
}
Self::DeviceLost => write!(fmt, "failed to connect to the device"),
Self::DeviceLost => write!(f, "failed to connect to the device"),
Self::TooManyQueuesForFamily => {
write!(fmt, "tried to create too many queues for a given family")
write!(f, "tried to create too many queues for a given family")
}
Self::FeatureNotPresent => {
write!(
fmt,
f,
"some of the requested features are unsupported by the physical device"
)
}
Self::PriorityOutOfRange => {
write!(
fmt,
f,
"the priority of one of the queues is out of the [0.0; 1.0] range"
)
}
Self::ExtensionNotPresent => {
write!(fmt,"some of the requested device extensions are not supported by the physical device")
write!(f,"some of the requested device extensions are not supported by the physical device")
}
Self::TooManyObjects => {
write!(fmt,"you have reached the limit to the number of devices that can be created from the same physical device")
write!(f,"you have reached the limit to the number of devices that can be created from the same physical device")
}
Self::ExtensionRestrictionNotMet(err) => err.fmt(fmt),
Self::FeatureRestrictionNotMet(err) => err.fmt(fmt),
Self::ExtensionRestrictionNotMet(err) => err.fmt(f),
Self::FeatureRestrictionNotMet(err) => err.fmt(f),
}
}
}
@ -938,9 +938,9 @@ pub enum MemoryFdPropertiesError {
/// No memory available on the host.
OutOfHostMemory,
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// The provided external handle was not valid.
@ -955,24 +955,29 @@ pub enum MemoryFdPropertiesError {
impl Error for MemoryFdPropertiesError {}
impl fmt::Display for MemoryFdPropertiesError {
impl Display for MemoryFdPropertiesError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
Self::OutOfHostMemory => write!(fmt, "no memory available on the host"),
Self::ExtensionNotEnabled { extension, reason } => write!(
fmt,
"the extension {} must be enabled: {}",
extension, reason
Self::OutOfHostMemory => write!(f, "no memory available on the host"),
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::InvalidExternalHandle => {
write!(fmt, "the provided external handle was not valid")
write!(f, "the provided external handle was not valid")
}
Self::InvalidExternalHandleType => {
write!(fmt, "the provided external handle type was not valid")
write!(f, "the provided external handle type was not valid")
}
Self::NotSupported => write!(
fmt,
f,
"the `khr_external_memory_fd` extension was not enabled on the device",
),
}
@ -990,12 +995,12 @@ impl From<VulkanError> for MemoryFdPropertiesError {
}
}
impl From<ExtensionNotEnabled> for MemoryFdPropertiesError {
impl From<RequirementNotMet> for MemoryFdPropertiesError {
#[inline]
fn from(err: ExtensionNotEnabled) -> Self {
Self::ExtensionNotEnabled {
extension: err.extension,
reason: err.reason,
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}
@ -1090,9 +1095,12 @@ impl Queue {
.enabled_extensions()
.ext_debug_utils
{
return Err(DebugUtilsError::ExtensionNotEnabled {
extension: "ext_debug_utils",
reason: "tried to submit a debug utils command",
return Err(DebugUtilsError::RequirementNotMet {
required_for: "`begin_debug_utils_label`",
requires_one_of: RequiresOneOf {
instance_extensions: &["ext_debug_utils"],
..Default::default()
},
});
}
@ -1128,9 +1136,12 @@ impl Queue {
.enabled_extensions()
.ext_debug_utils
{
return Err(DebugUtilsError::ExtensionNotEnabled {
extension: "ext_debug_utils",
reason: "tried to submit a debug utils command",
return Err(DebugUtilsError::RequirementNotMet {
required_for: "`end_debug_utils_label`",
requires_one_of: RequiresOneOf {
instance_extensions: &["ext_debug_utils"],
..Default::default()
},
});
}
@ -1183,9 +1194,12 @@ impl Queue {
.enabled_extensions()
.ext_debug_utils
{
return Err(DebugUtilsError::ExtensionNotEnabled {
extension: "ext_debug_utils",
reason: "tried to submit a debug utils command",
return Err(DebugUtilsError::RequirementNotMet {
required_for: "`insert_debug_utils_label`",
requires_one_of: RequiresOneOf {
instance_extensions: &["ext_debug_utils"],
..Default::default()
},
});
}
@ -1228,21 +1242,26 @@ impl Hash for Queue {
/// Error that can happen when submitting a debug utils command to a queue.
#[derive(Clone, Debug)]
pub enum DebugUtilsError {
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
}
impl Error for DebugUtilsError {}
impl fmt::Display for DebugUtilsError {
impl Display for DebugUtilsError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::ExtensionNotEnabled { extension, reason } => {
write!(f, "the extension {} must be enabled: {}", extension, reason)
}
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
}
}
}

View File

@ -19,9 +19,17 @@ use crate::{
SurfaceApi, SurfaceCapabilities, SurfaceInfo,
},
sync::{ExternalSemaphoreInfo, ExternalSemaphoreProperties, PipelineStage},
DeviceSize, OomError, Version, VulkanError, VulkanObject,
DeviceSize, OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
};
use std::{
error::Error,
ffi::CStr,
fmt::{Debug, Display, Error as FmtError, Formatter},
hash::Hash,
mem::MaybeUninit,
ptr,
sync::Arc,
};
use std::{error::Error, ffi::CStr, fmt, hash::Hash, mem::MaybeUninit, ptr, sync::Arc};
#[derive(Clone, Debug)]
pub(crate) struct PhysicalDeviceInfo {
@ -434,20 +442,27 @@ impl<'a> PhysicalDevice<'a> {
/// Retrieves the external memory properties supported for buffers with a given configuration.
///
/// Returns `None` if the instance API version is less than 1.1 and the
/// Instance API version must be at least 1.1, or the
/// [`khr_external_memory_capabilities`](crate::instance::InstanceExtensions::khr_external_memory_capabilities)
/// extension is not enabled on the instance.
/// extension must be enabled on the instance.
pub fn external_buffer_properties(
&self,
info: ExternalBufferInfo,
) -> Option<ExternalBufferProperties> {
) -> Result<ExternalBufferProperties, ExternalBufferPropertiesError> {
if !(self.instance.api_version() >= Version::V1_1
|| self
.instance
.enabled_extensions()
.khr_external_memory_capabilities)
{
return None;
return Err(ExternalBufferPropertiesError::RequirementNotMet {
required_for: "`external_buffer_properties`",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_1),
instance_extensions: &["khr_external_memory_capabilities"],
..Default::default()
},
});
}
/* Input */
@ -460,12 +475,12 @@ impl<'a> PhysicalDevice<'a> {
} = info;
// VUID-VkPhysicalDeviceExternalBufferInfo-usage-parameter
// TODO: usage.validate()?;
usage.validate_physical_device(self)?;
assert!(!usage.is_empty());
// VUID-VkPhysicalDeviceExternalBufferInfo-handleType-parameter
// TODO: handle_type.validate()?;
handle_type.validate_physical_device(self)?;
let external_buffer_info = ash::vk::PhysicalDeviceExternalBufferInfo {
flags: sparse.map(Into::into).unwrap_or_default(),
@ -499,7 +514,7 @@ impl<'a> PhysicalDevice<'a> {
}
}
Some(ExternalBufferProperties {
Ok(ExternalBufferProperties {
external_memory_properties: external_buffer_properties
.external_memory_properties
.into(),
@ -576,20 +591,27 @@ impl<'a> PhysicalDevice<'a> {
/// Retrieves the external handle properties supported for semaphores with a given
/// configuration.
///
/// Returns `None` if the instance API version is less than 1.1 and the
/// The instance API version must be at least 1.1, or the
/// [`khr_external_semaphore_capabilities`](crate::instance::InstanceExtensions::khr_external_semaphore_capabilities)
/// extension is not enabled on the instance.
/// extension must be enabled on the instance.
pub fn external_semaphore_properties(
&self,
info: ExternalSemaphoreInfo,
) -> Option<ExternalSemaphoreProperties> {
) -> Result<ExternalSemaphoreProperties, ExternalSemaphorePropertiesError> {
if !(self.instance.api_version() >= Version::V1_1
|| self
.instance
.enabled_extensions()
.khr_external_semaphore_capabilities)
{
return None;
return Err(ExternalSemaphorePropertiesError::RequirementNotMet {
required_for: "`external_semaphore_properties`",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_1),
instance_extensions: &["khr_external_semaphore_capabilities"],
..Default::default()
},
});
}
/* Input */
@ -600,7 +622,7 @@ impl<'a> PhysicalDevice<'a> {
} = info;
// VUID-VkPhysicalDeviceExternalSemaphoreInfo-handleType-parameter
// TODO: handle_type.validate()?;
handle_type.validate_physical_device(self)?;
let external_semaphore_info = ash::vk::PhysicalDeviceExternalSemaphoreInfo {
handle_type: handle_type.into(),
@ -632,7 +654,7 @@ impl<'a> PhysicalDevice<'a> {
}
}
Some(ExternalSemaphoreProperties {
Ok(ExternalSemaphoreProperties {
exportable: external_semaphore_properties
.external_semaphore_features
.intersects(ash::vk::ExternalSemaphoreFeatureFlags::EXPORTABLE),
@ -656,7 +678,7 @@ impl<'a> PhysicalDevice<'a> {
pub fn image_format_properties(
&self,
image_format_info: ImageFormatInfo,
) -> Result<Option<ImageFormatProperties>, OomError> {
) -> Result<Option<ImageFormatProperties>, ImageFormatPropertiesError> {
/* Input */
let ImageFormatInfo {
format,
@ -673,22 +695,16 @@ impl<'a> PhysicalDevice<'a> {
} = image_format_info;
// VUID-VkPhysicalDeviceImageFormatInfo2-format-parameter
// TODO: format.validate()?;
// TODO: format.validate_physical_device(self)?;
// VUID-VkPhysicalDeviceImageFormatInfo2-imageType-parameter
// TODO: image_type.validate()?;
image_type.validate_physical_device(self)?;
// VUID-VkPhysicalDeviceImageFormatInfo2-tiling-parameter
// TODO: tiling.validate()?;
tiling.validate_physical_device(self)?;
// VUID-VkPhysicalDeviceImageFormatInfo2-usage-parameter
// TODO: usage.validate()?;
// VUID-VkPhysicalDeviceExternalImageFormatInfo-handleType-parameter
// TODO: external_memory_handle_type.validate()?;
// VUID-VkPhysicalDeviceImageViewImageFormatInfoEXT-imageViewType-parameter
// TODO: image_view_type.validate()?;
usage.validate_physical_device(self)?;
let flags = ImageCreateFlags {
mutable_format,
@ -713,10 +729,19 @@ impl<'a> PhysicalDevice<'a> {
.enabled_extensions()
.khr_external_memory_capabilities)
{
// Can't query this, return unsupported
return Ok(None);
return Err(ImageFormatPropertiesError::RequirementNotMet {
required_for: "`image_format_info.external_memory_handle_type` is `Some`",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_1),
instance_extensions: &["khr_external_memory_capabilities"],
..Default::default()
},
});
}
// VUID-VkPhysicalDeviceExternalImageFormatInfo-handleType-parameter
handle_type.validate_physical_device(self)?;
Some(
ash::vk::PhysicalDeviceExternalImageFormatInfo::builder()
.handle_type(handle_type.into()),
@ -730,13 +755,19 @@ impl<'a> PhysicalDevice<'a> {
}
let mut image_view_image_format_info = if let Some(image_view_type) = image_view_type {
if !(self.supported_extensions().ext_filter_cubic
|| self.supported_extensions().img_filter_cubic)
{
// Can't query this, return unsupported
return Ok(None);
if !self.supported_extensions().ext_filter_cubic {
return Err(ImageFormatPropertiesError::RequirementNotMet {
required_for: "`image_format_info.image_view_type` is `Some`",
requires_one_of: RequiresOneOf {
device_extensions: &["ext_filter_cubic"],
..Default::default()
},
});
}
// VUID-VkPhysicalDeviceImageViewImageFormatInfoEXT-imageViewType-parameter
image_view_type.validate_physical_device(self)?;
if !image_view_type.is_compatible_with(image_type) {
return Ok(None);
}
@ -1680,15 +1711,15 @@ impl From<ash::vk::ConformanceVersion> for ConformanceVersion {
}
}
impl fmt::Debug for ConformanceVersion {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
impl Debug for ConformanceVersion {
fn fmt(&self, formatter: &mut Formatter) -> Result<(), FmtError> {
write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)
}
}
impl fmt::Display for ConformanceVersion {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, formatter)
impl Display for ConformanceVersion {
fn fmt(&self, formatter: &mut Formatter) -> Result<(), FmtError> {
Debug::fmt(self, formatter)
}
}
@ -1771,7 +1802,7 @@ vulkan_bitflags! {
// TODO: document
partitioned = PARTITIONED_NV {
extensions: [nv_shader_subgroup_partitioned],
device_extensions: [nv_shader_subgroup_partitioned],
},
}
@ -1814,9 +1845,143 @@ impl From<ash::vk::ShaderCorePropertiesFlagsAMD> for ShaderCoreProperties {
}
}
/// Error that can happen when retrieving properties of an external buffer.
#[derive(Clone, Debug)]
pub enum ExternalBufferPropertiesError {
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
}
impl Error for ExternalBufferPropertiesError {}
impl Display for ExternalBufferPropertiesError {
#[inline]
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
}
}
}
impl From<RequirementNotMet> for ExternalBufferPropertiesError {
#[inline]
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}
/// Error that can happen when retrieving properties of an external semaphore.
#[derive(Clone, Debug)]
pub enum ExternalSemaphorePropertiesError {
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
}
impl Error for ExternalSemaphorePropertiesError {}
impl Display for ExternalSemaphorePropertiesError {
#[inline]
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
}
}
}
impl From<RequirementNotMet> for ExternalSemaphorePropertiesError {
#[inline]
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}
/// Error that can happen when retrieving format properties of an image.
#[derive(Clone, Debug)]
pub enum ImageFormatPropertiesError {
/// Not enough memory.
OomError(OomError),
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
}
impl Error for ImageFormatPropertiesError {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::OomError(err) => Some(err),
_ => None,
}
}
}
impl Display for ImageFormatPropertiesError {
#[inline]
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::OomError(_) => write!(f, "not enough memory"),
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
}
}
}
impl From<VulkanError> for ImageFormatPropertiesError {
#[inline]
fn from(err: VulkanError) -> Self {
match err {
err @ VulkanError::OutOfHostMemory => Self::OomError(OomError::from(err)),
err @ VulkanError::OutOfDeviceMemory => Self::OomError(OomError::from(err)),
_ => panic!("unexpected error: {:?}", err),
}
}
}
impl From<RequirementNotMet> for ImageFormatPropertiesError {
#[inline]
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}
/// Error that can happen when retrieving properties of a surface.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum SurfacePropertiesError {
/// Not enough memory.
OomError(OomError),
@ -1838,11 +2003,11 @@ impl Error for SurfacePropertiesError {
}
}
impl fmt::Display for SurfacePropertiesError {
impl Display for SurfacePropertiesError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
fmt,
f,
"{}",
match *self {
Self::OomError(_) => "not enough memory",

View File

@ -7,7 +7,7 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::Version;
use crate::RequiresOneOf;
use std::{
error::Error,
fmt::{Display, Error as FmtError, Formatter},
@ -26,9 +26,9 @@ impl Error for ExtensionRestrictionError {}
impl Display for ExtensionRestrictionError {
#[inline]
fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
fmt,
f,
"a restriction for the extension {} was not met: {}",
self.extension, self.restriction,
)
@ -42,85 +42,31 @@ pub enum ExtensionRestriction {
/// Required to be enabled by the physical device.
RequiredIfSupported,
/// Requires one of the following.
Requires(OneOfRequirements),
Requires(RequiresOneOf),
/// Requires a device extension to be disabled.
ConflictsDeviceExtension(&'static str),
}
impl Display for ExtensionRestriction {
#[inline]
fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
ExtensionRestriction::NotSupported => {
write!(fmt, "not supported by the loader or physical device")
write!(f, "not supported by the loader or physical device")
}
ExtensionRestriction::RequiredIfSupported => {
write!(fmt, "required to be enabled by the physical device")
write!(f, "required to be enabled by the physical device")
}
ExtensionRestriction::Requires(requires) => {
if requires.has_multiple() {
write!(fmt, "requires one of: {}", requires)
if requires.len() > 1 {
write!(f, "requires one of: {}", requires)
} else {
write!(fmt, "requires: {}", requires)
write!(f, "requires: {}", requires)
}
}
ExtensionRestriction::ConflictsDeviceExtension(ext) => {
write!(fmt, "requires device extension {} to be disabled", ext)
write!(f, "requires device extension {} to be disabled", ext)
}
}
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct OneOfRequirements {
pub api_version: Option<Version>,
pub device_extensions: &'static [&'static str],
pub instance_extensions: &'static [&'static str],
}
impl OneOfRequirements {
/// Returns whether there is more than one possible requirement.
#[inline]
pub fn has_multiple(&self) -> bool {
self.api_version.iter().count()
+ self.device_extensions.len()
+ self.instance_extensions.len()
> 1
}
}
impl Display for OneOfRequirements {
#[inline]
fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
let mut items_written = 0;
if let Some(version) = self.api_version {
write!(
fmt,
"Vulkan API version {}.{}",
version.major, version.minor
)?;
items_written += 1;
}
for ext in self.instance_extensions.iter() {
if items_written != 0 {
write!(fmt, ", ")?;
}
write!(fmt, "instance extension {}", ext)?;
items_written += 1;
}
for ext in self.device_extensions.iter() {
if items_written != 0 {
write!(fmt, ", ")?;
}
write!(fmt, "device extension {}", ext)?;
items_written += 1;
}
Ok(())
}
}

View File

@ -760,14 +760,14 @@ vulkan_bitflags! {
/// image view.
storage_read_without_format = STORAGE_READ_WITHOUT_FORMAT {
api_version: V1_3,
extensions: [khr_format_feature_flags2],
device_extensions: [khr_format_feature_flags2],
},
/// Can be used with a storage image descriptor for writing, without specifying a format on the
/// image view.
storage_write_without_format = STORAGE_WRITE_WITHOUT_FORMAT {
api_version: V1_3,
extensions: [khr_format_feature_flags2],
device_extensions: [khr_format_feature_flags2],
},
/// Can be used with a color attachment in a framebuffer, or with an input attachment
@ -784,24 +784,24 @@ vulkan_bitflags! {
/// Can be used with a fragment density map attachment in a framebuffer.
fragment_density_map = FRAGMENT_DENSITY_MAP_EXT {
extensions: [ext_fragment_density_map],
device_extensions: [ext_fragment_density_map],
},
/// Can be used with a fragment shading rate attachment in a framebuffer.
fragment_shading_rate_attachment = FRAGMENT_SHADING_RATE_ATTACHMENT_KHR {
extensions: [khr_fragment_shading_rate],
device_extensions: [khr_fragment_shading_rate],
},
/// Can be used with the source image in a transfer (copy) operation.
transfer_src = TRANSFER_SRC {
api_version: V1_1,
extensions: [khr_maintenance1],
device_extensions: [khr_maintenance1],
},
/// Can be used with the destination image in a transfer (copy) operation.
transfer_dst = TRANSFER_DST {
api_version: V1_1,
extensions: [khr_maintenance1],
device_extensions: [khr_maintenance1],
},
/// Can be used with the source image in a blit operation.
@ -819,7 +819,7 @@ vulkan_bitflags! {
/// Can be used with samplers or as a blit source, using the
/// [`Cubic`](crate::sampler::Filter::Cubic) filter.
sampled_image_filter_cubic = SAMPLED_IMAGE_FILTER_CUBIC_EXT {
extensions: [ext_filter_cubic, img_filter_cubic],
device_extensions: [ext_filter_cubic, img_filter_cubic],
},
/// Can be used with samplers using a reduction mode of
@ -827,76 +827,76 @@ vulkan_bitflags! {
/// [`Max`](crate::sampler::SamplerReductionMode::Max).
sampled_image_filter_minmax = SAMPLED_IMAGE_FILTER_MINMAX {
api_version: V1_2,
extensions: [ext_sampler_filter_minmax],
device_extensions: [ext_sampler_filter_minmax],
},
/// Can be used with sampler YCbCr conversions using a chroma offset of
/// [`Midpoint`](crate::sampler::ycbcr::ChromaLocation::Midpoint).
midpoint_chroma_samples = MIDPOINT_CHROMA_SAMPLES {
api_version: V1_1,
extensions: [khr_sampler_ycbcr_conversion],
device_extensions: [khr_sampler_ycbcr_conversion],
},
/// Can be used with sampler YCbCr conversions using a chroma offset of
/// [`CositedEven`](crate::sampler::ycbcr::ChromaLocation::CositedEven).
cosited_chroma_samples = COSITED_CHROMA_SAMPLES {
api_version: V1_1,
extensions: [khr_sampler_ycbcr_conversion],
device_extensions: [khr_sampler_ycbcr_conversion],
},
/// Can be used with sampler YCbCr conversions using the
/// [`Linear`](crate::sampler::Filter::Linear) chroma filter.
sampled_image_ycbcr_conversion_linear_filter = SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER {
api_version: V1_1,
extensions: [khr_sampler_ycbcr_conversion],
device_extensions: [khr_sampler_ycbcr_conversion],
},
/// Can be used with sampler YCbCr conversions whose chroma filter differs from the filters of
/// the base sampler.
sampled_image_ycbcr_conversion_separate_reconstruction_filter = SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER {
api_version: V1_1,
extensions: [khr_sampler_ycbcr_conversion],
device_extensions: [khr_sampler_ycbcr_conversion],
},
/// When used with a sampler YCbCr conversion, the implementation will always perform
/// explicit chroma reconstruction.
sampled_image_ycbcr_conversion_chroma_reconstruction_explicit = SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT {
api_version: V1_1,
extensions: [khr_sampler_ycbcr_conversion],
device_extensions: [khr_sampler_ycbcr_conversion],
},
/// Can be used with sampler YCbCr conversions with forced explicit reconstruction.
sampled_image_ycbcr_conversion_chroma_reconstruction_explicit_forceable = SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE {
api_version: V1_1,
extensions: [khr_sampler_ycbcr_conversion],
device_extensions: [khr_sampler_ycbcr_conversion],
},
/// Can be used with samplers using depth comparison.
sampled_image_depth_comparison = SAMPLED_IMAGE_DEPTH_COMPARISON {
api_version: V1_3,
extensions: [khr_format_feature_flags2],
device_extensions: [khr_format_feature_flags2],
},
/* Video */
/// Can be used with the output image of a video decode operation.
video_decode_output = VIDEO_DECODE_OUTPUT_KHR {
extensions: [khr_video_decode_queue],
device_extensions: [khr_video_decode_queue],
},
/// Can be used with the DPB image of a video decode operation.
video_decode_dpb = VIDEO_DECODE_DPB_KHR {
extensions: [khr_video_decode_queue],
device_extensions: [khr_video_decode_queue],
},
/// Can be used with the input image of a video encode operation.
video_encode_input = VIDEO_ENCODE_INPUT_KHR {
extensions: [khr_video_encode_queue],
device_extensions: [khr_video_encode_queue],
},
/// Can be used with the DPB image of a video encode operation.
video_encode_dpb = VIDEO_ENCODE_DPB_KHR {
extensions: [khr_video_encode_queue],
device_extensions: [khr_video_encode_queue],
},
/* Misc image features */
@ -904,7 +904,7 @@ vulkan_bitflags! {
/// For multi-planar formats, can be used with images created with the `disjoint` flag.
disjoint = DISJOINT {
api_version: V1_1,
extensions: [khr_sampler_ycbcr_conversion],
device_extensions: [khr_sampler_ycbcr_conversion],
},
/* Buffer usage */
@ -924,7 +924,7 @@ vulkan_bitflags! {
/// Can be used with the vertex buffer of an acceleration structure.
acceleration_structure_vertex_buffer = ACCELERATION_STRUCTURE_VERTEX_BUFFER_KHR {
extensions: [khr_acceleration_structure],
device_extensions: [khr_acceleration_structure],
},
}

View File

@ -31,34 +31,34 @@ vulkan_enum! {
// TODO: document
Plane0 = PLANE_0 {
api_version: V1_1,
extensions: [khr_sampler_ycbcr_conversion],
device_extensions: [khr_sampler_ycbcr_conversion],
},
// TODO: document
Plane1 = PLANE_1 {
api_version: V1_1,
extensions: [khr_sampler_ycbcr_conversion],
device_extensions: [khr_sampler_ycbcr_conversion],
},
// TODO: document
Plane2 = PLANE_2 {
api_version: V1_1,
extensions: [khr_sampler_ycbcr_conversion],
device_extensions: [khr_sampler_ycbcr_conversion],
},
// TODO: document
MemoryPlane0 = MEMORY_PLANE_0_EXT {
extensions: [ext_image_drm_format_modifier],
device_extensions: [ext_image_drm_format_modifier],
},
// TODO: document
MemoryPlane1 = MEMORY_PLANE_1_EXT {
extensions: [ext_image_drm_format_modifier],
device_extensions: [ext_image_drm_format_modifier],
},
// TODO: document
MemoryPlane2 = MEMORY_PLANE_2_EXT {
extensions: [ext_image_drm_format_modifier],
device_extensions: [ext_image_drm_format_modifier],
},
}
@ -82,34 +82,34 @@ vulkan_bitflags! {
// TODO: document
plane0 = PLANE_0 {
api_version: V1_1,
extensions: [khr_sampler_ycbcr_conversion],
device_extensions: [khr_sampler_ycbcr_conversion],
},
// TODO: document
plane1 = PLANE_1 {
api_version: V1_1,
extensions: [khr_sampler_ycbcr_conversion],
device_extensions: [khr_sampler_ycbcr_conversion],
},
// TODO: document
plane2 = PLANE_2 {
api_version: V1_1,
extensions: [khr_sampler_ycbcr_conversion],
device_extensions: [khr_sampler_ycbcr_conversion],
},
// TODO: document
memory_plane0 = MEMORY_PLANE_0_EXT {
extensions: [ext_image_drm_format_modifier],
device_extensions: [ext_image_drm_format_modifier],
},
// TODO: document
memory_plane1 = MEMORY_PLANE_1_EXT {
extensions: [ext_image_drm_format_modifier],
device_extensions: [ext_image_drm_format_modifier],
},
// TODO: document
memory_plane2 = MEMORY_PLANE_2_EXT {
extensions: [ext_image_drm_format_modifier],
device_extensions: [ext_image_drm_format_modifier],
},
}

View File

@ -36,7 +36,7 @@ use crate::{
use smallvec::SmallVec;
use std::{
error::Error,
fmt,
fmt::{Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},
sync::Arc,
};
@ -485,9 +485,9 @@ impl Error for ImmutableImageCreationError {
}
}
impl fmt::Display for ImmutableImageCreationError {
impl Display for ImmutableImageCreationError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::ImageCreationError(err) => err.fmt(f),
Self::DeviceMemoryAllocationError(err) => err.fmt(f),

View File

@ -77,49 +77,49 @@ vulkan_enum! {
// TODO: document
DepthReadOnlyStencilAttachmentOptimal = DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL {
api_version: V1_1,
extensions: [khr_maintenance2],
device_extensions: [khr_maintenance2],
},
// TODO: document
DepthAttachmentStencilReadOnlyOptimal = DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL {
api_version: V1_1,
extensions: [khr_maintenance2],
device_extensions: [khr_maintenance2],
},
// TODO: document
DepthAttachmentOptimal = DEPTH_ATTACHMENT_OPTIMAL {
api_version: V1_2,
extensions: [khr_separate_depth_stencil_layouts],
device_extensions: [khr_separate_depth_stencil_layouts],
},
// TODO: document
DepthReadOnlyOptimal = DEPTH_READ_ONLY_OPTIMAL {
api_version: V1_2,
extensions: [khr_separate_depth_stencil_layouts],
device_extensions: [khr_separate_depth_stencil_layouts],
},
// TODO: document
StencilAttachmentOptimal = STENCIL_ATTACHMENT_OPTIMAL {
api_version: V1_2,
extensions: [khr_separate_depth_stencil_layouts],
device_extensions: [khr_separate_depth_stencil_layouts],
},
// TODO: document
StencilReadOnlyOptimal = STENCIL_READ_ONLY_OPTIMAL {
api_version: V1_2,
extensions: [khr_separate_depth_stencil_layouts],
device_extensions: [khr_separate_depth_stencil_layouts],
},
// TODO: document
ReadOnlyOptimal = READ_ONLY_OPTIMAL {
api_version: V1_3,
extensions: [khr_synchronization2],
device_extensions: [khr_synchronization2],
},
// TODO: document
AttachmentOptimal = ATTACHMENT_OPTIMAL {
api_version: V1_3,
extensions: [khr_synchronization2],
device_extensions: [khr_synchronization2],
},
*/
@ -127,53 +127,53 @@ vulkan_enum! {
/// acquired from the swapchain, and must be transitioned back into this layout before
/// presenting them.
PresentSrc = PRESENT_SRC_KHR {
extensions: [khr_swapchain],
device_extensions: [khr_swapchain],
},
/*
// TODO: document
VideoDecodeDst = VIDEO_DECODE_DST_KHR {
extensions: [khr_video_decode_queue],
device_extensions: [khr_video_decode_queue],
},
// TODO: document
VideoDecodeSrc = VIDEO_DECODE_SRC_KHR {
extensions: [khr_video_decode_queue],
device_extensions: [khr_video_decode_queue],
},
// TODO: document
VideoDecodeDpb = VIDEO_DECODE_DPB_KHR {
extensions: [khr_video_decode_queue],
device_extensions: [khr_video_decode_queue],
},
// TODO: document
SharedPresent = SHARED_PRESENT_KHR {
extensions: [khr_shared_presentable_image],
device_extensions: [khr_shared_presentable_image],
},
// TODO: document
FragmentDensityMapOptimal = FRAGMENT_DENSITY_MAP_OPTIMAL_EXT {
extensions: [ext_fragment_density_map],
device_extensions: [ext_fragment_density_map],
},
// TODO: document
FragmentShadingRateAttachmentOptimal = FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR {
extensions: [khr_fragment_shading_rate],
device_extensions: [khr_fragment_shading_rate],
},
// TODO: document
VideoEncodeDst = VIDEO_ENCODE_DST_KHR {
extensions: [khr_video_encode_queue],
device_extensions: [khr_video_encode_queue],
},
// TODO: document
VideoEncodeSrc = VIDEO_ENCODE_SRC_KHR {
extensions: [khr_video_encode_queue],
device_extensions: [khr_video_encode_queue],
},
// TODO: document
VideoEncodeDpb = VIDEO_ENCODE_DPB_KHR {
extensions: [khr_video_encode_queue],
device_extensions: [khr_video_encode_queue],
},
*/
}

View File

@ -246,7 +246,7 @@ vulkan_bitflags! {
/// For 3D images, allows creation of an image view of type `Dim2d` or `Dim2dArray`.
array_2d_compatible = TYPE_2D_ARRAY_COMPATIBLE {
api_version: V1_1,
extensions: [khr_maintenance1],
device_extensions: [khr_maintenance1],
},
/// For images with a compressed format, allows creation of an image view with an uncompressed
@ -256,7 +256,7 @@ vulkan_bitflags! {
/// Requires `mutable_format`.
block_texel_view_compatible = BLOCK_TEXEL_VIEW_COMPATIBLE {
api_version: V1_1,
extensions: [khr_maintenance1],
device_extensions: [khr_maintenance1],
},
}
@ -289,7 +289,7 @@ vulkan_enum! {
/*
// TODO: document
DrmFormatModifier = DRM_FORMAT_MODIFIER_EXT {
extensions: [ext_image_drm_format_modifier],
device_extensions: [ext_image_drm_format_modifier],
},
*/
}

View File

@ -20,24 +20,23 @@ use super::{
};
use crate::{
buffer::cpu_access::{ReadLockError, WriteLockError},
device::{Device, DeviceOwned},
device::{physical::ImageFormatPropertiesError, Device, DeviceOwned},
format::{ChromaSampling, Format, FormatFeatures, NumericType},
image::{view::ImageViewCreationError, ImageFormatInfo, ImageFormatProperties, ImageType},
macros::ExtensionNotEnabled,
memory::{
DeviceMemory, DeviceMemoryAllocationError, ExternalMemoryHandleType,
ExternalMemoryHandleTypes, MemoryRequirements,
},
range_map::RangeMap,
sync::{AccessError, CurrentAccess, Sharing},
DeviceSize, OomError, Version, VulkanError, VulkanObject,
DeviceSize, OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
};
use ash::vk::Handle;
use parking_lot::{Mutex, MutexGuard};
use smallvec::{smallvec, SmallVec};
use std::{
error::Error,
fmt,
fmt::{Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},
iter::{FusedIterator, Peekable},
mem::MaybeUninit,
@ -204,22 +203,22 @@ impl UnsafeImage {
let format = format.unwrap(); // Can be None for "external formats" but Vulkano doesn't support that yet
// VUID-VkImageCreateInfo-format-parameter
// TODO: format.validate(device)?;
// TODO: format.validate_device(device)?;
// VUID-VkImageCreateInfo-samples-parameter
samples.validate(device)?;
samples.validate_device(device)?;
// VUID-VkImageCreateInfo-tiling-parameter
tiling.validate(device)?;
tiling.validate_device(device)?;
// VUID-VkImageCreateInfo-usage-parameter
usage.validate(device)?;
usage.validate_device(device)?;
// VUID-VkImageCreateInfo-usage-requiredbitmask
assert!(!usage.is_empty());
// VUID-VkImageCreateInfo-initialLayout-parameter
initial_layout.validate(device)?;
initial_layout.validate_device(device)?;
if usage.transient_attachment {
// VUID-VkImageCreateInfo-usage-00966
@ -345,9 +344,12 @@ impl UnsafeImage {
// VUID-VkImageCreateInfo-format-06413
if array_layers > 1 && !device.enabled_features().ycbcr_image_arrays {
return Err(ImageCreationError::FeatureNotEnabled {
feature: "ycbcr_image_arrays",
reason: "format was an YCbCr format and array_layers was greater than 1",
return Err(ImageCreationError::RequirementNotMet {
required_for: "`create_info.format.ycbcr_chroma_sampling()` is `Some` and `create_info.dimensions.array_layers()` is greater than `1`",
requires_one_of: RequiresOneOf {
features: &["ycbcr_image_arrays"],
..Default::default()
},
});
}
@ -422,9 +424,12 @@ impl UnsafeImage {
if samples != SampleCount::Sample1
&& !device.enabled_features().shader_storage_image_multisample
{
return Err(ImageCreationError::FeatureNotEnabled {
feature: "shader_storage_image_multisample",
reason: "usage included `storage` and samples was not `Sample1`",
return Err(ImageCreationError::RequirementNotMet {
required_for: "`create_info.usage.storage` is set and `create_info.samples` is not `SampleCount::Sample1`",
requires_one_of: RequiresOneOf {
features: &["shader_storage_image_multisample"],
..Default::default()
},
});
}
}
@ -501,14 +506,18 @@ impl UnsafeImage {
if !(device.api_version() >= Version::V1_1
|| device.enabled_extensions().khr_external_memory)
{
return Err(ImageCreationError::ExtensionNotEnabled {
extension: "khr_external_memory",
reason: "one or more fields of external_memory_handle_types were set",
return Err(ImageCreationError::RequirementNotMet {
required_for: "`create_info.external_memory_handle_types` is not empty",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_1),
device_extensions: &["khr_external_memory"],
..Default::default()
},
});
}
// VUID-VkExternalMemoryImageCreateInfo-handleTypes-parameter
external_memory_handle_types.validate(device)?;
external_memory_handle_types.validate_device(device)?;
// VUID-VkImageCreateInfo-pNext-01443
if initial_layout != ImageLayout::Undefined {
@ -1533,13 +1542,9 @@ pub enum ImageCreationError {
/// Allocating memory failed.
AllocError(DeviceMemoryAllocationError),
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
},
FeatureNotEnabled {
feature: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// The array_2d_compatible flag was enabled, but the image type was not 3D.
@ -1653,129 +1658,125 @@ impl Error for ImageCreationError {
}
}
impl fmt::Display for ImageCreationError {
impl Display for ImageCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
Self::AllocError(_) => write!(fmt, "allocating memory failed"),
Self::ExtensionNotEnabled { extension, reason } => write!(
fmt,
"the extension {} must be enabled: {}",
extension, reason
Self::AllocError(_) => write!(f, "allocating memory failed"),
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::FeatureNotEnabled { feature, reason } => {
write!(fmt, "the feature {} must be enabled: {}", feature, reason)
}
Self::Array2dCompatibleNot3d => {
write!(
fmt,
f,
"the array_2d_compatible flag was enabled, but the image type was not 3D"
)
}
Self::BlockTexelViewCompatibleNotCompressed => {
write!(fmt, "the block_texel_view_compatible flag was enabled, but the given format was not compressed")
write!(f, "the block_texel_view_compatible flag was enabled, but the given format was not compressed")
}
Self::CubeCompatibleNot2d => {
write!(
fmt,
f,
"the cube_compatible flag was enabled, but the image type was not 2D"
)
}
Self::CubeCompatibleNotEnoughArrayLayers => {
write!(fmt, "the cube_compatible flag was enabled, but the number of array layers was less than 6")
write!(f, "the cube_compatible flag was enabled, but the number of array layers was less than 6")
}
Self::CubeCompatibleNotSquare => {
write!(fmt, "the cube_compatible flag was enabled, but the image dimensions were not square")
write!(f, "the cube_compatible flag was enabled, but the image dimensions were not square")
}
Self::CubeCompatibleMultisampling => {
write!(
fmt,
f,
"the cube_compatible flag was enabled together with multisampling"
)
}
Self::ExternalMemoryInvalidInitialLayout => {
write!(fmt, "one or more external memory handle types were provided, but the initial layout was not `Undefined`")
write!(f, "one or more external memory handle types were provided, but the initial layout was not `Undefined`")
}
Self::FormatNotSupported => {
write!(fmt, "the given format was not supported by the device")
write!(f, "the given format was not supported by the device")
}
Self::FormatUsageNotSupported { .. } => {
write!(
fmt,
f,
"a requested usage flag was not supported by the given format"
)
}
Self::ImageFormatPropertiesNotSupported => {
write!(fmt, "the image configuration as queried through the `image_format_properties` function was not supported by the device")
write!(f, "the image configuration as queried through the `image_format_properties` function was not supported by the device")
}
Self::MaxArrayLayersExceeded { .. } => {
write!(fmt, "the number of array layers exceeds the maximum supported by the device for this image configuration")
write!(f, "the number of array layers exceeds the maximum supported by the device for this image configuration")
}
Self::MaxDimensionsExceeded { .. } => {
write!(fmt, "the specified dimensions exceed the maximum supported by the device for this image configuration")
write!(f, "the specified dimensions exceed the maximum supported by the device for this image configuration")
}
Self::MaxFramebufferDimensionsExceeded { .. } => {
write!(fmt, "the usage included one of the attachment types, and the specified width and height exceeded the `max_framebuffer_width` or `max_framebuffer_height` limits")
write!(f, "the usage included one of the attachment types, and the specified width and height exceeded the `max_framebuffer_width` or `max_framebuffer_height` limits")
}
Self::MaxMipLevelsExceeded { .. } => {
write!(
fmt,
f,
"the maximum number of mip levels for the given dimensions has been exceeded"
)
}
Self::MultisampleCubeCompatible => {
write!(
fmt,
f,
"multisampling was enabled, and the `cube_compatible` flag was set"
)
}
Self::MultisampleLinearTiling => {
write!(fmt, "multisampling was enabled, and tiling was `Linear`")
write!(f, "multisampling was enabled, and tiling was `Linear`")
}
Self::MultisampleMultipleMipLevels => {
write!(
fmt,
f,
"multisampling was enabled, and multiple mip levels were specified"
)
}
Self::MultisampleNot2d => {
write!(
fmt,
f,
"multisampling was enabled, but the image type was not 2D"
)
}
Self::SampleCountNotSupported { .. } => {
write!(
fmt,
f,
"the sample count is not supported by the device for this image configuration"
)
}
Self::SharingInvalidQueueFamilyId { .. } => {
write!(fmt, "the sharing mode was set to `Concurrent`, but one of the specified queue family ids was not valid")
write!(f, "the sharing mode was set to `Concurrent`, but one of the specified queue family ids was not valid")
}
Self::YcbcrFormatInvalidDimensions => {
write!(fmt, "a YCbCr format was given, but the specified width and/or height was not a multiple of 2 as required by the format's chroma subsampling")
write!(f, "a YCbCr format was given, but the specified width and/or height was not a multiple of 2 as required by the format's chroma subsampling")
}
Self::YcbcrFormatMultipleMipLevels => {
write!(
fmt,
f,
"a YCbCr format was given, and multiple mip levels were specified"
)
}
Self::YcbcrFormatMultisampling => {
write!(
fmt,
"a YCbCr format was given, and multisampling was enabled"
)
write!(f, "a YCbCr format was given, and multisampling was enabled")
}
Self::YcbcrFormatNot2d => {
write!(
fmt,
"a YCbCr format was given, but the image type was not 2D"
)
write!(f, "a YCbCr format was given, but the image type was not 2D")
}
Self::DirectImageViewCreationFailed(e) => {
write!(fmt, "Image view creation failed {}", e)
write!(f, "Image view creation failed {}", e)
}
}
}
@ -1806,12 +1807,30 @@ impl From<VulkanError> for ImageCreationError {
}
}
impl From<ExtensionNotEnabled> for ImageCreationError {
impl From<RequirementNotMet> for ImageCreationError {
#[inline]
fn from(err: ExtensionNotEnabled) -> Self {
Self::ExtensionNotEnabled {
extension: err.extension,
reason: err.reason,
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}
impl From<ImageFormatPropertiesError> for ImageCreationError {
#[inline]
fn from(err: ImageFormatPropertiesError) -> Self {
match err {
ImageFormatPropertiesError::OomError(err) => {
Self::AllocError(DeviceMemoryAllocationError::OomError(err))
}
ImageFormatPropertiesError::RequirementNotMet {
required_for,
requires_one_of,
} => Self::RequirementNotMet {
required_for,
requires_one_of,
},
}
}
}
@ -2226,7 +2245,7 @@ mod tests {
sys::SubresourceRangeIterator, ImageAspect, ImageAspects, ImageDimensions,
ImageSubresourceRange, SampleCount,
},
DeviceSize,
DeviceSize, RequiresOneOf,
};
use smallvec::SmallVec;
@ -2353,10 +2372,10 @@ mod tests {
);
match res {
Err(ImageCreationError::FeatureNotEnabled {
feature: "shader_storage_image_multisample",
Err(ImageCreationError::RequirementNotMet {
requires_one_of: RequiresOneOf { features, .. },
..
}) => (),
}) if features.contains(&"shader_storage_image_multisample") => (),
Err(ImageCreationError::SampleCountNotSupported { .. }) => (), // unlikely but possible
_ => panic!(),
};

View File

@ -17,7 +17,7 @@ use crate::{
SafeDeref,
};
use std::{
fmt,
fmt::{Debug, Error as FmtError, Formatter},
hash::{Hash, Hasher},
sync::Arc,
};
@ -223,8 +223,8 @@ pub struct ImageInner<'a> {
pub num_mipmap_levels: u32,
}
impl fmt::Debug for dyn ImageAccess {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
impl Debug for dyn ImageAccess {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
f.debug_struct("dyn ImageAccess")
.field("inner", &self.inner())
.finish()

View File

@ -51,47 +51,47 @@ vulkan_bitflags! {
/*
// TODO: document
video_decode_dst = VIDEO_DECODE_DST_KHR {
extensions: [khr_video_decode_queue],
device_extensions: [khr_video_decode_queue],
},
// TODO: document
video_decode_src = VIDEO_DECODE_SRC_KHR {
extensions: [khr_video_decode_queue],
device_extensions: [khr_video_decode_queue],
},
// TODO: document
video_decode_dpb = VIDEO_DECODE_DPB_KHR {
extensions: [khr_video_decode_queue],
device_extensions: [khr_video_decode_queue],
},
// TODO: document
fragment_density_map = FRAGMENT_DENSITY_MAP_EXT {
extensions: [ext_fragment_density_map],
device_extensions: [ext_fragment_density_map],
},
// TODO: document
fragment_shading_rate_attachment = FRAGMENT_SHADING_RATE_ATTACHMENT_KHR {
extensions: [khr_fragment_shading_rate],
device_extensions: [khr_fragment_shading_rate],
},
// TODO: document
video_encode_dst = VIDEO_ENCODE_DST_KHR {
extensions: [khr_video_encode_queue],
device_extensions: [khr_video_encode_queue],
},
// TODO: document
video_encode_src = VIDEO_ENCODE_SRC_KHR {
extensions: [khr_video_encode_queue],
device_extensions: [khr_video_encode_queue],
},
// TODO: document
video_encode_dpb = VIDEO_ENCODE_DPB_KHR {
extensions: [khr_video_encode_queue],
device_extensions: [khr_video_encode_queue],
},
// TODO: document
invocation_mask = INVOCATION_MASK_HUAWEI {
extensions: [huawei_invocation_mask],
device_extensions: [huawei_invocation_mask],
},
*/
}

View File

@ -15,16 +15,16 @@
use super::{ImageAccess, ImageDimensions, ImageFormatInfo, ImageSubresourceRange, ImageUsage};
use crate::{
device::{Device, DeviceOwned},
device::{physical::ImageFormatPropertiesError, Device, DeviceOwned},
format::{ChromaSampling, Format, FormatFeatures},
image::{ImageAspects, ImageTiling, ImageType, SampleCount},
macros::{vulkan_enum, ExtensionNotEnabled},
macros::vulkan_enum,
sampler::{ycbcr::SamplerYcbcrConversion, ComponentMapping},
OomError, VulkanError, VulkanObject,
OomError, RequirementNotMet, RequiresOneOf, VulkanError, VulkanObject,
};
use std::{
error::Error,
fmt,
fmt::{Debug, Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},
mem::MaybeUninit,
ptr,
@ -85,7 +85,14 @@ where
let image_inner = image.inner().image;
let image_type = image.dimensions().image_type();
let (filter_cubic, filter_cubic_minmax) = if let Some(properties) = image_inner
let (filter_cubic, filter_cubic_minmax) = image
.device()
.physical_device()
.supported_extensions()
.ext_filter_cubic
.then_some(())
.and_then(|_| {
image_inner
.device()
.physical_device()
.image_format_properties(ImageFormatInfo {
@ -99,11 +106,12 @@ where
array_2d_compatible: image_inner.array_2d_compatible(),
block_texel_view_compatible: image_inner.block_texel_view_compatible(),
..Default::default()
})? {
})
.unwrap()
})
.map_or((false, false), |properties| {
(properties.filter_cubic, properties.filter_cubic_minmax)
} else {
(false, false)
};
});
Ok(Arc::new(ImageView {
handle,
@ -144,25 +152,25 @@ where
assert!(layer_count != 0);
// VUID-VkImageViewCreateInfo-viewType-parameter
view_type.validate(image.device())?;
view_type.validate_device(image.device())?;
// VUID-VkImageViewCreateInfo-format-parameter
// TODO: format.validate(image.device())?;
// TODO: format.validate_device(image.device())?;
// VUID-VkComponentMapping-r-parameter
component_mapping.r.validate(image.device())?;
component_mapping.r.validate_device(image.device())?;
// VUID-VkComponentMapping-g-parameter
component_mapping.g.validate(image.device())?;
component_mapping.g.validate_device(image.device())?;
// VUID-VkComponentMapping-b-parameter
component_mapping.b.validate(image.device())?;
component_mapping.b.validate_device(image.device())?;
// VUID-VkComponentMapping-a-parameter
component_mapping.a.validate(image.device())?;
component_mapping.a.validate_device(image.device())?;
// VUID-VkImageSubresourceRange-aspectMask-parameter
subresource_range.aspects.validate(image.device())?;
subresource_range.aspects.validate_device(image.device())?;
{
let ImageAspects {
@ -277,9 +285,12 @@ where
if view_type == ImageViewType::CubeArray
&& !image_inner.device().enabled_features().image_cube_array
{
return Err(ImageViewCreationError::FeatureNotEnabled {
feature: "image_cube_array",
reason: "the `CubeArray` view type was requested",
return Err(ImageViewCreationError::RequirementNotMet {
required_for: "`create_info.viewtype` is `ImageViewType::CubeArray`",
requires_one_of: RequiresOneOf {
features: &["image_cube_array"],
..Default::default()
},
});
}
@ -730,13 +741,9 @@ pub enum ImageViewCreationError {
/// Allocating memory failed.
OomError(OomError),
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
},
FeatureNotEnabled {
feature: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// A 2D image view was requested from a 3D image, but a range of multiple mip levels was
@ -833,22 +840,24 @@ impl Error for ImageViewCreationError {
}
}
impl fmt::Display for ImageViewCreationError {
impl Display for ImageViewCreationError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
Self::OomError(_) => write!(
f,
"allocating memory failed",
),
Self::ExtensionNotEnabled { extension, reason } => write!(
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"the extension {} must be enabled: {}",
extension, reason
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::FeatureNotEnabled { feature, reason } => {
write!(f, "the feature {} must be enabled: {}", feature, reason)
}
Self::Array2dCompatibleMultipleMipLevels => write!(
f,
"a 2D image view was requested from a 3D image, but a range of multiple mip levels was specified",
@ -959,12 +968,28 @@ impl From<VulkanError> for ImageViewCreationError {
}
}
impl From<ExtensionNotEnabled> for ImageViewCreationError {
impl From<RequirementNotMet> for ImageViewCreationError {
#[inline]
fn from(err: ExtensionNotEnabled) -> Self {
Self::ExtensionNotEnabled {
extension: err.extension,
reason: err.reason,
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}
impl From<ImageFormatPropertiesError> for ImageViewCreationError {
#[inline]
fn from(err: ImageFormatPropertiesError) -> Self {
match err {
ImageFormatPropertiesError::OomError(err) => Self::OomError(err),
ImageFormatPropertiesError::RequirementNotMet {
required_for,
requires_one_of,
} => Self::RequirementNotMet {
required_for,
requires_one_of,
},
}
}
}
@ -1027,7 +1052,7 @@ impl ImageViewType {
/// Trait for types that represent the GPU can access an image view.
pub unsafe trait ImageViewAbstract:
VulkanObject<Object = ash::vk::ImageView> + DeviceOwned + fmt::Debug + Send + Sync
VulkanObject<Object = ash::vk::ImageView> + DeviceOwned + Debug + Send + Sync
{
/// Returns the wrapped image that this image view was created from.
fn image(&self) -> Arc<dyn ImageAccess>;
@ -1094,7 +1119,7 @@ pub unsafe trait ImageViewAbstract:
unsafe impl<I> ImageViewAbstract for ImageView<I>
where
I: ImageAccess + fmt::Debug + 'static,
I: ImageAccess + Debug + 'static,
{
#[inline]
fn image(&self) -> Arc<dyn ImageAccess> {

View File

@ -43,11 +43,11 @@
//!
use super::Instance;
use crate::{macros::vulkan_bitflags, VulkanError, VulkanObject};
use crate::{macros::vulkan_bitflags, RequirementNotMet, RequiresOneOf, VulkanError, VulkanObject};
use std::{
error::Error,
ffi::{c_void, CStr},
fmt,
fmt::{Debug, Display, Error as FmtError, Formatter},
mem::MaybeUninit,
panic::{catch_unwind, AssertUnwindSafe, RefUnwindSafe},
ptr,
@ -102,20 +102,23 @@ impl DebugUtilsMessenger {
} = create_info;
if !instance.enabled_extensions().ext_debug_utils {
return Err(DebugUtilsMessengerCreationError::ExtensionNotEnabled {
extension: "ext_debug_utils",
reason: "tried to create a DebugUtilsMessenger",
return Err(DebugUtilsMessengerCreationError::RequirementNotMet {
required_for: "`DebugUtilsMessenger`",
requires_one_of: RequiresOneOf {
instance_extensions: &["ext_debug_utils"],
..Default::default()
},
});
}
// VUID-VkDebugUtilsMessengerCreateInfoEXT-messageSeverity-parameter
// TODO: message_severity.validate()?;
message_severity.validate_instance(instance)?;
// VUID-VkDebugUtilsMessengerCreateInfoEXT-messageSeverity-requiredbitmask
assert!(!message_severity.is_empty());
// VUID-VkDebugUtilsMessengerCreateInfoEXT-messageType-parameter
// TODO: message_type.validate()?;
message_type.validate_instance(instance)?;
// VUID-VkDebugUtilsMessengerCreateInfoEXT-messageType-requiredbitmask
assert!(!message_type.is_empty());
@ -186,8 +189,8 @@ impl Drop for DebugUtilsMessenger {
}
}
impl fmt::Debug for DebugUtilsMessenger {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
impl Debug for DebugUtilsMessenger {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
let Self {
handle,
instance,
@ -242,21 +245,26 @@ pub(super) unsafe extern "system" fn trampoline(
/// Error that can happen when creating a `DebugUtilsMessenger`.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum DebugUtilsMessengerCreationError {
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
}
impl Error for DebugUtilsMessengerCreationError {}
impl fmt::Display for DebugUtilsMessengerCreationError {
impl Display for DebugUtilsMessengerCreationError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::ExtensionNotEnabled { extension, reason } => {
write!(f, "the extension {} must be enabled: {}", extension, reason)
}
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
}
}
}
@ -268,6 +276,16 @@ impl From<VulkanError> for DebugUtilsMessengerCreationError {
}
}
impl From<RequirementNotMet> for DebugUtilsMessengerCreationError {
#[inline]
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}
/// Parameters to create a `DebugUtilsMessenger`.
#[derive(Clone)]
pub struct DebugUtilsMessengerCreateInfo {
@ -317,8 +335,8 @@ impl DebugUtilsMessengerCreateInfo {
}
}
impl fmt::Debug for DebugUtilsMessengerCreateInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
impl Debug for DebugUtilsMessengerCreateInfo {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
let Self {
message_severity,
message_type,

View File

@ -7,15 +7,7 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
pub use crate::{
extensions::{ExtensionRestriction, ExtensionRestrictionError, OneOfRequirements},
Version,
};
use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Sub, SubAssign};
use std::{
ffi::{CStr, CString},
fmt::Formatter,
};
pub use crate::extensions::{ExtensionRestriction, ExtensionRestrictionError};
// Generated by build.rs
include!(concat!(env!("OUT_DIR"), "/instance_extensions.rs"));

View File

@ -59,7 +59,7 @@ pub use self::{extensions::InstanceExtensions, layers::LayerProperties};
use crate::{
device::physical::{init_physical_devices, PhysicalDeviceInfo},
instance::debug::trampoline,
OomError, VulkanError, VulkanLibrary, VulkanObject,
OomError, RequiresOneOf, VulkanError, VulkanLibrary, VulkanObject,
};
pub use crate::{
extensions::{ExtensionRestriction, ExtensionRestrictionError},
@ -70,7 +70,7 @@ use smallvec::SmallVec;
use std::{
error::Error,
ffi::{c_void, CString},
fmt,
fmt::{Debug, Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},
mem::MaybeUninit,
panic::{RefUnwindSafe, UnwindSafe},
@ -386,15 +386,24 @@ impl Instance {
// VUID-VkInstanceCreateInfo-pNext-04926
if !enabled_extensions.ext_debug_utils {
return Err(InstanceCreationError::ExtensionNotEnabled {
extension: "ext_debug_utils",
reason: "debug_utils_messengers was not empty",
return Err(InstanceCreationError::RequirementNotMet {
required_for: "`debug_utils_messengers` is not empty",
requires_one_of: RequiresOneOf {
instance_extensions: &["ext_debug_utils"],
..Default::default()
},
});
}
// VUID-VkDebugUtilsMessengerCreateInfoEXT-messageSeverity-parameter
// TODO: message_severity.validate_instance()?;
// VUID-VkDebugUtilsMessengerCreateInfoEXT-messageSeverity-requiredbitmask
assert!(!message_severity.is_empty());
// VUID-VkDebugUtilsMessengerCreateInfoEXT-messageType-parameter
// TODO: message_type.validate_instance()?;
// VUID-VkDebugUtilsMessengerCreateInfoEXT-messageType-requiredbitmask
assert!(!message_type.is_empty());
@ -539,8 +548,8 @@ impl Hash for Instance {
}
}
impl fmt::Debug for Instance {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
impl Debug for Instance {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
let Self {
handle,
fns,
@ -684,9 +693,9 @@ pub enum InstanceCreationError {
/// A restriction for an extension was not met.
ExtensionRestrictionNotMet(ExtensionRestrictionError),
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
}
@ -700,20 +709,24 @@ impl Error for InstanceCreationError {
}
}
impl fmt::Display for InstanceCreationError {
impl Display for InstanceCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
Self::OomError(_) => write!(fmt, "not enough memory available"),
Self::InitializationFailed => write!(fmt, "initialization failed"),
Self::LayerNotPresent => write!(fmt, "layer not present"),
Self::ExtensionNotPresent => write!(fmt, "extension not present"),
Self::IncompatibleDriver => write!(fmt, "incompatible driver"),
Self::ExtensionRestrictionNotMet(err) => err.fmt(fmt),
Self::ExtensionNotEnabled { extension, reason } => write!(
fmt,
"the extension {} must be enabled: {}",
extension, reason
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::OomError(_) => write!(f, "not enough memory available"),
Self::InitializationFailed => write!(f, "initialization failed"),
Self::LayerNotPresent => write!(f, "layer not present"),
Self::ExtensionNotPresent => write!(f, "extension not present"),
Self::IncompatibleDriver => write!(f, "incompatible driver"),
Self::ExtensionRestrictionNotMet(err) => Display::fmt(err, f),
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
}
}

View File

@ -85,7 +85,12 @@ pub use ash::vk::Handle;
pub use half;
pub use library::{LoadingError, VulkanLibrary};
use parking_lot::MutexGuard;
use std::{error::Error, fmt, ops::Deref, sync::Arc};
use std::{
error::Error,
fmt::{Display, Error as FmtError, Formatter},
ops::Deref,
sync::Arc,
};
pub use version::Version;
#[macro_use]
@ -155,11 +160,11 @@ pub enum OomError {
impl Error for OomError {}
impl fmt::Display for OomError {
impl Display for OomError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
fmt,
f,
"{}",
match *self {
OomError::OutOfHostMemory => "no memory available on the host",
@ -185,8 +190,8 @@ include!(concat!(env!("OUT_DIR"), "/errors.rs"));
impl Error for VulkanError {}
impl fmt::Display for VulkanError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
impl Display for VulkanError {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
VulkanError::OutOfHostMemory => write!(
f,
@ -301,6 +306,112 @@ impl fmt::Display for VulkanError {
}
}
/// Used in errors to indicate a set of alternatives that needs to be available/enabled to allow
/// a given operation.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct RequiresOneOf {
/// A minimum Vulkan API version that would allow the operation.
pub api_version: Option<Version>,
/// Enabled features that would allow the operation.
pub features: &'static [&'static str],
/// Available/enabled device extensions that would allow the operation.
pub device_extensions: &'static [&'static str],
/// Available/enabled instance extensions that would allow the operation.
pub instance_extensions: &'static [&'static str],
}
impl RequiresOneOf {
/// Returns whether there is more than one possible requirement.
#[inline]
pub fn len(&self) -> usize {
self.api_version.map_or(0, |_| 1)
+ self.features.len()
+ self.device_extensions.len()
+ self.instance_extensions.len()
}
}
impl Display for RequiresOneOf {
#[inline]
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
let mut members_written = 0;
if let Some(version) = self.api_version {
write!(f, "Vulkan API version {}.{}", version.major, version.minor)?;
members_written += 1;
}
if let Some((last, rest)) = self.features.split_last() {
if members_written != 0 {
write!(f, ", ")?;
}
members_written += 1;
if rest.is_empty() {
write!(f, "feature {}", last)?;
} else {
write!(f, "features ")?;
for feature in rest {
write!(f, "{}, ", feature)?;
}
write!(f, "{}", last)?;
}
}
if let Some((last, rest)) = self.device_extensions.split_last() {
if members_written != 0 {
write!(f, ", ")?;
}
members_written += 1;
if rest.is_empty() {
write!(f, "device extension {}", last)?;
} else {
write!(f, "device extensions ")?;
for feature in rest {
write!(f, "{}, ", feature)?;
}
write!(f, "{}", last)?;
}
}
if let Some((last, rest)) = self.instance_extensions.split_last() {
if members_written != 0 {
write!(f, ", ")?;
}
if rest.is_empty() {
write!(f, "instance extension {}", last)?;
} else {
write!(f, "instance extensions ")?;
for feature in rest {
write!(f, "{}, ", feature)?;
}
write!(f, "{}", last)?;
}
}
Ok(())
}
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct RequirementNotMet {
pub(crate) required_for: &'static str,
pub(crate) requires_one_of: RequiresOneOf,
}
/// A helper type for non-exhaustive structs.
///
/// This type cannot be constructed outside Vulkano. Structures with a field of this type can only

View File

@ -25,7 +25,14 @@ use crate::{
};
use libloading::{Error as LibloadingError, Library};
use std::{
error::Error, ffi::CStr, fmt, mem::transmute, os::raw::c_char, path::Path, ptr, sync::Arc,
error::Error,
ffi::CStr,
fmt::{Debug, Display, Error as FmtError, Formatter},
mem::transmute,
os::raw::c_char,
path::Path,
ptr,
sync::Arc,
};
/// A loaded library containing a valid Vulkan implementation.
@ -262,9 +269,9 @@ where
}
}
impl fmt::Debug for dyn Loader {
impl Debug for dyn Loader {
#[inline]
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
fn fmt(&self, _f: &mut Formatter) -> Result<(), FmtError> {
Ok(())
}
}
@ -366,11 +373,11 @@ impl Error for LoadingError {
}
}
impl fmt::Display for LoadingError {
impl Display for LoadingError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
fmt,
f,
"{}",
match *self {
Self::LibraryLoadFailure(_) => "failed to load the Vulkan shared library",

View File

@ -14,12 +14,7 @@ macro_rules! vulkan_bitflags {
$(
$(#[doc = $flag_doc:literal])*
$flag_name:ident = $flag_name_ffi:ident
$({
$(api_version: $api_version:ident,)?
extensions: [$($extension:ident),+ $(,)?],
})?
,
$flag_name:ident = $flag_name_ffi:ident,
)+
} => {
$(#[doc = $ty_doc])*
@ -134,32 +129,6 @@ macro_rules! vulkan_bitflags {
)+
}
}
#[allow(dead_code)]
pub(crate) fn validate(
self,
#[allow(unused_variables)] device: &crate::device::Device
) -> Result<(), crate::macros::ExtensionNotEnabled> {
$(
$(
if self.$flag_name && !(
$(
device.api_version() >= crate::Version::$api_version ||
)?
$(
device.enabled_extensions().$extension
)||+
) {
return Err(crate::macros::ExtensionNotEnabled {
extension: stringify!($($extension)?),
reason: concat!(stringify!($ty), "::", stringify!($flag_name), " was used"),
});
}
)?
)+
Ok(())
}
}
impl From<$ty> for ash::vk::$ty_ffi {
@ -279,7 +248,8 @@ macro_rules! vulkan_bitflags {
$flag_name:ident = $flag_name_ffi:ident
$({
$(api_version: $api_version:ident,)?
extensions: [$($extension:ident),+ $(,)?],
$(device_extensions: [$($device_extension:ident),+ $(,)?],)?
$(instance_extensions: [$($instance_extension:ident),+ $(,)?],)?
})?
,
)+
@ -384,23 +354,95 @@ macro_rules! vulkan_bitflags {
}
#[allow(dead_code)]
pub(crate) fn validate(
pub(crate) fn validate_device(
self,
#[allow(unused_variables)] device: &crate::device::Device
) -> Result<(), crate::macros::ExtensionNotEnabled> {
#[allow(unused_variables)] device: &crate::device::Device,
) -> Result<(), crate::RequirementNotMet> {
$(
$(
if self.$flag_name && !(
if self.$flag_name && ![
$(
device.api_version() >= crate::Version::$api_version ||
device.api_version() >= crate::Version::$api_version,
)?
$($(
device.enabled_extensions().$device_extension,
)+)?
$($(
device.instance().enabled_extensions().$instance_extension,
)+)?
].into_iter().any(|x| x) {
return Err(crate::RequirementNotMet {
required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"),
requires_one_of: crate::RequiresOneOf {
$(api_version: Some(crate::Version::$api_version),)?
$(device_extensions: &[$(stringify!($device_extension)),+],)?
$(instance_extensions: &[$(stringify!($instance_extension)),+],)?
..Default::default()
},
});
}
)?
)+
Ok(())
}
#[allow(dead_code)]
pub(crate) fn validate_physical_device(
self,
#[allow(unused_variables)] physical_device: &crate::device::physical::PhysicalDevice,
) -> Result<(), crate::RequirementNotMet> {
$(
device.enabled_extensions().$extension
)||+
) {
return Err(crate::macros::ExtensionNotEnabled {
extension: stringify!($($extension)?),
reason: concat!(stringify!($ty), "::", stringify!($flag_name), " was used"),
$(
if self.$flag_name && ![
$(
physical_device.api_version() >= crate::Version::$api_version,
)?
$($(
physical_device.supported_extensions().$device_extension,
)+)?
$($(
physical_device.instance().enabled_extensions().$instance_extension,
)+)?
].into_iter().any(|x| x) {
return Err(crate::RequirementNotMet {
required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"),
requires_one_of: crate::RequiresOneOf {
$(api_version: Some(crate::Version::$api_version),)?
$(device_extensions: &[$(stringify!($device_extension)),+],)?
$(instance_extensions: &[$(stringify!($instance_extension)),+],)?
..Default::default()
},
});
}
)?
)+
Ok(())
}
#[allow(dead_code)]
pub(crate) fn validate_instance(
self,
#[allow(unused_variables)] instance: &crate::instance::Instance,
) -> Result<(), crate::RequirementNotMet> {
$(
$(
if self.$flag_name && ![
$(
instance.api_version() >= crate::Version::$api_version,
)?
$($(
instance.enabled_extensions().$instance_extension,
)+)?
].into_iter().any(|x| x) {
return Err(crate::RequirementNotMet {
required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"),
requires_one_of: crate::RequiresOneOf {
$(api_version: Some(crate::Version::$api_version),)?
$(instance_extensions: &[$(stringify!($instance_extension)),+],)?
..Default::default()
},
});
}
)?
@ -518,12 +560,7 @@ macro_rules! vulkan_enum {
$(
$(#[doc = $flag_doc:literal])*
$flag_name:ident = $flag_name_ffi:ident
$({
$(api_version: $api_version:ident,)?
extensions: [$($extension:ident),+ $(,)?],
})?
,
$flag_name:ident = $flag_name_ffi:ident,
)+
} => {
$(#[doc = $ty_doc])*
@ -568,7 +605,8 @@ macro_rules! vulkan_enum {
$flag_name:ident = $flag_name_ffi:ident
$({
$(api_version: $api_version:ident,)?
extensions: [$($extension:ident),+ $(,)?],
$(device_extensions: [$($device_extension:ident),+ $(,)?],)?
$(instance_extensions: [$($instance_extension:ident),+ $(,)?],)?
})?
,
)+
@ -586,25 +624,107 @@ macro_rules! vulkan_enum {
impl $ty {
#[allow(dead_code)]
pub(crate) fn validate(
pub(crate) fn validate_device(
self,
#[allow(unused_variables)] device: &crate::device::Device
) -> Result<(), crate::macros::ExtensionNotEnabled> {
#[allow(unused_variables)] device: &crate::device::Device,
) -> Result<(), crate::RequirementNotMet> {
match self {
$(
$(
Self::$flag_name => {
if !(
if ![
$(
device.api_version() >= crate::Version::$api_version ||
device.api_version() >= crate::Version::$api_version,
)?
$($(
device.enabled_extensions().$device_extension,
)+)?
$($(
device.instance().enabled_extensions().$instance_extension,
)+)?
].into_iter().any(|x| x) {
return Err(crate::RequirementNotMet {
required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"),
requires_one_of: crate::RequiresOneOf {
$(api_version: Some(crate::Version::$api_version),)?
$(device_extensions: &[$(stringify!($device_extension)),+],)?
$(instance_extensions: &[$(stringify!($instance_extension)),+],)?
..Default::default()
},
});
}
},
)?
)+
_ => (),
}
Ok(())
}
#[allow(dead_code)]
pub(crate) fn validate_physical_device(
self,
#[allow(unused_variables)] physical_device: &crate::device::physical::PhysicalDevice,
) -> Result<(), crate::RequirementNotMet> {
match self {
$(
device.enabled_extensions().$extension
)||+
) {
return Err(crate::macros::ExtensionNotEnabled {
extension: stringify!($($extension)?),
reason: concat!(stringify!($ty), "::", stringify!($flag_name), " was used"),
$(
Self::$flag_name => {
if ![
$(
physical_device.api_version() >= crate::Version::$api_version,
)?
$($(
physical_device.supported_extensions().$device_extension,
)+)?
$($(
physical_device.instance().enabled_extensions().$instance_extension,
)+)?
].into_iter().any(|x| x) {
return Err(crate::RequirementNotMet {
required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"),
requires_one_of: crate::RequiresOneOf {
$(api_version: Some(crate::Version::$api_version),)?
$(device_extensions: &[$(stringify!($device_extension)),+],)?
$(instance_extensions: &[$(stringify!($instance_extension)),+],)?
..Default::default()
},
});
}
},
)?
)+
_ => (),
}
Ok(())
}
#[allow(dead_code)]
pub(crate) fn validate_instance(
self,
#[allow(unused_variables)] instance: &crate::instance::Instance,
) -> Result<(), crate::RequirementNotMet> {
match self {
$(
$(
Self::$flag_name => {
if ![
$(
instance.api_version() >= crate::Version::$api_version,
)?
$($(
instance.enabled_extensions().$instance_extension,
)+)?
].into_iter().any(|x| x) {
return Err(crate::RequirementNotMet {
required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"),
requires_one_of: crate::RequiresOneOf {
$(api_version: Some(crate::Version::$api_version),)?
$(instance_extensions: &[$(stringify!($instance_extension)),+],)?
..Default::default()
},
});
}
},
@ -641,9 +761,3 @@ macro_rules! vulkan_enum {
}
pub(crate) use {vulkan_bitflags, vulkan_enum};
#[derive(Clone, Copy, Debug)]
pub(crate) struct ExtensionNotEnabled {
pub(crate) extension: &'static str,
pub(crate) reason: &'static str,
}

View File

@ -10,13 +10,13 @@
use super::DedicatedAllocation;
use crate::{
device::{physical::MemoryType, Device, DeviceOwned},
macros::{vulkan_bitflags, vulkan_enum, ExtensionNotEnabled},
DeviceSize, OomError, Version, VulkanError, VulkanObject,
macros::{vulkan_bitflags, vulkan_enum},
DeviceSize, OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
};
use std::{
error::Error,
ffi::c_void,
fmt,
fmt::{Display, Error as FmtError, Formatter},
fs::File,
hash::{Hash, Hasher},
mem::MaybeUninit,
@ -161,9 +161,12 @@ impl DeviceMemory {
// VUID-VkMemoryAllocateInfo-memoryTypeIndex-01872
if memory_type.is_protected() && !device.enabled_features().protected_memory {
return Err(DeviceMemoryAllocationError::FeatureNotEnabled {
feature: "protected_memory",
reason: "selected memory type is protected",
return Err(DeviceMemoryAllocationError::RequirementNotMet {
required_for: "`allocate_info.memory_type_index` refers to a memory type where `flags.protected` is set",
requires_one_of: RequiresOneOf {
features: &["protected_memory"],
..Default::default()
},
});
}
@ -220,14 +223,18 @@ impl DeviceMemory {
if !(device.api_version() >= Version::V1_1
|| device.enabled_extensions().khr_external_memory)
{
return Err(DeviceMemoryAllocationError::ExtensionNotEnabled {
extension: "khr_external_memory_fd",
reason: "`import_info` was `MemoryImportInfo::Fd`",
return Err(DeviceMemoryAllocationError::RequirementNotMet {
required_for: "`allocate_info.export_handle_types` is not empty",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_1),
device_extensions: &["khr_external_memory"],
..Default::default()
},
});
}
// VUID-VkExportMemoryAllocateInfo-handleTypes-parameter
export_handle_types.validate(device)?;
export_handle_types.validate_device(device)?;
// VUID-VkMemoryAllocateInfo-pNext-00639
// VUID-VkExportMemoryAllocateInfo-handleTypes-00656
@ -246,9 +253,13 @@ impl DeviceMemory {
file: _,
} => {
if !device.enabled_extensions().khr_external_memory_fd {
return Err(DeviceMemoryAllocationError::ExtensionNotEnabled {
extension: "khr_external_memory_fd",
reason: "`import_info` was `MemoryImportInfo::Fd`",
return Err(DeviceMemoryAllocationError::RequirementNotMet {
required_for:
"`allocate_info.import_info` is `Some(MemoryImportInfo::Fd)`",
requires_one_of: RequiresOneOf {
device_extensions: &["khr_external_memory_fd"],
..Default::default()
},
});
}
@ -260,7 +271,7 @@ impl DeviceMemory {
#[cfg(unix)]
{
// VUID-VkImportMemoryFdInfoKHR-handleType-parameter
handle_type.validate(device)?;
handle_type.validate_device(device)?;
// VUID-VkImportMemoryFdInfoKHR-handleType-00669
match handle_type {
@ -274,14 +285,7 @@ impl DeviceMemory {
// VUID-VkMemoryDedicatedAllocateInfo-image-01878
// Can't validate, must be ensured by user
}
ExternalMemoryHandleType::DmaBuf => {
if !device.enabled_extensions().ext_external_memory_dma_buf {
return Err(DeviceMemoryAllocationError::ExtensionNotEnabled {
extension: "ext_external_memory_dma_buf",
reason: "`import_info` was `MemoryImportInfo::Fd` and `handle_type` was `ExternalMemoryHandleType::DmaBuf`"
});
}
}
ExternalMemoryHandleType::DmaBuf => {}
_ => {
return Err(
DeviceMemoryAllocationError::ImportFdHandleTypeNotSupported {
@ -303,9 +307,13 @@ impl DeviceMemory {
handle: _,
} => {
if !device.enabled_extensions().khr_external_memory_win32 {
return Err(DeviceMemoryAllocationError::ExtensionNotEnabled {
extension: "khr_external_memory_win32",
reason: "`import_info` was `MemoryImportInfo::Win32`",
return Err(DeviceMemoryAllocationError::RequirementNotMet {
required_for:
"`allocate_info.import_info` is `Some(MemoryImportInfo::Win32)`",
requires_one_of: RequiresOneOf {
device_extensions: &["khr_external_memory_win32"],
..Default::default()
},
});
}
@ -317,7 +325,7 @@ impl DeviceMemory {
#[cfg(windows)]
{
// VUID-VkImportMemoryWin32HandleInfoKHR-handleType-parameter
handle_type.validate(device)?;
handle_type.validate_device(device)?;
// VUID-VkImportMemoryWin32HandleInfoKHR-handleType-00660
match handle_type {
@ -491,7 +499,7 @@ impl DeviceMemory {
handle_type: ExternalMemoryHandleType,
) -> Result<std::fs::File, DeviceMemoryExportError> {
// VUID-VkMemoryGetFdInfoKHR-handleType-parameter
handle_type.validate(&self.device)?;
handle_type.validate_device(&self.device)?;
// VUID-VkMemoryGetFdInfoKHR-handleType-00672
if !matches!(
@ -599,13 +607,9 @@ pub enum DeviceMemoryAllocationError {
/// An error occurred when mapping the memory.
MemoryMapError(MemoryMapError),
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
},
FeatureNotEnabled {
feature: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// `dedicated_allocation` was `Some`, but the provided `allocation_size` was different from
@ -658,54 +662,56 @@ impl Error for DeviceMemoryAllocationError {
}
}
impl fmt::Display for DeviceMemoryAllocationError {
impl Display for DeviceMemoryAllocationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
Self::OomError(_) => write!(fmt, "not enough memory available"),
Self::OomError(_) => write!(f, "not enough memory available"),
Self::TooManyObjects => {
write!(fmt, "the maximum number of allocations has been exceeded")
write!(f, "the maximum number of allocations has been exceeded")
}
Self::MemoryMapError(_) => write!(fmt, "error occurred when mapping the memory"),
Self::ExtensionNotEnabled { extension, reason } => write!(
fmt,
"the extension {} must be enabled: {}",
extension, reason
Self::MemoryMapError(_) => write!(f, "error occurred when mapping the memory"),
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::FeatureNotEnabled { feature, reason } => {
write!(fmt, "the feature {} must be enabled: {}", feature, reason)
}
Self::DedicatedAllocationSizeMismatch { allocation_size, required_size } => write!(
fmt,
f,
"`dedicated_allocation` was `Some`, but the provided `allocation_size` ({}) was different from the required size of the buffer or image ({})",
allocation_size, required_size,
),
Self::ImportFdHandleTypeNotSupported { handle_type } => write!(
fmt,
f,
"the provided `MemoryImportInfo::Fd::handle_type` ({:?}) is not supported for file descriptors",
handle_type,
),
Self::ImportWin32HandleTypeNotSupported { handle_type } => write!(
fmt,
f,
"the provided `MemoryImportInfo::Win32::handle_type` ({:?}) is not supported",
handle_type,
),
Self::MemoryTypeHeapSizeExceeded { allocation_size, heap_size } => write!(
fmt,
f,
"the provided `allocation_size` ({}) was greater than the memory type's heap size ({})",
allocation_size, heap_size,
),
Self::MemoryTypeIndexOutOfRange { memory_type_index, memory_type_count } => write!(
fmt,
f,
"the provided `memory_type_index` ({}) was not less than the number of memory types in the physical device ({})",
memory_type_index, memory_type_count,
),
Self::SpecViolation(u) => {
write!(fmt, "valid usage ID check {} failed", u)
write!(f, "valid usage ID check {} failed", u)
}
Self::ImplicitSpecViolation(e) => {
write!(fmt, "Implicit spec violation failed {}", e)
write!(f, "Implicit spec violation failed {}", e)
}
}
}
@ -738,12 +744,12 @@ impl From<MemoryMapError> for DeviceMemoryAllocationError {
}
}
impl From<ExtensionNotEnabled> for DeviceMemoryAllocationError {
impl From<RequirementNotMet> for DeviceMemoryAllocationError {
#[inline]
fn from(err: ExtensionNotEnabled) -> Self {
Self::ExtensionNotEnabled {
extension: err.extension,
reason: err.reason,
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}
@ -886,32 +892,32 @@ vulkan_enum! {
// TODO: document
DmaBuf = DMA_BUF_EXT {
extensions: [ext_external_memory_dma_buf],
device_extensions: [ext_external_memory_dma_buf],
},
// TODO: document
AndroidHardwareBuffer = ANDROID_HARDWARE_BUFFER_ANDROID {
extensions: [android_external_memory_android_hardware_buffer],
device_extensions: [android_external_memory_android_hardware_buffer],
},
// TODO: document
HostAllocation = HOST_ALLOCATION_EXT {
extensions: [ext_external_memory_host],
device_extensions: [ext_external_memory_host],
},
// TODO: document
HostMappedForeignMemory = HOST_MAPPED_FOREIGN_MEMORY_EXT {
extensions: [ext_external_memory_host],
device_extensions: [ext_external_memory_host],
},
// TODO: document
ZirconVmo = ZIRCON_VMO_FUCHSIA {
extensions: [fuchsia_external_memory],
device_extensions: [fuchsia_external_memory],
},
// TODO: document
RdmaAddress = RDMA_ADDRESS_NV {
extensions: [nv_external_memory_rdma],
device_extensions: [nv_external_memory_rdma],
},
}
@ -943,32 +949,32 @@ vulkan_bitflags! {
// TODO: document
dma_buf = DMA_BUF_EXT {
extensions: [ext_external_memory_dma_buf],
device_extensions: [ext_external_memory_dma_buf],
},
// TODO: document
android_hardware_buffer = ANDROID_HARDWARE_BUFFER_ANDROID {
extensions: [android_external_memory_android_hardware_buffer],
device_extensions: [android_external_memory_android_hardware_buffer],
},
// TODO: document
host_allocation = HOST_ALLOCATION_EXT {
extensions: [ext_external_memory_host],
device_extensions: [ext_external_memory_host],
},
// TODO: document
host_mapped_foreign_memory = HOST_MAPPED_FOREIGN_MEMORY_EXT {
extensions: [ext_external_memory_host],
device_extensions: [ext_external_memory_host],
},
// TODO: document
zircon_vmo = ZIRCON_VMO_FUCHSIA {
extensions: [fuchsia_external_memory],
device_extensions: [fuchsia_external_memory],
},
// TODO: document
rdma_address = RDMA_ADDRESS_NV {
extensions: [nv_external_memory_rdma],
device_extensions: [nv_external_memory_rdma],
},
}
@ -1020,14 +1026,14 @@ pub enum DeviceMemoryExportError {
/// Not enough memory available.
OomError(OomError),
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
},
/// The maximum number of allocations has been exceeded.
TooManyObjects,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// The requested export handle type is not supported for this operation, or was not provided in
/// `export_handle_types` when allocating the memory.
HandleTypeNotSupported {
@ -1045,23 +1051,28 @@ impl Error for DeviceMemoryExportError {
}
}
impl fmt::Display for DeviceMemoryExportError {
impl Display for DeviceMemoryExportError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
Self::OomError(_) => write!(fmt, "not enough memory available"),
Self::ExtensionNotEnabled { extension, reason } => write!(
fmt,
"the extension {} must be enabled: {}",
extension, reason
),
Self::OomError(_) => write!(f, "not enough memory available"),
Self::TooManyObjects => {
write!(fmt, "the maximum number of allocations has been exceeded")
write!(f, "the maximum number of allocations has been exceeded")
}
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::HandleTypeNotSupported {
handle_type,
} => write!(
fmt,
f,
"the requested export handle type ({:?}) is not supported for this operation, or was not provided in `export_handle_types` when allocating the memory",
handle_type,
),
@ -1089,12 +1100,12 @@ impl From<OomError> for DeviceMemoryExportError {
}
}
impl From<ExtensionNotEnabled> for DeviceMemoryExportError {
impl From<RequirementNotMet> for DeviceMemoryExportError {
#[inline]
fn from(err: ExtensionNotEnabled) -> Self {
Self::ExtensionNotEnabled {
extension: err.extension,
reason: err.reason,
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}
@ -1478,23 +1489,23 @@ impl Error for MemoryMapError {
}
}
impl fmt::Display for MemoryMapError {
impl Display for MemoryMapError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
Self::OomError(_) => write!(fmt, "not enough memory available"),
Self::MemoryMapFailed => write!(fmt, "memory map failed"),
Self::OomError(_) => write!(f, "not enough memory available"),
Self::MemoryMapFailed => write!(f, "memory map failed"),
Self::NotHostVisible => write!(
fmt,
f,
"tried to map memory whose type is not host-visible",
),
Self::OutOfRange { ref provided_range, ref allowed_range } => write!(
fmt,
f,
"the specified `range` ({:?}) was not contained within the allocated or mapped memory range ({:?})",
provided_range, allowed_range,
),
Self::RangeNotAlignedToAtomSize { ref range, atom_size } => write!(
fmt,
f,
"the memory is not host-coherent, and the specified `range` bounds ({:?}) are not a multiple of the `non_coherent_atom_size` device property ({})",
range, atom_size,
)

View File

@ -36,7 +36,15 @@ use crate::{
shader::{DescriptorRequirements, EntryPoint, SpecializationConstants},
DeviceSize, OomError, VulkanError, VulkanObject,
};
use std::{collections::HashMap, error::Error, fmt, mem, mem::MaybeUninit, ptr, sync::Arc};
use std::{
collections::HashMap,
error::Error,
fmt::{Debug, Display, Error as FmtError, Formatter},
mem,
mem::MaybeUninit,
ptr,
sync::Arc,
};
/// A pipeline object that describes to the Vulkan implementation how it should perform compute
/// operations.
@ -264,10 +272,10 @@ impl Pipeline for ComputePipeline {
}
}
impl fmt::Debug for ComputePipeline {
impl Debug for ComputePipeline {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "<Vulkan compute pipeline {:?}>", self.handle)
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(f, "<Vulkan compute pipeline {:?}>", self.handle)
}
}
@ -334,11 +342,11 @@ impl Error for ComputePipelineCreationError {
}
}
impl fmt::Display for ComputePipelineCreationError {
impl Display for ComputePipelineCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
fmt,
f,
"{}",
match *self {
ComputePipelineCreationError::OomError(_) => "not enough memory available",

File diff suppressed because it is too large Load Diff

View File

@ -411,232 +411,232 @@ vulkan_enum! {
/*
// TODO: document
Zero = ZERO_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Src = SRC_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Dst = DST_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
SrcOver = SRC_OVER_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
DstOver = DST_OVER_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
SrcIn = SRC_IN_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
DstIn = DST_IN_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
SrcOut = SRC_OUT_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
DstOut = DST_OUT_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
SrcAtop = SRC_ATOP_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
DstAtop = DST_ATOP_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Xor = XOR_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Multiply = MULTIPLY_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Screen = SCREEN_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Overlay = OVERLAY_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Darken = DARKEN_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Lighten = LIGHTEN_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Colordodge = COLORDODGE_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Colorburn = COLORBURN_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Hardlight = HARDLIGHT_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Softlight = SOFTLIGHT_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Difference = DIFFERENCE_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Exclusion = EXCLUSION_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Invert = INVERT_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
InvertRgb = INVERT_RGB_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Lineardodge = LINEARDODGE_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Linearburn = LINEARBURN_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Vividlight = VIVIDLIGHT_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Linearlight = LINEARLIGHT_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Pinlight = PINLIGHT_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Hardmix = HARDMIX_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
HslHue = HSL_HUE_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
HslSaturation = HSL_SATURATION_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
HslColor = HSL_COLOR_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
HslLuminosity = HSL_LUMINOSITY_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Plus = PLUS_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
PlusClamped = PLUS_CLAMPED_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
PlusClampedAlpha = PLUS_CLAMPED_ALPHA_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
PlusDarker = PLUS_DARKER_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Minus = MINUS_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
MinusClamped = MINUS_CLAMPED_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Contrast = CONTRAST_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
InvertOvg = INVERT_OVG_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Red = RED_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Green = GREEN_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// TODO: document
Blue = BLUE_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
*/
}

View File

@ -11,26 +11,21 @@ use super::vertex_input::IncompatibleVertexDefinitionError;
use crate::{
descriptor_set::layout::DescriptorSetLayoutCreationError,
format::{Format, NumericType},
macros::ExtensionNotEnabled,
pipeline::layout::{PipelineLayoutCreationError, PipelineLayoutSupersetError},
shader::ShaderInterfaceMismatchError,
OomError, VulkanError,
OomError, RequirementNotMet, RequiresOneOf, VulkanError,
};
use std::{
error::Error,
fmt::{Display, Error as FmtError, Formatter},
};
use std::{error::Error, fmt};
/// Error that can happen when creating a graphics pipeline.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum GraphicsPipelineCreationError {
/// A device extension that was required for a particular setting on the graphics pipeline was not enabled.
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
},
/// A device feature that was required for a particular setting on the graphics pipeline was not enabled.
FeatureNotEnabled {
feature: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// A color attachment has a format that does not support blending.
@ -215,20 +210,19 @@ impl Error for GraphicsPipelineCreationError {
}
}
impl fmt::Display for GraphicsPipelineCreationError {
impl Display for GraphicsPipelineCreationError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
Self::ExtensionNotEnabled { extension, reason } => write!(
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"the extension {} must be enabled: {}",
extension, reason
),
Self::FeatureNotEnabled { feature, reason } => write!(
f,
"the feature {} must be enabled: {}",
feature, reason
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::ColorAttachmentFormatBlendNotSupported { attachment_index } => write!(
f,
"color attachment {} has a format that does not support blending",
@ -436,12 +430,12 @@ impl From<VulkanError> for GraphicsPipelineCreationError {
}
}
impl From<ExtensionNotEnabled> for GraphicsPipelineCreationError {
impl From<RequirementNotMet> for GraphicsPipelineCreationError {
#[inline]
fn from(err: ExtensionNotEnabled) -> Self {
Self::ExtensionNotEnabled {
extension: err.extension,
reason: err.reason,
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}

View File

@ -228,7 +228,7 @@ vulkan_enum! {
// TODO: document
U8 = UINT8_EXT {
extensions: [ext_index_type_uint8],
device_extensions: [ext_index_type_uint8],
},
// TODO: document
@ -240,7 +240,7 @@ vulkan_enum! {
/*
// TODO: document
None = NONE_KHR {
extensions: [khr_acceleration_structure, nv_ray_tracing],
device_extensions: [khr_acceleration_structure, nv_ray_tracing],
},
*/
}

View File

@ -72,7 +72,7 @@ use crate::{
};
use std::{
collections::HashMap,
fmt,
fmt::{Debug, Error as FmtError, Formatter},
hash::{Hash, Hasher},
ptr,
sync::Arc,
@ -264,10 +264,10 @@ unsafe impl DeviceOwned for GraphicsPipeline {
}
}
impl fmt::Debug for GraphicsPipeline {
impl Debug for GraphicsPipeline {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "<Vulkan graphics pipeline {:?}>", self.handle)
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(f, "<Vulkan graphics pipeline {:?}>", self.handle)
}
}

View File

@ -245,7 +245,7 @@ vulkan_enum! {
/*
// TODO: document
FillRectangle = FILL_RECTANGLE_NV {
extensions: [nv_fill_rectangle],
device_extensions: [nv_fill_rectangle],
},
*/
}

View File

@ -130,7 +130,7 @@ fn bad_primitive_restart() {
);
match result {
Err(GraphicsPipelineCreationError::FeatureNotEnabled { .. }) => (),
Err(GraphicsPipelineCreationError::RequirementNotMet { .. }) => (),
_ => panic!(),
}
}

View File

@ -17,7 +17,10 @@ use crate::{
shader::ShaderInterface,
DeviceSize,
};
use std::mem;
use std::{
fmt::{Debug, Error as FmtError, Formatter},
mem,
};
/// A vertex definition for any number of vertex and instance buffers.
#[derive(Clone, Debug, Default)]
@ -30,8 +33,8 @@ struct VertexBuffer {
input_rate: VertexInputRate,
}
impl std::fmt::Debug for VertexBuffer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl Debug for VertexBuffer {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
f.debug_struct("VertexBuffer")
.field("stride", &self.stride)
.field("input_rate", &self.input_rate)

View File

@ -55,7 +55,10 @@ use crate::{
pipeline::graphics::vertex_input::{VertexInputState, VertexMemberTy},
shader::ShaderInterface,
};
use std::{error::Error, fmt};
use std::{
error::Error,
fmt::{Display, Error as FmtError, Formatter},
};
/// Trait for types that can create a [`VertexInputState`] from a [`ShaderInterface`].
pub unsafe trait VertexDefinition {
@ -99,15 +102,15 @@ pub enum IncompatibleVertexDefinitionError {
impl Error for IncompatibleVertexDefinitionError {}
impl fmt::Display for IncompatibleVertexDefinitionError {
impl Display for IncompatibleVertexDefinitionError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
IncompatibleVertexDefinitionError::MissingAttribute { .. } => {
write!(fmt, "an attribute is missing",)
write!(f, "an attribute is missing",)
}
IncompatibleVertexDefinitionError::FormatMismatch { .. } => {
write!(fmt, "the format of an attribute does not match")
write!(f, "the format of an attribute does not match")
}
}
}

View File

@ -66,14 +66,13 @@
use crate::{
descriptor_set::layout::{DescriptorRequirementsNotMet, DescriptorSetLayout, DescriptorType},
device::{Device, DeviceOwned},
macros::ExtensionNotEnabled,
shader::{DescriptorRequirements, ShaderStages},
OomError, VulkanError, VulkanObject,
OomError, RequirementNotMet, RequiresOneOf, VulkanError, VulkanObject,
};
use smallvec::SmallVec;
use std::{
error::Error,
fmt,
fmt::{Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},
mem::MaybeUninit,
ptr,
@ -471,7 +470,7 @@ impl PipelineLayout {
} = range;
// VUID-VkPushConstantRange-stageFlags-parameter
stages.validate(device)?;
stages.validate_device(device)?;
// VUID-VkPushConstantRange-stageFlags-requiredbitmask
assert!(!stages.is_empty());
@ -714,9 +713,9 @@ pub enum PipelineLayoutCreationError {
/// Not enough memory.
OomError(OomError),
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// The number of elements in `set_layouts` is greater than the
@ -830,15 +829,19 @@ impl Error for PipelineLayoutCreationError {
}
}
impl fmt::Display for PipelineLayoutCreationError {
impl Display for PipelineLayoutCreationError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
Self::OomError(_) => write!(f, "not enough memory available"),
Self::ExtensionNotEnabled { extension, reason } => write!(
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"the extension {} must be enabled: {}",
extension, reason
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::MaxBoundDescriptorSetsExceeded { provided, max_supported } => write!(
@ -960,12 +963,12 @@ impl From<VulkanError> for PipelineLayoutCreationError {
}
}
impl From<ExtensionNotEnabled> for PipelineLayoutCreationError {
impl From<RequirementNotMet> for PipelineLayoutCreationError {
#[inline]
fn from(err: ExtensionNotEnabled) -> Self {
Self::ExtensionNotEnabled {
extension: err.extension,
reason: err.reason,
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}
@ -1000,12 +1003,12 @@ impl Error for PipelineLayoutSupersetError {
}
}
impl fmt::Display for PipelineLayoutSupersetError {
impl Display for PipelineLayoutSupersetError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
PipelineLayoutSupersetError::DescriptorRequirementsNotMet { set_num, binding_num, .. } => write!(
fmt,
f,
"the descriptor at set {} binding {} does not meet the requirements",
set_num, binding_num
),
@ -1013,7 +1016,7 @@ impl fmt::Display for PipelineLayoutSupersetError {
set_num,
binding_num,
} => write!(
fmt,
f,
"a descriptor at set {} binding {} is required by the shaders, but is missing from the pipeline layout",
set_num, binding_num
),
@ -1022,19 +1025,19 @@ impl fmt::Display for PipelineLayoutSupersetError {
second_range,
} => {
writeln!(
fmt,
f,
"our range did not completely encompass the other range"
)?;
writeln!(fmt, " our stages: {:?}", first_range.stages)?;
writeln!(f, " our stages: {:?}", first_range.stages)?;
writeln!(
fmt,
f,
" our range: {} - {}",
first_range.offset,
first_range.offset + first_range.size
)?;
writeln!(fmt, " other stages: {:?}", second_range.stages)?;
writeln!(f, " other stages: {:?}", second_range.stages)?;
write!(
fmt,
f,
" other range: {} - {}",
second_range.offset,
second_range.offset + second_range.size

View File

@ -58,12 +58,12 @@ vulkan_enum! {
/*
// TODO: document
RayTracing = RAY_TRACING_KHR {
extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
},
// TODO: document
SubpassShading = SUBPASS_SHADING_HUAWEI {
extensions: [huawei_subpass_shading],
device_extensions: [huawei_subpass_shading],
},
*/
}
@ -104,156 +104,156 @@ vulkan_enum! {
// TODO: document
CullMode = CULL_MODE {
api_version: V1_3,
extensions: [ext_extended_dynamic_state],
device_extensions: [ext_extended_dynamic_state],
},
// TODO: document
FrontFace = FRONT_FACE {
api_version: V1_3,
extensions: [ext_extended_dynamic_state],
device_extensions: [ext_extended_dynamic_state],
},
// TODO: document
PrimitiveTopology = PRIMITIVE_TOPOLOGY {
api_version: V1_3,
extensions: [ext_extended_dynamic_state],
device_extensions: [ext_extended_dynamic_state],
},
// TODO: document
ViewportWithCount = VIEWPORT_WITH_COUNT {
api_version: V1_3,
extensions: [ext_extended_dynamic_state],
device_extensions: [ext_extended_dynamic_state],
},
// TODO: document
ScissorWithCount = SCISSOR_WITH_COUNT {
api_version: V1_3,
extensions: [ext_extended_dynamic_state],
device_extensions: [ext_extended_dynamic_state],
},
// TODO: document
VertexInputBindingStride = VERTEX_INPUT_BINDING_STRIDE {
api_version: V1_3,
extensions: [ext_extended_dynamic_state],
device_extensions: [ext_extended_dynamic_state],
},
// TODO: document
DepthTestEnable = DEPTH_TEST_ENABLE {
api_version: V1_3,
extensions: [ext_extended_dynamic_state],
device_extensions: [ext_extended_dynamic_state],
},
// TODO: document
DepthWriteEnable = DEPTH_WRITE_ENABLE {
api_version: V1_3,
extensions: [ext_extended_dynamic_state],
device_extensions: [ext_extended_dynamic_state],
},
// TODO: document
DepthCompareOp = DEPTH_COMPARE_OP {
api_version: V1_3,
extensions: [ext_extended_dynamic_state],
device_extensions: [ext_extended_dynamic_state],
},
// TODO: document
DepthBoundsTestEnable = DEPTH_BOUNDS_TEST_ENABLE {
api_version: V1_3,
extensions: [ext_extended_dynamic_state],
device_extensions: [ext_extended_dynamic_state],
},
// TODO: document
StencilTestEnable = STENCIL_TEST_ENABLE {
api_version: V1_3,
extensions: [ext_extended_dynamic_state],
device_extensions: [ext_extended_dynamic_state],
},
// TODO: document
StencilOp = STENCIL_OP {
api_version: V1_3,
extensions: [ext_extended_dynamic_state],
device_extensions: [ext_extended_dynamic_state],
},
// TODO: document
RasterizerDiscardEnable = RASTERIZER_DISCARD_ENABLE {
api_version: V1_3,
extensions: [ext_extended_dynamic_state2],
device_extensions: [ext_extended_dynamic_state2],
},
// TODO: document
DepthBiasEnable = DEPTH_BIAS_ENABLE {
api_version: V1_3,
extensions: [ext_extended_dynamic_state2],
device_extensions: [ext_extended_dynamic_state2],
},
// TODO: document
PrimitiveRestartEnable = PRIMITIVE_RESTART_ENABLE {
api_version: V1_3,
extensions: [ext_extended_dynamic_state2],
device_extensions: [ext_extended_dynamic_state2],
},
// TODO: document
ViewportWScaling = VIEWPORT_W_SCALING_NV {
extensions: [nv_clip_space_w_scaling],
device_extensions: [nv_clip_space_w_scaling],
},
// TODO: document
DiscardRectangle = DISCARD_RECTANGLE_EXT {
extensions: [ext_discard_rectangles],
device_extensions: [ext_discard_rectangles],
},
// TODO: document
SampleLocations = SAMPLE_LOCATIONS_EXT {
extensions: [ext_sample_locations],
device_extensions: [ext_sample_locations],
},
// TODO: document
RayTracingPipelineStackSize = RAY_TRACING_PIPELINE_STACK_SIZE_KHR {
extensions: [khr_ray_tracing_pipeline],
device_extensions: [khr_ray_tracing_pipeline],
},
// TODO: document
ViewportShadingRatePalette = VIEWPORT_SHADING_RATE_PALETTE_NV {
extensions: [nv_shading_rate_image],
device_extensions: [nv_shading_rate_image],
},
// TODO: document
ViewportCoarseSampleOrder = VIEWPORT_COARSE_SAMPLE_ORDER_NV {
extensions: [nv_shading_rate_image],
device_extensions: [nv_shading_rate_image],
},
// TODO: document
ExclusiveScissor = EXCLUSIVE_SCISSOR_NV {
extensions: [nv_scissor_exclusive],
device_extensions: [nv_scissor_exclusive],
},
// TODO: document
FragmentShadingRate = FRAGMENT_SHADING_RATE_KHR {
extensions: [khr_fragment_shading_rate],
device_extensions: [khr_fragment_shading_rate],
},
// TODO: document
LineStipple = LINE_STIPPLE_EXT {
extensions: [ext_line_rasterization],
device_extensions: [ext_line_rasterization],
},
// TODO: document
VertexInput = VERTEX_INPUT_EXT {
extensions: [ext_vertex_input_dynamic_state],
device_extensions: [ext_vertex_input_dynamic_state],
},
// TODO: document
PatchControlPoints = PATCH_CONTROL_POINTS_EXT {
extensions: [ext_extended_dynamic_state2],
device_extensions: [ext_extended_dynamic_state2],
},
// TODO: document
LogicOp = LOGIC_OP_EXT {
extensions: [ext_extended_dynamic_state2],
device_extensions: [ext_extended_dynamic_state2],
},
// TODO: document
ColorWriteEnable = COLOR_WRITE_ENABLE_EXT {
extensions: [ext_color_write_enable],
device_extensions: [ext_color_write_enable],
},
}

View File

@ -15,13 +15,13 @@
use crate::{
device::{Device, DeviceOwned},
macros::{vulkan_bitflags, ExtensionNotEnabled},
DeviceSize, OomError, VulkanError, VulkanObject,
macros::vulkan_bitflags,
DeviceSize, OomError, RequirementNotMet, RequiresOneOf, VulkanError, VulkanObject,
};
use std::{
error::Error,
ffi::c_void,
fmt,
fmt::{Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},
mem::{size_of_val, MaybeUninit},
ops::Range,
@ -255,13 +255,13 @@ impl Error for QueryPoolCreationError {
}
}
impl fmt::Display for QueryPoolCreationError {
impl Display for QueryPoolCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
fmt,
f,
"{}",
match *self {
match self {
QueryPoolCreationError::OomError(_) => "not enough memory available",
QueryPoolCreationError::PipelineStatisticsQueryFeatureNotEnabled => {
"a pipeline statistics pool was requested but the corresponding feature \
@ -396,7 +396,7 @@ impl<'a> QueriesRange<'a> {
{
// VUID-vkGetQueryPoolResults-flags-parameter
// VUID-vkCmdCopyQueryPoolResults-flags-parameter
flags.validate(&self.pool.device)?;
flags.validate_device(&self.pool.device)?;
assert!(buffer_len > 0);
@ -441,9 +441,9 @@ pub enum GetResultsError {
/// Not enough memory.
OomError(OomError),
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// The buffer is too small for the operation.
@ -468,15 +468,21 @@ impl Error for GetResultsError {
}
}
impl fmt::Display for GetResultsError {
impl Display for GetResultsError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::OomError(_) => write!(f, "not enough memory available"),
Self::DeviceLost => write!(f, "the connection to the device has been lost"),
Self::ExtensionNotEnabled { extension, reason } => {
write!(f, "the extension {} must be enabled: {}", extension, reason)
}
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::BufferTooSmall { .. } => write!(f, "the buffer is too small for the operation"),
Self::InvalidFlags => write!(
@ -507,12 +513,12 @@ impl From<OomError> for GetResultsError {
}
}
impl From<ExtensionNotEnabled> for GetResultsError {
impl From<RequirementNotMet> for GetResultsError {
#[inline]
fn from(err: ExtensionNotEnabled) -> Self {
Self::ExtensionNotEnabled {
extension: err.extension,
reason: err.reason,
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}
@ -626,12 +632,12 @@ vulkan_bitflags! {
/*
// TODO: document
task_shader_invocations = TASK_SHADER_INVOCATIONS_NV {
extensions: [nv_mesh_shader],
device_extensions: [nv_mesh_shader],
},
// TODO: document
mesh_shader_invocations = MESH_SHADER_INVOCATIONS_NV {
extensions: [nv_mesh_shader],
device_extensions: [nv_mesh_shader],
},
*/
}
@ -730,7 +736,7 @@ vulkan_bitflags! {
/*
// TODO: document
with_status = WITH_STATUS_KHR {
extensions: [khr_video_queue],
device_extensions: [khr_video_queue],
},
*/
}

View File

@ -4,7 +4,7 @@ use std::{
cmp,
cmp::Ordering,
collections::{btree_map, BTreeMap},
fmt::{self, Debug},
fmt::{Debug, Error as FmtError, Formatter},
iter::{FromIterator, FusedIterator, Peekable},
ops::{Add, Bound, Range, Sub},
};
@ -585,7 +585,7 @@ where
K: Ord + Clone,
V: Eq + Clone,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
f.debug_map().entries(self.iter()).finish()
}
}

View File

@ -14,12 +14,16 @@ use super::{
use crate::{
device::Device,
image::{ImageLayout, SampleCount},
macros::ExtensionNotEnabled,
sync::PipelineStages,
OomError, Version, VulkanError, VulkanObject,
OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
};
use smallvec::SmallVec;
use std::{error::Error, fmt, mem::MaybeUninit, ptr};
use std::{
error::Error,
fmt::{Display, Error as FmtError, Formatter},
mem::MaybeUninit,
ptr,
};
impl RenderPass {
pub(super) fn validate(
@ -79,24 +83,24 @@ impl RenderPass {
);
// VUID-VkAttachmentDescription2-samples-parameter
samples.validate(device)?;
samples.validate_device(device)?;
for load_op in [load_op, stencil_load_op] {
// VUID-VkAttachmentDescription2-loadOp-parameter
// VUID-VkAttachmentDescription2-stencilLoadOp-parameter
load_op.validate(device)?;
load_op.validate_device(device)?;
}
for store_op in [store_op, stencil_store_op] {
// VUID-VkAttachmentDescription2-storeOp-parameter
// VUID-VkAttachmentDescription2-stencilStoreOp-parameter
store_op.validate(device)?;
store_op.validate_device(device)?;
}
for layout in [initial_layout, final_layout] {
// VUID-VkAttachmentDescription2-initialLayout-parameter
// VUID-VkAttachmentDescription2-finalLayout-parameter
layout.validate(device)?;
layout.validate_device(device)?;
match layout {
ImageLayout::ColorAttachmentOptimal => {
@ -134,9 +138,12 @@ impl RenderPass {
// VUID-VkSubpassDescription2-multiview-06558
if is_multiview && !device.enabled_features().multiview {
return Err(RenderPassCreationError::FeatureNotEnabled {
feature: "multiview",
reason: "the subpasses specified a nonzero `view_mask`",
return Err(RenderPassCreationError::RequirementNotMet {
required_for: "`create_info.subpasses[0].view_mask` is not `0`",
requires_one_of: RequiresOneOf {
features: &["multiview"],
..Default::default()
},
});
}
@ -195,10 +202,10 @@ impl RenderPass {
// Common checks for all attachment types
let mut check_attachment = |atch_ref: &AttachmentReference| {
// VUID-VkAttachmentReference2-layout-parameter
atch_ref.layout.validate(device)?;
atch_ref.layout.validate_device(device)?;
// VUID?
atch_ref.aspects.validate(device)?;
atch_ref.aspects.validate_device(device)?;
// VUID-VkRenderPassCreateInfo2-attachment-03051
let atch = attachments.get(atch_ref.attachment as usize).ok_or(
@ -416,21 +423,14 @@ impl RenderPass {
|| device.enabled_extensions().khr_create_renderpass2
|| device.enabled_extensions().khr_maintenance2)
{
if device
.physical_device()
.supported_extensions()
.khr_create_renderpass2
{
return Err(RenderPassCreationError::ExtensionNotEnabled {
extension: "khr_create_renderpass2",
reason: "an attachment reference selected a subset of the `aspects` of the attachment's format",
return Err(RenderPassCreationError::RequirementNotMet {
required_for: "`create_info.subpasses` has an element, where `input_attachments` has an element that is `Some(atch_ref)`, where `atch_ref.aspects` does not match the aspects of the attachment itself",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_1),
device_extensions: &["khr_create_renderpass2", "khr_maintenance2"],
..Default::default()
},
});
} else {
return Err(RenderPassCreationError::ExtensionNotEnabled {
extension: "khr_maintenance2",
reason: "an attachment reference selected a subset of the `aspects` of the attachment's format",
});
}
}
// VUID-VkSubpassDescription2-attachment-02801
@ -600,18 +600,21 @@ impl RenderPass {
] {
// VUID-VkSubpassDependency2-srcStageMask-parameter
// VUID-VkSubpassDependency2-dstStageMask-parameter
stages.validate(device)?;
stages.validate_device(device)?;
// VUID-VkSubpassDependency2-srcAccessMask-parameter
// VUID-VkSubpassDependency2-dstAccessMask-parameter
access.validate(device)?;
access.validate_device(device)?;
// VUID-VkSubpassDependency2-srcStageMask-04090
// VUID-VkSubpassDependency2-dstStageMask-04090
if stages.geometry_shader && !device.enabled_features().geometry_shader {
return Err(RenderPassCreationError::FeatureNotEnabled {
feature: "geometry_shader",
reason: "a dependency specified the `geometry_shader` stage",
return Err(RenderPassCreationError::RequirementNotMet {
required_for: "`create_info.dependencies` has an element where `stages.geometry_shader` is set",
requires_one_of: RequiresOneOf {
features: &["geometry_shader"],
..Default::default()
},
});
}
@ -620,18 +623,25 @@ impl RenderPass {
if (stages.tessellation_control_shader || stages.tessellation_evaluation_shader)
&& !device.enabled_features().tessellation_shader
{
return Err(RenderPassCreationError::FeatureNotEnabled {
feature: "tessellation_shader",
reason: "a dependency specified the `tessellation_control_shader` or `tessellation_evaluation_shader` stage",
return Err(RenderPassCreationError::RequirementNotMet {
required_for: "`create_info.dependencies` has an element where `stages.tessellation_control_shader` or `stages.tessellation_evaluation_shader` are set",
requires_one_of: RequiresOneOf {
features: &["tessellation_shader"],
..Default::default()
},
});
}
// VUID-VkSubpassDependency2-srcStageMask-03937
// VUID-VkSubpassDependency2-dstStageMask-03937
if stages.is_empty() && !device.enabled_features().synchronization2 {
return Err(RenderPassCreationError::FeatureNotEnabled {
feature: "synchronization2",
reason: "a dependency specified no shader stages",
return Err(RenderPassCreationError::RequirementNotMet {
required_for:
"`create_info.dependencies` has an element where `stages` is empty",
requires_one_of: RequiresOneOf {
features: &["synchronization2"],
..Default::default()
},
});
}
@ -1367,13 +1377,9 @@ pub enum RenderPassCreationError {
/// Not enough memory.
OomError(OomError),
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
},
FeatureNotEnabled {
feature: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// An attachment is first used in the render pass with a read-only layout or as an input
@ -1541,74 +1547,76 @@ impl Error for RenderPassCreationError {
}
}
impl fmt::Display for RenderPassCreationError {
impl Display for RenderPassCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
Self::OomError(_) => write!(fmt, "not enough memory available",),
Self::ExtensionNotEnabled { extension, reason } => write!(
fmt,
"the extension {} must be enabled: {}",
extension, reason
Self::OomError(_) => write!(f, "not enough memory available",),
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::FeatureNotEnabled { feature, reason } => {
write!(fmt, "the feature {} must be enabled: {}", feature, reason)
}
Self::AttachmentFirstUseLoadOpInvalid { attachment, first_use_subpass } => write!(
fmt,
f,
"attachment {} is first used in the render pass in subpass {} with a read-only layout or as an input attachment, but its `load_op` or `stencil_load_op` is `LoadOp::Clear`",
attachment, first_use_subpass,
),
Self::AttachmentLayoutInvalid { attachment } => write!(
fmt,
f,
"attachment {} has an `initial_layout` or `final_layout` value that is invalid for the provided `format`",
attachment,
),
Self::CorrelatedViewMasksMultiviewNotEnabled => write!(
fmt,
f,
"correlated view masks were included, but multiview is not enabled on the render pass",
),
Self::CorrelatedViewMasksOverlapping => write!(
fmt,
f,
"the provided correlated view masks contain a bit that is set in more than one element",
),
Self::DependencyAccessNotSupportedByStages { dependency } => write!(
fmt,
f,
"subpass dependency {} specified an access type that was not supported by the given stages",
dependency,
),
Self::DependencySelfDependencyFramebufferStagesWithoutByRegion { dependency } => write!(
fmt,
f,
"subpass dependency {} specifies a subpass self-dependency and includes framebuffer stages in both `source_stages` and `destination_stages`, but the `by_region` dependency was not enabled",
dependency,
),
Self::DependencySelfDependencySourceStageAfterDestinationStage { dependency } => write!(
fmt,
f,
"subpass dependency {} specifies a subpass self-dependency and includes non-framebuffer stages, but the latest stage in `source_stages` is after the earliest stage in `destination_stages`",
dependency,
),
Self::DependencySelfDependencyViewLocalNonzeroOffset { dependency } => write!(
fmt,
f,
"subpass dependency {} specifies a subpass self-dependency and has the `view_local` dependency enabled, but the inner offset value was not 0",
dependency,
),
Self::DependencySelfDependencyViewMaskMultiple { dependency, subpass } => write!(
fmt,
f,
"subpass dependency {} specifies a subpass self-dependency without the `view_local` dependency, but the referenced subpass {} has more than one bit set in its `view_mask`",
dependency, subpass,
),
Self::DependencySourceSubpassAfterDestinationSubpass { dependency } => write!(
fmt,
f,
"subpass dependency {} has a `source_subpass` that is later than the `destination_subpass`",
dependency,
),
Self::DependencyStageNotSupported { dependency } => write!(
fmt,
f,
"subpass dependency {} has a bit set in the `source_stages` or `destination_stages` that is not supported for graphics pipelines",
dependency,
),
Self::DependencyBothSubpassesExternal { dependency } => write!(
fmt,
f,
"subpass dependency {} has both `source_subpass` and `destination_subpass` set to `None`",
dependency,
),
@ -1616,27 +1624,27 @@ impl fmt::Display for RenderPassCreationError {
dependency,
subpass,
} => write!(
fmt,
f,
"the subpass index {} in subpass dependency {} is not less than the number of subpasses in the render pass",
subpass, dependency,
),
Self::DependencyViewLocalExternalDependency { dependency } => write!(
fmt,
f,
"subpass dependency {} has the `view_local` dependency enabled, but `source_subpass` or `destination_subpass` were set to `None`",
dependency,
),
Self::DependencyViewLocalMultiviewNotEnabled { dependency } => write!(
fmt,
f,
"subpass dependency {} has the `view_local` dependency enabled, but multiview is not enabled on the render pass",
dependency,
),
Self::SubpassAttachmentAspectsNotEmpty { subpass, attachment } => write!(
fmt,
f,
"a reference to attachment {} used other than as an input attachment in subpass {} has one or more aspects selected",
attachment, subpass,
),
Self::SubpassAttachmentLayoutMismatch { subpass, attachment } => write!(
fmt,
f,
"the layouts of all uses of attachment {} in subpass {} do not match.",
attachment, subpass,
),
@ -1645,27 +1653,27 @@ impl fmt::Display for RenderPassCreationError {
attachment,
usage,
} => write!(
fmt,
f,
"attachment {} used as {} attachment in subpass {} has a layout that is not supported for that usage",
attachment, usage, subpass,
),
Self::SubpassAttachmentOutOfRange { subpass, attachment } => write!(
fmt,
f,
"the attachment index {} in subpass {} is not less than the number of attachments in the render pass",
attachment, subpass,
),
Self::SubpassAttachmentUsageColorDepthStencil { subpass, attachment } => write!(
fmt,
f,
"attachment {} is used as both a color attachment and a depth/stencil attachment in subpass {}",
attachment, subpass,
),
Self::SubpassAttachmentFormatUsageNotSupported { subpass, attachment, usage, } => write!(
fmt,
f,
"attachment {} used as {} attachment in subpass {} has a format that does not support that usage",
attachment, usage, subpass,
),
Self::SubpassColorAttachmentWithResolveNotMultisampled { subpass, attachment } => write!(
fmt,
f,
"attachment {} used as a color attachment in subpass {} with resolve attachments has a `samples` value of `SampleCount::Sample1`",
attachment, subpass,
),
@ -1675,37 +1683,37 @@ impl fmt::Display for RenderPassCreationError {
samples,
first_samples,
} => write!(
fmt,
f,
"attachment {} used as a color or depth/stencil attachment in subpass {} has a `samples` value {:?} that is different from the first color attachment ({:?})",
attachment, subpass, samples, first_samples,
),
Self::SubpassInputAttachmentAspectsNotCompatible { subpass, attachment } => write!(
fmt,
f,
"a reference to attachment {} used as an input attachment in subpass {} selects aspects that are not present in the format of the attachment",
attachment, subpass,
),
Self::SubpassMaxColorAttachmentsExceeded { .. } => {
write!(fmt, "the `max_color_attachments` limit has been exceeded",)
write!(f, "the `max_color_attachments` limit has been exceeded",)
}
Self::SubpassMaxMultiviewViewCountExceeded { .. } => {
write!(fmt, "the `max_multiview_view_count` limit has been exceeded for a subpass",)
write!(f, "the `max_multiview_view_count` limit has been exceeded for a subpass",)
},
Self::SubpassMultiviewMismatch {
subpass,
multiview,
first_subpass_multiview,
} => write!(
fmt,
f,
"the multiview state (whether `view_mask` is nonzero) of subpass {} is {}, which is different from the first subpass ({})",
subpass, multiview, first_subpass_multiview,
),
Self::SubpassPreserveAttachmentUsedElsewhere { subpass, attachment } => write!(
fmt,
f,
"attachment {} marked as a preserve attachment in subpass {} is also used as an attachment in that subpass",
attachment, subpass,
),
Self::SubpassResolveAttachmentsColorAttachmentsLenMismatch { subpass } => write!(
fmt,
f,
"the `resolve_attachments` field of subpass {} was not empty, but its length did not match the length of `color_attachments`",
subpass,
),
@ -1714,17 +1722,17 @@ impl fmt::Display for RenderPassCreationError {
resolve_attachment,
color_attachment,
} => write!(
fmt,
f,
"attachment {} used as a resolve attachment in subpass {} has a `format` value different from the corresponding color attachment {}",
subpass, resolve_attachment, color_attachment,
),
Self::SubpassResolveAttachmentMultisampled { subpass, attachment } => write!(
fmt,
f,
"attachment {} used as a resolve attachment in subpass {} has a `samples` value other than `SampleCount::Sample1`",
attachment, subpass,
),
Self::SubpassResolveAttachmentWithoutColorAttachment { subpass } => write!(
fmt,
f,
"a resolve attachment in subpass {} is `Some`, but the corresponding color attachment is `None`",
subpass,
),
@ -1754,12 +1762,12 @@ impl From<VulkanError> for RenderPassCreationError {
}
}
impl From<ExtensionNotEnabled> for RenderPassCreationError {
impl From<RequirementNotMet> for RenderPassCreationError {
#[inline]
fn from(err: ExtensionNotEnabled) -> Self {
Self::ExtensionNotEnabled {
extension: err.extension,
reason: err.reason,
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}

View File

@ -17,7 +17,7 @@ use crate::{
use smallvec::SmallVec;
use std::{
error::Error,
fmt,
fmt::{Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},
mem::MaybeUninit,
ops::Range,
@ -602,26 +602,26 @@ impl Error for FramebufferCreationError {
}
}
impl fmt::Display for FramebufferCreationError {
impl Display for FramebufferCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
Self::OomError(_) => write!(
fmt,
f,
"no memory available",
),
Self::Attachment2dArrayCompatibleDepthStencil { attachment } => write!(
fmt,
f,
"attachment image {} is a 2D image view created from a 3D image, and has a depth/stencil format",
attachment,
),
Self::AttachmentComponentMappingNotIdentity { attachment } => write!(
fmt,
f,
"attachment image {} has a non-identity component mapping",
attachment,
),
Self::AttachmentCountMismatch { .. } => write!(
fmt,
f,
"the number of attachments doesn't match the number expected by the render pass",
),
Self::AttachmentExtentTooSmall {
@ -629,7 +629,7 @@ impl fmt::Display for FramebufferCreationError {
provided,
min,
} => write!(
fmt,
f,
"attachment image {} has an extent ({:?}) smaller than the provided `extent` ({:?})",
attachment, provided, min,
),
@ -638,7 +638,7 @@ impl fmt::Display for FramebufferCreationError {
provided,
required,
} => write!(
fmt,
f,
"attachment image {} has a `format` ({:?}) different from what the render pass requires ({:?})",
attachment, provided, required,
),
@ -646,14 +646,14 @@ impl fmt::Display for FramebufferCreationError {
attachment,
usage,
} => write!(
fmt,
f,
"attachment image {} is missing usage `{}` that the render pass requires it to have",
attachment, usage,
),
Self::AttachmentMultipleMipLevels {
attachment,
} => write!(
fmt,
f,
"attachment image {} has multiple mip levels",
attachment,
),
@ -662,7 +662,7 @@ impl fmt::Display for FramebufferCreationError {
provided,
min,
} => write!(
fmt,
f,
"attachment image {} has less layers ({}) than the provided `layers` ({})",
attachment, provided, min,
),
@ -671,32 +671,32 @@ impl fmt::Display for FramebufferCreationError {
provided,
required,
} => write!(
fmt,
f,
"attachment image {} has a `samples` ({:?}) different from what the render pass requires ({:?})",
attachment, provided, required,
),
Self::AttachmentViewType3d {
attachment,
} => write!(
fmt,
f,
"attachment image {} has a `ty` of `ImageViewType::Dim3d`",
attachment,
),
Self::AutoExtentAttachmentsEmpty => write!(
fmt,
f,
"one of the elements of `extent` is zero, but no attachment images were given to calculate the extent from",
),
Self::AutoLayersAttachmentsEmpty => write!(
fmt,
f,
"`layers` is zero, but no attachment images were given to calculate the number of layers from",
),
Self::MaxFramebufferExtentExceeded { provided, max } => write!(
fmt,
f,
"the provided `extent` ({:?}) exceeds the `max_framebuffer_width` or `max_framebuffer_height` limits ({:?})",
provided, max,
),
Self::MaxFramebufferLayersExceeded { provided, max } => write!(
fmt,
f,
"the provided `layers` ({}) exceeds the `max_framebuffer_layers` limit ({})",
provided, max,
),
@ -705,12 +705,12 @@ impl fmt::Display for FramebufferCreationError {
provided,
min,
} => write!(
fmt,
f,
"the render pass has multiview enabled, and attachment image {} has less layers ({}) than the number of views in the render pass ({})",
attachment, provided, min,
),
Self::MultiviewLayersInvalid => write!(
fmt,
f,
"the render pass has multiview enabled, but `layers` was not 0 or 1",
),
}

View File

@ -1124,7 +1124,7 @@ vulkan_enum! {
/*
// TODO: document
None = NONE_EXT {
extensions: [ext_load_store_op_none],
device_extensions: [ext_load_store_op_none],
},
*/
}
@ -1155,7 +1155,7 @@ vulkan_enum! {
// TODO: document
None = NONE {
api_version: V1_3,
extensions: [ext_load_store_op_none],
device_extensions: [ext_load_store_op_none],
},
*/
}

View File

@ -50,14 +50,14 @@ use self::ycbcr::SamplerYcbcrConversion;
use crate::{
device::{Device, DeviceOwned},
image::{view::ImageViewType, ImageViewAbstract},
macros::{vulkan_enum, ExtensionNotEnabled},
macros::vulkan_enum,
pipeline::graphics::depth_stencil::CompareOp,
shader::ShaderScalarType,
OomError, VulkanError, VulkanObject,
OomError, RequirementNotMet, RequiresOneOf, VulkanError, VulkanObject,
};
use std::{
error::Error,
fmt,
fmt::{Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},
mem::MaybeUninit,
ops::RangeInclusive,
@ -143,46 +143,36 @@ impl Sampler {
for filter in [mag_filter, min_filter] {
// VUID-VkSamplerCreateInfo-magFilter-parameter
// VUID-VkSamplerCreateInfo-minFilter-parameter
filter.validate(&device)?;
filter.validate_device(&device)?;
}
// VUID-VkSamplerCreateInfo-mipmapMode-parameter
mipmap_mode.validate(&device)?;
mipmap_mode.validate_device(&device)?;
for mode in address_mode {
// VUID-VkSamplerCreateInfo-addressModeU-parameter
// VUID-VkSamplerCreateInfo-addressModeV-parameter
// VUID-VkSamplerCreateInfo-addressModeW-parameter
mode.validate(&device)?;
mode.validate_device(&device)?;
if mode == SamplerAddressMode::ClampToBorder {
// VUID-VkSamplerCreateInfo-addressModeU-01078
border_color.validate(&device)?;
border_color.validate_device(&device)?;
}
}
if address_mode
.into_iter()
.any(|mode| mode == SamplerAddressMode::MirrorClampToEdge)
{
if address_mode.contains(&SamplerAddressMode::MirrorClampToEdge) {
if !device.enabled_features().sampler_mirror_clamp_to_edge
&& !device.enabled_extensions().khr_sampler_mirror_clamp_to_edge
{
if device
.physical_device()
.supported_features()
.sampler_mirror_clamp_to_edge
{
return Err(SamplerCreationError::FeatureNotEnabled {
feature: "sampler_mirror_clamp_to_edge",
reason: "one or more address modes were MirrorClampToEdge",
return Err(SamplerCreationError::RequirementNotMet {
required_for: "`create_info.address_mode` contains `SamplerAddressMode::MirrorClampToEdge`",
requires_one_of: RequiresOneOf {
features: &["sampler_mirror_clamp_to_edge"],
device_extensions: &["khr_sampler_mirror_clamp_to_edge"],
..Default::default()
},
});
} else {
return Err(SamplerCreationError::ExtensionNotEnabled {
extension: "khr_sampler_mirror_clamp_to_edge",
reason: "one or more address modes were MirrorClampToEdge",
});
}
}
}
@ -201,9 +191,12 @@ impl Sampler {
assert!(max_anisotropy >= 1.0);
if !device.enabled_features().sampler_anisotropy {
return Err(SamplerCreationError::FeatureNotEnabled {
feature: "sampler_anisotropy",
reason: "anisotropy was set to `Some`",
return Err(SamplerCreationError::RequirementNotMet {
required_for: "`create_info.anisotropy` is `Some`",
requires_one_of: RequiresOneOf {
features: &["sampler_anisotropy"],
..Default::default()
},
});
}
@ -232,7 +225,7 @@ impl Sampler {
let (compare_enable, compare_op) = if let Some(compare_op) = compare {
// VUID-VkSamplerCreateInfo-compareEnable-01080
compare_op.validate(&device)?;
compare_op.validate_device(&device)?;
if reduction_mode != SamplerReductionMode::WeightedAverage {
return Err(SamplerCreationError::CompareInvalidReductionMode { reduction_mode });
@ -285,30 +278,24 @@ impl Sampler {
}
}
let mut sampler_reduction_mode_create_info =
if reduction_mode != SamplerReductionMode::WeightedAverage {
let mut sampler_reduction_mode_create_info = if reduction_mode
!= SamplerReductionMode::WeightedAverage
{
if !(device.enabled_features().sampler_filter_minmax
|| device.enabled_extensions().ext_sampler_filter_minmax)
{
if device
.physical_device()
.supported_features()
.sampler_filter_minmax
{
return Err(SamplerCreationError::FeatureNotEnabled {
feature: "sampler_filter_minmax",
reason: "reduction_mode was not WeightedAverage",
return Err(SamplerCreationError::RequirementNotMet {
required_for: "`create_info.reduction_mode` is not `SamplerReductionMode::WeightedAverage`",
requires_one_of: RequiresOneOf {
features: &["sampler_filter_minmax"],
device_extensions: &["ext_sampler_filter_minmax"],
..Default::default()
},
});
} else {
return Err(SamplerCreationError::ExtensionNotEnabled {
extension: "ext_sampler_filter_minmax",
reason: "reduction_mode was not WeightedAverage",
});
}
}
// VUID-VkSamplerReductionModeCreateInfo-reductionMode-parameter
reduction_mode.validate(&device)?;
reduction_mode.validate_device(&device)?;
Some(ash::vk::SamplerReductionModeCreateInfo {
reduction_mode: reduction_mode.into(),
@ -780,13 +767,9 @@ pub enum SamplerCreationError {
/// Note the specs guarantee that at least 4000 samplers can exist simultaneously.
TooManyObjects,
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
},
FeatureNotEnabled {
feature: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// Anisotropy was enabled with an invalid filter.
@ -878,59 +861,61 @@ impl Error for SamplerCreationError {
}
}
impl fmt::Display for SamplerCreationError {
impl Display for SamplerCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
Self::OomError(_) => write!(fmt, "not enough memory available"),
Self::TooManyObjects => write!(fmt, "too many simultaneous sampler objects",),
Self::ExtensionNotEnabled { extension, reason } => write!(
fmt,
"the extension {} must be enabled: {}",
extension, reason
Self::OomError(_) => write!(f, "not enough memory available"),
Self::TooManyObjects => write!(f, "too many simultaneous sampler objects",),
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::FeatureNotEnabled { feature, reason } => {
write!(fmt, "the feature {} must be enabled: {}", feature, reason)
}
Self::AnisotropyInvalidFilter { .. } => write!(fmt, "anisotropy was enabled with an invalid filter"),
Self::CompareInvalidReductionMode { .. } => write!(fmt, "depth comparison was enabled with an invalid reduction mode"),
Self::AnisotropyInvalidFilter { .. } => write!(f, "anisotropy was enabled with an invalid filter"),
Self::CompareInvalidReductionMode { .. } => write!(f, "depth comparison was enabled with an invalid reduction mode"),
Self::MaxSamplerAnisotropyExceeded { .. } => {
write!(fmt, "max_sampler_anisotropy limit exceeded")
write!(f, "max_sampler_anisotropy limit exceeded")
}
Self::MaxSamplerLodBiasExceeded { .. } => write!(fmt, "mip lod bias limit exceeded"),
Self::MaxSamplerLodBiasExceeded { .. } => write!(f, "mip lod bias limit exceeded"),
Self::SamplerYcbcrConversionAnisotropyEnabled => write!(
fmt,
f,
"sampler YCbCr conversion was enabled together with anisotropy"
),
Self::SamplerYcbcrConversionChromaFilterMismatch { .. } => write!(fmt, "sampler YCbCr conversion was enabled, and its format does not support `sampled_image_ycbcr_conversion_separate_reconstruction_filter`, but `mag_filter` or `min_filter` did not match the conversion's `chroma_filter`"),
Self::SamplerYcbcrConversionInvalidAddressMode { .. } => write!(fmt, "sampler YCbCr conversion was enabled, but the address mode for u, v or w was something other than `ClampToEdge`"),
Self::SamplerYcbcrConversionInvalidReductionMode { .. } => write!(fmt, "sampler YCbCr conversion was enabled, but the reduction mode was something other than `WeightedAverage`"),
Self::SamplerYcbcrConversionChromaFilterMismatch { .. } => write!(f, "sampler YCbCr conversion was enabled, and its format does not support `sampled_image_ycbcr_conversion_separate_reconstruction_filter`, but `mag_filter` or `min_filter` did not match the conversion's `chroma_filter`"),
Self::SamplerYcbcrConversionInvalidAddressMode { .. } => write!(f, "sampler YCbCr conversion was enabled, but the address mode for u, v or w was something other than `ClampToEdge`"),
Self::SamplerYcbcrConversionInvalidReductionMode { .. } => write!(f, "sampler YCbCr conversion was enabled, but the reduction mode was something other than `WeightedAverage`"),
Self::SamplerYcbcrConversionUnnormalizedCoordinatesEnabled => write!(
fmt,
f,
"sampler YCbCr conversion was enabled together with unnormalized coordinates"
),
Self::UnnormalizedCoordinatesAnisotropyEnabled => write!(
fmt,
f,
"unnormalized coordinates were enabled together with anisotropy"
),
Self::UnnormalizedCoordinatesCompareEnabled => write!(
fmt,
f,
"unnormalized coordinates were enabled together with depth comparison"
),
Self::UnnormalizedCoordinatesFiltersNotEqual { .. } => write!(
fmt,
f,
"unnormalized coordinates were enabled, but the min and mag filters were not equal"
),
Self::UnnormalizedCoordinatesInvalidAddressMode { .. } => write!(
fmt,
f,
"unnormalized coordinates were enabled, but the address mode for u or v was something other than `ClampToEdge` or `ClampToBorder`"
),
Self::UnnormalizedCoordinatesInvalidMipmapMode { .. } => write!(
fmt,
f,
"unnormalized coordinates were enabled, but the mipmap mode was not `Nearest`"
),
Self::UnnormalizedCoordinatesNonzeroLod { .. } => write!(
fmt,
f,
"unnormalized coordinates were enabled, but the LOD range was not zero"
),
}
@ -956,12 +941,12 @@ impl From<VulkanError> for SamplerCreationError {
}
}
impl From<ExtensionNotEnabled> for SamplerCreationError {
impl From<RequirementNotMet> for SamplerCreationError {
#[inline]
fn from(err: ExtensionNotEnabled) -> Self {
Self::ExtensionNotEnabled {
extension: err.extension,
reason: err.reason,
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}
@ -1318,7 +1303,7 @@ vulkan_enum! {
/// be enabled on the device, and anisotropy must be disabled. Sampled image views must have
/// a type of [`Dim2d`](crate::image::view::ImageViewType::Dim2d).
Cubic = CUBIC_EXT {
extensions: [ext_filter_cubic, img_filter_cubic],
device_extensions: [ext_filter_cubic, img_filter_cubic],
},
}
@ -1372,7 +1357,7 @@ vulkan_enum! {
/// extension must be enabled on the device.
MirrorClampToEdge = MIRROR_CLAMP_TO_EDGE {
api_version: V1_2,
extensions: [khr_sampler_mirror_clamp_to_edge],
device_extensions: [khr_sampler_mirror_clamp_to_edge],
},
}
@ -1407,12 +1392,12 @@ vulkan_enum! {
/*
// TODO: document
FloatCustom = VK_BORDER_COLOR_FLOAT_CUSTOM_EXT {
extensions: [ext_custom_border_color],
device_extensions: [ext_custom_border_color],
},
// TODO: document
IntCustom = INT_CUSTOM_EXT {
extensions: [ext_custom_border_color],
device_extensions: [ext_custom_border_color],
},
*/
}
@ -1485,19 +1470,19 @@ pub enum SamplerImageViewIncompatibleError {
impl Error for SamplerImageViewIncompatibleError {}
impl fmt::Display for SamplerImageViewIncompatibleError {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
impl Display for SamplerImageViewIncompatibleError {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::BorderColorFormatNotCompatible => write!(fmt, "the sampler has a border color with a numeric type different from the image view"),
Self::BorderColorOpaqueBlackNotIdentitySwizzled => write!(fmt, "the sampler has an opaque black border color, but the image view is not identity swizzled"),
Self::DepthComparisonNotSupported => write!(fmt, "the sampler has depth comparison enabled, but this is not supported by the image view"),
Self::DepthComparisonWrongAspect => write!(fmt, "the sampler has depth comparison enabled, but the image view does not select the `depth` aspect"),
Self::FilterLinearNotSupported => write!(fmt, "the sampler uses a linear filter, but this is not supported by the image view's format features"),
Self::FilterCubicNotSupported => write!(fmt, "the sampler uses a cubic filter, but this is not supported by the image view's format features"),
Self::FilterCubicMinmaxNotSupported => write!(fmt, "the sampler uses a cubic filter with a `Min` or `Max` reduction mode, but this is not supported by the image view's format features"),
Self::MipmapModeLinearNotSupported => write!(fmt, "the sampler uses a linear mipmap mode, but this is not supported by the image view's format features"),
Self::UnnormalizedCoordinatesMultipleMipLevels => write!(fmt, "the sampler uses unnormalized coordinates, but the image view has multiple mip levels"),
Self::UnnormalizedCoordinatesViewTypeNotCompatible => write!(fmt, "the sampler uses unnormalized coordinates, but the image view has a type other than `Dim1d` or `Dim2d`"),
Self::BorderColorFormatNotCompatible => write!(f, "the sampler has a border color with a numeric type different from the image view"),
Self::BorderColorOpaqueBlackNotIdentitySwizzled => write!(f, "the sampler has an opaque black border color, but the image view is not identity swizzled"),
Self::DepthComparisonNotSupported => write!(f, "the sampler has depth comparison enabled, but this is not supported by the image view"),
Self::DepthComparisonWrongAspect => write!(f, "the sampler has depth comparison enabled, but the image view does not select the `depth` aspect"),
Self::FilterLinearNotSupported => write!(f, "the sampler uses a linear filter, but this is not supported by the image view's format features"),
Self::FilterCubicNotSupported => write!(f, "the sampler uses a cubic filter, but this is not supported by the image view's format features"),
Self::FilterCubicMinmaxNotSupported => write!(f, "the sampler uses a cubic filter with a `Min` or `Max` reduction mode, but this is not supported by the image view's format features"),
Self::MipmapModeLinearNotSupported => write!(f, "the sampler uses a linear mipmap mode, but this is not supported by the image view's format features"),
Self::UnnormalizedCoordinatesMultipleMipLevels => write!(f, "the sampler uses unnormalized coordinates, but the image view has multiple mip levels"),
Self::UnnormalizedCoordinatesViewTypeNotCompatible => write!(f, "the sampler uses unnormalized coordinates, but the image view has a type other than `Dim1d` or `Dim2d`"),
}
}
}
@ -1510,6 +1495,7 @@ mod tests {
Filter, Sampler, SamplerAddressMode, SamplerCreateInfo, SamplerCreationError,
SamplerReductionMode,
},
RequiresOneOf,
};
#[test]
@ -1640,10 +1626,10 @@ mod tests {
);
match r {
Err(SamplerCreationError::FeatureNotEnabled {
feature: "sampler_anisotropy",
Err(SamplerCreationError::RequirementNotMet {
requires_one_of: RequiresOneOf { features, .. },
..
}) => (),
}) if features.contains(&"sampler_anisotropy") => (),
_ => panic!(),
}
}
@ -1710,16 +1696,16 @@ mod tests {
);
match r {
Err(
SamplerCreationError::FeatureNotEnabled {
feature: "sampler_mirror_clamp_to_edge",
..
}
| SamplerCreationError::ExtensionNotEnabled {
extension: "khr_sampler_mirror_clamp_to_edge",
Err(SamplerCreationError::RequirementNotMet {
requires_one_of:
RequiresOneOf {
features,
device_extensions,
..
},
) => (),
..
}) if features.contains(&"sampler_mirror_clamp_to_edge")
&& device_extensions.contains(&"khr_sampler_mirror_clamp_to_edge") => {}
_ => panic!(),
}
}
@ -1739,16 +1725,16 @@ mod tests {
);
match r {
Err(
SamplerCreationError::FeatureNotEnabled {
feature: "sampler_filter_minmax",
..
}
| SamplerCreationError::ExtensionNotEnabled {
extension: "ext_sampler_filter_minmax",
Err(SamplerCreationError::RequirementNotMet {
requires_one_of:
RequiresOneOf {
features,
device_extensions,
..
},
) => (),
..
}) if features.contains(&"sampler_filter_minmax")
&& device_extensions.contains(&"ext_sampler_filter_minmax") => {}
_ => panic!(),
}
}

View File

@ -87,13 +87,13 @@
use crate::{
device::{Device, DeviceOwned},
format::{ChromaSampling, Format, NumericType},
macros::{vulkan_enum, ExtensionNotEnabled},
macros::vulkan_enum,
sampler::{ComponentMapping, ComponentSwizzle, Filter},
OomError, Version, VulkanError, VulkanObject,
OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
};
use std::{
error::Error,
fmt,
fmt::{Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},
mem::MaybeUninit,
ptr,
@ -136,38 +136,41 @@ impl SamplerYcbcrConversion {
} = create_info;
if !device.enabled_features().sampler_ycbcr_conversion {
return Err(SamplerYcbcrConversionCreationError::FeatureNotEnabled {
feature: "sampler_ycbcr_conversion",
reason: "tried to create a SamplerYcbcrConversion",
return Err(SamplerYcbcrConversionCreationError::RequirementNotMet {
required_for: "`SamplerYcbcrConversion`",
requires_one_of: RequiresOneOf {
features: &["sampler_ycbcr_conversion"],
..Default::default()
},
});
}
// VUID-VkSamplerYcbcrConversionCreateInfo-ycbcrModel-parameter
ycbcr_model.validate(&device)?;
ycbcr_model.validate_device(&device)?;
// VUID-VkSamplerYcbcrConversionCreateInfo-ycbcrRange-parameter
ycbcr_range.validate(&device)?;
ycbcr_range.validate_device(&device)?;
// VUID-VkComponentMapping-r-parameter
component_mapping.r.validate(&device)?;
component_mapping.r.validate_device(&device)?;
// VUID-VkComponentMapping-g-parameter
component_mapping.g.validate(&device)?;
component_mapping.g.validate_device(&device)?;
// VUID-VkComponentMapping-b-parameter
component_mapping.b.validate(&device)?;
component_mapping.b.validate_device(&device)?;
// VUID-VkComponentMapping-a-parameter
component_mapping.a.validate(&device)?;
component_mapping.a.validate_device(&device)?;
for offset in chroma_offset {
// VUID-VkSamplerYcbcrConversionCreateInfo-xChromaOffset-parameter
// VUID-VkSamplerYcbcrConversionCreateInfo-yChromaOffset-parameter
offset.validate(&device)?;
offset.validate_device(&device)?;
}
// VUID-VkSamplerYcbcrConversionCreateInfo-chromaFilter-parameter
chroma_filter.validate(&device)?;
chroma_filter.validate_device(&device)?;
let format = match format {
Some(f) => f,
@ -508,13 +511,9 @@ pub enum SamplerYcbcrConversionCreationError {
/// Not enough memory.
OomError(OomError),
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
},
FeatureNotEnabled {
feature: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// The `Cubic` filter was specified.
@ -559,17 +558,20 @@ impl Error for SamplerYcbcrConversionCreationError {
}
}
impl fmt::Display for SamplerYcbcrConversionCreationError {
impl Display for SamplerYcbcrConversionCreationError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
Self::OomError(_) => write!(f, "not enough memory available"),
Self::ExtensionNotEnabled { extension, reason } => {
write!(f, "the extension {} must be enabled: {}", extension, reason)
}
Self::FeatureNotEnabled { feature, reason } => {
write!(f, "the feature {} must be enabled: {}", feature, reason)
}
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::CubicFilterNotSupported => {
write!(f, "the `Cubic` filter was specified")
@ -636,12 +638,12 @@ impl From<VulkanError> for SamplerYcbcrConversionCreationError {
}
}
impl From<ExtensionNotEnabled> for SamplerYcbcrConversionCreationError {
impl From<RequirementNotMet> for SamplerYcbcrConversionCreationError {
#[inline]
fn from(err: ExtensionNotEnabled) -> Self {
Self::ExtensionNotEnabled {
extension: err.extension,
reason: err.reason,
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}
@ -790,6 +792,7 @@ vulkan_enum! {
#[cfg(test)]
mod tests {
use super::{SamplerYcbcrConversion, SamplerYcbcrConversionCreationError};
use crate::RequiresOneOf;
#[test]
fn feature_not_enabled() {
@ -798,10 +801,10 @@ mod tests {
let r = SamplerYcbcrConversion::new(device, Default::default());
match r {
Err(SamplerYcbcrConversionCreationError::FeatureNotEnabled {
feature: "sampler_ycbcr_conversion",
Err(SamplerYcbcrConversionCreationError::RequirementNotMet {
requires_one_of: RequiresOneOf { features, .. },
..
}) => (),
}) if features.contains(&"sampler_ycbcr_conversion") => (),
_ => panic!(),
}
}

View File

@ -33,8 +33,7 @@ use std::{
collections::{HashMap, HashSet},
error::Error,
ffi::{CStr, CString},
fmt,
fmt::Display,
fmt::{Display, Error as FmtError, Formatter},
mem,
mem::MaybeUninit,
ptr,
@ -308,7 +307,7 @@ impl Error for ShaderCreationError {
}
impl Display for ShaderCreationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::OomError(_) => write!(f, "not enough memory available"),
Self::SpirvCapabilityNotSupported { capability, .. } => write!(
@ -353,7 +352,7 @@ pub enum ShaderSupportError {
impl Error for ShaderSupportError {}
impl Display for ShaderSupportError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::NotSupportedByVulkan => write!(f, "not supported by Vulkan"),
Self::RequirementsNotMet(requirements) => write!(
@ -686,24 +685,24 @@ pub enum DescriptorRequirementsIncompatible {
impl Error for DescriptorRequirementsIncompatible {}
impl Display for DescriptorRequirementsIncompatible {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
DescriptorRequirementsIncompatible::DescriptorType => write!(
fmt,
f,
"the allowed descriptor types of the two descriptors do not overlap",
),
DescriptorRequirementsIncompatible::ImageFormat => {
write!(fmt, "the descriptors require different formats",)
write!(f, "the descriptors require different formats",)
}
DescriptorRequirementsIncompatible::ImageMultisampled => write!(
fmt,
f,
"the multisampling requirements of the descriptors differ",
),
DescriptorRequirementsIncompatible::ImageScalarType => {
write!(fmt, "the descriptors require different scalar types",)
write!(f, "the descriptors require different scalar types",)
}
DescriptorRequirementsIncompatible::ImageViewType => {
write!(fmt, "the descriptors require different image view types",)
write!(f, "the descriptors require different image view types",)
}
}
}
@ -1020,11 +1019,11 @@ pub enum ShaderInterfaceMismatchError {
impl Error for ShaderInterfaceMismatchError {}
impl fmt::Display for ShaderInterfaceMismatchError {
impl Display for ShaderInterfaceMismatchError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
fmt,
f,
"{}",
match *self {
ShaderInterfaceMismatchError::ElementsCountMismatch { .. } => {
@ -1064,48 +1063,48 @@ vulkan_enum! {
// TODO: document
Raygen = RAYGEN_KHR {
extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
},
// TODO: document
AnyHit = ANY_HIT_KHR {
extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
},
// TODO: document
ClosestHit = CLOSEST_HIT_KHR {
extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
},
// TODO: document
Miss = MISS_KHR {
extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
},
// TODO: document
Intersection = INTERSECTION_KHR {
extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
},
// TODO: document
Callable = CALLABLE_KHR {
extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
},
/*
// TODO: document
Task = TASK_NV {
extensions: [nv_mesh_shader],
device_extensions: [nv_mesh_shader],
},
// TODO: document
Mesh = MESH_NV {
extensions: [nv_mesh_shader],
device_extensions: [nv_mesh_shader],
},
// TODO: document
SubpassShading = SUBPASS_SHADING_HUAWEI {
extensions: [huawei_subpass_shading],
device_extensions: [huawei_subpass_shading],
},
*/
}
@ -1211,48 +1210,48 @@ vulkan_bitflags! {
// TODO: document
raygen = RAYGEN_KHR {
extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
},
// TODO: document
any_hit = ANY_HIT_KHR {
extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
},
// TODO: document
closest_hit = CLOSEST_HIT_KHR {
extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
},
// TODO: document
miss = MISS_KHR {
extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
},
// TODO: document
intersection = INTERSECTION_KHR {
extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
},
// TODO: document
callable = CALLABLE_KHR {
extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
},
/*
// TODO: document
task = TASK_NV {
extensions: [nv_mesh_shader],
device_extensions: [nv_mesh_shader],
},
// TODO: document
mesh = MESH_NV {
extensions: [nv_mesh_shader],
device_extensions: [nv_mesh_shader],
},
// TODO: document
subpass_shading = SUBPASS_SHADING_HUAWEI {
extensions: [huawei_subpass_shading],
device_extensions: [huawei_subpass_shading],
},
*/
}

View File

@ -19,7 +19,7 @@ use crate::Version;
use std::{
collections::HashMap,
error::Error,
fmt::{self, Display, Formatter},
fmt::{Display, Error as FmtError, Formatter},
ops::Range,
string::FromUtf8Error,
};
@ -571,7 +571,7 @@ impl From<Id> for u32 {
}
impl Display for Id {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(f, "%{}", self.0)
}
}
@ -687,7 +687,7 @@ pub enum SpirvError {
impl Display for SpirvError {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
match self {
Self::BadLayout { index } => write!(
f,
@ -746,7 +746,7 @@ pub struct ParseError {
impl Display for ParseError {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
write!(
f,
"at instruction {}, word {}: {}",
@ -771,7 +771,7 @@ pub enum ParseErrors {
impl Display for ParseErrors {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
match self {
Self::FromUtf8Error(_) => write!(f, "invalid UTF-8 in string literal"),
Self::LeftoverOperands => write!(f, "unparsed operands remaining"),

View File

@ -32,7 +32,13 @@ use crate::{
device::physical::PhysicalDevice, instance::Instance, swapchain::SupportedSurfaceTransforms,
OomError, VulkanError, VulkanObject,
};
use std::{ffi::CStr, fmt, fmt::Formatter, ptr, sync::Arc, vec::IntoIter};
use std::{
ffi::CStr,
fmt::{Display as FmtDisplay, Error as FmtError, Formatter},
ptr,
sync::Arc,
vec::IntoIter,
};
// TODO: extract this to a `display` module and solve the visibility problems
@ -421,9 +427,9 @@ impl DisplayMode {
}
}
impl fmt::Display for DisplayMode {
impl FmtDisplay for DisplayMode {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
let visible_region = self.visible_region();
write!(

View File

@ -16,7 +16,7 @@ use crate::{
display::{DisplayMode, DisplayPlane},
SurfaceSwapchainLock,
},
OomError, VulkanError, VulkanObject,
OomError, RequiresOneOf, VulkanError, VulkanObject,
};
#[cfg(target_os = "ios")]
@ -24,7 +24,7 @@ use objc::{class, msg_send, runtime::Object, sel, sel_impl};
use std::{
error::Error,
fmt,
fmt::{Debug, Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},
mem::MaybeUninit,
os::raw::c_ulong,
@ -91,8 +91,12 @@ impl<W> Surface<W> {
.enabled_extensions()
.khr_display
{
return Err(SurfaceCreationError::MissingExtension {
name: "VK_KHR_display",
return Err(SurfaceCreationError::RequirementNotMet {
required_for: "`from_display_plane`",
requires_one_of: RequiresOneOf {
instance_extensions: &["khr_display"],
..Default::default()
},
});
}
@ -159,8 +163,12 @@ impl<W> Surface<W> {
win: W,
) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
if !instance.enabled_extensions().khr_android_surface {
return Err(SurfaceCreationError::MissingExtension {
name: "VK_KHR_android_surface",
return Err(SurfaceCreationError::RequirementNotMet {
required_for: "`from_android`",
requires_one_of: RequiresOneOf {
instance_extensions: &["khr_android_surface"],
..Default::default()
},
});
}
@ -211,8 +219,12 @@ impl<W> Surface<W> {
win: W,
) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
if !instance.enabled_extensions().mvk_ios_surface {
return Err(SurfaceCreationError::MissingExtension {
name: "VK_MVK_ios_surface",
return Err(SurfaceCreationError::RequirementNotMet {
required_for: "`from_ios`",
requires_one_of: RequiresOneOf {
instance_extensions: &["mvk_ios_surface"],
..Default::default()
},
});
}
@ -262,8 +274,12 @@ impl<W> Surface<W> {
win: W,
) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
if !instance.enabled_extensions().mvk_macos_surface {
return Err(SurfaceCreationError::MissingExtension {
name: "VK_MVK_macos_surface",
return Err(SurfaceCreationError::RequirementNotMet {
required_for: "`from_mac_os`",
requires_one_of: RequiresOneOf {
instance_extensions: &["mvk_macos_surface"],
..Default::default()
},
});
}
@ -312,8 +328,12 @@ impl<W> Surface<W> {
win: W,
) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
if !instance.enabled_extensions().ext_metal_surface {
return Err(SurfaceCreationError::MissingExtension {
name: "VK_EXT_metal_surface",
return Err(SurfaceCreationError::RequirementNotMet {
required_for: "`from_metal`",
requires_one_of: RequiresOneOf {
instance_extensions: &["ext_metal_surface"],
..Default::default()
},
});
}
@ -362,8 +382,12 @@ impl<W> Surface<W> {
win: W,
) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
if !instance.enabled_extensions().nn_vi_surface {
return Err(SurfaceCreationError::MissingExtension {
name: "VK_NN_vi_surface",
return Err(SurfaceCreationError::RequirementNotMet {
required_for: "`from_vi`",
requires_one_of: RequiresOneOf {
instance_extensions: &["nn_vi_surface"],
..Default::default()
},
});
}
@ -415,8 +439,12 @@ impl<W> Surface<W> {
win: W,
) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
if !instance.enabled_extensions().khr_wayland_surface {
return Err(SurfaceCreationError::MissingExtension {
name: "VK_KHR_wayland_surface",
return Err(SurfaceCreationError::RequirementNotMet {
required_for: "`from_wayland`",
requires_one_of: RequiresOneOf {
instance_extensions: &["khr_wayland_surface"],
..Default::default()
},
});
}
@ -469,8 +497,12 @@ impl<W> Surface<W> {
win: W,
) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
if !instance.enabled_extensions().khr_win32_surface {
return Err(SurfaceCreationError::MissingExtension {
name: "VK_KHR_win32_surface",
return Err(SurfaceCreationError::RequirementNotMet {
required_for: "`from_win32`",
requires_one_of: RequiresOneOf {
instance_extensions: &["khr_win32_surface"],
..Default::default()
},
});
}
@ -523,8 +555,12 @@ impl<W> Surface<W> {
win: W,
) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
if !instance.enabled_extensions().khr_xcb_surface {
return Err(SurfaceCreationError::MissingExtension {
name: "VK_KHR_xcb_surface",
return Err(SurfaceCreationError::RequirementNotMet {
required_for: "`from_xcb`",
requires_one_of: RequiresOneOf {
instance_extensions: &["khr_xcb_surface"],
..Default::default()
},
});
}
@ -577,8 +613,12 @@ impl<W> Surface<W> {
win: W,
) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
if !instance.enabled_extensions().khr_xlib_surface {
return Err(SurfaceCreationError::MissingExtension {
name: "VK_KHR_xlib_surface",
return Err(SurfaceCreationError::RequirementNotMet {
required_for: "`from_xlib`",
requires_one_of: RequiresOneOf {
instance_extensions: &["khr_xlib_surface"],
..Default::default()
},
});
}
@ -675,9 +715,9 @@ unsafe impl<W> VulkanObject for Surface<W> {
}
}
impl<W> fmt::Debug for Surface<W> {
impl<W> Debug for Surface<W> {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
let Self {
handle,
instance,
@ -687,7 +727,7 @@ impl<W> fmt::Debug for Surface<W> {
..
} = self;
fmt.debug_struct("Surface")
f.debug_struct("Surface")
.field("handle", handle)
.field("instance", instance)
.field("api", api)
@ -727,37 +767,38 @@ pub enum SurfaceCreationError {
/// Not enough memory.
OomError(OomError),
/// The extension required for this function was not enabled.
MissingExtension {
/// Name of the missing extension.
name: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
}
impl Error for SurfaceCreationError {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
match *self {
SurfaceCreationError::OomError(ref err) => Some(err),
match self {
SurfaceCreationError::OomError(err) => Some(err),
_ => None,
}
}
}
impl fmt::Display for SurfaceCreationError {
impl Display for SurfaceCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(
fmt,
"{}",
match *self {
SurfaceCreationError::OomError(_) => "not enough memory available",
SurfaceCreationError::MissingExtension { .. } => {
"the extension required for this function was not enabled"
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
SurfaceCreationError::OomError(_) => write!(f, "not enough memory available"),
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
}
}
)
}
}
impl From<OomError> for SurfaceCreationError {
@ -830,12 +871,12 @@ vulkan_enum! {
/*
// TODO: document
SharedDemandRefresh = SHARED_DEMAND_REFRESH_KHR {
extensions: [khr_shared_presentable_image],
device_extensions: [khr_shared_presentable_image],
},
// TODO: document
SharedContinuousRefresh = SHARED_CONTINUOUS_REFRESH_KHR {
extensions: [khr_shared_presentable_image],
device_extensions: [khr_shared_presentable_image],
},
*/
}
@ -1114,78 +1155,78 @@ vulkan_enum! {
/*
// TODO: document
DisplayP3NonLinear = DISPLAY_P3_NONLINEAR_EXT {
extensions: [ext_swapchain_colorspace],
device_extensions: [ext_swapchain_colorspace],
},
// TODO: document
ExtendedSrgbLinear = EXTENDED_SRGB_LINEAR_EXT {
extensions: [ext_swapchain_colorspace],
device_extensions: [ext_swapchain_colorspace],
},
// TODO: document
ExtendedSrgbNonLinear = EXTENDED_SRGB_NONLINEAR_EXT {
extensions: [ext_swapchain_colorspace],
device_extensions: [ext_swapchain_colorspace],
},
// TODO: document
DisplayP3Linear = DISPLAY_P3_LINEAR_EXT {
extensions: [ext_swapchain_colorspace],
device_extensions: [ext_swapchain_colorspace],
},
// TODO: document
DciP3NonLinear = DCI_P3_NONLINEAR_EXT {
extensions: [ext_swapchain_colorspace],
device_extensions: [ext_swapchain_colorspace],
},
// TODO: document
Bt709Linear = BT709_LINEAR_EXT {
extensions: [ext_swapchain_colorspace],
device_extensions: [ext_swapchain_colorspace],
},
// TODO: document
Bt709NonLinear = BT709_NONLINEAR_EXT {
extensions: [ext_swapchain_colorspace],
device_extensions: [ext_swapchain_colorspace],
},
// TODO: document
Bt2020Linear = BT2020_LINEAR_EXT {
extensions: [ext_swapchain_colorspace],
device_extensions: [ext_swapchain_colorspace],
},
// TODO: document
Hdr10St2084 = HDR10_ST2084_EXT {
extensions: [ext_swapchain_colorspace],
device_extensions: [ext_swapchain_colorspace],
},
// TODO: document
DolbyVision = DOLBYVISION_EXT {
extensions: [ext_swapchain_colorspace],
device_extensions: [ext_swapchain_colorspace],
},
// TODO: document
Hdr10Hlg = HDR10_HLG_EXT {
extensions: [ext_swapchain_colorspace],
device_extensions: [ext_swapchain_colorspace],
},
// TODO: document
AdobeRgbLinear = ADOBERGB_LINEAR_EXT {
extensions: [ext_swapchain_colorspace],
device_extensions: [ext_swapchain_colorspace],
},
// TODO: document
AdobeRgbNonLinear = ADOBERGB_NONLINEAR_EXT {
extensions: [ext_swapchain_colorspace],
device_extensions: [ext_swapchain_colorspace],
},
// TODO: document
PassThrough = PASS_THROUGH_EXT {
extensions: [ext_swapchain_colorspace],
device_extensions: [ext_swapchain_colorspace],
},
*/
// TODO: document
DisplayNative = DISPLAY_NATIVE_AMD {
extensions: [amd_display_native_hdr],
device_extensions: [amd_display_native_hdr],
},
}
@ -1289,14 +1330,24 @@ pub struct SurfaceCapabilities {
#[cfg(test)]
mod tests {
use crate::swapchain::{Surface, SurfaceCreationError};
use crate::{
swapchain::{Surface, SurfaceCreationError},
RequiresOneOf,
};
use std::ptr;
#[test]
fn khr_win32_surface_ext_missing() {
let instance = instance!();
match unsafe { Surface::from_win32(instance, ptr::null::<u8>(), ptr::null::<u8>(), ()) } {
Err(SurfaceCreationError::MissingExtension { .. }) => (),
Err(SurfaceCreationError::RequirementNotMet {
requires_one_of:
RequiresOneOf {
instance_extensions,
..
},
..
}) if instance_extensions.contains(&"khr_win32_surface") => (),
_ => panic!(),
}
}
@ -1305,7 +1356,14 @@ mod tests {
fn khr_xcb_surface_ext_missing() {
let instance = instance!();
match unsafe { Surface::from_xcb(instance, ptr::null::<u8>(), 0, ()) } {
Err(SurfaceCreationError::MissingExtension { .. }) => (),
Err(SurfaceCreationError::RequirementNotMet {
requires_one_of:
RequiresOneOf {
instance_extensions,
..
},
..
}) if instance_extensions.contains(&"khr_xcb_surface") => (),
_ => panic!(),
}
}
@ -1314,7 +1372,14 @@ mod tests {
fn khr_xlib_surface_ext_missing() {
let instance = instance!();
match unsafe { Surface::from_xlib(instance, ptr::null::<u8>(), 0, ()) } {
Err(SurfaceCreationError::MissingExtension { .. }) => (),
Err(SurfaceCreationError::RequirementNotMet {
requires_one_of:
RequiresOneOf {
instance_extensions,
..
},
..
}) if instance_extensions.contains(&"khr_xlib_surface") => (),
_ => panic!(),
}
}
@ -1323,7 +1388,14 @@ mod tests {
fn khr_wayland_surface_ext_missing() {
let instance = instance!();
match unsafe { Surface::from_wayland(instance, ptr::null::<u8>(), ptr::null::<u8>(), ()) } {
Err(SurfaceCreationError::MissingExtension { .. }) => (),
Err(SurfaceCreationError::RequirementNotMet {
requires_one_of:
RequiresOneOf {
instance_extensions,
..
},
..
}) if instance_extensions.contains(&"khr_wayland_surface") => (),
_ => panic!(),
}
}
@ -1332,7 +1404,14 @@ mod tests {
fn khr_android_surface_ext_missing() {
let instance = instance!();
match unsafe { Surface::from_android(instance, ptr::null::<u8>(), ()) } {
Err(SurfaceCreationError::MissingExtension { .. }) => (),
Err(SurfaceCreationError::RequirementNotMet {
requires_one_of:
RequiresOneOf {
instance_extensions,
..
},
..
}) if instance_extensions.contains(&"khr_android_surface") => (),
_ => panic!(),
}
}

View File

@ -16,25 +16,28 @@ use crate::{
command_buffer::submit::{
SubmitAnyBuilder, SubmitPresentBuilder, SubmitPresentError, SubmitSemaphoresWaitBuilder,
},
device::{physical::SurfacePropertiesError, Device, DeviceOwned, Queue},
device::{
physical::{ImageFormatPropertiesError, SurfacePropertiesError},
Device, DeviceOwned, Queue,
},
format::Format,
image::{
sys::UnsafeImage, ImageCreateFlags, ImageDimensions, ImageFormatInfo, ImageInner,
ImageLayout, ImageTiling, ImageType, ImageUsage, SampleCount, SwapchainImage,
},
macros::{vulkan_enum, ExtensionNotEnabled},
macros::vulkan_enum,
swapchain::{SurfaceApi, SurfaceInfo, SurfaceSwapchainLock},
sync::{
AccessCheckError, AccessError, AccessFlags, Fence, FlushError, GpuFuture, PipelineStages,
Semaphore, SemaphoreCreationError, Sharing,
},
DeviceSize, OomError, VulkanError, VulkanObject,
DeviceSize, OomError, RequirementNotMet, RequiresOneOf, VulkanError, VulkanObject,
};
use parking_lot::Mutex;
use smallvec::SmallVec;
use std::{
error::Error,
fmt,
fmt::{Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},
mem::MaybeUninit,
ops::Range,
@ -113,9 +116,12 @@ impl<W> Swapchain<W> {
);
if !device.enabled_extensions().khr_swapchain {
return Err(SwapchainCreationError::ExtensionNotEnabled {
extension: "khr_swapchain",
reason: "created a new swapchain",
return Err(SwapchainCreationError::RequirementNotMet {
required_for: "`Swapchain`",
requires_one_of: RequiresOneOf {
device_extensions: &["khr_swapchain"],
..Default::default()
},
});
}
@ -297,33 +303,37 @@ impl<W> Swapchain<W> {
} = create_info;
// VUID-VkSwapchainCreateInfoKHR-imageColorSpace-parameter
image_color_space.validate(device)?;
image_color_space.validate_device(device)?;
// VUID-VkSwapchainCreateInfoKHR-imageUsage-parameter
image_usage.validate(device)?;
image_usage.validate_device(device)?;
// VUID-VkSwapchainCreateInfoKHR-imageUsage-requiredbitmask
assert!(!image_usage.is_empty());
// VUID-VkSwapchainCreateInfoKHR-preTransform-parameter
pre_transform.validate(device)?;
pre_transform.validate_device(device)?;
// VUID-VkSwapchainCreateInfoKHR-compositeAlpha-parameter
composite_alpha.validate(device)?;
composite_alpha.validate_device(device)?;
// VUID-VkSwapchainCreateInfoKHR-presentMode-parameter
present_mode.validate(device)?;
present_mode.validate_device(device)?;
if full_screen_exclusive != FullScreenExclusive::Default {
if !device.enabled_extensions().ext_full_screen_exclusive {
return Err(SwapchainCreationError::ExtensionNotEnabled {
extension: "ext_full_screen_exclusive",
reason: "`full_screen_exclusive` was not `FullScreenExclusive::Default`",
return Err(SwapchainCreationError::RequirementNotMet {
required_for:
"`create_info.full_screen_exclusive` is not `FullScreenExclusive::Default`",
requires_one_of: RequiresOneOf {
device_extensions: &["ext_full_screen_exclusive"],
..Default::default()
},
});
}
// VUID-VkSurfaceFullScreenExclusiveInfoEXT-fullScreenExclusive-parameter
full_screen_exclusive.validate(device)?;
full_screen_exclusive.validate_device(device)?;
}
if surface.api() == SurfaceApi::Win32
@ -351,7 +361,7 @@ impl<W> Swapchain<W> {
if let Some(format) = image_format {
// VUID-VkSwapchainCreateInfoKHR-imageFormat-parameter
// TODO: format.validate(device)?;
// TODO: format.validate_device(device)?;
// VUID-VkSwapchainCreateInfoKHR-imageFormat-01273
if !surface_formats
@ -1063,9 +1073,9 @@ pub enum SwapchainCreationError {
/// The window is already in use by another API.
NativeWindowInUse,
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// The provided `composite_alpha` is not supported by the surface for this device.
@ -1145,80 +1155,83 @@ impl Error for SwapchainCreationError {
}
}
impl fmt::Display for SwapchainCreationError {
impl Display for SwapchainCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
Self::OomError(_) => write!(fmt, "not enough memory available",),
Self::DeviceLost => write!(fmt, "the device was lost",),
Self::SurfaceLost => write!(fmt, "the surface was lost",),
Self::OomError(_) => write!(f, "not enough memory available",),
Self::DeviceLost => write!(f, "the device was lost",),
Self::SurfaceLost => write!(f, "the surface was lost",),
Self::SurfaceInUse => {
write!(fmt, "the surface is already used by another swapchain",)
write!(f, "the surface is already used by another swapchain",)
}
Self::NativeWindowInUse => {
write!(fmt, "the window is already in use by another API")
write!(f, "the window is already in use by another API")
}
Self::ExtensionNotEnabled { extension, reason } => write!(
fmt,
"the extension {} must be enabled: {}",
extension, reason
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::CompositeAlphaNotSupported { .. } => write!(
fmt,
f,
"the provided `composite_alpha` is not supported by the surface for this device",
),
Self::FormatColorSpaceNotSupported => write!(
fmt,
f,
"the provided `format` and `color_space` are not supported by the surface for this device",
),
Self::ImageArrayLayersNotSupported { provided, max_supported } => write!(
fmt,
f,
"the provided `image_array_layers` ({}) is greater than what is supported ({}) by the surface for this device",
provided, max_supported,
),
Self::ImageExtentNotSupported { provided, min_supported, max_supported } => write!(
fmt,
f,
"the provided `image_extent` ({:?}) is not within the range (min: {:?}, max: {:?}) supported by the surface for this device",
provided, min_supported, max_supported,
),
Self::ImageExtentZeroLengthDimensions => write!(
fmt,
f,
"the provided `image_extent` contained at least one dimension of zero length",
),
Self::ImageFormatPropertiesNotSupported => write!(
fmt,
f,
"the provided image parameters are not supported as queried from `image_format_properties`",
),
Self::ImageSharingInvalidQueueFamilyId { id } => write!(
fmt,
f,
"the provided `image_sharing` was set to `Concurrent`, but one of the specified queue family ids ({}) was not valid",
id,
),
Self::ImageUsageNotSupported { .. } => write!(
fmt,
f,
"the provided `image_usage` has fields set that are not supported by the surface for this device",
),
Self::MinImageCountNotSupported { provided, min_supported, max_supported } => write!(
fmt,
f,
"the provided `min_image_count` ({}) is not within the range (min: {}, max: {:?}) supported by the surface for this device",
provided, min_supported, max_supported,
),
Self::PresentModeNotSupported => write!(
fmt,
f,
"the provided `present_mode` is not supported by the surface for this device",
),
Self::PreTransformNotSupported { .. } => write!(
fmt,
f,
"the provided `pre_transform` is not supported by the surface for this device",
),
Self::SwapchainAlreadyRetired => write!(
fmt,
f,
"the swapchain has already been used to create a new one",
),
Self::Win32MonitorInvalid => write!(
fmt,
f,
"the `win32_monitor` value was `Some` when it must be `None` or vice-versa",
),
}
@ -1257,12 +1270,28 @@ impl From<SurfacePropertiesError> for SwapchainCreationError {
}
}
impl From<ExtensionNotEnabled> for SwapchainCreationError {
impl From<RequirementNotMet> for SwapchainCreationError {
#[inline]
fn from(err: ExtensionNotEnabled) -> Self {
Self::ExtensionNotEnabled {
extension: err.extension,
reason: err.reason,
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}
impl From<ImageFormatPropertiesError> for SwapchainCreationError {
#[inline]
fn from(err: ImageFormatPropertiesError) -> Self {
match err {
ImageFormatPropertiesError::OomError(err) => Self::OomError(err),
ImageFormatPropertiesError::RequirementNotMet {
required_for,
requires_one_of,
} => Self::RequirementNotMet {
required_for,
requires_one_of,
},
}
}
}
@ -1345,11 +1374,11 @@ impl Error for FullScreenExclusiveError {
}
}
impl fmt::Display for FullScreenExclusiveError {
impl Display for FullScreenExclusiveError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
fmt,
f,
"{}",
match *self {
FullScreenExclusiveError::OomError(_) => "not enough memory",
@ -1688,11 +1717,11 @@ impl Error for AcquireError {
}
}
impl fmt::Display for AcquireError {
impl Display for AcquireError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
fmt,
f,
"{}",
match *self {
AcquireError::OomError(_) => "not enough memory",

View File

@ -14,7 +14,7 @@ use crate::{
use smallvec::SmallVec;
use std::{
error::Error,
fmt,
fmt::{Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},
mem::MaybeUninit,
ptr,
@ -413,11 +413,11 @@ impl Error for FenceWaitError {
}
}
impl fmt::Display for FenceWaitError {
impl Display for FenceWaitError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
fmt,
f,
"{}",
match *self {
FenceWaitError::OomError(_) => "no memory available",

View File

@ -27,7 +27,12 @@ use crate::{
swapchain::{self, PresentFuture, PresentRegion, Swapchain},
DeviceSize, OomError,
};
use std::{error::Error, fmt, ops::Range, sync::Arc};
use std::{
error::Error,
fmt::{Display, Error as FmtError, Formatter},
ops::Range,
sync::Arc,
};
mod fence_signal;
mod join;
@ -407,11 +412,11 @@ pub enum AccessError {
impl Error for AccessError {}
impl fmt::Display for AccessError {
impl Display for AccessError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
fmt,
f,
"{}",
match *self {
AccessError::ExclusiveDenied => "only shared access is allowed for this resource",
@ -448,11 +453,11 @@ pub enum AccessCheckError {
impl Error for AccessCheckError {}
impl fmt::Display for AccessCheckError {
impl Display for AccessCheckError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
fmt,
f,
"{}",
match *self {
AccessCheckError::Denied(_) => "access to the resource has been denied",
@ -507,11 +512,11 @@ impl Error for FlushError {
}
}
impl fmt::Display for FlushError {
impl Display for FlushError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
fmt,
f,
"{}",
match *self {
FlushError::AccessError(_) => "access to a resource has been denied",

View File

@ -75,49 +75,49 @@ vulkan_enum! {
/*
// TODO: document
TransformFeedback = TRANSFORM_FEEDBACK_EXT {
extensions: [ext_transform_feedback],
device_extensions: [ext_transform_feedback],
},
// TODO: document
ConditionalRendering = CONDITIONAL_RENDERING_EXT {
extensions: [ext_conditional_rendering],
device_extensions: [ext_conditional_rendering],
},
// TODO: document
AccelerationStructureBuild = ACCELERATION_STRUCTURE_BUILD_KHR {
extensions: [khr_acceleration_structure, nv_ray_tracing],
device_extensions: [khr_acceleration_structure, nv_ray_tracing],
},
*/
// TODO: document
RayTracingShader = RAY_TRACING_SHADER_KHR {
extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
},
/*
// TODO: document
FragmentDensityProcess = FRAGMENT_DENSITY_PROCESS_EXT {
extensions: [ext_fragment_density_map],
device_extensions: [ext_fragment_density_map],
},
// TODO: document
FragmentShadingRateAttachment = FRAGMENT_SHADING_RATE_ATTACHMENT_KHR {
extensions: [khr_fragment_shading_rate],
device_extensions: [khr_fragment_shading_rate],
},
// TODO: document
CommandPreprocess = COMMAND_PREPROCESS_NV {
extensions: [nv_device_generated_commands],
device_extensions: [nv_device_generated_commands],
},
// TODO: document
TaskShader = TASK_SHADER_NV {
extensions: [nv_mesh_shader],
device_extensions: [nv_mesh_shader],
},
// TODO: document
MeshShader = MESH_SHADER_NV {
extensions: [nv_mesh_shader],
device_extensions: [nv_mesh_shader],
},
*/
}
@ -222,49 +222,49 @@ vulkan_bitflags! {
/*
// TODO: document
transform_feedback = TRANSFORM_FEEDBACK_EXT {
extensions: [ext_transform_feedback],
device_extensions: [ext_transform_feedback],
},
// TODO: document
conditional_rendering = CONDITIONAL_RENDERING_EXT {
extensions: [ext_conditional_rendering],
device_extensions: [ext_conditional_rendering],
},
// TODO: document
acceleration_structure_build = ACCELERATION_STRUCTURE_BUILD_KHR {
extensions: [khr_acceleration_structure, nv_ray_tracing],
device_extensions: [khr_acceleration_structure, nv_ray_tracing],
},
*/
// TODO: document
ray_tracing_shader = RAY_TRACING_SHADER_KHR {
extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
},
/*
// TODO: document
fragment_density_process = FRAGMENT_DENSITY_PROCESS_EXT {
extensions: [ext_fragment_density_map],
device_extensions: [ext_fragment_density_map],
},
// TODO: document
fragment_shading_rate_attachment = FRAGMENT_SHADING_RATE_ATTACHMENT_KHR {
extensions: [khr_fragment_shading_rate],
device_extensions: [khr_fragment_shading_rate],
},
// TODO: document
command_preprocess = COMMAND_PREPROCESS_NV {
extensions: [nv_device_generated_commands],
device_extensions: [nv_device_generated_commands],
},
// TODO: document
task_shader = TASK_SHADER_NV {
extensions: [nv_mesh_shader],
device_extensions: [nv_mesh_shader],
},
// TODO: document
mesh_shader = MESH_SHADER_NV {
extensions: [nv_mesh_shader],
device_extensions: [nv_mesh_shader],
},
*/
}
@ -459,57 +459,57 @@ vulkan_bitflags! {
/*
// Provided by VK_EXT_transform_feedback
transform_feedback_write = TRANSFORM_FEEDBACK_WRITE_EXT {
extensions: [ext_transform_feedback],
device_extensions: [ext_transform_feedback],
},
// Provided by VK_EXT_transform_feedback
transform_feedback_counter_read = TRANSFORM_FEEDBACK_COUNTER_READ_EXT {
extensions: [ext_transform_feedback],
device_extensions: [ext_transform_feedback],
},
// Provided by VK_EXT_transform_feedback
transform_feedback_counter_write = TRANSFORM_FEEDBACK_COUNTER_WRITE_EXT {
extensions: [ext_transform_feedback],
device_extensions: [ext_transform_feedback],
},
// Provided by VK_EXT_conditional_rendering
conditional_rendering_read = CONDITIONAL_RENDERING_READ_EXT {
extensions: [ext_conditional_rendering],
device_extensions: [ext_conditional_rendering],
},
// Provided by VK_EXT_blend_operation_advanced
color_attachment_read_noncoherent = COLOR_ATTACHMENT_READ_NONCOHERENT_EXT {
extensions: [ext_blend_operation_advanced],
device_extensions: [ext_blend_operation_advanced],
},
// Provided by VK_KHR_acceleration_structure
acceleration_structure_read = ACCELERATION_STRUCTURE_READ_KHR {
extensions: [khr_acceleration_structure, nv_ray_tracing],
device_extensions: [khr_acceleration_structure, nv_ray_tracing],
},
// Provided by VK_KHR_acceleration_structure
acceleration_structure_write = ACCELERATION_STRUCTURE_WRITE_KHR {
extensions: [khr_acceleration_structure, nv_ray_tracing],
device_extensions: [khr_acceleration_structure, nv_ray_tracing],
},
// Provided by VK_EXT_fragment_density_map
fragment_density_map_read = FRAGMENT_DENSITY_MAP_READ_EXT {
extensions: [ext_fragment_density_map],
device_extensions: [ext_fragment_density_map],
},
// Provided by VK_KHR_fragment_shading_rate
fragment_shading_rate_attachment_read = FRAGMENT_SHADING_RATE_ATTACHMENT_READ_KHR {
extensions: [khr_fragment_shading_rate],
device_extensions: [khr_fragment_shading_rate],
},
// Provided by VK_NV_device_generated_commands
command_preprocess_read = COMMAND_PREPROCESS_READ_NV {
extensions: [nv_device_generated_commands],
device_extensions: [nv_device_generated_commands],
},
// Provided by VK_NV_device_generated_commands
command_preprocess_write = COMMAND_PREPROCESS_WRITE_NV {
extensions: [nv_device_generated_commands],
device_extensions: [nv_device_generated_commands],
},
*/
}

View File

@ -9,12 +9,12 @@
use crate::{
device::{Device, DeviceOwned},
macros::{vulkan_bitflags, vulkan_enum, ExtensionNotEnabled},
OomError, Version, VulkanError, VulkanObject,
macros::{vulkan_bitflags, vulkan_enum},
OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
};
use std::{
error::Error,
fmt,
fmt::{Display, Error as FmtError, Formatter},
fs::File,
hash::{Hash, Hasher},
mem::MaybeUninit,
@ -50,14 +50,18 @@ impl Semaphore {
if !(device.api_version() >= Version::V1_1
|| device.enabled_extensions().khr_external_semaphore)
{
return Err(SemaphoreCreationError::ExtensionNotEnabled {
extension: "khr_external_semaphore",
reason: "export_handle_types was not empty",
return Err(SemaphoreCreationError::RequirementNotMet {
required_for: "`create_info.export_handle_types` is not empty",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_1),
device_extensions: &["khr_external_semaphore"],
..Default::default()
},
});
}
// VUID-VkExportSemaphoreCreateInfo-handleTypes-parameter
export_handle_types.validate(&device)?;
export_handle_types.validate_device(&device)?;
// VUID-VkExportSemaphoreCreateInfo-handleTypes-01124
// TODO: `vkGetPhysicalDeviceExternalSemaphoreProperties` can only be called with one
@ -258,9 +262,9 @@ pub enum SemaphoreCreationError {
/// Not enough memory available.
OomError(OomError),
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
}
@ -274,13 +278,19 @@ impl Error for SemaphoreCreationError {
}
}
impl fmt::Display for SemaphoreCreationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl Display for SemaphoreCreationError {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::OomError(_) => write!(f, "not enough memory available"),
Self::ExtensionNotEnabled { extension, reason } => {
write!(f, "the extension {} must be enabled: {}", extension, reason)
}
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
}
}
}
@ -304,12 +314,12 @@ impl From<OomError> for SemaphoreCreationError {
}
}
impl From<ExtensionNotEnabled> for SemaphoreCreationError {
impl From<RequirementNotMet> for SemaphoreCreationError {
#[inline]
fn from(err: ExtensionNotEnabled) -> Self {
Self::ExtensionNotEnabled {
extension: err.extension,
reason: err.reason,
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}
@ -358,7 +368,7 @@ vulkan_enum! {
/*
// TODO: document
ZirconEvent = ZIRCON_EVENT_FUCHSIA {
extensions: [fuchsia_external_semaphore],
device_extensions: [fuchsia_external_semaphore],
},
*/
}
@ -386,7 +396,7 @@ vulkan_bitflags! {
/*
// TODO: document
zircon_event = ZIRCON_EVENT_FUCHSIA {
extensions: [fuchsia_external_semaphore],
device_extensions: [fuchsia_external_semaphore],
},
*/
}
@ -446,12 +456,12 @@ pub enum SemaphoreExportError {
},
}
impl fmt::Display for SemaphoreExportError {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl Display for SemaphoreExportError {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
Self::OomError(_) => write!(fmt, "not enough memory available"),
Self::OomError(_) => write!(f, "not enough memory available"),
Self::HandleTypeNotSupported { handle_type } => write!(
fmt,
f,
"the requested export handle type ({:?}) was not provided in `export_handle_types` when creating the semaphore",
handle_type,
),

View File

@ -9,7 +9,11 @@
// The `Version` object is reexported from the `instance` module.
use std::{fmt, num::ParseIntError, str::FromStr};
use std::{
fmt::{Debug, Display, Error as FmtError, Formatter},
num::ParseIntError,
str::FromStr,
};
// Generated by build.rs
include!(concat!(env!("OUT_DIR"), "/version.rs"));
@ -94,15 +98,15 @@ impl FromStr for Version {
}
}
impl fmt::Debug for Version {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
impl Debug for Version {
fn fmt(&self, formatter: &mut Formatter) -> Result<(), FmtError> {
write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)
}
}
impl fmt::Display for Version {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, formatter)
impl Display for Version {
fn fmt(&self, formatter: &mut Formatter) -> Result<(), FmtError> {
Debug::fmt(self, formatter)
}
}