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 //! # Examples
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 //!   [`DescriptorPool`] 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 [`DescriptorSetAllocator`] trait can be implemented on types from which you can allocate
66 //!   and free descriptor sets. However it is different from Vulkan descriptor pools in the sense
67 //!   that an implementation of the [`DescriptorSetAllocator`] trait can manage multiple Vulkan
68 //!   descriptor pools.
69 //! - The [`StandardDescriptorSetAllocator`] type is a default implementation of the
70 //!   [`DescriptorSetAllocator`] trait.
71 //! - The [`DescriptorSet`] trait is implemented on types that wrap around Vulkan descriptor sets in
72 //!   a safe way. A Vulkan descriptor set is inherently unsafe, so we need safe wrappers around
73 //!   them.
74 //! - The [`DescriptorSetsCollection`] trait is implemented on collections of types that implement
75 //!   [`DescriptorSet`]. It is what you pass to the draw functions.
76 //!
77 //! [`DescriptorPool`]: pool::DescriptorPool
78 //! [`DescriptorSetAllocator`]: allocator::DescriptorSetAllocator
79 //! [`StandardDescriptorSetAllocator`]: allocator::StandardDescriptorSetAllocator
80 
81 pub(crate) use self::update::{check_descriptor_write, DescriptorWriteInfo};
82 pub use self::{
83     collection::DescriptorSetsCollection,
84     persistent::PersistentDescriptorSet,
85     update::{DescriptorSetUpdateError, WriteDescriptorSet, WriteDescriptorSetElements},
86 };
87 use self::{layout::DescriptorSetLayout, sys::UnsafeDescriptorSet};
88 use crate::{
89     buffer::{view::BufferView, Subbuffer},
90     descriptor_set::layout::DescriptorType,
91     device::DeviceOwned,
92     image::view::ImageViewAbstract,
93     sampler::Sampler,
94     DeviceSize, OomError, VulkanObject,
95 };
96 use ahash::HashMap;
97 use smallvec::{smallvec, SmallVec};
98 use std::{
99     error::Error,
100     fmt::{Display, Error as FmtError, Formatter},
101     hash::{Hash, Hasher},
102     ops::Range,
103     ptr,
104     sync::Arc,
105 };
106 
107 pub mod allocator;
108 mod collection;
109 pub mod layout;
110 pub mod persistent;
111 pub mod pool;
112 pub mod sys;
113 mod update;
114 
115 /// Trait for objects that contain a collection of resources that will be accessible by shaders.
116 ///
117 /// Objects of this type can be passed when submitting a draw command.
118 pub unsafe trait DescriptorSet: DeviceOwned + Send + Sync {
119     /// Returns the inner `UnsafeDescriptorSet`.
inner(&self) -> &UnsafeDescriptorSet120     fn inner(&self) -> &UnsafeDescriptorSet;
121 
122     /// Returns the layout of this descriptor set.
layout(&self) -> &Arc<DescriptorSetLayout>123     fn layout(&self) -> &Arc<DescriptorSetLayout>;
124 
125     /// Returns the variable descriptor count that this descriptor set was allocated with.
variable_descriptor_count(&self) -> u32126     fn variable_descriptor_count(&self) -> u32;
127 
128     /// Creates a [`DescriptorSetWithOffsets`] with the given dynamic offsets.
offsets( self: Arc<Self>, dynamic_offsets: impl IntoIterator<Item = u32>, ) -> DescriptorSetWithOffsets where Self: Sized + 'static,129     fn offsets(
130         self: Arc<Self>,
131         dynamic_offsets: impl IntoIterator<Item = u32>,
132     ) -> DescriptorSetWithOffsets
133     where
134         Self: Sized + 'static,
135     {
136         DescriptorSetWithOffsets::new(self, dynamic_offsets)
137     }
138 
139     /// Returns the resources bound to this descriptor set.
resources(&self) -> &DescriptorSetResources140     fn resources(&self) -> &DescriptorSetResources;
141 }
142 
143 impl PartialEq for dyn DescriptorSet {
144     #[inline]
eq(&self, other: &Self) -> bool145     fn eq(&self, other: &Self) -> bool {
146         self.inner() == other.inner()
147     }
148 }
149 
150 impl Eq for dyn DescriptorSet {}
151 
152 impl Hash for dyn DescriptorSet {
hash<H: Hasher>(&self, state: &mut H)153     fn hash<H: Hasher>(&self, state: &mut H) {
154         self.inner().hash(state);
155     }
156 }
157 
158 pub(crate) struct DescriptorSetInner {
159     layout: Arc<DescriptorSetLayout>,
160     variable_descriptor_count: u32,
161     resources: DescriptorSetResources,
162 }
163 
164 impl DescriptorSetInner {
new( handle: ash::vk::DescriptorSet, layout: Arc<DescriptorSetLayout>, variable_descriptor_count: u32, descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>, ) -> Result<Self, DescriptorSetUpdateError>165     pub(crate) fn new(
166         handle: ash::vk::DescriptorSet,
167         layout: Arc<DescriptorSetLayout>,
168         variable_descriptor_count: u32,
169         descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
170     ) -> Result<Self, DescriptorSetUpdateError> {
171         assert!(
172             !layout.push_descriptor(),
173             "the provided descriptor set layout is for push descriptors, and cannot be used to \
174             build a descriptor set object",
175         );
176 
177         let max_count = layout.variable_descriptor_count();
178 
179         assert!(
180             variable_descriptor_count <= max_count,
181             "the provided variable_descriptor_count ({}) is greater than the maximum number of \
182             variable count descriptors in the layout ({})",
183             variable_descriptor_count,
184             max_count,
185         );
186 
187         let mut resources = DescriptorSetResources::new(&layout, variable_descriptor_count);
188 
189         let descriptor_writes = descriptor_writes.into_iter();
190         let (lower_size_bound, _) = descriptor_writes.size_hint();
191         let mut descriptor_write_info: SmallVec<[_; 8]> = SmallVec::with_capacity(lower_size_bound);
192         let mut write_descriptor_set: SmallVec<[_; 8]> = SmallVec::with_capacity(lower_size_bound);
193 
194         for write in descriptor_writes {
195             let layout_binding =
196                 check_descriptor_write(&write, &layout, variable_descriptor_count)?;
197 
198             resources.update(&write);
199             descriptor_write_info.push(write.to_vulkan_info(layout_binding.descriptor_type));
200             write_descriptor_set.push(write.to_vulkan(handle, layout_binding.descriptor_type));
201         }
202 
203         if !write_descriptor_set.is_empty() {
204             for (info, write) in descriptor_write_info
205                 .iter()
206                 .zip(write_descriptor_set.iter_mut())
207             {
208                 match info {
209                     DescriptorWriteInfo::Image(info) => {
210                         write.descriptor_count = info.len() as u32;
211                         write.p_image_info = info.as_ptr();
212                     }
213                     DescriptorWriteInfo::Buffer(info) => {
214                         write.descriptor_count = info.len() as u32;
215                         write.p_buffer_info = info.as_ptr();
216                     }
217                     DescriptorWriteInfo::BufferView(info) => {
218                         write.descriptor_count = info.len() as u32;
219                         write.p_texel_buffer_view = info.as_ptr();
220                     }
221                 }
222             }
223         }
224 
225         unsafe {
226             let fns = layout.device().fns();
227 
228             (fns.v1_0.update_descriptor_sets)(
229                 layout.device().handle(),
230                 write_descriptor_set.len() as u32,
231                 write_descriptor_set.as_ptr(),
232                 0,
233                 ptr::null(),
234             );
235         }
236 
237         Ok(DescriptorSetInner {
238             layout,
239             variable_descriptor_count,
240             resources,
241         })
242     }
243 
layout(&self) -> &Arc<DescriptorSetLayout>244     pub(crate) fn layout(&self) -> &Arc<DescriptorSetLayout> {
245         &self.layout
246     }
247 
resources(&self) -> &DescriptorSetResources248     pub(crate) fn resources(&self) -> &DescriptorSetResources {
249         &self.resources
250     }
251 }
252 
253 /// The resources that are bound to a descriptor set.
254 #[derive(Clone)]
255 pub struct DescriptorSetResources {
256     binding_resources: HashMap<u32, DescriptorBindingResources>,
257 }
258 
259 impl DescriptorSetResources {
260     /// Creates a new `DescriptorSetResources` matching the provided descriptor set layout, and
261     /// all descriptors set to `None`.
262     #[inline]
new(layout: &DescriptorSetLayout, variable_descriptor_count: u32) -> Self263     pub fn new(layout: &DescriptorSetLayout, variable_descriptor_count: u32) -> Self {
264         assert!(variable_descriptor_count <= layout.variable_descriptor_count());
265 
266         let binding_resources = layout
267             .bindings()
268             .iter()
269             .map(|(&binding_num, binding)| {
270                 let count = if binding.variable_descriptor_count {
271                     variable_descriptor_count
272                 } else {
273                     binding.descriptor_count
274                 } as usize;
275 
276                 let binding_resources = match binding.descriptor_type {
277                     DescriptorType::UniformBuffer
278                     | DescriptorType::StorageBuffer
279                     | DescriptorType::UniformBufferDynamic
280                     | DescriptorType::StorageBufferDynamic => {
281                         DescriptorBindingResources::Buffer(smallvec![None; count])
282                     }
283                     DescriptorType::UniformTexelBuffer | DescriptorType::StorageTexelBuffer => {
284                         DescriptorBindingResources::BufferView(smallvec![None; count])
285                     }
286                     DescriptorType::SampledImage
287                     | DescriptorType::StorageImage
288                     | DescriptorType::InputAttachment => {
289                         DescriptorBindingResources::ImageView(smallvec![None; count])
290                     }
291                     DescriptorType::CombinedImageSampler => {
292                         if binding.immutable_samplers.is_empty() {
293                             DescriptorBindingResources::ImageViewSampler(smallvec![None; count])
294                         } else {
295                             DescriptorBindingResources::ImageView(smallvec![None; count])
296                         }
297                     }
298                     DescriptorType::Sampler => {
299                         if binding.immutable_samplers.is_empty() {
300                             DescriptorBindingResources::Sampler(smallvec![None; count])
301                         } else if layout.push_descriptor() {
302                             // For push descriptors, no resource is written by default, this needs
303                             // to be done explicitly via a dummy write.
304                             DescriptorBindingResources::None(smallvec![None; count])
305                         } else {
306                             // For regular descriptor sets, all descriptors are considered valid
307                             // from the start.
308                             DescriptorBindingResources::None(smallvec![Some(()); count])
309                         }
310                     }
311                 };
312                 (binding_num, binding_resources)
313             })
314             .collect();
315 
316         Self { binding_resources }
317     }
318 
319     /// Applies a descriptor write to the resources.
320     ///
321     /// # Panics
322     ///
323     /// - Panics if the binding number of a write does not exist in the resources.
324     /// - See also [`DescriptorBindingResources::update`].
325     #[inline]
update(&mut self, write: &WriteDescriptorSet)326     pub fn update(&mut self, write: &WriteDescriptorSet) {
327         self.binding_resources
328             .get_mut(&write.binding())
329             .expect("descriptor write has invalid binding number")
330             .update(write)
331     }
332 
333     /// Returns a reference to the bound resources for `binding`. Returns `None` if the binding
334     /// doesn't exist.
335     #[inline]
binding(&self, binding: u32) -> Option<&DescriptorBindingResources>336     pub fn binding(&self, binding: u32) -> Option<&DescriptorBindingResources> {
337         self.binding_resources.get(&binding)
338     }
339 }
340 
341 /// The resources that are bound to a single descriptor set binding.
342 #[derive(Clone)]
343 pub enum DescriptorBindingResources {
344     None(Elements<()>),
345     Buffer(Elements<(Subbuffer<[u8]>, Range<DeviceSize>)>),
346     BufferView(Elements<Arc<BufferView>>),
347     ImageView(Elements<Arc<dyn ImageViewAbstract>>),
348     ImageViewSampler(Elements<(Arc<dyn ImageViewAbstract>, Arc<Sampler>)>),
349     Sampler(Elements<Arc<Sampler>>),
350 }
351 
352 type Elements<T> = SmallVec<[Option<T>; 1]>;
353 
354 impl DescriptorBindingResources {
355     /// Applies a descriptor write to the resources.
356     ///
357     /// # Panics
358     ///
359     /// - Panics if the resource types do not match.
360     /// - Panics if the write goes out of bounds.
361     #[inline]
update(&mut self, write: &WriteDescriptorSet)362     pub fn update(&mut self, write: &WriteDescriptorSet) {
363         fn write_resources<T: Clone>(first: usize, resources: &mut [Option<T>], elements: &[T]) {
364             resources
365                 .get_mut(first..first + elements.len())
366                 .expect("descriptor write for binding out of bounds")
367                 .iter_mut()
368                 .zip(elements)
369                 .for_each(|(resource, element)| {
370                     *resource = Some(element.clone());
371                 });
372         }
373 
374         let first = write.first_array_element() as usize;
375 
376         match (self, write.elements()) {
377             (
378                 DescriptorBindingResources::None(resources),
379                 WriteDescriptorSetElements::None(num_elements),
380             ) => {
381                 resources
382                     .get_mut(first..first + *num_elements as usize)
383                     .expect("descriptor write for binding out of bounds")
384                     .iter_mut()
385                     .for_each(|resource| {
386                         *resource = Some(());
387                     });
388             }
389             (
390                 DescriptorBindingResources::Buffer(resources),
391                 WriteDescriptorSetElements::Buffer(elements),
392             ) => write_resources(first, resources, elements),
393             (
394                 DescriptorBindingResources::BufferView(resources),
395                 WriteDescriptorSetElements::BufferView(elements),
396             ) => write_resources(first, resources, elements),
397             (
398                 DescriptorBindingResources::ImageView(resources),
399                 WriteDescriptorSetElements::ImageView(elements),
400             ) => write_resources(first, resources, elements),
401             (
402                 DescriptorBindingResources::ImageViewSampler(resources),
403                 WriteDescriptorSetElements::ImageViewSampler(elements),
404             ) => write_resources(first, resources, elements),
405             (
406                 DescriptorBindingResources::Sampler(resources),
407                 WriteDescriptorSetElements::Sampler(elements),
408             ) => write_resources(first, resources, elements),
409             _ => panic!(
410                 "descriptor write for binding {} has wrong resource type",
411                 write.binding(),
412             ),
413         }
414     }
415 }
416 
417 #[derive(Clone)]
418 pub struct DescriptorSetWithOffsets {
419     descriptor_set: Arc<dyn DescriptorSet>,
420     dynamic_offsets: SmallVec<[u32; 4]>,
421 }
422 
423 impl DescriptorSetWithOffsets {
new( descriptor_set: Arc<dyn DescriptorSet>, dynamic_offsets: impl IntoIterator<Item = u32>, ) -> Self424     pub fn new(
425         descriptor_set: Arc<dyn DescriptorSet>,
426         dynamic_offsets: impl IntoIterator<Item = u32>,
427     ) -> Self {
428         Self {
429             descriptor_set,
430             dynamic_offsets: dynamic_offsets.into_iter().collect(),
431         }
432     }
433 
434     #[inline]
as_ref(&self) -> (&Arc<dyn DescriptorSet>, &[u32])435     pub fn as_ref(&self) -> (&Arc<dyn DescriptorSet>, &[u32]) {
436         (&self.descriptor_set, &self.dynamic_offsets)
437     }
438 
439     #[inline]
into_tuple(self) -> (Arc<dyn DescriptorSet>, impl ExactSizeIterator<Item = u32>)440     pub fn into_tuple(self) -> (Arc<dyn DescriptorSet>, impl ExactSizeIterator<Item = u32>) {
441         (self.descriptor_set, self.dynamic_offsets.into_iter())
442     }
443 }
444 
445 impl<S> From<Arc<S>> for DescriptorSetWithOffsets
446 where
447     S: DescriptorSet + 'static,
448 {
from(descriptor_set: Arc<S>) -> Self449     fn from(descriptor_set: Arc<S>) -> Self {
450         DescriptorSetWithOffsets::new(descriptor_set, std::iter::empty())
451     }
452 }
453 
454 #[derive(Clone, Copy, Debug)]
455 pub enum DescriptorSetCreationError {
456     DescriptorSetUpdateError(DescriptorSetUpdateError),
457     OomError(OomError),
458 }
459 
460 impl Error for DescriptorSetCreationError {
source(&self) -> Option<&(dyn Error + 'static)>461     fn source(&self) -> Option<&(dyn Error + 'static)> {
462         match self {
463             Self::DescriptorSetUpdateError(err) => Some(err),
464             Self::OomError(err) => Some(err),
465         }
466     }
467 }
468 
469 impl Display for DescriptorSetCreationError {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>470     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
471         match self {
472             Self::DescriptorSetUpdateError(_) => {
473                 write!(f, "an error occurred while updating the descriptor set")
474             }
475             Self::OomError(_) => write!(f, "out of memory"),
476         }
477     }
478 }
479 
480 impl From<DescriptorSetUpdateError> for DescriptorSetCreationError {
from(err: DescriptorSetUpdateError) -> Self481     fn from(err: DescriptorSetUpdateError) -> Self {
482         Self::DescriptorSetUpdateError(err)
483     }
484 }
485 
486 impl From<OomError> for DescriptorSetCreationError {
from(err: OomError) -> Self487     fn from(err: OomError) -> Self {
488         Self::OomError(err)
489     }
490 }
491