mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-22 06:45:23 +00:00
Better validation and errors (#1966)
* Better validation and errors * Small fix
This commit is contained in:
parent
896b49e92e
commit
b06b29afd2
@ -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 {
|
||||
|
@ -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",
|
||||
|
@ -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)*
|
||||
|
@ -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",
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
@ -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",
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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!(),
|
||||
}
|
||||
}
|
||||
|
@ -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",
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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],
|
||||
},
|
||||
*/
|
||||
}
|
||||
|
@ -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",
|
||||
),
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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"),
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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());
|
||||
|
@ -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!()
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
@ -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 { .. } =>
|
||||
|
@ -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],
|
||||
},
|
||||
*/
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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",
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
),
|
||||
|
@ -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"));
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
@ -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],
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -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],
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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],
|
||||
},
|
||||
*/
|
||||
}
|
||||
|
@ -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],
|
||||
},
|
||||
*/
|
||||
}
|
||||
|
@ -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!(),
|
||||
};
|
||||
|
@ -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()
|
||||
|
@ -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],
|
||||
},
|
||||
*/
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -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,
|
||||
|
@ -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"));
|
||||
|
@ -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,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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
@ -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],
|
||||
},
|
||||
*/
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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],
|
||||
},
|
||||
*/
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -245,7 +245,7 @@ vulkan_enum! {
|
||||
/*
|
||||
// TODO: document
|
||||
FillRectangle = FILL_RECTANGLE_NV {
|
||||
extensions: [nv_fill_rectangle],
|
||||
device_extensions: [nv_fill_rectangle],
|
||||
},
|
||||
*/
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ fn bad_primitive_restart() {
|
||||
);
|
||||
|
||||
match result {
|
||||
Err(GraphicsPipelineCreationError::FeatureNotEnabled { .. }) => (),
|
||||
Err(GraphicsPipelineCreationError::RequirementNotMet { .. }) => (),
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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],
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -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],
|
||||
},
|
||||
*/
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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",
|
||||
),
|
||||
}
|
||||
|
@ -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],
|
||||
},
|
||||
*/
|
||||
}
|
||||
|
@ -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!(),
|
||||
}
|
||||
}
|
||||
|
@ -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!(),
|
||||
}
|
||||
}
|
||||
|
@ -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],
|
||||
},
|
||||
*/
|
||||
}
|
||||
|
@ -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"),
|
||||
|
@ -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!(
|
||||
|
@ -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!(),
|
||||
}
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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],
|
||||
},
|
||||
*/
|
||||
}
|
||||
|
@ -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,
|
||||
),
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user