aboutsummaryrefslogtreecommitdiff
path: root/src/descriptor_set/persistent.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/descriptor_set/persistent.rs')
-rw-r--r--src/descriptor_set/persistent.rs1304
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",
+ }
+ )
+ }
+}