mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-21 22:34:43 +00:00
Refactoring of DescriptorDesc and related changes (#1680)
* Various changes to DescriptorSetDesc * More changes to DescriptorSetDesc * Small comment fix
This commit is contained in:
parent
ca50c2a33c
commit
b6b423c3d3
@ -343,13 +343,7 @@ where
|
||||
#[allow(unused_imports)]
|
||||
use vulkano::descriptor_set::layout::DescriptorDescTy;
|
||||
#[allow(unused_imports)]
|
||||
use vulkano::descriptor_set::layout::DescriptorBufferDesc;
|
||||
#[allow(unused_imports)]
|
||||
use vulkano::descriptor_set::layout::DescriptorImageDesc;
|
||||
#[allow(unused_imports)]
|
||||
use vulkano::descriptor_set::layout::DescriptorImageDescDimensions;
|
||||
#[allow(unused_imports)]
|
||||
use vulkano::descriptor_set::layout::DescriptorImageDescArray;
|
||||
use vulkano::descriptor_set::layout::DescriptorDescImage;
|
||||
#[allow(unused_imports)]
|
||||
use vulkano::descriptor_set::layout::DescriptorSetDesc;
|
||||
#[allow(unused_imports)]
|
||||
@ -359,6 +353,8 @@ where
|
||||
#[allow(unused_imports)]
|
||||
use vulkano::format::Format;
|
||||
#[allow(unused_imports)]
|
||||
use vulkano::image::view::ImageViewType;
|
||||
#[allow(unused_imports)]
|
||||
use vulkano::pipeline::layout::PipelineLayout;
|
||||
#[allow(unused_imports)]
|
||||
use vulkano::pipeline::layout::PipelineLayoutPcRange;
|
||||
|
@ -19,8 +19,8 @@ struct Descriptor {
|
||||
set: u32,
|
||||
binding: u32,
|
||||
desc_ty: TokenStream,
|
||||
array_count: u64,
|
||||
readonly: bool,
|
||||
descriptor_count: u64,
|
||||
mutable: bool,
|
||||
}
|
||||
|
||||
pub(super) fn write_descriptor_set_layout_descs(
|
||||
@ -51,14 +51,14 @@ pub(super) fn write_descriptor_set_layout_descs(
|
||||
{
|
||||
Some(d) => {
|
||||
let desc_ty = &d.desc_ty;
|
||||
let array_count = d.array_count as u32;
|
||||
let readonly = d.readonly;
|
||||
let descriptor_count = d.descriptor_count as u32;
|
||||
let mutable = d.mutable;
|
||||
quote! {
|
||||
Some(DescriptorDesc {
|
||||
ty: #desc_ty,
|
||||
array_count: #array_count,
|
||||
descriptor_count: #descriptor_count,
|
||||
stages: #stages,
|
||||
readonly: #readonly,
|
||||
mutable: #mutable,
|
||||
}),
|
||||
}
|
||||
}
|
||||
@ -84,7 +84,11 @@ pub(super) fn write_descriptor_set_layout_descs(
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn write_push_constant_ranges(doc: &Spirv, stage: &TokenStream, types_meta: &TypesMeta) -> TokenStream {
|
||||
pub(super) fn write_push_constant_ranges(
|
||||
doc: &Spirv,
|
||||
stage: &TokenStream,
|
||||
types_meta: &TypesMeta,
|
||||
) -> TokenStream {
|
||||
// TODO: somewhat implemented correctly
|
||||
|
||||
// Looping to find all the push constant structs.
|
||||
@ -173,7 +177,7 @@ fn find_descriptors(
|
||||
.is_some();
|
||||
|
||||
// Find information about the kind of binding for this descriptor.
|
||||
let (desc_ty, readonly, array_count) =
|
||||
let (desc_ty, mutable, descriptor_count) =
|
||||
descriptor_infos(doc, pointed_ty, storage_class, false).expect(&format!(
|
||||
"Couldn't find relevant type for uniform `{}` (type {}, maybe unimplemented)",
|
||||
name, pointed_ty
|
||||
@ -182,8 +186,8 @@ fn find_descriptors(
|
||||
desc_ty,
|
||||
set,
|
||||
binding,
|
||||
array_count,
|
||||
readonly: nonwritable || readonly,
|
||||
descriptor_count,
|
||||
mutable: !nonwritable && mutable,
|
||||
});
|
||||
}
|
||||
|
||||
@ -385,26 +389,20 @@ fn descriptor_infos(
|
||||
"Structs in shader interface are expected to be decorated with one of Block or BufferBlock"
|
||||
);
|
||||
|
||||
// false -> VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
|
||||
// true -> VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
|
||||
let storage = decoration_buffer_block || decoration_block && pointer_storage == StorageClass::StorageBuffer;
|
||||
let (ty, mutable) = if decoration_buffer_block || decoration_block && pointer_storage == StorageClass::StorageBuffer {
|
||||
// VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
|
||||
// Determine whether all members have a NonWritable decoration.
|
||||
let nonwritable = (0..member_types.len() as u32).all(|i| {
|
||||
doc.get_member_decoration_params(pointed_ty, i, Decoration::NonWritable).is_some()
|
||||
});
|
||||
|
||||
// Determine whether all members have a NonWritable decoration.
|
||||
let nonwritable = (0..member_types.len() as u32).all(|i| {
|
||||
doc.get_member_decoration_params(pointed_ty, i, Decoration::NonWritable).is_some()
|
||||
});
|
||||
|
||||
// Uniforms are never writable.
|
||||
let readonly = !storage || nonwritable;
|
||||
|
||||
let desc = quote! {
|
||||
DescriptorDescTy::Buffer(DescriptorBufferDesc {
|
||||
dynamic: None,
|
||||
storage: #storage,
|
||||
})
|
||||
(quote! { DescriptorDescTy::StorageBuffer }, !nonwritable)
|
||||
} else {
|
||||
// VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
|
||||
(quote! { DescriptorDescTy::UniformBuffer }, false) // Uniforms are never mutable.
|
||||
};
|
||||
|
||||
Some((desc, readonly, 1))
|
||||
|
||||
Some((ty, mutable, 1))
|
||||
}
|
||||
&Instruction::TypeImage {
|
||||
result_id,
|
||||
@ -422,11 +420,6 @@ fn descriptor_infos(
|
||||
|
||||
let vulkan_format = to_vulkan_format(*format);
|
||||
|
||||
let arrayed = match arrayed {
|
||||
true => quote! { DescriptorImageDescArray::Arrayed { max_layers: None } },
|
||||
false => quote! { DescriptorImageDescArray::NonArrayed },
|
||||
};
|
||||
|
||||
match dim {
|
||||
Dim::DimSubpassData => {
|
||||
// VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT
|
||||
@ -441,67 +434,71 @@ fn descriptor_infos(
|
||||
"If Dim is SubpassData, Image Format must be Unknown"
|
||||
);
|
||||
assert!(!sampled, "If Dim is SubpassData, Sampled must be 2");
|
||||
assert!(!arrayed, "If Dim is SubpassData, Arrayed must be 0");
|
||||
|
||||
let desc = quote! {
|
||||
DescriptorDescTy::InputAttachment {
|
||||
multisampled: #ms,
|
||||
array_layers: #arrayed
|
||||
}
|
||||
};
|
||||
|
||||
Some((desc, true, 1)) // Never writable.
|
||||
}
|
||||
Dim::DimBuffer => {
|
||||
// false -> VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
|
||||
// true -> VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER
|
||||
let storage = !sampled;
|
||||
let (ty, mutable) = if sampled {
|
||||
// VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
|
||||
(quote! { DescriptorDescTy::UniformTexelBuffer }, false) // Uniforms are never mutable.
|
||||
} else {
|
||||
// VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER
|
||||
(quote! { DescriptorDescTy::StorageTexelBuffer }, true)
|
||||
};
|
||||
|
||||
let desc = quote! {
|
||||
DescriptorDescTy::TexelBuffer {
|
||||
storage: #storage,
|
||||
#ty {
|
||||
format: #vulkan_format,
|
||||
}
|
||||
};
|
||||
|
||||
Some((desc, !storage, 1)) // Uniforms are never writable.
|
||||
Some((desc, mutable, 1))
|
||||
|
||||
}
|
||||
_ => {
|
||||
let (ty, readonly) = match force_combined_image_sampled {
|
||||
let (ty, mutable) = if force_combined_image_sampled {
|
||||
// VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
|
||||
// Never writable.
|
||||
true => (quote! { DescriptorDescTy::CombinedImageSampler }, true),
|
||||
false => {
|
||||
// false -> VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE
|
||||
// true -> VK_DESCRIPTOR_TYPE_STORAGE_IMAGE
|
||||
let storage = !sampled;
|
||||
(quote! { DescriptorDescTy::Image }, !storage) // Sampled images are never writable.
|
||||
},
|
||||
assert!(sampled, "A combined image sampler must not reference a storage image");
|
||||
(quote! { DescriptorDescTy::CombinedImageSampler }, false) // Sampled images are never mutable.
|
||||
} else {
|
||||
if sampled {
|
||||
// VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE
|
||||
(quote! { DescriptorDescTy::SampledImage }, false) // Sampled images are never mutable.
|
||||
} else {
|
||||
// VK_DESCRIPTOR_TYPE_STORAGE_IMAGE
|
||||
(quote! { DescriptorDescTy::StorageImage }, true)
|
||||
}
|
||||
};
|
||||
let dim = match *dim {
|
||||
Dim::Dim1D => {
|
||||
quote! { DescriptorImageDescDimensions::OneDimensional }
|
||||
}
|
||||
Dim::Dim2D => {
|
||||
quote! { DescriptorImageDescDimensions::TwoDimensional }
|
||||
}
|
||||
Dim::Dim3D => {
|
||||
quote! { DescriptorImageDescDimensions::ThreeDimensional }
|
||||
}
|
||||
Dim::DimCube => quote! { DescriptorImageDescDimensions::Cube },
|
||||
Dim::DimRect => panic!("Vulkan doesn't support rectangle textures"),
|
||||
let view_type = match (dim, arrayed) {
|
||||
(Dim::Dim1D, false) => quote! { ImageViewType::Dim1d },
|
||||
(Dim::Dim1D, true) => quote! { ImageViewType::Dim1dArray },
|
||||
(Dim::Dim2D, false) => quote! { ImageViewType::Dim2d },
|
||||
(Dim::Dim2D, true) => quote! { ImageViewType::Dim2dArray },
|
||||
(Dim::Dim3D, false) => quote! { ImageViewType::Dim3d },
|
||||
(Dim::Dim3D, true) => panic!("Vulkan doesn't support arrayed 3D textures"),
|
||||
(Dim::DimCube, false) => quote! { ImageViewType::Cube },
|
||||
(Dim::DimCube, true) => quote! { ImageViewType::CubeArray },
|
||||
(Dim::DimRect, _) => panic!("Vulkan doesn't support rectangle textures"),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let desc = quote! {
|
||||
#ty(DescriptorImageDesc {
|
||||
sampled: #sampled,
|
||||
dimensions: #dim,
|
||||
#ty(DescriptorDescImage {
|
||||
format: #vulkan_format,
|
||||
multisampled: #ms,
|
||||
array_layers: #arrayed,
|
||||
view_type: #view_type,
|
||||
})
|
||||
};
|
||||
|
||||
Some((desc, readonly, 1))
|
||||
Some((desc, mutable, 1))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -515,14 +512,14 @@ fn descriptor_infos(
|
||||
|
||||
&Instruction::TypeSampler { result_id } if result_id == pointed_ty => {
|
||||
let desc = quote! { DescriptorDescTy::Sampler };
|
||||
Some((desc, true, 1))
|
||||
Some((desc, false, 1))
|
||||
}
|
||||
&Instruction::TypeArray {
|
||||
result_id,
|
||||
type_id,
|
||||
length_id,
|
||||
} if result_id == pointed_ty => {
|
||||
let (desc, readonly, arr) =
|
||||
let (desc, mutable, arr) =
|
||||
match descriptor_infos(doc, type_id, pointer_storage.clone(), false) {
|
||||
None => return None,
|
||||
Some(v) => v,
|
||||
@ -542,7 +539,7 @@ fn descriptor_infos(
|
||||
.next()
|
||||
.expect("failed to find array length");
|
||||
let len = len.iter().rev().fold(0, |a, &b| (a << 32) | b as u64);
|
||||
Some((desc, readonly, len))
|
||||
Some((desc, mutable, len))
|
||||
}
|
||||
_ => None, // TODO: other types
|
||||
}
|
||||
|
@ -2631,7 +2631,7 @@ impl SyncCommandBufferBuilder {
|
||||
.layout()
|
||||
.descriptor(ds.buffer(buf_num).unwrap().1 as usize)
|
||||
.unwrap();
|
||||
let exclusive = !desc.readonly;
|
||||
let exclusive = desc.mutable;
|
||||
let (stages, access) = desc.pipeline_stages_and_access();
|
||||
resources.push((
|
||||
KeyTy::Buffer,
|
||||
@ -2650,7 +2650,7 @@ impl SyncCommandBufferBuilder {
|
||||
for img_num in 0..ds.num_images() {
|
||||
let (image_view, desc_num) = ds.image(img_num).unwrap();
|
||||
let desc = ds.layout().descriptor(desc_num as usize).unwrap();
|
||||
let exclusive = !desc.readonly;
|
||||
let exclusive = desc.mutable;
|
||||
let (stages, access) = desc.pipeline_stages_and_access();
|
||||
let mut ignore_me_hack = false;
|
||||
let layouts = image_view
|
||||
@ -2659,13 +2659,8 @@ impl SyncCommandBufferBuilder {
|
||||
.expect("descriptor_layouts must return Some when used in an image view");
|
||||
let layout = match desc.ty {
|
||||
DescriptorDescTy::CombinedImageSampler(_) => layouts.combined_image_sampler,
|
||||
DescriptorDescTy::Image(ref img) => {
|
||||
if img.sampled {
|
||||
layouts.sampled_image
|
||||
} else {
|
||||
layouts.storage_image
|
||||
}
|
||||
}
|
||||
DescriptorDescTy::SampledImage(_) => layouts.sampled_image,
|
||||
DescriptorDescTy::StorageImage(_) => layouts.storage_image,
|
||||
DescriptorDescTy::InputAttachment { .. } => {
|
||||
// FIXME: This is tricky. Since we read from the input attachment
|
||||
// and this input attachment is being written in an earlier pass,
|
||||
|
@ -711,9 +711,9 @@ mod tests {
|
||||
device.clone(),
|
||||
[Some(DescriptorDesc {
|
||||
ty: DescriptorDescTy::Sampler,
|
||||
array_count: 1,
|
||||
descriptor_count: 1,
|
||||
stages: ShaderStages::all(),
|
||||
readonly: true,
|
||||
mutable: false,
|
||||
})],
|
||||
)
|
||||
.unwrap(),
|
||||
|
@ -7,46 +7,31 @@
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
|
||||
use crate::descriptor_set::layout::DescriptorDescSupersetError;
|
||||
use crate::descriptor_set::layout::DescriptorSetCompatibilityError;
|
||||
use crate::descriptor_set::DescriptorSetWithOffsets;
|
||||
use crate::pipeline::layout::PipelineLayout;
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
|
||||
/// Checks whether descriptor sets are compatible with the pipeline.
|
||||
pub fn check_descriptor_sets_validity(
|
||||
pipeline_layout: &PipelineLayout,
|
||||
descriptor_sets: &[DescriptorSetWithOffsets],
|
||||
) -> Result<(), CheckDescriptorSetsValidityError> {
|
||||
// What's important is not that the pipeline layout and the descriptor sets *match*. Instead
|
||||
// what's important is that the descriptor sets are a superset of the pipeline layout. It's not
|
||||
// a problem if the descriptor sets provide more elements than expected.
|
||||
for (set_index, pipeline_set) in pipeline_layout.descriptor_set_layouts().iter().enumerate() {
|
||||
let set_num = set_index as u32;
|
||||
|
||||
for (set_num, set) in pipeline_layout.descriptor_set_layouts().iter().enumerate() {
|
||||
for (binding_num, pipeline_desc) in
|
||||
(0..set.num_bindings()).filter_map(|i| set.descriptor(i).map(|d| (i, d)))
|
||||
{
|
||||
let set_desc = descriptor_sets
|
||||
.get(set_num)
|
||||
.and_then(|so| so.as_ref().0.layout().descriptor(binding_num));
|
||||
let descriptor_set = match descriptor_sets.get(set_index) {
|
||||
Some(s) => s,
|
||||
None => return Err(CheckDescriptorSetsValidityError::MissingDescriptorSet { set_num }),
|
||||
};
|
||||
|
||||
let set_desc = match set_desc {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
return Err(CheckDescriptorSetsValidityError::MissingDescriptor {
|
||||
set_num: set_num,
|
||||
binding_num: binding_num,
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(err) = set_desc.ensure_superset_of(&pipeline_desc) {
|
||||
return Err(CheckDescriptorSetsValidityError::IncompatibleDescriptor {
|
||||
error: err,
|
||||
set_num: set_num,
|
||||
binding_num: binding_num,
|
||||
});
|
||||
match pipeline_set.ensure_compatible_with_bind(descriptor_set.as_ref().0.layout()) {
|
||||
Ok(_) => (),
|
||||
Err(error) => {
|
||||
return Err(
|
||||
CheckDescriptorSetsValidityError::IncompatibleDescriptorSet { error, set_num },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -57,32 +42,22 @@ pub fn check_descriptor_sets_validity(
|
||||
/// Error that can happen when checking descriptor sets validity.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum CheckDescriptorSetsValidityError {
|
||||
/// A descriptor is missing in the descriptor sets that were provided.
|
||||
MissingDescriptor {
|
||||
/// The index of the set of the descriptor.
|
||||
set_num: usize,
|
||||
/// The binding number of the descriptor.
|
||||
binding_num: usize,
|
||||
MissingDescriptorSet {
|
||||
set_num: u32,
|
||||
},
|
||||
|
||||
/// A descriptor in the provided sets is not compatible with what is expected.
|
||||
IncompatibleDescriptor {
|
||||
/// The reason why the two descriptors aren't compatible.
|
||||
error: DescriptorDescSupersetError,
|
||||
IncompatibleDescriptorSet {
|
||||
/// The error returned by the descriptor set.
|
||||
error: DescriptorSetCompatibilityError,
|
||||
/// The index of the set of the descriptor.
|
||||
set_num: usize,
|
||||
/// The binding number of the descriptor.
|
||||
binding_num: usize,
|
||||
set_num: u32,
|
||||
},
|
||||
}
|
||||
|
||||
impl error::Error for CheckDescriptorSetsValidityError {
|
||||
#[inline]
|
||||
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
||||
match *self {
|
||||
CheckDescriptorSetsValidityError::IncompatibleDescriptor { ref error, .. } => {
|
||||
Some(error)
|
||||
}
|
||||
match self {
|
||||
Self::IncompatibleDescriptorSet { error, .. } => Some(error),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -91,18 +66,14 @@ impl error::Error for CheckDescriptorSetsValidityError {
|
||||
impl fmt::Display for CheckDescriptorSetsValidityError {
|
||||
#[inline]
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
write!(
|
||||
fmt,
|
||||
"{}",
|
||||
match *self {
|
||||
CheckDescriptorSetsValidityError::MissingDescriptor { .. } => {
|
||||
"a descriptor is missing in the descriptor sets that were provided"
|
||||
}
|
||||
CheckDescriptorSetsValidityError::IncompatibleDescriptor { .. } => {
|
||||
"a descriptor in the provided sets is not compatible with what is expected"
|
||||
}
|
||||
match self {
|
||||
Self::MissingDescriptorSet { set_num } => {
|
||||
write!(fmt, "descriptor set {} has not been not bound, but is required by the pipeline layout", set_num)
|
||||
}
|
||||
)
|
||||
Self::IncompatibleDescriptorSet { set_num, .. } => {
|
||||
write!(fmt, "compatibility error in descriptor set {}", set_num)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -13,15 +13,12 @@
|
||||
//! can create a descriptor set layout manually, but it is normally created automatically by each
|
||||
//! pipeline layout.
|
||||
|
||||
pub use self::desc::DescriptorBufferDesc;
|
||||
pub use self::desc::DescriptorCompatibilityError;
|
||||
pub use self::desc::DescriptorDesc;
|
||||
pub use self::desc::DescriptorDescSupersetError;
|
||||
pub use self::desc::DescriptorDescImage;
|
||||
pub use self::desc::DescriptorDescTy;
|
||||
pub use self::desc::DescriptorImageDesc;
|
||||
pub use self::desc::DescriptorImageDescArray;
|
||||
pub use self::desc::DescriptorImageDescDimensions;
|
||||
pub use self::desc::DescriptorSetCompatibilityError;
|
||||
pub use self::desc::DescriptorSetDesc;
|
||||
pub use self::desc::DescriptorSetDescSupersetError;
|
||||
pub use self::desc::DescriptorType;
|
||||
pub use self::sys::DescriptorSetLayout;
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
use crate::check_errors;
|
||||
use crate::descriptor_set::layout::DescriptorDesc;
|
||||
use crate::descriptor_set::layout::DescriptorSetCompatibilityError;
|
||||
use crate::descriptor_set::layout::DescriptorSetDesc;
|
||||
use crate::descriptor_set::pool::DescriptorsCount;
|
||||
use crate::device::Device;
|
||||
@ -60,12 +61,12 @@ impl DescriptorSetLayout {
|
||||
// doesn't have tess shaders enabled
|
||||
|
||||
let ty = desc.ty.ty();
|
||||
descriptors_count.add_num(ty, desc.array_count);
|
||||
descriptors_count.add_num(ty, desc.descriptor_count);
|
||||
|
||||
Some(ash::vk::DescriptorSetLayoutBinding {
|
||||
binding: binding as u32,
|
||||
descriptor_type: ty.into(),
|
||||
descriptor_count: desc.array_count,
|
||||
descriptor_count: desc.descriptor_count,
|
||||
stage_flags: desc.stages.into(),
|
||||
p_immutable_samplers: ptr::null(), // FIXME: not yet implemented
|
||||
})
|
||||
@ -122,6 +123,19 @@ impl DescriptorSetLayout {
|
||||
pub fn descriptor(&self, binding: usize) -> Option<DescriptorDesc> {
|
||||
self.desc.bindings().get(binding).cloned().unwrap_or(None)
|
||||
}
|
||||
|
||||
/// Checks whether the descriptor of a pipeline layout `self` is compatible with the descriptor
|
||||
/// of a descriptor set being bound `other`.
|
||||
pub fn ensure_compatible_with_bind(
|
||||
&self,
|
||||
other: &DescriptorSetLayout,
|
||||
) -> Result<(), DescriptorSetCompatibilityError> {
|
||||
if self.internal_object() == other.internal_object() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.desc.ensure_compatible_with_bind(&other.desc)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl DeviceOwned for DescriptorSetLayout {
|
||||
@ -156,7 +170,6 @@ impl Drop for DescriptorSetLayout {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::descriptor_set::layout::DescriptorBufferDesc;
|
||||
use crate::descriptor_set::layout::DescriptorDesc;
|
||||
use crate::descriptor_set::layout::DescriptorDescTy;
|
||||
use crate::descriptor_set::layout::DescriptorSetDesc;
|
||||
@ -176,13 +189,10 @@ mod tests {
|
||||
let (device, _) = gfx_dev_and_queue!();
|
||||
|
||||
let layout = DescriptorDesc {
|
||||
ty: DescriptorDescTy::Buffer(DescriptorBufferDesc {
|
||||
dynamic: Some(false),
|
||||
storage: false,
|
||||
}),
|
||||
array_count: 1,
|
||||
ty: DescriptorDescTy::UniformBuffer,
|
||||
descriptor_count: 1,
|
||||
stages: ShaderStages::all_graphics(),
|
||||
readonly: true,
|
||||
mutable: false,
|
||||
};
|
||||
|
||||
let sl = DescriptorSetLayout::new(
|
||||
|
@ -81,7 +81,7 @@ pub use self::persistent::PersistentDescriptorSetBuildError;
|
||||
pub use self::persistent::PersistentDescriptorSetError;
|
||||
use self::sys::UnsafeDescriptorSet;
|
||||
use crate::buffer::BufferAccess;
|
||||
use crate::descriptor_set::layout::{DescriptorBufferDesc, DescriptorDescTy};
|
||||
use crate::descriptor_set::layout::DescriptorDescTy;
|
||||
use crate::device::DeviceOwned;
|
||||
use crate::image::view::ImageViewAbstract;
|
||||
use crate::SafeDeref;
|
||||
@ -213,22 +213,22 @@ impl DescriptorSetWithOffsets {
|
||||
// dynamic offset is a multiple of the minimum offset alignment specified
|
||||
// by the physical device.
|
||||
for desc in layout.desc().bindings() {
|
||||
let desc = desc.as_ref().unwrap();
|
||||
if let DescriptorDescTy::Buffer(DescriptorBufferDesc {
|
||||
dynamic: Some(true),
|
||||
storage,
|
||||
}) = desc.ty
|
||||
{
|
||||
// Don't check alignment if there are not enough offsets anyway
|
||||
if dynamic_offsets.len() > dynamic_offset_index {
|
||||
if storage {
|
||||
match desc.as_ref().unwrap().ty {
|
||||
DescriptorDescTy::StorageBufferDynamic => {
|
||||
// Don't check alignment if there are not enough offsets anyway
|
||||
if dynamic_offsets.len() > dynamic_offset_index {
|
||||
assert!(
|
||||
dynamic_offsets[dynamic_offset_index] % min_storage_off_align == 0,
|
||||
"Dynamic storage buffer offset must be a multiple of min_storage_buffer_offset_alignment: got {}, expected a multiple of {}",
|
||||
dynamic_offsets[dynamic_offset_index],
|
||||
min_storage_off_align
|
||||
);
|
||||
} else {
|
||||
}
|
||||
dynamic_offset_index += 1;
|
||||
}
|
||||
DescriptorDescTy::UniformBufferDynamic => {
|
||||
// Don't check alignment if there are not enough offsets anyway
|
||||
if dynamic_offsets.len() > dynamic_offset_index {
|
||||
assert!(
|
||||
dynamic_offsets[dynamic_offset_index] % min_uniform_off_align == 0,
|
||||
"Dynamic uniform buffer offset must be a multiple of min_uniform_buffer_offset_alignment: got {}, expected a multiple of {}",
|
||||
@ -236,8 +236,9 @@ impl DescriptorSetWithOffsets {
|
||||
min_uniform_off_align
|
||||
);
|
||||
}
|
||||
dynamic_offset_index += 1;
|
||||
}
|
||||
dynamic_offset_index += 1;
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,10 +29,8 @@
|
||||
use crate::buffer::BufferAccess;
|
||||
use crate::buffer::BufferViewRef;
|
||||
use crate::descriptor_set::layout::DescriptorDesc;
|
||||
use crate::descriptor_set::layout::DescriptorDescImage;
|
||||
use crate::descriptor_set::layout::DescriptorDescTy;
|
||||
use crate::descriptor_set::layout::DescriptorImageDesc;
|
||||
use crate::descriptor_set::layout::DescriptorImageDescArray;
|
||||
use crate::descriptor_set::layout::DescriptorImageDescDimensions;
|
||||
use crate::descriptor_set::layout::DescriptorSetLayout;
|
||||
use crate::descriptor_set::layout::DescriptorType;
|
||||
use crate::descriptor_set::pool::standard::StdDescriptorPoolAlloc;
|
||||
@ -45,6 +43,7 @@ use crate::device::Device;
|
||||
use crate::device::DeviceOwned;
|
||||
use crate::format::Format;
|
||||
use crate::image::view::ImageViewAbstract;
|
||||
use crate::image::view::ImageViewType;
|
||||
use crate::image::SampleCount;
|
||||
use crate::sampler::Sampler;
|
||||
use crate::OomError;
|
||||
@ -398,14 +397,14 @@ impl<R> PersistentDescriptorSetBuilderArray<R> {
|
||||
pub fn leave_array(
|
||||
mut self,
|
||||
) -> Result<PersistentDescriptorSetBuilder<R>, PersistentDescriptorSetError> {
|
||||
if self.desc.array_count > self.array_element as u32 {
|
||||
if self.desc.descriptor_count > self.array_element as u32 {
|
||||
return Err(PersistentDescriptorSetError::MissingArrayElements {
|
||||
expected: self.desc.array_count,
|
||||
expected: self.desc.descriptor_count,
|
||||
obtained: self.array_element as u32,
|
||||
});
|
||||
}
|
||||
|
||||
debug_assert_eq!(self.desc.array_count, self.array_element as u32);
|
||||
debug_assert_eq!(self.desc.descriptor_count, self.array_element as u32);
|
||||
|
||||
self.builder.binding_id += 1;
|
||||
Ok(self.builder)
|
||||
@ -434,21 +433,21 @@ impl<R> PersistentDescriptorSetBuilderArray<R> {
|
||||
buffer.inner().buffer.device().internal_object()
|
||||
);
|
||||
|
||||
if self.array_element as u32 >= self.desc.array_count {
|
||||
if self.array_element as u32 >= self.desc.descriptor_count {
|
||||
return Err(PersistentDescriptorSetError::ArrayOutOfBounds);
|
||||
}
|
||||
|
||||
self.builder.writes.push(match self.desc.ty {
|
||||
DescriptorDescTy::Buffer(ref buffer_desc) => {
|
||||
// Note that the buffer content is not checked. This is technically not unsafe as
|
||||
// long as the data in the buffer has no invalid memory representation (ie. no
|
||||
// bool, no enum, no pointer, no str) and as long as the robust buffer access
|
||||
// feature is enabled.
|
||||
// TODO: this is not checked ^
|
||||
// Note that the buffer content is not checked. This is technically not unsafe as
|
||||
// long as the data in the buffer has no invalid memory representation (ie. no
|
||||
// bool, no enum, no pointer, no str) and as long as the robust buffer access
|
||||
// feature is enabled.
|
||||
// TODO: this is not checked ^
|
||||
|
||||
// TODO: eventually shouldn't be an assert ; for now robust_buffer_access is always
|
||||
// enabled so this assert should never fail in practice, but we put it anyway
|
||||
// in case we forget to adjust this code
|
||||
// TODO: eventually shouldn't be an assert ; for now robust_buffer_access is always
|
||||
// enabled so this assert should never fail in practice, but we put it anyway
|
||||
// in case we forget to adjust this code
|
||||
self.builder.writes.push(match self.desc.ty {
|
||||
DescriptorDescTy::StorageBuffer | DescriptorDescTy::StorageBufferDynamic => {
|
||||
assert!(
|
||||
self.builder
|
||||
.layout
|
||||
@ -457,44 +456,64 @@ impl<R> PersistentDescriptorSetBuilderArray<R> {
|
||||
.robust_buffer_access
|
||||
);
|
||||
|
||||
if buffer_desc.storage {
|
||||
if !buffer.inner().buffer.usage().storage_buffer {
|
||||
return Err(PersistentDescriptorSetError::MissingBufferUsage(
|
||||
MissingBufferUsage::StorageBuffer,
|
||||
));
|
||||
}
|
||||
if !buffer.inner().buffer.usage().storage_buffer {
|
||||
return Err(PersistentDescriptorSetError::MissingBufferUsage(
|
||||
MissingBufferUsage::StorageBuffer,
|
||||
));
|
||||
}
|
||||
|
||||
unsafe {
|
||||
DescriptorWrite::storage_buffer(
|
||||
self.builder.binding_id as u32,
|
||||
self.array_element as u32,
|
||||
&buffer,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if !buffer.inner().buffer.usage().uniform_buffer {
|
||||
return Err(PersistentDescriptorSetError::MissingBufferUsage(
|
||||
MissingBufferUsage::UniformBuffer,
|
||||
));
|
||||
}
|
||||
unsafe {
|
||||
DescriptorWrite::storage_buffer(
|
||||
self.builder.binding_id as u32,
|
||||
self.array_element as u32,
|
||||
&buffer,
|
||||
)
|
||||
}
|
||||
}
|
||||
DescriptorDescTy::UniformBuffer => {
|
||||
assert!(
|
||||
self.builder
|
||||
.layout
|
||||
.device()
|
||||
.enabled_features()
|
||||
.robust_buffer_access
|
||||
);
|
||||
|
||||
if buffer_desc.dynamic.unwrap_or(false) {
|
||||
unsafe {
|
||||
DescriptorWrite::dynamic_uniform_buffer(
|
||||
self.builder.binding_id as u32,
|
||||
self.array_element as u32,
|
||||
&buffer,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
unsafe {
|
||||
DescriptorWrite::uniform_buffer(
|
||||
self.builder.binding_id as u32,
|
||||
self.array_element as u32,
|
||||
&buffer,
|
||||
)
|
||||
}
|
||||
}
|
||||
if !buffer.inner().buffer.usage().uniform_buffer {
|
||||
return Err(PersistentDescriptorSetError::MissingBufferUsage(
|
||||
MissingBufferUsage::UniformBuffer,
|
||||
));
|
||||
}
|
||||
|
||||
unsafe {
|
||||
DescriptorWrite::uniform_buffer(
|
||||
self.builder.binding_id as u32,
|
||||
self.array_element as u32,
|
||||
&buffer,
|
||||
)
|
||||
}
|
||||
}
|
||||
DescriptorDescTy::UniformBufferDynamic => {
|
||||
assert!(
|
||||
self.builder
|
||||
.layout
|
||||
.device()
|
||||
.enabled_features()
|
||||
.robust_buffer_access
|
||||
);
|
||||
|
||||
if !buffer.inner().buffer.usage().uniform_buffer {
|
||||
return Err(PersistentDescriptorSetError::MissingBufferUsage(
|
||||
MissingBufferUsage::UniformBuffer,
|
||||
));
|
||||
}
|
||||
|
||||
unsafe {
|
||||
DescriptorWrite::dynamic_uniform_buffer(
|
||||
self.builder.binding_id as u32,
|
||||
self.array_element as u32,
|
||||
&buffer,
|
||||
)
|
||||
}
|
||||
}
|
||||
ref d => {
|
||||
@ -543,39 +562,38 @@ impl<R> PersistentDescriptorSetBuilderArray<R> {
|
||||
view.view().device().internal_object()
|
||||
);
|
||||
|
||||
if self.array_element as u32 >= self.desc.array_count {
|
||||
if self.array_element as u32 >= self.desc.descriptor_count {
|
||||
return Err(PersistentDescriptorSetError::ArrayOutOfBounds);
|
||||
}
|
||||
|
||||
self.builder.writes.push(match self.desc.ty {
|
||||
DescriptorDescTy::TexelBuffer { storage, .. } => {
|
||||
if storage {
|
||||
// TODO: storage_texel_buffer_atomic
|
||||
DescriptorDescTy::StorageTexelBuffer { .. } => {
|
||||
// TODO: storage_texel_buffer_atomic
|
||||
|
||||
if !view.view().storage_texel_buffer() {
|
||||
return Err(PersistentDescriptorSetError::MissingBufferUsage(
|
||||
MissingBufferUsage::StorageTexelBuffer,
|
||||
));
|
||||
}
|
||||
|
||||
DescriptorWrite::storage_texel_buffer(
|
||||
self.builder.binding_id as u32,
|
||||
self.array_element as u32,
|
||||
view.view(),
|
||||
)
|
||||
} else {
|
||||
if !view.view().uniform_texel_buffer() {
|
||||
return Err(PersistentDescriptorSetError::MissingBufferUsage(
|
||||
MissingBufferUsage::UniformTexelBuffer,
|
||||
));
|
||||
}
|
||||
|
||||
DescriptorWrite::uniform_texel_buffer(
|
||||
self.builder.binding_id as u32,
|
||||
self.array_element as u32,
|
||||
view.view(),
|
||||
)
|
||||
if !view.view().storage_texel_buffer() {
|
||||
return Err(PersistentDescriptorSetError::MissingBufferUsage(
|
||||
MissingBufferUsage::StorageTexelBuffer,
|
||||
));
|
||||
}
|
||||
|
||||
DescriptorWrite::storage_texel_buffer(
|
||||
self.builder.binding_id as u32,
|
||||
self.array_element as u32,
|
||||
view.view(),
|
||||
)
|
||||
}
|
||||
DescriptorDescTy::UniformTexelBuffer { .. } => {
|
||||
if !view.view().uniform_texel_buffer() {
|
||||
return Err(PersistentDescriptorSetError::MissingBufferUsage(
|
||||
MissingBufferUsage::UniformTexelBuffer,
|
||||
));
|
||||
}
|
||||
|
||||
DescriptorWrite::uniform_texel_buffer(
|
||||
self.builder.binding_id as u32,
|
||||
self.array_element as u32,
|
||||
view.view(),
|
||||
)
|
||||
}
|
||||
ref d => {
|
||||
return Err(PersistentDescriptorSetError::WrongDescriptorTy { expected: d.ty() });
|
||||
@ -623,7 +641,7 @@ impl<R> PersistentDescriptorSetBuilderArray<R> {
|
||||
image_view.image().inner().image.device().internal_object()
|
||||
);
|
||||
|
||||
if self.array_element as u32 >= self.desc.array_count {
|
||||
if self.array_element as u32 >= self.desc.descriptor_count {
|
||||
return Err(PersistentDescriptorSetError::ArrayOutOfBounds);
|
||||
}
|
||||
|
||||
@ -633,31 +651,41 @@ impl<R> PersistentDescriptorSetBuilderArray<R> {
|
||||
};
|
||||
|
||||
self.builder.writes.push(match desc.ty {
|
||||
DescriptorDescTy::Image(ref desc) => {
|
||||
DescriptorDescTy::SampledImage(ref desc) => {
|
||||
if !image_view.image().inner().image.usage().sampled {
|
||||
return Err(PersistentDescriptorSetError::MissingImageUsage(
|
||||
MissingImageUsage::Sampled,
|
||||
));
|
||||
}
|
||||
|
||||
image_match_desc(&image_view, &desc)?;
|
||||
|
||||
if desc.sampled {
|
||||
DescriptorWrite::sampled_image(
|
||||
self.builder.binding_id as u32,
|
||||
self.array_element as u32,
|
||||
&image_view,
|
||||
)
|
||||
} else {
|
||||
if !image_view.component_mapping().is_identity() {
|
||||
return Err(PersistentDescriptorSetError::NotIdentitySwizzled);
|
||||
}
|
||||
|
||||
DescriptorWrite::storage_image(
|
||||
self.builder.binding_id as u32,
|
||||
self.array_element as u32,
|
||||
&image_view,
|
||||
)
|
||||
}
|
||||
DescriptorWrite::sampled_image(
|
||||
self.builder.binding_id as u32,
|
||||
self.array_element as u32,
|
||||
&image_view,
|
||||
)
|
||||
}
|
||||
DescriptorDescTy::InputAttachment {
|
||||
multisampled,
|
||||
array_layers,
|
||||
} => {
|
||||
DescriptorDescTy::StorageImage(ref desc) => {
|
||||
if !image_view.image().inner().image.usage().storage {
|
||||
return Err(PersistentDescriptorSetError::MissingImageUsage(
|
||||
MissingImageUsage::Storage,
|
||||
));
|
||||
}
|
||||
|
||||
image_match_desc(&image_view, &desc)?;
|
||||
|
||||
if !image_view.component_mapping().is_identity() {
|
||||
return Err(PersistentDescriptorSetError::NotIdentitySwizzled);
|
||||
}
|
||||
|
||||
DescriptorWrite::storage_image(
|
||||
self.builder.binding_id as u32,
|
||||
self.array_element as u32,
|
||||
&image_view,
|
||||
)
|
||||
}
|
||||
DescriptorDescTy::InputAttachment { multisampled } => {
|
||||
if !image_view.image().inner().image.usage().input_attachment {
|
||||
return Err(PersistentDescriptorSetError::MissingImageUsage(
|
||||
MissingImageUsage::InputAttachment,
|
||||
@ -677,28 +705,9 @@ impl<R> PersistentDescriptorSetBuilderArray<R> {
|
||||
let image_layers = image_view.array_layers();
|
||||
let num_layers = image_layers.end - image_layers.start;
|
||||
|
||||
match array_layers {
|
||||
DescriptorImageDescArray::NonArrayed => {
|
||||
if num_layers != 1 {
|
||||
return Err(PersistentDescriptorSetError::ArrayLayersMismatch {
|
||||
expected: 1,
|
||||
obtained: num_layers,
|
||||
});
|
||||
}
|
||||
}
|
||||
DescriptorImageDescArray::Arrayed {
|
||||
max_layers: Some(max_layers),
|
||||
} => {
|
||||
if num_layers > max_layers {
|
||||
// TODO: is this correct? "max" layers? or is it in fact min layers?
|
||||
return Err(PersistentDescriptorSetError::ArrayLayersMismatch {
|
||||
expected: max_layers,
|
||||
obtained: num_layers,
|
||||
});
|
||||
}
|
||||
}
|
||||
DescriptorImageDescArray::Arrayed { max_layers: None } => {}
|
||||
};
|
||||
if image_view.ty().is_arrayed() {
|
||||
return Err(PersistentDescriptorSetError::UnexpectedArrayed);
|
||||
}
|
||||
|
||||
DescriptorWrite::input_attachment(
|
||||
self.builder.binding_id as u32,
|
||||
@ -760,7 +769,7 @@ impl<R> PersistentDescriptorSetBuilderArray<R> {
|
||||
sampler.device().internal_object()
|
||||
);
|
||||
|
||||
if self.array_element as u32 >= self.desc.array_count {
|
||||
if self.array_element as u32 >= self.desc.descriptor_count {
|
||||
return Err(PersistentDescriptorSetError::ArrayOutOfBounds);
|
||||
}
|
||||
|
||||
@ -769,6 +778,12 @@ impl<R> PersistentDescriptorSetBuilderArray<R> {
|
||||
None => return Err(PersistentDescriptorSetError::EmptyExpected),
|
||||
};
|
||||
|
||||
if !image_view.image().inner().image.usage().sampled {
|
||||
return Err(PersistentDescriptorSetError::MissingImageUsage(
|
||||
MissingImageUsage::Sampled,
|
||||
));
|
||||
}
|
||||
|
||||
if !image_view.can_be_sampled(&sampler) {
|
||||
return Err(PersistentDescriptorSetError::IncompatibleImageViewSampler);
|
||||
}
|
||||
@ -829,7 +844,7 @@ impl<R> PersistentDescriptorSetBuilderArray<R> {
|
||||
sampler.device().internal_object()
|
||||
);
|
||||
|
||||
if self.array_element as u32 >= self.desc.array_count {
|
||||
if self.array_element as u32 >= self.desc.descriptor_count {
|
||||
return Err(PersistentDescriptorSetError::ArrayOutOfBounds);
|
||||
}
|
||||
|
||||
@ -868,26 +883,15 @@ impl<R> PersistentDescriptorSetBuilderArray<R> {
|
||||
// Checks whether an image view matches the descriptor.
|
||||
fn image_match_desc<I>(
|
||||
image_view: &I,
|
||||
desc: &DescriptorImageDesc,
|
||||
desc: &DescriptorDescImage,
|
||||
) -> Result<(), PersistentDescriptorSetError>
|
||||
where
|
||||
I: ?Sized + ImageViewAbstract,
|
||||
{
|
||||
if desc.sampled && !image_view.image().inner().image.usage().sampled {
|
||||
return Err(PersistentDescriptorSetError::MissingImageUsage(
|
||||
MissingImageUsage::Sampled,
|
||||
));
|
||||
} else if !desc.sampled && !image_view.image().inner().image.usage().storage {
|
||||
return Err(PersistentDescriptorSetError::MissingImageUsage(
|
||||
MissingImageUsage::Storage,
|
||||
));
|
||||
}
|
||||
|
||||
let image_view_ty = DescriptorImageDescDimensions::from_image_view_type(image_view.ty());
|
||||
if image_view_ty != desc.dimensions {
|
||||
if image_view.ty() != desc.view_type {
|
||||
return Err(PersistentDescriptorSetError::ImageViewTypeMismatch {
|
||||
expected: desc.dimensions,
|
||||
obtained: image_view_ty,
|
||||
expected: desc.view_type,
|
||||
obtained: image_view.ty(),
|
||||
});
|
||||
}
|
||||
|
||||
@ -906,46 +910,6 @@ where
|
||||
return Err(PersistentDescriptorSetError::UnexpectedMultisampled);
|
||||
}
|
||||
|
||||
let image_layers = image_view.array_layers();
|
||||
let num_layers = image_layers.end - image_layers.start;
|
||||
|
||||
match desc.array_layers {
|
||||
DescriptorImageDescArray::NonArrayed => {
|
||||
// TODO: when a non-array is expected, can we pass an image view that is in fact an
|
||||
// array with one layer? need to check
|
||||
let required_layers = if desc.dimensions == DescriptorImageDescDimensions::Cube {
|
||||
6
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
if num_layers != required_layers {
|
||||
return Err(PersistentDescriptorSetError::ArrayLayersMismatch {
|
||||
expected: 1,
|
||||
obtained: num_layers,
|
||||
});
|
||||
}
|
||||
}
|
||||
DescriptorImageDescArray::Arrayed {
|
||||
max_layers: Some(max_layers),
|
||||
} => {
|
||||
let required_layers = if desc.dimensions == DescriptorImageDescDimensions::Cube {
|
||||
max_layers * 6
|
||||
} else {
|
||||
max_layers
|
||||
};
|
||||
|
||||
// TODO: is this correct? "max" layers? or is it in fact min layers?
|
||||
if num_layers > required_layers {
|
||||
return Err(PersistentDescriptorSetError::ArrayLayersMismatch {
|
||||
expected: max_layers,
|
||||
obtained: num_layers,
|
||||
});
|
||||
}
|
||||
}
|
||||
DescriptorImageDescArray::Arrayed { max_layers: None } => {}
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -1147,12 +1111,12 @@ pub enum MissingImageUsage {
|
||||
/// Error related to the persistent descriptor set.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PersistentDescriptorSetError {
|
||||
/// The number of array layers of an image doesn't match what was expected.
|
||||
ArrayLayersMismatch {
|
||||
/// Number of expected array layers for the image.
|
||||
expected: u32,
|
||||
/// Number of array layers of the image that was added.
|
||||
obtained: u32,
|
||||
/// The arrayed-ness of an image view doesn't match what was expected.
|
||||
ArrayedMismatch {
|
||||
/// Whether the shader expects an arrayed image.
|
||||
expected: bool,
|
||||
/// Whether an arrayed image view was provided.
|
||||
obtained: bool,
|
||||
},
|
||||
|
||||
/// Tried to add too many elements to an array.
|
||||
@ -1175,9 +1139,9 @@ pub enum PersistentDescriptorSetError {
|
||||
/// The type of an image view doesn't match what was expected.
|
||||
ImageViewTypeMismatch {
|
||||
/// Expected type.
|
||||
expected: DescriptorImageDescDimensions,
|
||||
expected: ImageViewType,
|
||||
/// Type of the image view that was passed.
|
||||
obtained: DescriptorImageDescDimensions,
|
||||
obtained: ImageViewType,
|
||||
},
|
||||
|
||||
/// The image view isn't compatible with the sampler.
|
||||
@ -1200,6 +1164,9 @@ pub enum PersistentDescriptorSetError {
|
||||
/// The image view has a component swizzle that is different from identity.
|
||||
NotIdentitySwizzled,
|
||||
|
||||
/// Expected a non-arrayed image, but got an arrayed image.
|
||||
UnexpectedArrayed,
|
||||
|
||||
/// Expected a single-sampled image, but got a multisampled image.
|
||||
UnexpectedMultisampled,
|
||||
|
||||
@ -1219,8 +1186,8 @@ impl fmt::Display for PersistentDescriptorSetError {
|
||||
fmt,
|
||||
"{}",
|
||||
match *self {
|
||||
PersistentDescriptorSetError::ArrayLayersMismatch { .. } => {
|
||||
"the number of array layers of an image doesn't match what was expected"
|
||||
PersistentDescriptorSetError::ArrayedMismatch { .. } => {
|
||||
"the arrayed-ness of an image view doesn't match what was expected"
|
||||
}
|
||||
PersistentDescriptorSetError::ArrayOutOfBounds => {
|
||||
"tried to add too many elements to an array"
|
||||
@ -1252,6 +1219,9 @@ impl fmt::Display for PersistentDescriptorSetError {
|
||||
PersistentDescriptorSetError::NotIdentitySwizzled => {
|
||||
"the image view's component mapping is not identity swizzled"
|
||||
}
|
||||
PersistentDescriptorSetError::UnexpectedArrayed => {
|
||||
"expected a non-arrayed image, but got an arrayed image"
|
||||
}
|
||||
PersistentDescriptorSetError::UnexpectedMultisampled => {
|
||||
"expected a single-sampled image, but got a multisampled image"
|
||||
}
|
||||
|
@ -194,9 +194,9 @@ mod tests {
|
||||
|
||||
let desc = DescriptorDesc {
|
||||
ty: DescriptorDescTy::Sampler,
|
||||
array_count: 1,
|
||||
descriptor_count: 1,
|
||||
stages: ShaderStages::all(),
|
||||
readonly: false,
|
||||
mutable: true,
|
||||
};
|
||||
let layout = DescriptorSetLayout::new(
|
||||
device.clone(),
|
||||
|
@ -373,7 +373,6 @@ impl ExactSizeIterator for UnsafeDescriptorPoolAllocIter {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::descriptor_set::layout::DescriptorBufferDesc;
|
||||
use crate::descriptor_set::layout::DescriptorDesc;
|
||||
use crate::descriptor_set::layout::DescriptorDescTy;
|
||||
use crate::descriptor_set::layout::DescriptorSetDesc;
|
||||
@ -421,13 +420,10 @@ mod tests {
|
||||
let (device, _) = gfx_dev_and_queue!();
|
||||
|
||||
let layout = DescriptorDesc {
|
||||
ty: DescriptorDescTy::Buffer(DescriptorBufferDesc {
|
||||
dynamic: Some(false),
|
||||
storage: false,
|
||||
}),
|
||||
array_count: 1,
|
||||
ty: DescriptorDescTy::UniformBuffer,
|
||||
descriptor_count: 1,
|
||||
stages: ShaderStages::all_graphics(),
|
||||
readonly: true,
|
||||
mutable: false,
|
||||
};
|
||||
|
||||
let set_layout = DescriptorSetLayout::new(
|
||||
@ -454,13 +450,10 @@ mod tests {
|
||||
let (device2, _) = gfx_dev_and_queue!();
|
||||
|
||||
let layout = DescriptorDesc {
|
||||
ty: DescriptorDescTy::Buffer(DescriptorBufferDesc {
|
||||
dynamic: Some(false),
|
||||
storage: false,
|
||||
}),
|
||||
array_count: 1,
|
||||
ty: DescriptorDescTy::UniformBuffer,
|
||||
descriptor_count: 1,
|
||||
stages: ShaderStages::all_graphics(),
|
||||
readonly: true,
|
||||
mutable: false,
|
||||
};
|
||||
|
||||
let set_layout =
|
||||
|
@ -181,12 +181,10 @@ where
|
||||
(ImageViewType::Dim1dArray, ImageDimensions::Dim1d { .. }, _, _) => (),
|
||||
(ImageViewType::Dim2d, ImageDimensions::Dim2d { .. }, 1, _) => (),
|
||||
(ImageViewType::Dim2dArray, ImageDimensions::Dim2d { .. }, _, _) => (),
|
||||
(ImageViewType::Cubemap, ImageDimensions::Dim2d { .. }, 6, _)
|
||||
if flags.cube_compatible =>
|
||||
{
|
||||
(ImageViewType::Cube, ImageDimensions::Dim2d { .. }, 6, _) if flags.cube_compatible => {
|
||||
()
|
||||
}
|
||||
(ImageViewType::CubemapArray, ImageDimensions::Dim2d { .. }, n, _)
|
||||
(ImageViewType::CubeArray, ImageDimensions::Dim2d { .. }, n, _)
|
||||
if flags.cube_compatible && n % 6 == 0 =>
|
||||
{
|
||||
()
|
||||
@ -407,8 +405,18 @@ pub enum ImageViewType {
|
||||
Dim2d = ash::vk::ImageViewType::TYPE_2D.as_raw(),
|
||||
Dim2dArray = ash::vk::ImageViewType::TYPE_2D_ARRAY.as_raw(),
|
||||
Dim3d = ash::vk::ImageViewType::TYPE_3D.as_raw(),
|
||||
Cubemap = ash::vk::ImageViewType::CUBE.as_raw(),
|
||||
CubemapArray = ash::vk::ImageViewType::CUBE_ARRAY.as_raw(),
|
||||
Cube = ash::vk::ImageViewType::CUBE.as_raw(),
|
||||
CubeArray = ash::vk::ImageViewType::CUBE_ARRAY.as_raw(),
|
||||
}
|
||||
|
||||
impl ImageViewType {
|
||||
#[inline]
|
||||
pub fn is_arrayed(&self) -> bool {
|
||||
match self {
|
||||
Self::Dim1d | Self::Dim2d | Self::Dim3d | Self::Cube => false,
|
||||
Self::Dim1dArray | Self::Dim2dArray | Self::CubeArray => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ImageViewType> for ash::vk::ImageViewType {
|
||||
|
@ -107,7 +107,7 @@ impl ComputePipeline {
|
||||
}
|
||||
|
||||
unsafe {
|
||||
pipeline_layout.ensure_superset_of(
|
||||
pipeline_layout.ensure_compatible_with_shader(
|
||||
shader.descriptor_set_layout_descs(),
|
||||
shader.push_constant_range(),
|
||||
)?;
|
||||
@ -343,7 +343,6 @@ mod tests {
|
||||
use crate::buffer::CpuAccessibleBuffer;
|
||||
use crate::command_buffer::AutoCommandBufferBuilder;
|
||||
use crate::command_buffer::CommandBufferUsage;
|
||||
use crate::descriptor_set::layout::DescriptorBufferDesc;
|
||||
use crate::descriptor_set::layout::DescriptorDesc;
|
||||
use crate::descriptor_set::layout::DescriptorDescTy;
|
||||
use crate::descriptor_set::layout::DescriptorSetDesc;
|
||||
@ -414,16 +413,13 @@ mod tests {
|
||||
module.compute_entry_point(
|
||||
CStr::from_ptr(NAME.as_ptr() as *const _),
|
||||
[DescriptorSetDesc::new([Some(DescriptorDesc {
|
||||
ty: DescriptorDescTy::Buffer(DescriptorBufferDesc {
|
||||
dynamic: Some(false),
|
||||
storage: true,
|
||||
}),
|
||||
array_count: 1,
|
||||
ty: DescriptorDescTy::StorageBuffer,
|
||||
descriptor_count: 1,
|
||||
stages: ShaderStages {
|
||||
compute: true,
|
||||
..ShaderStages::none()
|
||||
},
|
||||
readonly: true,
|
||||
mutable: false,
|
||||
})])],
|
||||
None,
|
||||
SpecConsts::descriptors(),
|
||||
|
@ -192,17 +192,19 @@ where
|
||||
match range_map.entry((range.offset, range.size)) {
|
||||
Entry::Vacant(entry) => {
|
||||
entry.insert(range.stages);
|
||||
},
|
||||
}
|
||||
Entry::Occupied(mut entry) => {
|
||||
*entry.get_mut() = *entry.get() | range.stages;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let push_constant_ranges: Vec<_> = range_map
|
||||
.iter()
|
||||
.map(|((offset, size), stages)| {
|
||||
PipelineLayoutPcRange { offset: *offset, size: *size, stages: *stages }
|
||||
.map(|((offset, size), stages)| PipelineLayoutPcRange {
|
||||
offset: *offset,
|
||||
size: *size,
|
||||
stages: *stages,
|
||||
})
|
||||
.collect();
|
||||
|
||||
@ -239,7 +241,7 @@ where
|
||||
|
||||
{
|
||||
let shader = &self.vertex_shader.as_ref().unwrap().0;
|
||||
pipeline_layout.ensure_superset_of(
|
||||
pipeline_layout.ensure_compatible_with_shader(
|
||||
shader.descriptor_set_layout_descs(),
|
||||
shader.push_constant_range(),
|
||||
)?;
|
||||
@ -247,7 +249,7 @@ where
|
||||
|
||||
if let Some(ref geometry_shader) = self.geometry_shader {
|
||||
let shader = &geometry_shader.0;
|
||||
pipeline_layout.ensure_superset_of(
|
||||
pipeline_layout.ensure_compatible_with_shader(
|
||||
shader.descriptor_set_layout_descs(),
|
||||
shader.push_constant_range(),
|
||||
)?;
|
||||
@ -256,7 +258,7 @@ where
|
||||
if let Some(ref tess) = self.tessellation {
|
||||
{
|
||||
let shader = &tess.tessellation_control_shader.0;
|
||||
pipeline_layout.ensure_superset_of(
|
||||
pipeline_layout.ensure_compatible_with_shader(
|
||||
shader.descriptor_set_layout_descs(),
|
||||
shader.push_constant_range(),
|
||||
)?;
|
||||
@ -264,7 +266,7 @@ where
|
||||
|
||||
{
|
||||
let shader = &tess.tessellation_evaluation_shader.0;
|
||||
pipeline_layout.ensure_superset_of(
|
||||
pipeline_layout.ensure_compatible_with_shader(
|
||||
shader.descriptor_set_layout_descs(),
|
||||
shader.push_constant_range(),
|
||||
)?;
|
||||
@ -273,7 +275,7 @@ where
|
||||
|
||||
if let Some(ref fragment_shader) = self.fragment_shader {
|
||||
let shader = &fragment_shader.0;
|
||||
pipeline_layout.ensure_superset_of(
|
||||
pipeline_layout.ensure_compatible_with_shader(
|
||||
shader.descriptor_set_layout_descs(),
|
||||
shader.push_constant_range(),
|
||||
)?;
|
||||
@ -795,26 +797,10 @@ where
|
||||
return Err(GraphicsPipelineCreationError::MaxViewportDimensionsExceeded);
|
||||
}
|
||||
|
||||
if vp.x
|
||||
< device
|
||||
.physical_device()
|
||||
.properties()
|
||||
.viewport_bounds_range[0]
|
||||
|| vp.x + vp.width
|
||||
> device
|
||||
.physical_device()
|
||||
.properties()
|
||||
.viewport_bounds_range[1]
|
||||
|| vp.y
|
||||
< device
|
||||
.physical_device()
|
||||
.properties()
|
||||
.viewport_bounds_range[0]
|
||||
|| vp.y + vp.height
|
||||
> device
|
||||
.physical_device()
|
||||
.properties()
|
||||
.viewport_bounds_range[1]
|
||||
if vp.x < device.physical_device().properties().viewport_bounds_range[0]
|
||||
|| vp.x + vp.width > device.physical_device().properties().viewport_bounds_range[1]
|
||||
|| vp.y < device.physical_device().properties().viewport_bounds_range[0]
|
||||
|| vp.y + vp.height > device.physical_device().properties().viewport_bounds_range[1]
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::ViewportBoundsExceeded);
|
||||
}
|
||||
|
@ -36,39 +36,40 @@ pub fn check_desc_against_limits(
|
||||
|
||||
for set in descriptor_set_layouts {
|
||||
for descriptor in (0..set.num_bindings()).filter_map(|i| set.descriptor(i).map(|d| d)) {
|
||||
num_resources.increment(descriptor.array_count, &descriptor.stages);
|
||||
num_resources.increment(descriptor.descriptor_count, &descriptor.stages);
|
||||
|
||||
match descriptor.ty.ty() {
|
||||
// TODO:
|
||||
DescriptorType::Sampler => {
|
||||
num_samplers.increment(descriptor.array_count, &descriptor.stages);
|
||||
num_samplers.increment(descriptor.descriptor_count, &descriptor.stages);
|
||||
}
|
||||
DescriptorType::CombinedImageSampler => {
|
||||
num_samplers.increment(descriptor.array_count, &descriptor.stages);
|
||||
num_sampled_images.increment(descriptor.array_count, &descriptor.stages);
|
||||
num_samplers.increment(descriptor.descriptor_count, &descriptor.stages);
|
||||
num_sampled_images.increment(descriptor.descriptor_count, &descriptor.stages);
|
||||
}
|
||||
DescriptorType::SampledImage | DescriptorType::UniformTexelBuffer => {
|
||||
num_sampled_images.increment(descriptor.array_count, &descriptor.stages);
|
||||
num_sampled_images.increment(descriptor.descriptor_count, &descriptor.stages);
|
||||
}
|
||||
DescriptorType::StorageImage | DescriptorType::StorageTexelBuffer => {
|
||||
num_storage_images.increment(descriptor.array_count, &descriptor.stages);
|
||||
num_storage_images.increment(descriptor.descriptor_count, &descriptor.stages);
|
||||
}
|
||||
DescriptorType::UniformBuffer => {
|
||||
num_uniform_buffers.increment(descriptor.array_count, &descriptor.stages);
|
||||
num_uniform_buffers.increment(descriptor.descriptor_count, &descriptor.stages);
|
||||
}
|
||||
DescriptorType::UniformBufferDynamic => {
|
||||
num_uniform_buffers.increment(descriptor.array_count, &descriptor.stages);
|
||||
num_uniform_buffers.increment(descriptor.descriptor_count, &descriptor.stages);
|
||||
num_uniform_buffers_dynamic += 1;
|
||||
}
|
||||
DescriptorType::StorageBuffer => {
|
||||
num_storage_buffers.increment(descriptor.array_count, &descriptor.stages);
|
||||
num_storage_buffers.increment(descriptor.descriptor_count, &descriptor.stages);
|
||||
}
|
||||
DescriptorType::StorageBufferDynamic => {
|
||||
num_storage_buffers.increment(descriptor.array_count, &descriptor.stages);
|
||||
num_storage_buffers.increment(descriptor.descriptor_count, &descriptor.stages);
|
||||
num_storage_buffers_dynamic += 1;
|
||||
}
|
||||
DescriptorType::InputAttachment => {
|
||||
num_input_attachments.increment(descriptor.array_count, &descriptor.stages);
|
||||
num_input_attachments
|
||||
.increment(descriptor.descriptor_count, &descriptor.stages);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -98,9 +99,7 @@ pub fn check_desc_against_limits(
|
||||
},
|
||||
);
|
||||
}
|
||||
if num_uniform_buffers.max_per_stage()
|
||||
> properties.max_per_stage_descriptor_uniform_buffers
|
||||
{
|
||||
if num_uniform_buffers.max_per_stage() > properties.max_per_stage_descriptor_uniform_buffers {
|
||||
return Err(
|
||||
PipelineLayoutLimitsError::MaxPerStageDescriptorUniformBuffersLimitExceeded {
|
||||
limit: properties.max_per_stage_descriptor_uniform_buffers,
|
||||
@ -108,9 +107,7 @@ pub fn check_desc_against_limits(
|
||||
},
|
||||
);
|
||||
}
|
||||
if num_storage_buffers.max_per_stage()
|
||||
> properties.max_per_stage_descriptor_storage_buffers
|
||||
{
|
||||
if num_storage_buffers.max_per_stage() > properties.max_per_stage_descriptor_storage_buffers {
|
||||
return Err(
|
||||
PipelineLayoutLimitsError::MaxPerStageDescriptorStorageBuffersLimitExceeded {
|
||||
limit: properties.max_per_stage_descriptor_storage_buffers,
|
||||
@ -118,9 +115,7 @@ pub fn check_desc_against_limits(
|
||||
},
|
||||
);
|
||||
}
|
||||
if num_sampled_images.max_per_stage()
|
||||
> properties.max_per_stage_descriptor_sampled_images
|
||||
{
|
||||
if num_sampled_images.max_per_stage() > properties.max_per_stage_descriptor_sampled_images {
|
||||
return Err(
|
||||
PipelineLayoutLimitsError::MaxPerStageDescriptorSampledImagesLimitExceeded {
|
||||
limit: properties.max_per_stage_descriptor_sampled_images,
|
||||
@ -128,9 +123,7 @@ pub fn check_desc_against_limits(
|
||||
},
|
||||
);
|
||||
}
|
||||
if num_storage_images.max_per_stage()
|
||||
> properties.max_per_stage_descriptor_storage_images
|
||||
{
|
||||
if num_storage_images.max_per_stage() > properties.max_per_stage_descriptor_storage_images {
|
||||
return Err(
|
||||
PipelineLayoutLimitsError::MaxPerStageDescriptorStorageImagesLimitExceeded {
|
||||
limit: properties.max_per_stage_descriptor_storage_images,
|
||||
@ -138,14 +131,11 @@ pub fn check_desc_against_limits(
|
||||
},
|
||||
);
|
||||
}
|
||||
if num_input_attachments.max_per_stage()
|
||||
> properties
|
||||
.max_per_stage_descriptor_input_attachments
|
||||
if num_input_attachments.max_per_stage() > properties.max_per_stage_descriptor_input_attachments
|
||||
{
|
||||
return Err(
|
||||
PipelineLayoutLimitsError::MaxPerStageDescriptorInputAttachmentsLimitExceeded {
|
||||
limit: properties
|
||||
.max_per_stage_descriptor_input_attachments,
|
||||
limit: properties.max_per_stage_descriptor_input_attachments,
|
||||
requested: num_input_attachments.max_per_stage(),
|
||||
},
|
||||
);
|
||||
@ -167,14 +157,10 @@ pub fn check_desc_against_limits(
|
||||
},
|
||||
);
|
||||
}
|
||||
if num_uniform_buffers_dynamic
|
||||
> properties
|
||||
.max_descriptor_set_uniform_buffers_dynamic
|
||||
{
|
||||
if num_uniform_buffers_dynamic > properties.max_descriptor_set_uniform_buffers_dynamic {
|
||||
return Err(
|
||||
PipelineLayoutLimitsError::MaxDescriptorSetUniformBuffersDynamicLimitExceeded {
|
||||
limit: properties
|
||||
.max_descriptor_set_uniform_buffers_dynamic,
|
||||
limit: properties.max_descriptor_set_uniform_buffers_dynamic,
|
||||
requested: num_uniform_buffers_dynamic,
|
||||
},
|
||||
);
|
||||
@ -187,14 +173,10 @@ pub fn check_desc_against_limits(
|
||||
},
|
||||
);
|
||||
}
|
||||
if num_storage_buffers_dynamic
|
||||
> properties
|
||||
.max_descriptor_set_storage_buffers_dynamic
|
||||
{
|
||||
if num_storage_buffers_dynamic > properties.max_descriptor_set_storage_buffers_dynamic {
|
||||
return Err(
|
||||
PipelineLayoutLimitsError::MaxDescriptorSetStorageBuffersDynamicLimitExceeded {
|
||||
limit: properties
|
||||
.max_descriptor_set_storage_buffers_dynamic,
|
||||
limit: properties.max_descriptor_set_storage_buffers_dynamic,
|
||||
requested: num_storage_buffers_dynamic,
|
||||
},
|
||||
);
|
||||
|
@ -9,8 +9,8 @@
|
||||
|
||||
use super::limits_check;
|
||||
use crate::check_errors;
|
||||
use crate::descriptor_set::layout::DescriptorSetCompatibilityError;
|
||||
use crate::descriptor_set::layout::DescriptorSetDesc;
|
||||
use crate::descriptor_set::layout::DescriptorSetDescSupersetError;
|
||||
use crate::descriptor_set::layout::DescriptorSetLayout;
|
||||
use crate::device::Device;
|
||||
use crate::device::DeviceOwned;
|
||||
@ -167,7 +167,7 @@ impl PipelineLayout {
|
||||
|
||||
/// Makes sure that `self` is a superset of the provided descriptor set layouts and push
|
||||
/// constant ranges. Returns an `Err` if this is not the case.
|
||||
pub fn ensure_superset_of(
|
||||
pub fn ensure_compatible_with_shader(
|
||||
&self,
|
||||
descriptor_set_layout_descs: &[DescriptorSetDesc],
|
||||
push_constant_range: &Option<PipelineLayoutPcRange>,
|
||||
@ -189,7 +189,7 @@ impl PipelineLayout {
|
||||
.get(set_num)
|
||||
.unwrap_or_else(|| &empty);
|
||||
|
||||
if let Err(error) = first.ensure_superset_of(second) {
|
||||
if let Err(error) = first.ensure_compatible_with_shader(second) {
|
||||
return Err(PipelineLayoutSupersetError::DescriptorSet {
|
||||
error,
|
||||
set_num: set_num as u32,
|
||||
@ -202,7 +202,8 @@ impl PipelineLayout {
|
||||
for own_range in self.push_constant_ranges.as_ref().into_iter() {
|
||||
if range.stages.intersects(&own_range.stages) && // check if it shares any stages
|
||||
(range.offset < own_range.offset || // our range must start before and end after the given range
|
||||
own_range.offset + own_range.size < range.offset + range.size) {
|
||||
own_range.offset + own_range.size < range.offset + range.size)
|
||||
{
|
||||
return Err(PipelineLayoutSupersetError::PushConstantRange {
|
||||
first_range: *own_range,
|
||||
second_range: *range,
|
||||
@ -338,7 +339,7 @@ impl From<Error> for PipelineLayoutCreationError {
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum PipelineLayoutSupersetError {
|
||||
DescriptorSet {
|
||||
error: DescriptorSetDescSupersetError,
|
||||
error: DescriptorSetCompatibilityError,
|
||||
set_num: u32,
|
||||
},
|
||||
PushConstantRange {
|
||||
@ -362,13 +363,16 @@ impl fmt::Display for PipelineLayoutSupersetError {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
match *self {
|
||||
PipelineLayoutSupersetError::DescriptorSet { .. } => {
|
||||
write!(
|
||||
write!(fmt, "the descriptor set was not a superset of the other")
|
||||
}
|
||||
PipelineLayoutSupersetError::PushConstantRange {
|
||||
first_range,
|
||||
second_range,
|
||||
} => {
|
||||
writeln!(
|
||||
fmt,
|
||||
"the descriptor set was not a superset of the other"
|
||||
)
|
||||
},
|
||||
PipelineLayoutSupersetError::PushConstantRange { first_range, second_range } => {
|
||||
writeln!(fmt, "our range did not completely encompass the other range")?;
|
||||
"our range did not completely encompass the other range"
|
||||
)?;
|
||||
writeln!(fmt, " our stages: {:?}", first_range.stages)?;
|
||||
writeln!(
|
||||
fmt,
|
||||
@ -377,12 +381,13 @@ impl fmt::Display for PipelineLayoutSupersetError {
|
||||
first_range.offset + first_range.size
|
||||
)?;
|
||||
writeln!(fmt, " other stages: {:?}", second_range.stages)?;
|
||||
write!(fmt,
|
||||
write!(
|
||||
fmt,
|
||||
" other range: {} - {}",
|
||||
second_range.offset,
|
||||
second_range.offset + second_range.size
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -681,24 +681,16 @@ impl ShaderStages {
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether we have more stages enabled than `other`.
|
||||
/// Returns whether `self` contains all the stages of `other`.
|
||||
// TODO: add example
|
||||
#[inline]
|
||||
pub const fn ensure_superset_of(
|
||||
&self,
|
||||
other: &ShaderStages,
|
||||
) -> Result<(), ShaderStagesSupersetError> {
|
||||
if (self.vertex || !other.vertex)
|
||||
pub const fn is_superset_of(&self, other: &ShaderStages) -> bool {
|
||||
(self.vertex || !other.vertex)
|
||||
&& (self.tessellation_control || !other.tessellation_control)
|
||||
&& (self.tessellation_evaluation || !other.tessellation_evaluation)
|
||||
&& (self.geometry || !other.geometry)
|
||||
&& (self.fragment || !other.fragment)
|
||||
&& (self.compute || !other.compute)
|
||||
{
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ShaderStagesSupersetError::NotSuperset)
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether any of the stages in `self` are also present in `other`.
|
||||
@ -785,24 +777,3 @@ impl From<ShaderStages> for PipelineStages {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Error when checking that a `ShaderStages` object is a superset of another.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ShaderStagesSupersetError {
|
||||
NotSuperset,
|
||||
}
|
||||
|
||||
impl error::Error for ShaderStagesSupersetError {}
|
||||
|
||||
impl fmt::Display for ShaderStagesSupersetError {
|
||||
#[inline]
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
write!(
|
||||
fmt,
|
||||
"{}",
|
||||
match *self {
|
||||
ShaderStagesSupersetError::NotSuperset => "shader stages not a superset",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user