diff options
Diffstat (limited to 'src/descriptor_set/persistent.rs')
-rw-r--r-- | src/descriptor_set/persistent.rs | 1304 |
1 files changed, 1304 insertions, 0 deletions
diff --git a/src/descriptor_set/persistent.rs b/src/descriptor_set/persistent.rs new file mode 100644 index 0000000..c949f88 --- /dev/null +++ b/src/descriptor_set/persistent.rs @@ -0,0 +1,1304 @@ +// Copyright (c) 2017 The vulkano developers +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT +// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, +// at your option. All files in the project carrying such +// notice may not be copied, modified, or distributed except +// according to those terms. + +//! A simple, immutable descriptor set that is expected to be long-lived. +//! +//! Creating a persistent descriptor set allocates from a pool, and can't be modified once created. +//! You are therefore encouraged to create them at initialization and not the during +//! performance-critical paths. +//! +//! > **Note**: You can control of the pool that is used to create the descriptor set, if you wish +//! > so. By creating a implementation of the `DescriptorPool` trait that doesn't perform any +//! > actual allocation, you can skip this allocation and make it acceptable to use a persistent +//! > descriptor set in performance-critical paths.. +//! +//! The template parameter of the `PersistentDescriptorSet` is complex, and you shouldn't try to +//! express it explicitly. If you want to store your descriptor set in a struct or in a `Vec` for +//! example, you are encouraged to turn the `PersistentDescriptorSet` into a `Box<DescriptorSet>` +//! or a `Arc<DescriptorSet>`. +//! +//! # Example +//! TODO: + +use crate::buffer::BufferAccess; +use crate::buffer::BufferViewRef; +use crate::descriptor_set::layout::DescriptorDesc; +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; +use crate::descriptor_set::pool::DescriptorPool; +use crate::descriptor_set::pool::DescriptorPoolAlloc; +use crate::descriptor_set::sys::DescriptorWrite; +use crate::descriptor_set::DescriptorSet; +use crate::descriptor_set::UnsafeDescriptorSet; +use crate::device::Device; +use crate::device::DeviceOwned; +use crate::format::Format; +use crate::image::view::ImageViewAbstract; +use crate::image::SampleCount; +use crate::sampler::Sampler; +use crate::OomError; +use crate::VulkanObject; +use std::error; +use std::fmt; +use std::hash::Hash; +use std::hash::Hasher; +use std::sync::Arc; + +/// A simple, immutable descriptor set that is expected to be long-lived. +pub struct PersistentDescriptorSet<R, P = StdDescriptorPoolAlloc> { + inner: P, + resources: R, + layout: Arc<DescriptorSetLayout>, +} + +impl PersistentDescriptorSet<()> { + /// Starts the process of building a `PersistentDescriptorSet`. Returns a builder. + /// + /// # Panic + /// + /// - Panics if the set id is out of range. + /// + pub fn start(layout: Arc<DescriptorSetLayout>) -> PersistentDescriptorSetBuilder<()> { + let cap = layout.num_bindings(); + + PersistentDescriptorSetBuilder { + layout, + binding_id: 0, + writes: Vec::with_capacity(cap), + resources: (), + } + } +} + +unsafe impl<R, P> DescriptorSet for PersistentDescriptorSet<R, P> +where + P: DescriptorPoolAlloc, + R: PersistentDescriptorSetResources, +{ + #[inline] + fn inner(&self) -> &UnsafeDescriptorSet { + self.inner.inner() + } + + #[inline] + fn layout(&self) -> &Arc<DescriptorSetLayout> { + &self.layout + } + + #[inline] + fn num_buffers(&self) -> usize { + self.resources.num_buffers() + } + + #[inline] + fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> { + self.resources.buffer(index) + } + + #[inline] + fn num_images(&self) -> usize { + self.resources.num_images() + } + + #[inline] + fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> { + self.resources.image(index) + } +} + +unsafe impl<R, P> DeviceOwned for PersistentDescriptorSet<R, P> { + #[inline] + fn device(&self) -> &Arc<Device> { + self.layout.device() + } +} + +impl<R, P> PartialEq for PersistentDescriptorSet<R, P> +where + P: DescriptorPoolAlloc, + R: PersistentDescriptorSetResources, +{ + #[inline] + fn eq(&self, other: &Self) -> bool { + self.inner().internal_object() == other.inner().internal_object() + && self.device() == other.device() + } +} + +impl<R, P> Eq for PersistentDescriptorSet<R, P> +where + P: DescriptorPoolAlloc, + R: PersistentDescriptorSetResources, +{ +} + +impl<R, P> Hash for PersistentDescriptorSet<R, P> +where + P: DescriptorPoolAlloc, + R: PersistentDescriptorSetResources, +{ + #[inline] + fn hash<H: Hasher>(&self, state: &mut H) { + self.inner().internal_object().hash(state); + self.device().hash(state); + } +} + +/// Prototype of a `PersistentDescriptorSet`. +/// +/// The template parameter `R` is an unspecified type that represents the list of resources. +/// +/// See the docs of `PersistentDescriptorSet` for an example. +pub struct PersistentDescriptorSetBuilder<R> { + // The descriptor set layout. + layout: Arc<DescriptorSetLayout>, + // Binding currently being filled. + binding_id: usize, + // The writes to perform on a descriptor set in order to put the resources in it. + writes: Vec<DescriptorWrite>, + // Holds the resources alive. + resources: R, +} + +// TODO: lots of checks are still missing, see the docs of +// VkDescriptorImageInfo and VkWriteDescriptorSet + +impl<R> PersistentDescriptorSetBuilder<R> { + /// Builds a `PersistentDescriptorSet` from the builder. + #[inline] + pub fn build( + self, + ) -> Result<PersistentDescriptorSet<R, StdDescriptorPoolAlloc>, PersistentDescriptorSetBuildError> + { + let mut pool = Device::standard_descriptor_pool(self.layout.device()); + self.build_with_pool(&mut pool) + } + + /// Builds a `PersistentDescriptorSet` from the builder. + /// + /// # Panic + /// + /// Panics if the pool doesn't have the same device as the descriptor set layout. + /// + pub fn build_with_pool<P>( + self, + pool: &mut P, + ) -> Result<PersistentDescriptorSet<R, P::Alloc>, PersistentDescriptorSetBuildError> + where + P: ?Sized + DescriptorPool, + { + assert_eq!( + self.layout.device().internal_object(), + pool.device().internal_object() + ); + + let expected_desc = self.layout.num_bindings(); + + if expected_desc > self.binding_id { + return Err(PersistentDescriptorSetBuildError::MissingDescriptors { + expected: expected_desc as u32, + obtained: self.binding_id as u32, + }); + } + + debug_assert_eq!(expected_desc, self.binding_id); + + let set = unsafe { + let mut set = pool.alloc(&self.layout)?; + set.inner_mut() + .write(pool.device(), self.writes.into_iter()); + set + }; + + Ok(PersistentDescriptorSet { + inner: set, + resources: self.resources, + layout: self.layout, + }) + } + + /// Call this function if the next element of the set is an array in order to set the value of + /// each element. + /// + /// Returns an error if the descriptor is empty. + /// + /// This function can be called even if the descriptor isn't an array, and it is valid to enter + /// the "array", add one element, then leave. + #[inline] + pub fn enter_array( + self, + ) -> Result<PersistentDescriptorSetBuilderArray<R>, PersistentDescriptorSetError> { + let desc = match self.layout.descriptor(self.binding_id) { + Some(d) => d, + None => return Err(PersistentDescriptorSetError::EmptyExpected), + }; + + Ok(PersistentDescriptorSetBuilderArray { + builder: self, + desc, + array_element: 0, + }) + } + + /// Skips the current descriptor if it is empty. + #[inline] + pub fn add_empty( + mut self, + ) -> Result<PersistentDescriptorSetBuilder<R>, PersistentDescriptorSetError> { + match self.layout.descriptor(self.binding_id) { + None => (), + Some(desc) => { + return Err(PersistentDescriptorSetError::WrongDescriptorTy { + expected: desc.ty.ty(), + }) + } + } + + self.binding_id += 1; + Ok(self) + } + + /// Binds a buffer as the next descriptor. + /// + /// An error is returned if the buffer isn't compatible with the descriptor. + /// + /// # Panic + /// + /// Panics if the buffer doesn't have the same device as the descriptor set layout. + /// + #[inline] + pub fn add_buffer<T>( + self, + buffer: T, + ) -> Result< + PersistentDescriptorSetBuilder<(R, PersistentDescriptorSetBuf<T>)>, + PersistentDescriptorSetError, + > + where + T: BufferAccess, + { + self.enter_array()?.add_buffer(buffer)?.leave_array() + } + + /// Binds a buffer view as the next descriptor. + /// + /// An error is returned if the buffer isn't compatible with the descriptor. + /// + /// # Panic + /// + /// Panics if the buffer view doesn't have the same device as the descriptor set layout. + /// + pub fn add_buffer_view<T>( + self, + view: T, + ) -> Result< + PersistentDescriptorSetBuilder<(R, PersistentDescriptorSetBufView<T>)>, + PersistentDescriptorSetError, + > + where + T: BufferViewRef, + { + self.enter_array()?.add_buffer_view(view)?.leave_array() + } + + /// Binds an image view as the next descriptor. + /// + /// An error is returned if the image view isn't compatible with the descriptor. + /// + /// # Panic + /// + /// Panics if the image view doesn't have the same device as the descriptor set layout. + /// + #[inline] + pub fn add_image<T>( + self, + image_view: T, + ) -> Result< + PersistentDescriptorSetBuilder<(R, PersistentDescriptorSetImg<T>)>, + PersistentDescriptorSetError, + > + where + T: ImageViewAbstract, + { + self.enter_array()?.add_image(image_view)?.leave_array() + } + + /// Binds an image view with a sampler as the next descriptor. + /// + /// An error is returned if the image view isn't compatible with the descriptor. + /// + /// # Panic + /// + /// Panics if the image view or the sampler doesn't have the same device as the descriptor set + /// layout. + /// + #[inline] + pub fn add_sampled_image<T>( + self, + image_view: T, + sampler: Arc<Sampler>, + ) -> Result< + PersistentDescriptorSetBuilder<( + (R, PersistentDescriptorSetImg<T>), + PersistentDescriptorSetSampler, + )>, + PersistentDescriptorSetError, + > + where + T: ImageViewAbstract, + { + self.enter_array()? + .add_sampled_image(image_view, sampler)? + .leave_array() + } + + /// Binds a sampler as the next descriptor. + /// + /// An error is returned if the sampler isn't compatible with the descriptor. + /// + /// # Panic + /// + /// Panics if the sampler doesn't have the same device as the descriptor set layout. + /// + #[inline] + pub fn add_sampler( + self, + sampler: Arc<Sampler>, + ) -> Result< + PersistentDescriptorSetBuilder<(R, PersistentDescriptorSetSampler)>, + PersistentDescriptorSetError, + > { + self.enter_array()?.add_sampler(sampler)?.leave_array() + } +} + +/// Same as `PersistentDescriptorSetBuilder`, but we're in an array. +pub struct PersistentDescriptorSetBuilderArray<R> { + // The original builder. + builder: PersistentDescriptorSetBuilder<R>, + // Current array elements. + array_element: usize, + // Description of the descriptor. + desc: DescriptorDesc, +} + +impl<R> PersistentDescriptorSetBuilderArray<R> { + /// Leaves the array. Call this once you added all the elements of the array. + pub fn leave_array( + mut self, + ) -> Result<PersistentDescriptorSetBuilder<R>, PersistentDescriptorSetError> { + if self.desc.array_count > self.array_element as u32 { + return Err(PersistentDescriptorSetError::MissingArrayElements { + expected: self.desc.array_count, + obtained: self.array_element as u32, + }); + } + + debug_assert_eq!(self.desc.array_count, self.array_element as u32); + + self.builder.binding_id += 1; + Ok(self.builder) + } + + /// Binds a buffer as the next element in the array. + /// + /// An error is returned if the buffer isn't compatible with the descriptor. + /// + /// # Panic + /// + /// Panics if the buffer doesn't have the same device as the descriptor set layout. + /// + pub fn add_buffer<T>( + mut self, + buffer: T, + ) -> Result< + PersistentDescriptorSetBuilderArray<(R, PersistentDescriptorSetBuf<T>)>, + PersistentDescriptorSetError, + > + where + T: BufferAccess, + { + assert_eq!( + self.builder.layout.device().internal_object(), + buffer.inner().buffer.device().internal_object() + ); + + if self.array_element as u32 >= self.desc.array_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 ^ + + // 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 + assert!( + self.builder + .layout + .device() + .enabled_features() + .robust_buffer_access + ); + + if buffer_desc.storage { + 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, + )); + } + + 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, + ) + } + } + } + } + ref d => { + return Err(PersistentDescriptorSetError::WrongDescriptorTy { expected: d.ty() }); + } + }); + + Ok(PersistentDescriptorSetBuilderArray { + builder: PersistentDescriptorSetBuilder { + layout: self.builder.layout, + binding_id: self.builder.binding_id, + writes: self.builder.writes, + resources: ( + self.builder.resources, + PersistentDescriptorSetBuf { + buffer, + descriptor_num: self.builder.binding_id as u32, + }, + ), + }, + desc: self.desc, + array_element: self.array_element + 1, + }) + } + + /// Binds a buffer view as the next element in the array. + /// + /// An error is returned if the buffer isn't compatible with the descriptor. + /// + /// # Panic + /// + /// Panics if the buffer view doesn't have the same device as the descriptor set layout. + /// + pub fn add_buffer_view<T>( + mut self, + view: T, + ) -> Result< + PersistentDescriptorSetBuilderArray<(R, PersistentDescriptorSetBufView<T>)>, + PersistentDescriptorSetError, + > + where + T: BufferViewRef, + { + assert_eq!( + self.builder.layout.device().internal_object(), + view.view().device().internal_object() + ); + + if self.array_element as u32 >= self.desc.array_count { + return Err(PersistentDescriptorSetError::ArrayOutOfBounds); + } + + self.builder.writes.push(match self.desc.ty { + DescriptorDescTy::TexelBuffer { storage, .. } => { + if storage { + // 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(), + ) + } + } + ref d => { + return Err(PersistentDescriptorSetError::WrongDescriptorTy { expected: d.ty() }); + } + }); + + Ok(PersistentDescriptorSetBuilderArray { + builder: PersistentDescriptorSetBuilder { + layout: self.builder.layout, + binding_id: self.builder.binding_id, + writes: self.builder.writes, + resources: ( + self.builder.resources, + PersistentDescriptorSetBufView { + view, + descriptor_num: self.builder.binding_id as u32, + }, + ), + }, + desc: self.desc, + array_element: self.array_element + 1, + }) + } + + /// Binds an image view as the next element in the array. + /// + /// An error is returned if the image view isn't compatible with the descriptor. + /// + /// # Panic + /// + /// Panics if the image view doesn't have the same device as the descriptor set layout. + /// + pub fn add_image<T>( + mut self, + image_view: T, + ) -> Result< + PersistentDescriptorSetBuilderArray<(R, PersistentDescriptorSetImg<T>)>, + PersistentDescriptorSetError, + > + where + T: ImageViewAbstract, + { + assert_eq!( + self.builder.layout.device().internal_object(), + image_view.image().inner().image.device().internal_object() + ); + + if self.array_element as u32 >= self.desc.array_count { + return Err(PersistentDescriptorSetError::ArrayOutOfBounds); + } + + let desc = match self.builder.layout.descriptor(self.builder.binding_id) { + Some(d) => d, + None => return Err(PersistentDescriptorSetError::EmptyExpected), + }; + + self.builder.writes.push(match desc.ty { + DescriptorDescTy::Image(ref desc) => { + 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, + ) + } + } + DescriptorDescTy::InputAttachment { + multisampled, + array_layers, + } => { + if !image_view.image().inner().image.usage().input_attachment { + return Err(PersistentDescriptorSetError::MissingImageUsage( + MissingImageUsage::InputAttachment, + )); + } + + if !image_view.component_mapping().is_identity() { + return Err(PersistentDescriptorSetError::NotIdentitySwizzled); + } + + if multisampled && image_view.image().samples() == SampleCount::Sample1 { + return Err(PersistentDescriptorSetError::ExpectedMultisampled); + } else if !multisampled && image_view.image().samples() != SampleCount::Sample1 { + return Err(PersistentDescriptorSetError::UnexpectedMultisampled); + } + + 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 } => {} + }; + + DescriptorWrite::input_attachment( + self.builder.binding_id as u32, + self.array_element as u32, + &image_view, + ) + } + ty => { + return Err(PersistentDescriptorSetError::WrongDescriptorTy { expected: ty.ty() }); + } + }); + + Ok(PersistentDescriptorSetBuilderArray { + builder: PersistentDescriptorSetBuilder { + layout: self.builder.layout, + binding_id: self.builder.binding_id, + writes: self.builder.writes, + resources: ( + self.builder.resources, + PersistentDescriptorSetImg { + image: image_view, + descriptor_num: self.builder.binding_id as u32, + }, + ), + }, + desc: self.desc, + array_element: self.array_element + 1, + }) + } + + /// Binds an image view with a sampler as the next element in the array. + /// + /// An error is returned if the image view isn't compatible with the descriptor. + /// + /// # Panic + /// + /// Panics if the image or the sampler doesn't have the same device as the descriptor set layout. + /// + pub fn add_sampled_image<T>( + mut self, + image_view: T, + sampler: Arc<Sampler>, + ) -> Result< + PersistentDescriptorSetBuilderArray<( + (R, PersistentDescriptorSetImg<T>), + PersistentDescriptorSetSampler, + )>, + PersistentDescriptorSetError, + > + where + T: ImageViewAbstract, + { + assert_eq!( + self.builder.layout.device().internal_object(), + image_view.image().inner().image.device().internal_object() + ); + assert_eq!( + self.builder.layout.device().internal_object(), + sampler.device().internal_object() + ); + + if self.array_element as u32 >= self.desc.array_count { + return Err(PersistentDescriptorSetError::ArrayOutOfBounds); + } + + let desc = match self.builder.layout.descriptor(self.builder.binding_id) { + Some(d) => d, + None => return Err(PersistentDescriptorSetError::EmptyExpected), + }; + + if !image_view.can_be_sampled(&sampler) { + return Err(PersistentDescriptorSetError::IncompatibleImageViewSampler); + } + + self.builder.writes.push(match desc.ty { + DescriptorDescTy::CombinedImageSampler(ref desc) => { + image_match_desc(&image_view, &desc)?; + DescriptorWrite::combined_image_sampler( + self.builder.binding_id as u32, + self.array_element as u32, + &sampler, + &image_view, + ) + } + ty => { + return Err(PersistentDescriptorSetError::WrongDescriptorTy { expected: ty.ty() }); + } + }); + + Ok(PersistentDescriptorSetBuilderArray { + builder: PersistentDescriptorSetBuilder { + layout: self.builder.layout, + binding_id: self.builder.binding_id, + writes: self.builder.writes, + resources: ( + ( + self.builder.resources, + PersistentDescriptorSetImg { + image: image_view, + descriptor_num: self.builder.binding_id as u32, + }, + ), + PersistentDescriptorSetSampler { sampler }, + ), + }, + desc: self.desc, + array_element: self.array_element + 1, + }) + } + + /// Binds a sampler as the next element in the array. + /// + /// An error is returned if the sampler isn't compatible with the descriptor. + /// + /// # Panic + /// + /// Panics if the sampler doesn't have the same device as the descriptor set layout. + /// + pub fn add_sampler( + mut self, + sampler: Arc<Sampler>, + ) -> Result< + PersistentDescriptorSetBuilderArray<(R, PersistentDescriptorSetSampler)>, + PersistentDescriptorSetError, + > { + assert_eq!( + self.builder.layout.device().internal_object(), + sampler.device().internal_object() + ); + + if self.array_element as u32 >= self.desc.array_count { + return Err(PersistentDescriptorSetError::ArrayOutOfBounds); + } + + let desc = match self.builder.layout.descriptor(self.builder.binding_id) { + Some(d) => d, + None => return Err(PersistentDescriptorSetError::EmptyExpected), + }; + + self.builder.writes.push(match desc.ty { + DescriptorDescTy::Sampler => DescriptorWrite::sampler( + self.builder.binding_id as u32, + self.array_element as u32, + &sampler, + ), + ty => { + return Err(PersistentDescriptorSetError::WrongDescriptorTy { expected: ty.ty() }); + } + }); + + Ok(PersistentDescriptorSetBuilderArray { + builder: PersistentDescriptorSetBuilder { + layout: self.builder.layout, + binding_id: self.builder.binding_id, + writes: self.builder.writes, + resources: ( + self.builder.resources, + PersistentDescriptorSetSampler { sampler }, + ), + }, + desc: self.desc, + array_element: self.array_element + 1, + }) + } +} + +// Checks whether an image view matches the descriptor. +fn image_match_desc<I>( + image_view: &I, + desc: &DescriptorImageDesc, +) -> 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 { + return Err(PersistentDescriptorSetError::ImageViewTypeMismatch { + expected: desc.dimensions, + obtained: image_view_ty, + }); + } + + if let Some(format) = desc.format { + if image_view.format() != format { + return Err(PersistentDescriptorSetError::ImageViewFormatMismatch { + expected: format, + obtained: image_view.format(), + }); + } + } + + if desc.multisampled && image_view.image().samples() == SampleCount::Sample1 { + return Err(PersistentDescriptorSetError::ExpectedMultisampled); + } else if !desc.multisampled && image_view.image().samples() != SampleCount::Sample1 { + 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(()) +} + +pub unsafe trait PersistentDescriptorSetResources { + fn num_buffers(&self) -> usize; + fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)>; + fn num_images(&self) -> usize; + fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)>; +} + +unsafe impl PersistentDescriptorSetResources for () { + #[inline] + fn num_buffers(&self) -> usize { + 0 + } + + #[inline] + fn buffer(&self, _: usize) -> Option<(&dyn BufferAccess, u32)> { + None + } + + #[inline] + fn num_images(&self) -> usize { + 0 + } + + #[inline] + fn image(&self, _: usize) -> Option<(&dyn ImageViewAbstract, u32)> { + None + } +} + +/// Internal object related to the `PersistentDescriptorSet` system. +pub struct PersistentDescriptorSetBuf<B> { + buffer: B, + descriptor_num: u32, +} + +unsafe impl<R, B> PersistentDescriptorSetResources for (R, PersistentDescriptorSetBuf<B>) +where + R: PersistentDescriptorSetResources, + B: BufferAccess, +{ + #[inline] + fn num_buffers(&self) -> usize { + self.0.num_buffers() + 1 + } + + #[inline] + fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> { + if let Some(buf) = self.0.buffer(index) { + Some(buf) + } else if index == self.0.num_buffers() { + Some((&self.1.buffer, self.1.descriptor_num)) + } else { + None + } + } + + #[inline] + fn num_images(&self) -> usize { + self.0.num_images() + } + + #[inline] + fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> { + self.0.image(index) + } +} + +/// Internal object related to the `PersistentDescriptorSet` system. +pub struct PersistentDescriptorSetBufView<V> +where + V: BufferViewRef, +{ + view: V, + descriptor_num: u32, +} + +unsafe impl<R, V> PersistentDescriptorSetResources for (R, PersistentDescriptorSetBufView<V>) +where + R: PersistentDescriptorSetResources, + V: BufferViewRef, +{ + #[inline] + fn num_buffers(&self) -> usize { + self.0.num_buffers() + 1 + } + + #[inline] + fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> { + if let Some(buf) = self.0.buffer(index) { + Some(buf) + } else if index == self.0.num_buffers() { + Some((self.1.view.view().buffer(), self.1.descriptor_num)) + } else { + None + } + } + + #[inline] + fn num_images(&self) -> usize { + self.0.num_images() + } + + #[inline] + fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> { + self.0.image(index) + } +} + +/// Internal object related to the `PersistentDescriptorSet` system. +pub struct PersistentDescriptorSetImg<I> { + image: I, + descriptor_num: u32, +} + +unsafe impl<R, I> PersistentDescriptorSetResources for (R, PersistentDescriptorSetImg<I>) +where + R: PersistentDescriptorSetResources, + I: ImageViewAbstract, +{ + #[inline] + fn num_buffers(&self) -> usize { + self.0.num_buffers() + } + + #[inline] + fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> { + self.0.buffer(index) + } + + #[inline] + fn num_images(&self) -> usize { + self.0.num_images() + 1 + } + + #[inline] + fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> { + if let Some(img) = self.0.image(index) { + Some(img) + } else if index == self.0.num_images() { + Some((&self.1.image, self.1.descriptor_num)) + } else { + None + } + } +} + +/// Internal object related to the `PersistentDescriptorSet` system. +pub struct PersistentDescriptorSetSampler { + sampler: Arc<Sampler>, +} + +unsafe impl<R> PersistentDescriptorSetResources for (R, PersistentDescriptorSetSampler) +where + R: PersistentDescriptorSetResources, +{ + #[inline] + fn num_buffers(&self) -> usize { + self.0.num_buffers() + } + + #[inline] + fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> { + self.0.buffer(index) + } + + #[inline] + fn num_images(&self) -> usize { + self.0.num_images() + } + + #[inline] + fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> { + self.0.image(index) + } +} + +// Part of the PersistentDescriptorSetError for the case +// of missing usage on a buffer. +#[derive(Debug, Clone)] +pub enum MissingBufferUsage { + StorageBuffer, + UniformBuffer, + StorageTexelBuffer, + UniformTexelBuffer, +} + +// Part of the PersistentDescriptorSetError for the case +// of missing usage on an image. +#[derive(Debug, Clone)] +pub enum MissingImageUsage { + InputAttachment, + Sampled, + Storage, +} + +/// 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, + }, + + /// Tried to add too many elements to an array. + ArrayOutOfBounds, + + /// Expected nothing. + EmptyExpected, + + /// Expected a multisampled image, but got a single-sampled image. + ExpectedMultisampled, + + /// The format of an image view doesn't match what was expected. + ImageViewFormatMismatch { + /// Expected format. + expected: Format, + /// Format of the image view that was passed. + obtained: Format, + }, + + /// The type of an image view doesn't match what was expected. + ImageViewTypeMismatch { + /// Expected type. + expected: DescriptorImageDescDimensions, + /// Type of the image view that was passed. + obtained: DescriptorImageDescDimensions, + }, + + /// The image view isn't compatible with the sampler. + IncompatibleImageViewSampler, + + /// Didn't fill all the elements of an array before leaving. + MissingArrayElements { + /// Number of expected elements. + expected: u32, + /// Number of elements that were added. + obtained: u32, + }, + + /// The buffer is missing the correct usage. + MissingBufferUsage(MissingBufferUsage), + + /// The image is missing the correct usage. + MissingImageUsage(MissingImageUsage), + + /// The image view has a component swizzle that is different from identity. + NotIdentitySwizzled, + + /// Expected a single-sampled image, but got a multisampled image. + UnexpectedMultisampled, + + /// Expected one type of resource but got another. + WrongDescriptorTy { + /// The expected descriptor type. + expected: DescriptorType, + }, +} + +impl error::Error for PersistentDescriptorSetError {} + +impl fmt::Display for PersistentDescriptorSetError { + #[inline] + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!( + fmt, + "{}", + match *self { + PersistentDescriptorSetError::ArrayLayersMismatch { .. } => { + "the number of array layers of an image doesn't match what was expected" + } + PersistentDescriptorSetError::ArrayOutOfBounds => { + "tried to add too many elements to an array" + } + PersistentDescriptorSetError::EmptyExpected => { + "expected an empty descriptor but got something" + } + PersistentDescriptorSetError::ExpectedMultisampled => { + "expected a multisampled image, but got a single-sampled image" + } + PersistentDescriptorSetError::ImageViewFormatMismatch { .. } => { + "the format of an image view doesn't match what was expected" + } + PersistentDescriptorSetError::ImageViewTypeMismatch { .. } => { + "the type of an image view doesn't match what was expected" + } + PersistentDescriptorSetError::IncompatibleImageViewSampler => { + "the image view isn't compatible with the sampler" + } + PersistentDescriptorSetError::MissingArrayElements { .. } => { + "didn't fill all the elements of an array before leaving" + } + PersistentDescriptorSetError::MissingBufferUsage { .. } => { + "the buffer is missing the correct usage" + } + PersistentDescriptorSetError::MissingImageUsage { .. } => { + "the image is missing the correct usage" + } + PersistentDescriptorSetError::NotIdentitySwizzled => { + "the image view's component mapping is not identity swizzled" + } + PersistentDescriptorSetError::UnexpectedMultisampled => { + "expected a single-sampled image, but got a multisampled image" + } + PersistentDescriptorSetError::WrongDescriptorTy { .. } => { + "expected one type of resource but got another" + } + } + ) + } +} + +/// Error when building a persistent descriptor set. +#[derive(Debug, Clone)] +pub enum PersistentDescriptorSetBuildError { + /// Out of memory. + OomError(OomError), + + /// Didn't fill all the descriptors before building. + MissingDescriptors { + /// Number of expected descriptors. + expected: u32, + /// Number of descriptors that were added. + obtained: u32, + }, +} + +impl error::Error for PersistentDescriptorSetBuildError {} + +impl From<OomError> for PersistentDescriptorSetBuildError { + #[inline] + fn from(err: OomError) -> PersistentDescriptorSetBuildError { + PersistentDescriptorSetBuildError::OomError(err) + } +} + +impl fmt::Display for PersistentDescriptorSetBuildError { + #[inline] + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!( + fmt, + "{}", + match *self { + PersistentDescriptorSetBuildError::MissingDescriptors { .. } => { + "didn't fill all the descriptors before building" + } + PersistentDescriptorSetBuildError::OomError(_) => "not enough memory available", + } + ) + } +} |