• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2021 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 //! Describes the layout of all descriptors within a descriptor set.
11 //!
12 //! When creating a new descriptor set, you must provide a *layout* object to create it from.
13 
14 use crate::{
15     device::{Device, DeviceOwned},
16     macros::{impl_id_counter, vulkan_enum},
17     sampler::Sampler,
18     shader::{DescriptorBindingRequirements, ShaderStages},
19     OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
20 };
21 use ahash::HashMap;
22 use std::{
23     collections::BTreeMap,
24     error::Error,
25     fmt::{Display, Error as FmtError, Formatter},
26     mem::MaybeUninit,
27     num::NonZeroU64,
28     ptr,
29     sync::Arc,
30 };
31 
32 /// Describes to the Vulkan implementation the layout of all descriptors within a descriptor set.
33 #[derive(Debug)]
34 pub struct DescriptorSetLayout {
35     handle: ash::vk::DescriptorSetLayout,
36     device: Arc<Device>,
37     id: NonZeroU64,
38 
39     bindings: BTreeMap<u32, DescriptorSetLayoutBinding>,
40     push_descriptor: bool,
41 
42     descriptor_counts: HashMap<DescriptorType, u32>,
43 }
44 
45 impl DescriptorSetLayout {
46     /// Creates a new `DescriptorSetLayout`.
47     #[inline]
new( device: Arc<Device>, mut create_info: DescriptorSetLayoutCreateInfo, ) -> Result<Arc<DescriptorSetLayout>, DescriptorSetLayoutCreationError>48     pub fn new(
49         device: Arc<Device>,
50         mut create_info: DescriptorSetLayoutCreateInfo,
51     ) -> Result<Arc<DescriptorSetLayout>, DescriptorSetLayoutCreationError> {
52         let descriptor_counts = Self::validate(&device, &mut create_info)?;
53         let handle = unsafe { Self::create(&device, &create_info)? };
54 
55         let DescriptorSetLayoutCreateInfo {
56             bindings,
57             push_descriptor,
58             _ne: _,
59         } = create_info;
60 
61         Ok(Arc::new(DescriptorSetLayout {
62             handle,
63             device,
64             id: Self::next_id(),
65             bindings,
66             push_descriptor,
67             descriptor_counts,
68         }))
69     }
70 
71     /// Creates a new `DescriptorSetLayout` from a raw object handle.
72     ///
73     /// # Safety
74     ///
75     /// - `handle` must be a valid Vulkan object handle created from `device`.
76     /// - `create_info` must match the info used to create the object.
77     #[inline]
from_handle( device: Arc<Device>, handle: ash::vk::DescriptorSetLayout, create_info: DescriptorSetLayoutCreateInfo, ) -> Arc<DescriptorSetLayout>78     pub unsafe fn from_handle(
79         device: Arc<Device>,
80         handle: ash::vk::DescriptorSetLayout,
81         create_info: DescriptorSetLayoutCreateInfo,
82     ) -> Arc<DescriptorSetLayout> {
83         let DescriptorSetLayoutCreateInfo {
84             bindings,
85             push_descriptor,
86             _ne: _,
87         } = create_info;
88 
89         let mut descriptor_counts = HashMap::default();
90         for binding in bindings.values() {
91             if binding.descriptor_count != 0 {
92                 *descriptor_counts
93                     .entry(binding.descriptor_type)
94                     .or_default() += binding.descriptor_count;
95             }
96         }
97 
98         Arc::new(DescriptorSetLayout {
99             handle,
100             device,
101             id: Self::next_id(),
102             bindings,
103             push_descriptor,
104             descriptor_counts,
105         })
106     }
107 
validate( device: &Device, create_info: &mut DescriptorSetLayoutCreateInfo, ) -> Result<HashMap<DescriptorType, u32>, DescriptorSetLayoutCreationError>108     fn validate(
109         device: &Device,
110         create_info: &mut DescriptorSetLayoutCreateInfo,
111     ) -> Result<HashMap<DescriptorType, u32>, DescriptorSetLayoutCreationError> {
112         let &mut DescriptorSetLayoutCreateInfo {
113             ref bindings,
114             push_descriptor,
115             _ne: _,
116         } = create_info;
117 
118         let mut descriptor_counts = HashMap::default();
119 
120         if push_descriptor {
121             if !device.enabled_extensions().khr_push_descriptor {
122                 return Err(DescriptorSetLayoutCreationError::RequirementNotMet {
123                     required_for: "`create_info.push_descriptor` is set",
124                     requires_one_of: RequiresOneOf {
125                         device_extensions: &["khr_push_descriptor"],
126                         ..Default::default()
127                     },
128                 });
129             }
130         }
131 
132         let highest_binding_num = bindings.keys().copied().next_back();
133 
134         for (&binding_num, binding) in bindings.iter() {
135             let &DescriptorSetLayoutBinding {
136                 descriptor_type,
137                 descriptor_count,
138                 variable_descriptor_count,
139                 stages,
140                 ref immutable_samplers,
141                 _ne: _,
142             } = binding;
143 
144             // VUID-VkDescriptorSetLayoutBinding-descriptorType-parameter
145             descriptor_type.validate_device(device)?;
146 
147             if descriptor_count != 0 {
148                 // VUID-VkDescriptorSetLayoutBinding-descriptorCount-00283
149                 stages.validate_device(device)?;
150 
151                 *descriptor_counts.entry(descriptor_type).or_default() += descriptor_count;
152             }
153 
154             if push_descriptor {
155                 // VUID-VkDescriptorSetLayoutCreateInfo-flags-00280
156                 if matches!(
157                     descriptor_type,
158                     DescriptorType::StorageBufferDynamic | DescriptorType::UniformBufferDynamic
159                 ) {
160                     return Err(
161                         DescriptorSetLayoutCreationError::PushDescriptorDescriptorTypeIncompatible {
162                             binding_num,
163                         },
164                     );
165                 }
166 
167                 // VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-flags-03003
168                 if variable_descriptor_count {
169                     return Err(
170                         DescriptorSetLayoutCreationError::PushDescriptorVariableDescriptorCount {
171                             binding_num,
172                         },
173                     );
174                 }
175             }
176 
177             if !immutable_samplers.is_empty() {
178                 if immutable_samplers
179                     .iter()
180                     .any(|sampler| sampler.sampler_ycbcr_conversion().is_some())
181                 {
182                     if !matches!(descriptor_type, DescriptorType::CombinedImageSampler) {
183                         return Err(
184                             DescriptorSetLayoutCreationError::ImmutableSamplersDescriptorTypeIncompatible {
185                                 binding_num,
186                             },
187                         );
188                     }
189                 } else {
190                     if !matches!(
191                         descriptor_type,
192                         DescriptorType::Sampler | DescriptorType::CombinedImageSampler
193                     ) {
194                         return Err(
195                             DescriptorSetLayoutCreationError::ImmutableSamplersDescriptorTypeIncompatible {
196                                 binding_num,
197                             },
198                         );
199                     }
200                 }
201 
202                 // VUID-VkDescriptorSetLayoutBinding-descriptorType-00282
203                 if descriptor_count != immutable_samplers.len() as u32 {
204                     return Err(
205                         DescriptorSetLayoutCreationError::ImmutableSamplersCountMismatch {
206                             binding_num,
207                             sampler_count: immutable_samplers.len() as u32,
208                             descriptor_count,
209                         },
210                     );
211                 }
212             }
213 
214             // VUID-VkDescriptorSetLayoutBinding-descriptorType-01510
215             // If descriptorType is VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT and descriptorCount is not 0, then stageFlags must be 0 or VK_SHADER_STAGE_FRAGMENT_BIT
216 
217             if variable_descriptor_count {
218                 // VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingVariableDescriptorCount-03014
219                 if !device
220                     .enabled_features()
221                     .descriptor_binding_variable_descriptor_count
222                 {
223                     return Err(DescriptorSetLayoutCreationError::RequirementNotMet {
224                         required_for: "`create_info.bindings` has an element where \
225                             `variable_descriptor_count` is set",
226                         requires_one_of: RequiresOneOf {
227                             features: &["descriptor_binding_variable_descriptor_count"],
228                             ..Default::default()
229                         },
230                     });
231                 }
232 
233                 // VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-pBindingFlags-03004
234                 if Some(binding_num) != highest_binding_num {
235                     return Err(
236                         DescriptorSetLayoutCreationError::VariableDescriptorCountBindingNotHighest {
237                             binding_num,
238                             highest_binding_num: highest_binding_num.unwrap(),
239                         },
240                     );
241                 }
242 
243                 // VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-pBindingFlags-03015
244                 if matches!(
245                     descriptor_type,
246                     DescriptorType::UniformBufferDynamic | DescriptorType::StorageBufferDynamic
247                 ) {
248                     return Err(
249                         DescriptorSetLayoutCreationError::VariableDescriptorCountDescriptorTypeIncompatible {
250                             binding_num,
251                         },
252                     );
253                 }
254             }
255         }
256 
257         // VUID-VkDescriptorSetLayoutCreateInfo-flags-00281
258         if push_descriptor
259             && descriptor_counts.values().copied().sum::<u32>()
260                 > device
261                     .physical_device()
262                     .properties()
263                     .max_push_descriptors
264                     .unwrap_or(0)
265         {
266             return Err(
267                 DescriptorSetLayoutCreationError::MaxPushDescriptorsExceeded {
268                     provided: descriptor_counts.values().copied().sum(),
269                     max_supported: device
270                         .physical_device()
271                         .properties()
272                         .max_push_descriptors
273                         .unwrap_or(0),
274                 },
275             );
276         }
277 
278         Ok(descriptor_counts)
279     }
280 
create( device: &Device, create_info: &DescriptorSetLayoutCreateInfo, ) -> Result<ash::vk::DescriptorSetLayout, DescriptorSetLayoutCreationError>281     unsafe fn create(
282         device: &Device,
283         create_info: &DescriptorSetLayoutCreateInfo,
284     ) -> Result<ash::vk::DescriptorSetLayout, DescriptorSetLayoutCreationError> {
285         let &DescriptorSetLayoutCreateInfo {
286             ref bindings,
287             push_descriptor,
288             _ne: _,
289         } = create_info;
290 
291         let mut bindings_vk = Vec::with_capacity(bindings.len());
292         let mut binding_flags_vk = Vec::with_capacity(bindings.len());
293         let mut immutable_samplers_vk: Vec<Box<[ash::vk::Sampler]>> = Vec::new(); // only to keep the arrays of handles alive
294         let mut flags = ash::vk::DescriptorSetLayoutCreateFlags::empty();
295 
296         if push_descriptor {
297             flags |= ash::vk::DescriptorSetLayoutCreateFlags::PUSH_DESCRIPTOR_KHR;
298         }
299 
300         for (&binding_num, binding) in bindings.iter() {
301             let mut binding_flags = ash::vk::DescriptorBindingFlags::empty();
302 
303             let p_immutable_samplers = if !binding.immutable_samplers.is_empty() {
304                 // VUID-VkDescriptorSetLayoutBinding-descriptorType-00282
305                 let sampler_handles = binding
306                     .immutable_samplers
307                     .iter()
308                     .map(|s| s.handle())
309                     .collect::<Vec<_>>()
310                     .into_boxed_slice();
311                 let p_immutable_samplers = sampler_handles.as_ptr();
312                 immutable_samplers_vk.push(sampler_handles);
313                 p_immutable_samplers
314             } else {
315                 ptr::null()
316             };
317 
318             if binding.variable_descriptor_count {
319                 binding_flags |= ash::vk::DescriptorBindingFlags::VARIABLE_DESCRIPTOR_COUNT;
320             }
321 
322             // VUID-VkDescriptorSetLayoutCreateInfo-binding-00279
323             // Guaranteed by BTreeMap
324             bindings_vk.push(ash::vk::DescriptorSetLayoutBinding {
325                 binding: binding_num,
326                 descriptor_type: binding.descriptor_type.into(),
327                 descriptor_count: binding.descriptor_count,
328                 stage_flags: binding.stages.into(),
329                 p_immutable_samplers,
330             });
331             binding_flags_vk.push(binding_flags);
332         }
333 
334         let mut binding_flags_create_info = if device.api_version() >= Version::V1_2
335             || device.enabled_extensions().ext_descriptor_indexing
336         {
337             Some(ash::vk::DescriptorSetLayoutBindingFlagsCreateInfo {
338                 // VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-bindingCount-03002
339                 binding_count: binding_flags_vk.len() as u32,
340                 p_binding_flags: binding_flags_vk.as_ptr(),
341                 ..Default::default()
342             })
343         } else {
344             None
345         };
346 
347         let mut create_info = ash::vk::DescriptorSetLayoutCreateInfo {
348             flags,
349             binding_count: bindings_vk.len() as u32,
350             p_bindings: bindings_vk.as_ptr(),
351             ..Default::default()
352         };
353 
354         if let Some(binding_flags_create_info) = binding_flags_create_info.as_mut() {
355             binding_flags_create_info.p_next = create_info.p_next;
356             create_info.p_next = binding_flags_create_info as *const _ as *const _;
357         }
358 
359         let handle = {
360             let fns = device.fns();
361             let mut output = MaybeUninit::uninit();
362             (fns.v1_0.create_descriptor_set_layout)(
363                 device.handle(),
364                 &create_info,
365                 ptr::null(),
366                 output.as_mut_ptr(),
367             )
368             .result()
369             .map_err(VulkanError::from)?;
370             output.assume_init()
371         };
372 
373         Ok(handle)
374     }
375 
id(&self) -> NonZeroU64376     pub(crate) fn id(&self) -> NonZeroU64 {
377         self.id
378     }
379 
380     /// Returns the bindings of the descriptor set layout.
381     #[inline]
bindings(&self) -> &BTreeMap<u32, DescriptorSetLayoutBinding>382     pub fn bindings(&self) -> &BTreeMap<u32, DescriptorSetLayoutBinding> {
383         &self.bindings
384     }
385 
386     /// Returns whether the descriptor set layout is for push descriptors or regular descriptor
387     /// sets.
388     #[inline]
push_descriptor(&self) -> bool389     pub fn push_descriptor(&self) -> bool {
390         self.push_descriptor
391     }
392 
393     /// Returns the number of descriptors of each type.
394     ///
395     /// The map is guaranteed to not contain any elements with a count of `0`.
396     #[inline]
descriptor_counts(&self) -> &HashMap<DescriptorType, u32>397     pub fn descriptor_counts(&self) -> &HashMap<DescriptorType, u32> {
398         &self.descriptor_counts
399     }
400 
401     /// If the highest-numbered binding has a variable count, returns its `descriptor_count`.
402     /// Otherwise returns `0`.
403     #[inline]
variable_descriptor_count(&self) -> u32404     pub fn variable_descriptor_count(&self) -> u32 {
405         self.bindings
406             .values()
407             .next_back()
408             .map(|binding| {
409                 if binding.variable_descriptor_count {
410                     binding.descriptor_count
411                 } else {
412                     0
413                 }
414             })
415             .unwrap_or(0)
416     }
417 
418     /// Returns whether `self` is compatible with `other`.
419     ///
420     /// "Compatible" in this sense is defined by the Vulkan specification under the section
421     /// "Pipeline layout compatibility": either the two are the same descriptor set layout object,
422     /// or they must be identically defined to the Vulkan API.
423     #[inline]
is_compatible_with(&self, other: &DescriptorSetLayout) -> bool424     pub fn is_compatible_with(&self, other: &DescriptorSetLayout) -> bool {
425         self == other
426             || (self.bindings == other.bindings && self.push_descriptor == other.push_descriptor)
427     }
428 }
429 
430 impl Drop for DescriptorSetLayout {
431     #[inline]
drop(&mut self)432     fn drop(&mut self) {
433         unsafe {
434             let fns = self.device.fns();
435             (fns.v1_0.destroy_descriptor_set_layout)(
436                 self.device.handle(),
437                 self.handle,
438                 ptr::null(),
439             );
440         }
441     }
442 }
443 
444 unsafe impl VulkanObject for DescriptorSetLayout {
445     type Handle = ash::vk::DescriptorSetLayout;
446 
447     #[inline]
handle(&self) -> Self::Handle448     fn handle(&self) -> Self::Handle {
449         self.handle
450     }
451 }
452 
453 unsafe impl DeviceOwned for DescriptorSetLayout {
454     #[inline]
device(&self) -> &Arc<Device>455     fn device(&self) -> &Arc<Device> {
456         &self.device
457     }
458 }
459 
460 impl_id_counter!(DescriptorSetLayout);
461 
462 /// Error related to descriptor set layout.
463 #[derive(Debug, Clone, PartialEq, Eq)]
464 pub enum DescriptorSetLayoutCreationError {
465     /// Out of Memory.
466     OomError(OomError),
467 
468     RequirementNotMet {
469         required_for: &'static str,
470         requires_one_of: RequiresOneOf,
471     },
472 
473     /// A binding includes immutable samplers but their number differs from  `descriptor_count`.
474     ImmutableSamplersCountMismatch {
475         binding_num: u32,
476         sampler_count: u32,
477         descriptor_count: u32,
478     },
479 
480     /// A binding includes immutable samplers but it has an incompatible `descriptor_type`.
481     ImmutableSamplersDescriptorTypeIncompatible { binding_num: u32 },
482 
483     /// More descriptors were provided in all bindings than the
484     /// [`max_push_descriptors`](crate::device::Properties::max_push_descriptors) limit.
485     MaxPushDescriptorsExceeded { provided: u32, max_supported: u32 },
486 
487     /// `push_descriptor` is enabled, but a binding has an incompatible `descriptor_type`.
488     PushDescriptorDescriptorTypeIncompatible { binding_num: u32 },
489 
490     /// `push_descriptor` is enabled, but a binding has `variable_descriptor_count` enabled.
491     PushDescriptorVariableDescriptorCount { binding_num: u32 },
492 
493     /// A binding has `variable_descriptor_count` enabled, but it is not the highest-numbered
494     /// binding.
495     VariableDescriptorCountBindingNotHighest {
496         binding_num: u32,
497         highest_binding_num: u32,
498     },
499 
500     /// A binding has `variable_descriptor_count` enabled, but it has an incompatible
501     /// `descriptor_type`.
502     VariableDescriptorCountDescriptorTypeIncompatible { binding_num: u32 },
503 }
504 
505 impl From<VulkanError> for DescriptorSetLayoutCreationError {
from(error: VulkanError) -> Self506     fn from(error: VulkanError) -> Self {
507         Self::OomError(error.into())
508     }
509 }
510 
511 impl Error for DescriptorSetLayoutCreationError {}
512 
513 impl Display for DescriptorSetLayoutCreationError {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>514     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
515         match self {
516             Self::OomError(_) => {
517                 write!(f, "out of memory")
518             }
519             Self::RequirementNotMet {
520                 required_for,
521                 requires_one_of,
522             } => write!(
523                 f,
524                 "a requirement was not met for: {}; requires one of: {}",
525                 required_for, requires_one_of,
526             ),
527             Self::ImmutableSamplersCountMismatch {
528                 binding_num,
529                 sampler_count,
530                 descriptor_count,
531             } => write!(
532                 f,
533                 "binding {} includes immutable samplers but their number ({}) differs from \
534                 `descriptor_count` ({})",
535                 binding_num, sampler_count, descriptor_count,
536             ),
537             Self::ImmutableSamplersDescriptorTypeIncompatible { binding_num } => write!(
538                 f,
539                 "binding {} includes immutable samplers but it has an incompatible \
540                 `descriptor_type`",
541                 binding_num,
542             ),
543             Self::MaxPushDescriptorsExceeded {
544                 provided,
545                 max_supported,
546             } => write!(
547                 f,
548                 "more descriptors were provided in all bindings ({}) than the \
549                 `max_push_descriptors` limit ({})",
550                 provided, max_supported,
551             ),
552             Self::PushDescriptorDescriptorTypeIncompatible { binding_num } => write!(
553                 f,
554                 "`push_descriptor` is enabled, but binding {} has an incompatible \
555                 `descriptor_type`",
556                 binding_num,
557             ),
558             Self::PushDescriptorVariableDescriptorCount { binding_num } => write!(
559                 f,
560                 "`push_descriptor` is enabled, but binding {} has `variable_descriptor_count` \
561                 enabled",
562                 binding_num,
563             ),
564             Self::VariableDescriptorCountBindingNotHighest {
565                 binding_num,
566                 highest_binding_num,
567             } => write!(
568                 f,
569                 "binding {} has `variable_descriptor_count` enabled, but it is not the \
570                 highest-numbered binding ({})",
571                 binding_num, highest_binding_num,
572             ),
573             Self::VariableDescriptorCountDescriptorTypeIncompatible { binding_num } => write!(
574                 f,
575                 "binding {} has `variable_descriptor_count` enabled, but it has an incompatible \
576                 `descriptor_type`",
577                 binding_num,
578             ),
579         }
580     }
581 }
582 
583 impl From<RequirementNotMet> for DescriptorSetLayoutCreationError {
from(err: RequirementNotMet) -> Self584     fn from(err: RequirementNotMet) -> Self {
585         Self::RequirementNotMet {
586             required_for: err.required_for,
587             requires_one_of: err.requires_one_of,
588         }
589     }
590 }
591 
592 /// Parameters to create a new `DescriptorSetLayout`.
593 #[derive(Clone, Debug)]
594 pub struct DescriptorSetLayoutCreateInfo {
595     /// The bindings of the desriptor set layout. These are specified according to binding number.
596     ///
597     /// It is generally advisable to keep the binding numbers low. Higher binding numbers may
598     /// use more memory inside Vulkan.
599     ///
600     /// The default value is empty.
601     pub bindings: BTreeMap<u32, DescriptorSetLayoutBinding>,
602 
603     /// Whether the descriptor set layout should be created for push descriptors.
604     ///
605     /// If `true`, the layout can only be used for push descriptors, and if `false`, it can only
606     /// be used for regular descriptor sets.
607     ///
608     /// If set to `true`, the
609     /// [`khr_push_descriptor`](crate::device::DeviceExtensions::khr_push_descriptor) extension must
610     /// be enabled on the device, and there are several restrictions:
611     /// - There must be no bindings with a type of [`DescriptorType::UniformBufferDynamic`]
612     ///   or [`DescriptorType::StorageBufferDynamic`].
613     /// - There must be no bindings with `variable_descriptor_count` enabled.
614     /// - The total number of descriptors across all bindings must be less than the
615     ///   [`max_push_descriptors`](crate::device::Properties::max_push_descriptors) limit.
616     ///
617     /// The default value is `false`.
618     pub push_descriptor: bool,
619 
620     pub _ne: crate::NonExhaustive,
621 }
622 
623 impl Default for DescriptorSetLayoutCreateInfo {
624     #[inline]
default() -> Self625     fn default() -> Self {
626         Self {
627             bindings: BTreeMap::new(),
628             push_descriptor: false,
629             _ne: crate::NonExhaustive(()),
630         }
631     }
632 }
633 
634 impl DescriptorSetLayoutCreateInfo {
635     /// Builds a list of `DescriptorSetLayoutCreateInfo` from an iterator of
636     /// `DescriptorBindingRequirements` originating from a shader.
from_requirements<'a>( descriptor_requirements: impl IntoIterator< Item = ((u32, u32), &'a DescriptorBindingRequirements), >, ) -> Vec<Self>637     pub fn from_requirements<'a>(
638         descriptor_requirements: impl IntoIterator<
639             Item = ((u32, u32), &'a DescriptorBindingRequirements),
640         >,
641     ) -> Vec<Self> {
642         let mut create_infos: Vec<Self> = Vec::new();
643 
644         for ((set_num, binding_num), reqs) in descriptor_requirements {
645             let set_num = set_num as usize;
646 
647             if set_num >= create_infos.len() {
648                 create_infos.resize(set_num + 1, Self::default());
649             }
650 
651             let bindings = &mut create_infos[set_num].bindings;
652             bindings.insert(binding_num, reqs.into());
653         }
654 
655         create_infos
656     }
657 }
658 
659 /// A binding in a descriptor set layout.
660 #[derive(Clone, Debug, PartialEq, Eq)]
661 pub struct DescriptorSetLayoutBinding {
662     /// The content and layout of each array element of a binding.
663     ///
664     /// There is no default value.
665     pub descriptor_type: DescriptorType,
666 
667     /// How many descriptors (array elements) this binding is made of.
668     ///
669     /// If the binding is a single element rather than an array, then you must specify `1`.
670     ///
671     /// The default value is `1`.
672     pub descriptor_count: u32,
673 
674     /// Whether the binding has a variable number of descriptors.
675     ///
676     /// If set to `true`, the [`descriptor_binding_variable_descriptor_count`] feature must be
677     /// enabled. The value of `descriptor_count` specifies the maximum number of descriptors
678     /// allowed.
679     ///
680     /// There may only be one binding with a variable count in a descriptor set, and it must be the
681     /// binding with the highest binding number. The `descriptor_type` must not be
682     /// [`DescriptorType::UniformBufferDynamic`] or [`DescriptorType::StorageBufferDynamic`].
683     ///
684     /// The default value is `false`.
685     ///
686     /// [`descriptor_binding_variable_descriptor_count`]: crate::device::Features::descriptor_binding_variable_descriptor_count
687     pub variable_descriptor_count: bool,
688 
689     /// Which shader stages are going to access the descriptors in this binding.
690     ///
691     /// The default value is [`ShaderStages::empty()`], which must be overridden.
692     pub stages: ShaderStages,
693 
694     /// Samplers that are included as a fixed part of the descriptor set layout. Once bound, they
695     /// do not need to be provided when creating a descriptor set.
696     ///
697     /// The list must be either empty, or contain exactly `descriptor_count` samplers. It can only
698     /// be non-empty if `descriptor_type` is [`DescriptorType::Sampler`] or
699     /// [`DescriptorType::CombinedImageSampler`]. If any of the samplers has an attached sampler
700     /// YCbCr conversion, then only [`DescriptorType::CombinedImageSampler`] is allowed.
701     ///
702     /// The default value is empty.
703     pub immutable_samplers: Vec<Arc<Sampler>>,
704 
705     pub _ne: crate::NonExhaustive,
706 }
707 
708 impl DescriptorSetLayoutBinding {
709     /// Returns a `DescriptorSetLayoutBinding` with the given type.
710     #[inline]
descriptor_type(descriptor_type: DescriptorType) -> Self711     pub fn descriptor_type(descriptor_type: DescriptorType) -> Self {
712         Self {
713             descriptor_type,
714             descriptor_count: 1,
715             variable_descriptor_count: false,
716             stages: ShaderStages::empty(),
717             immutable_samplers: Vec::new(),
718             _ne: crate::NonExhaustive(()),
719         }
720     }
721 
722     /// Checks whether the descriptor of a pipeline layout `self` is compatible with the
723     /// requirements of a shader `other`.
724     #[inline]
ensure_compatible_with_shader( &self, binding_requirements: &DescriptorBindingRequirements, ) -> Result<(), DescriptorRequirementsNotMet>725     pub fn ensure_compatible_with_shader(
726         &self,
727         binding_requirements: &DescriptorBindingRequirements,
728     ) -> Result<(), DescriptorRequirementsNotMet> {
729         let &DescriptorBindingRequirements {
730             ref descriptor_types,
731             descriptor_count,
732             image_format: _,
733             image_multisampled: _,
734             image_scalar_type: _,
735             image_view_type: _,
736             stages,
737             descriptors: _,
738         } = binding_requirements;
739 
740         if !descriptor_types.contains(&self.descriptor_type) {
741             return Err(DescriptorRequirementsNotMet::DescriptorType {
742                 required: descriptor_types.clone(),
743                 obtained: self.descriptor_type,
744             });
745         }
746 
747         if let Some(required) = descriptor_count {
748             if self.descriptor_count < required {
749                 return Err(DescriptorRequirementsNotMet::DescriptorCount {
750                     required,
751                     obtained: self.descriptor_count,
752                 });
753             }
754         }
755 
756         if !self.stages.contains(stages) {
757             return Err(DescriptorRequirementsNotMet::ShaderStages {
758                 required: stages,
759                 obtained: self.stages,
760             });
761         }
762 
763         Ok(())
764     }
765 }
766 
767 impl From<&DescriptorBindingRequirements> for DescriptorSetLayoutBinding {
768     #[inline]
from(reqs: &DescriptorBindingRequirements) -> Self769     fn from(reqs: &DescriptorBindingRequirements) -> Self {
770         Self {
771             descriptor_type: reqs.descriptor_types[0],
772             descriptor_count: reqs.descriptor_count.unwrap_or(0),
773             variable_descriptor_count: false,
774             stages: reqs.stages,
775             immutable_samplers: Vec::new(),
776             _ne: crate::NonExhaustive(()),
777         }
778     }
779 }
780 
781 /// Error when checking whether the requirements for a binding have been met.
782 #[derive(Debug, Clone, PartialEq, Eq)]
783 pub enum DescriptorRequirementsNotMet {
784     /// The binding's `descriptor_type` is not one of those required.
785     DescriptorType {
786         required: Vec<DescriptorType>,
787         obtained: DescriptorType,
788     },
789 
790     /// The binding's `descriptor_count` is less than what is required.
791     DescriptorCount { required: u32, obtained: u32 },
792 
793     /// The binding's `stages` does not contain the stages that are required.
794     ShaderStages {
795         required: ShaderStages,
796         obtained: ShaderStages,
797     },
798 }
799 
800 impl Error for DescriptorRequirementsNotMet {}
801 
802 impl Display for DescriptorRequirementsNotMet {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>803     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
804         match self {
805             Self::DescriptorType { required, obtained } => write!(
806                 f,
807                 "the descriptor's type ({:?}) is not one of those required ({:?})",
808                 obtained, required,
809             ),
810             Self::DescriptorCount { required, obtained } => write!(
811                 f,
812                 "the descriptor count ({}) is less than what is required ({})",
813                 obtained, required,
814             ),
815             Self::ShaderStages { .. } => write!(
816                 f,
817                 "the descriptor's shader stages do not contain the stages that are required",
818             ),
819         }
820     }
821 }
822 
823 vulkan_enum! {
824     #[non_exhaustive]
825 
826     /// Describes what kind of resource may later be bound to a descriptor.
827     DescriptorType = DescriptorType(i32);
828 
829     /// Describes how a `SampledImage` descriptor should be read.
830     Sampler = SAMPLER,
831 
832     /// Combines `SampledImage` and `Sampler` in one descriptor.
833     CombinedImageSampler = COMBINED_IMAGE_SAMPLER,
834 
835     /// Gives read-only access to an image via a sampler. The image must be combined with a sampler
836     /// inside the shader.
837     SampledImage = SAMPLED_IMAGE,
838 
839     /// Gives read and/or write access to individual pixels in an image. The image cannot be
840     /// sampled, so you have exactly specify which pixel to read or write.
841     StorageImage = STORAGE_IMAGE,
842 
843     /// Gives read-only access to the content of a buffer, interpreted as an array of texel data.
844     UniformTexelBuffer = UNIFORM_TEXEL_BUFFER,
845 
846     /// Gives read and/or write access to the content of a buffer, interpreted as an array of texel
847     /// data. Less restrictive but sometimes slower than a uniform texel buffer.
848     StorageTexelBuffer = STORAGE_TEXEL_BUFFER,
849 
850     /// Gives read-only access to the content of a buffer, interpreted as a structure.
851     UniformBuffer = UNIFORM_BUFFER,
852 
853     /// Gives read and/or write access to the content of a buffer, interpreted as a structure. Less
854     /// restrictive but sometimes slower than a uniform buffer.
855     StorageBuffer = STORAGE_BUFFER,
856 
857     /// As `UniformBuffer`, but the offset within the buffer is specified at the time the descriptor
858     /// set is bound, rather than when the descriptor set is updated.
859     UniformBufferDynamic = UNIFORM_BUFFER_DYNAMIC,
860 
861     /// As `StorageBuffer`, but the offset within the buffer is specified at the time the descriptor
862     /// set is bound, rather than when the descriptor set is updated.
863     StorageBufferDynamic = STORAGE_BUFFER_DYNAMIC,
864 
865     /// Gives access to an image inside a fragment shader via a render pass. You can only access the
866     /// pixel that is currently being processed by the fragment shader.
867     InputAttachment = INPUT_ATTACHMENT,
868 
869     /* TODO: enable
870     // TODO: document
871     InlineUniformBlock = INLINE_UNIFORM_BLOCK {
872         api_version: V1_3,
873         device_extensions: [ext_inline_uniform_block],
874     },*/
875 
876     /* TODO: enable
877     // TODO: document
878     AccelerationStructure = ACCELERATION_STRUCTURE_KHR {
879         device_extensions: [khr_acceleration_structure],
880     },*/
881 
882     /* TODO: enable
883     // TODO: document
884     AccelerationStructureNV = ACCELERATION_STRUCTURE_NV {
885         device_extensions: [nv_ray_tracing],
886     },*/
887 
888     /* TODO: enable
889     // TODO: document
890     SampleWeightImage = SAMPLE_WEIGHT_IMAGE_QCOM {
891         device_extensions: [qcom_image_processing],
892     },*/
893 
894     /* TODO: enable
895     // TODO: document
896     BlockMatchImage = BLOCK_MATCH_IMAGE_QCOM {
897         device_extensions: [qcom_image_processing],
898     },*/
899 
900     /* TODO: enable
901     // TODO: document
902     Mutable = MUTABLE_VALVE {
903         device_extensions: [valve_mutable_descriptor_type],
904     },*/
905 }
906 
907 #[cfg(test)]
908 mod tests {
909     use crate::{
910         descriptor_set::layout::{
911             DescriptorSetLayout, DescriptorSetLayoutBinding, DescriptorSetLayoutCreateInfo,
912             DescriptorType,
913         },
914         shader::ShaderStages,
915     };
916     use ahash::HashMap;
917 
918     #[test]
empty()919     fn empty() {
920         let (device, _) = gfx_dev_and_queue!();
921         let _layout = DescriptorSetLayout::new(device, Default::default());
922     }
923 
924     #[test]
basic_create()925     fn basic_create() {
926         let (device, _) = gfx_dev_and_queue!();
927 
928         let sl = DescriptorSetLayout::new(
929             device,
930             DescriptorSetLayoutCreateInfo {
931                 bindings: [(
932                     0,
933                     DescriptorSetLayoutBinding {
934                         stages: ShaderStages::all_graphics(),
935                         ..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::UniformBuffer)
936                     },
937                 )]
938                 .into(),
939                 ..Default::default()
940             },
941         )
942         .unwrap();
943 
944         assert_eq!(
945             sl.descriptor_counts(),
946             &[(DescriptorType::UniformBuffer, 1)]
947                 .into_iter()
948                 .collect::<HashMap<_, _>>(),
949         );
950     }
951 }
952