• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2016 The vulkano developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
6 // at your option. All files in the project carrying such
7 // notice may not be copied, modified, or distributed except
8 // according to those terms.
9 
10 //! Bindings between shaders and the resources they access.
11 //!
12 //! # Overview
13 //!
14 //! In order to access a buffer or an image from a shader, that buffer or image must be put in a
15 //! *descriptor*. Each descriptor contains one buffer or one image alongside with the way that it
16 //! can be accessed. A descriptor can also be an array, in which case it contains multiple buffers
17 //! or images that all have the same layout.
18 //!
19 //! Descriptors are grouped in what is called *descriptor sets*. In Vulkan you don't bind
20 //! individual descriptors one by one, but you create then bind descriptor sets one by one. As
21 //! binding a descriptor set has (small but non-null) a cost, you are encouraged to put descriptors
22 //! that are often used together in the same set so that you can keep the same set binding through
23 //! multiple draws.
24 //!
25 //! # Example
26 //!
27 //! > **Note**: This section describes the simple way to bind resources. There are more optimized
28 //! > ways.
29 //!
30 //! There are two steps to give access to a resource in a shader: creating the descriptor set, and
31 //! passing the descriptor sets when drawing.
32 //!
33 //! ## Creating a descriptor set
34 //!
35 //! TODO: write example for: PersistentDescriptorSet::start(layout.clone()).add_buffer(data_buffer.clone())
36 //!
37 //! ## Passing the descriptor set when drawing
38 //!
39 //! TODO: write
40 //!
41 //! # When drawing
42 //!
43 //! When you call a function that adds a draw command to a command buffer, one of the parameters
44 //! corresponds to the list of descriptor sets to use. Vulkano will check that what you passed is
45 //! compatible with the layout of the pipeline.
46 //!
47 //! TODO: talk about perfs of changing sets
48 //!
49 //! # Descriptor sets creation and management
50 //!
51 //! There are three concepts in Vulkan related to descriptor sets:
52 //!
53 //! - A `DescriptorSetLayout` is a Vulkan object that describes to the Vulkan implementation the
54 //!   layout of a future descriptor set. When you allocate a descriptor set, you have to pass an
55 //!   instance of this object. This is represented with the `DescriptorSetLayout` type in
56 //!   vulkano.
57 //! - A `DescriptorPool` is a Vulkan object that holds the memory of descriptor sets and that can
58 //!   be used to allocate and free individual descriptor sets. This is represented with the
59 //!   `UnsafeDescriptorPool` type in vulkano.
60 //! - A `DescriptorSet` contains the bindings to resources and is allocated from a pool. This is
61 //!   represented with the `UnsafeDescriptorSet` type in vulkano.
62 //!
63 //! In addition to this, vulkano defines the following:
64 //!
65 //! - The `DescriptorPool` trait can be implemented on types from which you can allocate and free
66 //!   descriptor sets. However it is different from Vulkan descriptor pools in the sense that an
67 //!   implementation of the `DescriptorPool` trait can manage multiple Vulkan descriptor pools.
68 //! - The `StdDescriptorPool` type is a default implementation of the `DescriptorPool` trait.
69 //! - The `DescriptorSet` trait is implemented on types that wrap around Vulkan descriptor sets in
70 //!   a safe way. A Vulkan descriptor set is inherently unsafe, so we need safe wrappers around
71 //!   them.
72 //! - The `SimpleDescriptorSet` type is a default implementation of the `DescriptorSet` trait.
73 //! - The `DescriptorSetsCollection` trait is implemented on collections of types that implement
74 //!   `DescriptorSet`. It is what you pass to the draw functions.
75 
76 pub use self::collection::DescriptorSetsCollection;
77 pub use self::fixed_size_pool::FixedSizeDescriptorSetsPool;
78 use self::layout::DescriptorSetLayout;
79 pub use self::persistent::PersistentDescriptorSet;
80 pub use self::persistent::PersistentDescriptorSetBuildError;
81 pub use self::persistent::PersistentDescriptorSetError;
82 use self::sys::UnsafeDescriptorSet;
83 use crate::buffer::BufferAccess;
84 use crate::descriptor_set::layout::{DescriptorBufferDesc, DescriptorDescTy};
85 use crate::device::DeviceOwned;
86 use crate::image::view::ImageViewAbstract;
87 use crate::SafeDeref;
88 use crate::VulkanObject;
89 use smallvec::SmallVec;
90 use std::hash::Hash;
91 use std::hash::Hasher;
92 use std::sync::Arc;
93 
94 mod collection;
95 pub mod fixed_size_pool;
96 pub mod layout;
97 pub mod persistent;
98 pub mod pool;
99 pub mod sys;
100 
101 /// Trait for objects that contain a collection of resources that will be accessible by shaders.
102 ///
103 /// Objects of this type can be passed when submitting a draw command.
104 pub unsafe trait DescriptorSet: DeviceOwned {
105     /// Returns the inner `UnsafeDescriptorSet`.
inner(&self) -> &UnsafeDescriptorSet106     fn inner(&self) -> &UnsafeDescriptorSet;
107 
108     /// Returns the layout of this descriptor set.
layout(&self) -> &Arc<DescriptorSetLayout>109     fn layout(&self) -> &Arc<DescriptorSetLayout>;
110 
111     /// Creates a [`DescriptorSetWithOffsets`] with the given dynamic offsets.
offsets<I>(self, dynamic_offsets: I) -> DescriptorSetWithOffsets where Self: Sized + Send + Sync + 'static, I: IntoIterator<Item = u32>,112     fn offsets<I>(self, dynamic_offsets: I) -> DescriptorSetWithOffsets
113     where
114         Self: Sized + Send + Sync + 'static,
115         I: IntoIterator<Item = u32>,
116     {
117         DescriptorSetWithOffsets::new(self, dynamic_offsets)
118     }
119 
120     /// Returns the number of buffers within this descriptor set.
num_buffers(&self) -> usize121     fn num_buffers(&self) -> usize;
122 
123     /// Returns the `index`th buffer of this descriptor set, or `None` if out of range. Also
124     /// returns the index of the descriptor that uses this buffer.
125     ///
126     /// The valid range is between 0 and `num_buffers()`.
buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)>127     fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)>;
128 
129     /// Returns the number of images within this descriptor set.
num_images(&self) -> usize130     fn num_images(&self) -> usize;
131 
132     /// Returns the `index`th image of this descriptor set, or `None` if out of range. Also returns
133     /// the index of the descriptor that uses this image.
134     ///
135     /// The valid range is between 0 and `num_images()`.
image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)>136     fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)>;
137 }
138 
139 unsafe impl<T> DescriptorSet for T
140 where
141     T: SafeDeref,
142     T::Target: DescriptorSet,
143 {
144     #[inline]
inner(&self) -> &UnsafeDescriptorSet145     fn inner(&self) -> &UnsafeDescriptorSet {
146         (**self).inner()
147     }
148 
149     #[inline]
layout(&self) -> &Arc<DescriptorSetLayout>150     fn layout(&self) -> &Arc<DescriptorSetLayout> {
151         (**self).layout()
152     }
153 
154     #[inline]
num_buffers(&self) -> usize155     fn num_buffers(&self) -> usize {
156         (**self).num_buffers()
157     }
158 
159     #[inline]
buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)>160     fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> {
161         (**self).buffer(index)
162     }
163 
164     #[inline]
num_images(&self) -> usize165     fn num_images(&self) -> usize {
166         (**self).num_images()
167     }
168 
169     #[inline]
image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)>170     fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> {
171         (**self).image(index)
172     }
173 }
174 
175 impl PartialEq for dyn DescriptorSet + Send + Sync {
176     #[inline]
eq(&self, other: &Self) -> bool177     fn eq(&self, other: &Self) -> bool {
178         self.inner().internal_object() == other.inner().internal_object()
179             && self.device() == other.device()
180     }
181 }
182 
183 impl Eq for dyn DescriptorSet + Send + Sync {}
184 
185 impl Hash for dyn DescriptorSet + Send + Sync {
186     #[inline]
hash<H: Hasher>(&self, state: &mut H)187     fn hash<H: Hasher>(&self, state: &mut H) {
188         self.inner().internal_object().hash(state);
189         self.device().hash(state);
190     }
191 }
192 
193 pub struct DescriptorSetWithOffsets {
194     descriptor_set: Box<dyn DescriptorSet + Send + Sync>,
195     dynamic_offsets: SmallVec<[u32; 4]>,
196 }
197 
198 impl DescriptorSetWithOffsets {
199     #[inline]
new<S, O>(descriptor_set: S, dynamic_offsets: O) -> Self where S: DescriptorSet + Send + Sync + 'static, O: IntoIterator<Item = u32>,200     pub fn new<S, O>(descriptor_set: S, dynamic_offsets: O) -> Self
201     where
202         S: DescriptorSet + Send + Sync + 'static,
203         O: IntoIterator<Item = u32>,
204     {
205         let dynamic_offsets: SmallVec<_> = dynamic_offsets.into_iter().collect();
206         let layout = descriptor_set.layout();
207         let properties = layout.device().physical_device().properties();
208         let min_uniform_off_align = properties.min_uniform_buffer_offset_alignment as u32;
209         let min_storage_off_align = properties.min_storage_buffer_offset_alignment as u32;
210         let mut dynamic_offset_index = 0;
211 
212         // Ensure that the number of dynamic_offsets is correct and that each
213         // dynamic offset is a multiple of the minimum offset alignment specified
214         // by the physical device.
215         for desc in layout.desc().bindings() {
216             let desc = desc.as_ref().unwrap();
217             if let DescriptorDescTy::Buffer(DescriptorBufferDesc {
218                 dynamic: Some(true),
219                 storage,
220             }) = desc.ty
221             {
222                 // Don't check alignment if there are not enough offsets anyway
223                 if dynamic_offsets.len() > dynamic_offset_index {
224                     if storage {
225                         assert!(
226                             dynamic_offsets[dynamic_offset_index] % min_storage_off_align == 0,
227                             "Dynamic storage buffer offset must be a multiple of min_storage_buffer_offset_alignment: got {}, expected a multiple of {}",
228                             dynamic_offsets[dynamic_offset_index],
229                             min_storage_off_align
230                         );
231                     } else {
232                         assert!(
233                             dynamic_offsets[dynamic_offset_index] % min_uniform_off_align == 0,
234                             "Dynamic uniform buffer offset must be a multiple of min_uniform_buffer_offset_alignment: got {}, expected a multiple of {}",
235                             dynamic_offsets[dynamic_offset_index],
236                             min_uniform_off_align
237                         );
238                     }
239                 }
240                 dynamic_offset_index += 1;
241             }
242         }
243 
244         assert!(
245             !(dynamic_offsets.len() < dynamic_offset_index),
246             "Too few dynamic offsets: got {}, expected {}",
247             dynamic_offsets.len(),
248             dynamic_offset_index
249         );
250         assert!(
251             !(dynamic_offsets.len() > dynamic_offset_index),
252             "Too many dynamic offsets: got {}, expected {}",
253             dynamic_offsets.len(),
254             dynamic_offset_index
255         );
256 
257         DescriptorSetWithOffsets {
258             descriptor_set: Box::new(descriptor_set),
259             dynamic_offsets,
260         }
261     }
262 
263     #[inline]
as_ref(&self) -> (&dyn DescriptorSet, &[u32])264     pub fn as_ref(&self) -> (&dyn DescriptorSet, &[u32]) {
265         (&self.descriptor_set, &self.dynamic_offsets)
266     }
267 
268     #[inline]
into_tuple( self, ) -> ( Box<dyn DescriptorSet + Send + Sync>, impl ExactSizeIterator<Item = u32>, )269     pub fn into_tuple(
270         self,
271     ) -> (
272         Box<dyn DescriptorSet + Send + Sync>,
273         impl ExactSizeIterator<Item = u32>,
274     ) {
275         (self.descriptor_set, self.dynamic_offsets.into_iter())
276     }
277 }
278 
279 impl<S> From<S> for DescriptorSetWithOffsets
280 where
281     S: DescriptorSet + Send + Sync + 'static,
282 {
283     #[inline]
from(descriptor_set: S) -> Self284     fn from(descriptor_set: S) -> Self {
285         Self::new(descriptor_set, std::iter::empty())
286     }
287 }
288