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 //! The layout of descriptor sets and push constants used by a pipeline.
11 //!
12 //! # Overview
13 //!
14 //! The layout itself only *describes* the descriptors and push constants, and does not contain
15 //! their content itself. Instead, you can think of it as a `struct` definition that states which
16 //! members there are, what types they have, and in what order.
17 //! One could imagine a Rust definition somewhat like this:
18 //!
19 //! ```text
20 //! #[repr(C)]
21 //! struct MyPipelineLayout {
22 //!     push_constants: Pc,
23 //!     descriptor_set0: Ds0,
24 //!     descriptor_set1: Ds1,
25 //!     descriptor_set2: Ds2,
26 //!     descriptor_set3: Ds3,
27 //! }
28 //! ```
29 //!
30 //! Of course, a pipeline layout is created at runtime, unlike a Rust type.
31 //!
32 //! # Layout compatibility
33 //!
34 //! When binding descriptor sets or setting push constants, you must provide a pipeline layout.
35 //! This layout is used to decide where in memory Vulkan should write the new data. The
36 //! descriptor sets and push constants can later be read by dispatch or draw calls, but only if
37 //! the bound pipeline being used for the command has a layout that is *compatible* with the layout
38 //! that was used to bind the resources.
39 //!
40 //! *Compatible* means that the pipeline layout must be the same object, or a different layout in
41 //! which the push constant ranges and descriptor set layouts were be identically defined.
42 //! However, Vulkan allows for partial compatibility as well. In the `struct` analogy used above,
43 //! one could imagine that using a different definition would leave some members with the same
44 //! offset and size within the struct as in the old definition, while others are no longer
45 //! positioned correctly. For example, if a new, incompatible type were used for `Ds1`, then the
46 //! `descriptor_set1`, `descriptor_set2` and `descriptor_set3` members would no longer be correct,
47 //! but `descriptor_set0` and `push_constants` would remain accessible in the new layout.
48 //! Because of this behaviour, the following rules apply to compatibility between the layouts used
49 //! in subsequent descriptor set binding calls:
50 //!
51 //! - An incompatible definition of `Pc` invalidates all bound descriptor sets.
52 //! - An incompatible definition of `DsN` invalidates all bound descriptor sets *N* and higher.
53 //! - If *N* is the highest set being assigned in a bind command, and it and all lower sets
54 //!   have compatible definitions, including the push constants, then descriptor sets above *N*
55 //!   remain valid.
56 //!
57 //! [`SyncCommandBufferBuilder`](crate::command_buffer::synced::SyncCommandBufferBuilder) keeps
58 //! track of this state and will automatically remove descriptor sets that have been invalidated
59 //! by incompatible layouts in subsequent binding commands.
60 //!
61 //! # Creating pipeline layouts
62 //!
63 //! A pipeline layout is a Vulkan object type, represented in Vulkano with the `PipelineLayout`
64 //! type. Each pipeline that you create holds a pipeline layout object.
65 
66 use crate::{
67     descriptor_set::layout::{DescriptorRequirementsNotMet, DescriptorSetLayout, DescriptorType},
68     device::{Device, DeviceOwned},
69     macros::impl_id_counter,
70     shader::{DescriptorBindingRequirements, ShaderStages},
71     OomError, RequirementNotMet, RequiresOneOf, VulkanError, VulkanObject,
72 };
73 use smallvec::SmallVec;
74 use std::{
75     error::Error,
76     fmt::{Display, Error as FmtError, Formatter},
77     mem::MaybeUninit,
78     num::NonZeroU64,
79     ptr,
80     sync::Arc,
81 };
82 
83 /// Describes the layout of descriptor sets and push constants that are made available to shaders.
84 #[derive(Debug)]
85 pub struct PipelineLayout {
86     handle: ash::vk::PipelineLayout,
87     device: Arc<Device>,
88     id: NonZeroU64,
89 
90     set_layouts: Vec<Arc<DescriptorSetLayout>>,
91     push_constant_ranges: Vec<PushConstantRange>,
92 
93     push_constant_ranges_disjoint: Vec<PushConstantRange>,
94 }
95 
96 impl PipelineLayout {
97     /// Creates a new `PipelineLayout`.
98     ///
99     /// # Panics
100     ///
101     /// - Panics if an element of `create_info.push_constant_ranges` has an empty `stages` value.
102     /// - Panics if an element of `create_info.push_constant_ranges` has an `offset` or `size`
103     ///   that's not divisible by 4.
104     /// - Panics if an element of `create_info.push_constant_ranges` has an `size` of zero.
new( device: Arc<Device>, mut create_info: PipelineLayoutCreateInfo, ) -> Result<Arc<PipelineLayout>, PipelineLayoutCreationError>105     pub fn new(
106         device: Arc<Device>,
107         mut create_info: PipelineLayoutCreateInfo,
108     ) -> Result<Arc<PipelineLayout>, PipelineLayoutCreationError> {
109         Self::validate(&device, &mut create_info)?;
110         let handle = unsafe { Self::create(&device, &create_info)? };
111 
112         let PipelineLayoutCreateInfo {
113             set_layouts,
114             mut push_constant_ranges,
115             _ne: _,
116         } = create_info;
117 
118         // Sort the ranges for the purpose of comparing for equality.
119         // The stage mask is guaranteed to be unique, so it's a suitable sorting key.
120         push_constant_ranges.sort_unstable_by_key(|range| {
121             (
122                 range.offset,
123                 range.size,
124                 ash::vk::ShaderStageFlags::from(range.stages),
125             )
126         });
127 
128         let push_constant_ranges_disjoint =
129             Self::create_push_constant_ranges_disjoint(&push_constant_ranges);
130 
131         Ok(Arc::new(PipelineLayout {
132             handle,
133             device,
134             id: Self::next_id(),
135             set_layouts,
136             push_constant_ranges,
137             push_constant_ranges_disjoint,
138         }))
139     }
140 
create_push_constant_ranges_disjoint( push_constant_ranges: &Vec<PushConstantRange>, ) -> Vec<PushConstantRange>141     fn create_push_constant_ranges_disjoint(
142         push_constant_ranges: &Vec<PushConstantRange>,
143     ) -> Vec<PushConstantRange> {
144         let mut push_constant_ranges_disjoint: Vec<PushConstantRange> =
145             Vec::with_capacity(push_constant_ranges.len());
146 
147         if !push_constant_ranges.is_empty() {
148             let mut min_offset = push_constant_ranges[0].offset;
149             loop {
150                 let mut max_offset = u32::MAX;
151                 let mut stages = ShaderStages::empty();
152 
153                 for range in push_constant_ranges.iter() {
154                     // new start (begin next time from it)
155                     if range.offset > min_offset {
156                         max_offset = max_offset.min(range.offset);
157                         break;
158                     } else if range.offset + range.size > min_offset {
159                         // inside the range, include the stage
160                         // use the minimum of the end of all ranges that are overlapping
161                         max_offset = max_offset.min(range.offset + range.size);
162                         stages |= range.stages;
163                     }
164                 }
165                 // finished all stages
166                 if stages.is_empty() {
167                     break;
168                 }
169 
170                 push_constant_ranges_disjoint.push(PushConstantRange {
171                     stages,
172                     offset: min_offset,
173                     size: max_offset - min_offset,
174                 });
175                 // prepare for next range
176                 min_offset = max_offset;
177             }
178         }
179         push_constant_ranges_disjoint
180     }
181 
validate( device: &Device, create_info: &mut PipelineLayoutCreateInfo, ) -> Result<(), PipelineLayoutCreationError>182     fn validate(
183         device: &Device,
184         create_info: &mut PipelineLayoutCreateInfo,
185     ) -> Result<(), PipelineLayoutCreationError> {
186         let &mut PipelineLayoutCreateInfo {
187             ref set_layouts,
188             ref push_constant_ranges,
189             _ne: _,
190         } = create_info;
191 
192         let properties = device.physical_device().properties();
193 
194         /* Check descriptor set layouts */
195 
196         // VUID-VkPipelineLayoutCreateInfo-setLayoutCount-00286
197         if set_layouts.len() > properties.max_bound_descriptor_sets as usize {
198             return Err(
199                 PipelineLayoutCreationError::MaxBoundDescriptorSetsExceeded {
200                     provided: set_layouts.len() as u32,
201                     max_supported: properties.max_bound_descriptor_sets,
202                 },
203             );
204         }
205 
206         {
207             let mut num_resources = Counter::default();
208             let mut num_samplers = Counter::default();
209             let mut num_uniform_buffers = Counter::default();
210             let mut num_uniform_buffers_dynamic = 0;
211             let mut num_storage_buffers = Counter::default();
212             let mut num_storage_buffers_dynamic = 0;
213             let mut num_sampled_images = Counter::default();
214             let mut num_storage_images = Counter::default();
215             let mut num_input_attachments = Counter::default();
216             let mut push_descriptor_set = None;
217 
218             for (set_num, set_layout) in set_layouts.iter().enumerate() {
219                 let set_num = set_num as u32;
220 
221                 if set_layout.push_descriptor() {
222                     // VUID-VkPipelineLayoutCreateInfo-pSetLayouts-00293
223                     if push_descriptor_set.is_some() {
224                         return Err(PipelineLayoutCreationError::SetLayoutsPushDescriptorMultiple);
225                     } else {
226                         push_descriptor_set = Some(set_num);
227                     }
228                 }
229 
230                 for layout_binding in set_layout.bindings().values() {
231                     num_resources.increment(layout_binding.descriptor_count, layout_binding.stages);
232 
233                     match layout_binding.descriptor_type {
234                         DescriptorType::Sampler => {
235                             num_samplers
236                                 .increment(layout_binding.descriptor_count, layout_binding.stages);
237                         }
238                         DescriptorType::CombinedImageSampler => {
239                             num_samplers
240                                 .increment(layout_binding.descriptor_count, layout_binding.stages);
241                             num_sampled_images
242                                 .increment(layout_binding.descriptor_count, layout_binding.stages);
243                         }
244                         DescriptorType::SampledImage | DescriptorType::UniformTexelBuffer => {
245                             num_sampled_images
246                                 .increment(layout_binding.descriptor_count, layout_binding.stages);
247                         }
248                         DescriptorType::StorageImage | DescriptorType::StorageTexelBuffer => {
249                             num_storage_images
250                                 .increment(layout_binding.descriptor_count, layout_binding.stages);
251                         }
252                         DescriptorType::UniformBuffer => {
253                             num_uniform_buffers
254                                 .increment(layout_binding.descriptor_count, layout_binding.stages);
255                         }
256                         DescriptorType::UniformBufferDynamic => {
257                             num_uniform_buffers
258                                 .increment(layout_binding.descriptor_count, layout_binding.stages);
259                             num_uniform_buffers_dynamic += 1;
260                         }
261                         DescriptorType::StorageBuffer => {
262                             num_storage_buffers
263                                 .increment(layout_binding.descriptor_count, layout_binding.stages);
264                         }
265                         DescriptorType::StorageBufferDynamic => {
266                             num_storage_buffers
267                                 .increment(layout_binding.descriptor_count, layout_binding.stages);
268                             num_storage_buffers_dynamic += 1;
269                         }
270                         DescriptorType::InputAttachment => {
271                             num_input_attachments
272                                 .increment(layout_binding.descriptor_count, layout_binding.stages);
273                         }
274                     }
275                 }
276             }
277 
278             if num_resources.max_per_stage() > properties.max_per_stage_resources {
279                 return Err(PipelineLayoutCreationError::MaxPerStageResourcesExceeded {
280                     provided: num_resources.max_per_stage(),
281                     max_supported: properties.max_per_stage_resources,
282                 });
283             }
284 
285             // VUID-VkPipelineLayoutCreateInfo-descriptorType-03016
286             if num_samplers.max_per_stage() > properties.max_per_stage_descriptor_samplers {
287                 return Err(
288                     PipelineLayoutCreationError::MaxPerStageDescriptorSamplersExceeded {
289                         provided: num_samplers.max_per_stage(),
290                         max_supported: properties.max_per_stage_descriptor_samplers,
291                     },
292                 );
293             }
294 
295             // VUID-VkPipelineLayoutCreateInfo-descriptorType-03017
296             if num_uniform_buffers.max_per_stage()
297                 > properties.max_per_stage_descriptor_uniform_buffers
298             {
299                 return Err(
300                     PipelineLayoutCreationError::MaxPerStageDescriptorUniformBuffersExceeded {
301                         provided: num_uniform_buffers.max_per_stage(),
302                         max_supported: properties.max_per_stage_descriptor_uniform_buffers,
303                     },
304                 );
305             }
306 
307             // VUID-VkPipelineLayoutCreateInfo-descriptorType-03018
308             if num_storage_buffers.max_per_stage()
309                 > properties.max_per_stage_descriptor_storage_buffers
310             {
311                 return Err(
312                     PipelineLayoutCreationError::MaxPerStageDescriptorStorageBuffersExceeded {
313                         provided: num_storage_buffers.max_per_stage(),
314                         max_supported: properties.max_per_stage_descriptor_storage_buffers,
315                     },
316                 );
317             }
318 
319             // VUID-VkPipelineLayoutCreateInfo-descriptorType-03019
320             if num_sampled_images.max_per_stage()
321                 > properties.max_per_stage_descriptor_sampled_images
322             {
323                 return Err(
324                     PipelineLayoutCreationError::MaxPerStageDescriptorSampledImagesExceeded {
325                         provided: num_sampled_images.max_per_stage(),
326                         max_supported: properties.max_per_stage_descriptor_sampled_images,
327                     },
328                 );
329             }
330 
331             // VUID-VkPipelineLayoutCreateInfo-descriptorType-03020
332             if num_storage_images.max_per_stage()
333                 > properties.max_per_stage_descriptor_storage_images
334             {
335                 return Err(
336                     PipelineLayoutCreationError::MaxPerStageDescriptorStorageImagesExceeded {
337                         provided: num_storage_images.max_per_stage(),
338                         max_supported: properties.max_per_stage_descriptor_storage_images,
339                     },
340                 );
341             }
342 
343             // VUID-VkPipelineLayoutCreateInfo-descriptorType-03021
344             if num_input_attachments.max_per_stage()
345                 > properties.max_per_stage_descriptor_input_attachments
346             {
347                 return Err(
348                     PipelineLayoutCreationError::MaxPerStageDescriptorInputAttachmentsExceeded {
349                         provided: num_input_attachments.max_per_stage(),
350                         max_supported: properties.max_per_stage_descriptor_input_attachments,
351                     },
352                 );
353             }
354 
355             // VUID-VkPipelineLayoutCreateInfo-descriptorType-03028
356             if num_samplers.total > properties.max_descriptor_set_samplers {
357                 return Err(
358                     PipelineLayoutCreationError::MaxDescriptorSetSamplersExceeded {
359                         provided: num_samplers.total,
360                         max_supported: properties.max_descriptor_set_samplers,
361                     },
362                 );
363             }
364 
365             // VUID-VkPipelineLayoutCreateInfo-descriptorType-03029
366             if num_uniform_buffers.total > properties.max_descriptor_set_uniform_buffers {
367                 return Err(
368                     PipelineLayoutCreationError::MaxDescriptorSetUniformBuffersExceeded {
369                         provided: num_uniform_buffers.total,
370                         max_supported: properties.max_descriptor_set_uniform_buffers,
371                     },
372                 );
373             }
374 
375             // VUID-VkPipelineLayoutCreateInfo-descriptorType-03030
376             if num_uniform_buffers_dynamic > properties.max_descriptor_set_uniform_buffers_dynamic {
377                 return Err(
378                     PipelineLayoutCreationError::MaxDescriptorSetUniformBuffersDynamicExceeded {
379                         provided: num_uniform_buffers_dynamic,
380                         max_supported: properties.max_descriptor_set_uniform_buffers_dynamic,
381                     },
382                 );
383             }
384 
385             // VUID-VkPipelineLayoutCreateInfo-descriptorType-03031
386             if num_storage_buffers.total > properties.max_descriptor_set_storage_buffers {
387                 return Err(
388                     PipelineLayoutCreationError::MaxDescriptorSetStorageBuffersExceeded {
389                         provided: num_storage_buffers.total,
390                         max_supported: properties.max_descriptor_set_storage_buffers,
391                     },
392                 );
393             }
394 
395             // VUID-VkPipelineLayoutCreateInfo-descriptorType-03032
396             if num_storage_buffers_dynamic > properties.max_descriptor_set_storage_buffers_dynamic {
397                 return Err(
398                     PipelineLayoutCreationError::MaxDescriptorSetStorageBuffersDynamicExceeded {
399                         provided: num_storage_buffers_dynamic,
400                         max_supported: properties.max_descriptor_set_storage_buffers_dynamic,
401                     },
402                 );
403             }
404 
405             // VUID-VkPipelineLayoutCreateInfo-descriptorType-03033
406             if num_sampled_images.total > properties.max_descriptor_set_sampled_images {
407                 return Err(
408                     PipelineLayoutCreationError::MaxDescriptorSetSampledImagesExceeded {
409                         provided: num_sampled_images.total,
410                         max_supported: properties.max_descriptor_set_sampled_images,
411                     },
412                 );
413             }
414 
415             // VUID-VkPipelineLayoutCreateInfo-descriptorType-03034
416             if num_storage_images.total > properties.max_descriptor_set_storage_images {
417                 return Err(
418                     PipelineLayoutCreationError::MaxDescriptorSetStorageImagesExceeded {
419                         provided: num_storage_images.total,
420                         max_supported: properties.max_descriptor_set_storage_images,
421                     },
422                 );
423             }
424 
425             // VUID-VkPipelineLayoutCreateInfo-descriptorType-03035
426             if num_input_attachments.total > properties.max_descriptor_set_input_attachments {
427                 return Err(
428                     PipelineLayoutCreationError::MaxDescriptorSetInputAttachmentsExceeded {
429                         provided: num_input_attachments.total,
430                         max_supported: properties.max_descriptor_set_input_attachments,
431                     },
432                 );
433             }
434         }
435 
436         /* Check push constant ranges */
437 
438         push_constant_ranges
439             .iter()
440             .try_fold(ShaderStages::empty(), |total, range| {
441                 let &PushConstantRange {
442                     stages,
443                     offset,
444                     size,
445                 } = range;
446 
447                 // VUID-VkPushConstantRange-stageFlags-parameter
448                 stages.validate_device(device)?;
449 
450                 // VUID-VkPushConstantRange-stageFlags-requiredbitmask
451                 assert!(!stages.is_empty());
452 
453                 // VUID-VkPushConstantRange-offset-00295
454                 assert!(offset % 4 == 0);
455 
456                 // VUID-VkPushConstantRange-size-00296
457                 assert!(size != 0);
458 
459                 // VUID-VkPushConstantRange-size-00297
460                 assert!(size % 4 == 0);
461 
462                 // VUID-VkPushConstantRange-offset-00294
463                 // VUID-VkPushConstantRange-size-00298
464                 if offset + size > properties.max_push_constants_size {
465                     return Err(PipelineLayoutCreationError::MaxPushConstantsSizeExceeded {
466                         provided: offset + size,
467                         max_supported: properties.max_push_constants_size,
468                     });
469                 }
470 
471                 // VUID-VkPipelineLayoutCreateInfo-pPushConstantRanges-00292
472                 if !(total & stages).is_empty() {
473                     return Err(PipelineLayoutCreationError::PushConstantRangesStageMultiple);
474                 }
475 
476                 Ok(total | stages)
477             })?;
478 
479         Ok(())
480     }
481 
create( device: &Device, create_info: &PipelineLayoutCreateInfo, ) -> Result<ash::vk::PipelineLayout, PipelineLayoutCreationError>482     unsafe fn create(
483         device: &Device,
484         create_info: &PipelineLayoutCreateInfo,
485     ) -> Result<ash::vk::PipelineLayout, PipelineLayoutCreationError> {
486         let PipelineLayoutCreateInfo {
487             set_layouts,
488             push_constant_ranges,
489             _ne: _,
490         } = create_info;
491 
492         let set_layouts: SmallVec<[_; 4]> = set_layouts.iter().map(|l| l.handle()).collect();
493 
494         let push_constant_ranges: SmallVec<[_; 4]> = push_constant_ranges
495             .iter()
496             .map(|range| ash::vk::PushConstantRange {
497                 stage_flags: range.stages.into(),
498                 offset: range.offset,
499                 size: range.size,
500             })
501             .collect();
502 
503         let create_info = ash::vk::PipelineLayoutCreateInfo {
504             flags: ash::vk::PipelineLayoutCreateFlags::empty(),
505             set_layout_count: set_layouts.len() as u32,
506             p_set_layouts: set_layouts.as_ptr(),
507             push_constant_range_count: push_constant_ranges.len() as u32,
508             p_push_constant_ranges: push_constant_ranges.as_ptr(),
509             ..Default::default()
510         };
511 
512         let handle = {
513             let fns = device.fns();
514             let mut output = MaybeUninit::uninit();
515             (fns.v1_0.create_pipeline_layout)(
516                 device.handle(),
517                 &create_info,
518                 ptr::null(),
519                 output.as_mut_ptr(),
520             )
521             .result()
522             .map_err(VulkanError::from)?;
523             output.assume_init()
524         };
525 
526         Ok(handle)
527     }
528 
529     /// Creates a new `PipelineLayout` from a raw object handle.
530     ///
531     /// # Safety
532     ///
533     /// - `handle` must be a valid Vulkan object handle created from `device`.
534     /// - `create_info` must match the info used to create the object.
535     #[inline]
from_handle( device: Arc<Device>, handle: ash::vk::PipelineLayout, create_info: PipelineLayoutCreateInfo, ) -> Arc<PipelineLayout>536     pub unsafe fn from_handle(
537         device: Arc<Device>,
538         handle: ash::vk::PipelineLayout,
539         create_info: PipelineLayoutCreateInfo,
540     ) -> Arc<PipelineLayout> {
541         let PipelineLayoutCreateInfo {
542             set_layouts,
543             push_constant_ranges,
544             _ne: _,
545         } = create_info;
546 
547         let push_constant_ranges_disjoint =
548             Self::create_push_constant_ranges_disjoint(&push_constant_ranges);
549 
550         Arc::new(PipelineLayout {
551             handle,
552             device,
553             id: Self::next_id(),
554             set_layouts,
555             push_constant_ranges,
556             push_constant_ranges_disjoint,
557         })
558     }
559 
560     /// Returns the descriptor set layouts this pipeline layout was created from.
561     #[inline]
set_layouts(&self) -> &[Arc<DescriptorSetLayout>]562     pub fn set_layouts(&self) -> &[Arc<DescriptorSetLayout>] {
563         &self.set_layouts
564     }
565 
566     /// Returns a slice containing the push constant ranges this pipeline layout was created from.
567     ///
568     /// The ranges are guaranteed to be sorted deterministically by offset, size, then stages.
569     /// This means that two slices containing the same elements will always have the same order.
570     #[inline]
push_constant_ranges(&self) -> &[PushConstantRange]571     pub fn push_constant_ranges(&self) -> &[PushConstantRange] {
572         &self.push_constant_ranges
573     }
574 
575     /// Returns a slice containing the push constant ranges in with all disjoint stages.
576     ///
577     /// For example, if we have these `push_constant_ranges`:
578     /// - `offset=0, size=4, stages=vertex`
579     /// - `offset=0, size=12, stages=fragment`
580     ///
581     /// The returned value will be:
582     /// - `offset=0, size=4, stages=vertex|fragment`
583     /// - `offset=4, size=8, stages=fragment`
584     ///
585     /// The ranges are guaranteed to be sorted deterministically by offset, and
586     /// guaranteed to be disjoint, meaning that there is no overlap between the ranges.
587     #[inline]
push_constant_ranges_disjoint(&self) -> &[PushConstantRange]588     pub(crate) fn push_constant_ranges_disjoint(&self) -> &[PushConstantRange] {
589         &self.push_constant_ranges_disjoint
590     }
591 
592     /// Returns whether `self` is compatible with `other` for the given number of sets.
593     #[inline]
is_compatible_with(&self, other: &PipelineLayout, num_sets: u32) -> bool594     pub fn is_compatible_with(&self, other: &PipelineLayout, num_sets: u32) -> bool {
595         let num_sets = num_sets as usize;
596         assert!(num_sets >= self.set_layouts.len());
597 
598         if self == other {
599             return true;
600         }
601 
602         if self.push_constant_ranges != other.push_constant_ranges {
603             return false;
604         }
605 
606         let other_sets = match other.set_layouts.get(0..num_sets) {
607             Some(x) => x,
608             None => return false,
609         };
610 
611         self.set_layouts
612             .iter()
613             .zip(other_sets)
614             .all(|(self_set_layout, other_set_layout)| {
615                 self_set_layout.is_compatible_with(other_set_layout)
616             })
617     }
618 
619     /// Makes sure that `self` is a superset of the provided descriptor set layouts and push
620     /// constant ranges. Returns an `Err` if this is not the case.
ensure_compatible_with_shader<'a>( &self, descriptor_requirements: impl IntoIterator< Item = ((u32, u32), &'a DescriptorBindingRequirements), >, push_constant_range: Option<&PushConstantRange>, ) -> Result<(), PipelineLayoutSupersetError>621     pub fn ensure_compatible_with_shader<'a>(
622         &self,
623         descriptor_requirements: impl IntoIterator<
624             Item = ((u32, u32), &'a DescriptorBindingRequirements),
625         >,
626         push_constant_range: Option<&PushConstantRange>,
627     ) -> Result<(), PipelineLayoutSupersetError> {
628         for ((set_num, binding_num), reqs) in descriptor_requirements.into_iter() {
629             let layout_binding = self
630                 .set_layouts
631                 .get(set_num as usize)
632                 .and_then(|set_layout| set_layout.bindings().get(&binding_num));
633 
634             let layout_binding = match layout_binding {
635                 Some(x) => x,
636                 None => {
637                     return Err(PipelineLayoutSupersetError::DescriptorMissing {
638                         set_num,
639                         binding_num,
640                     })
641                 }
642             };
643 
644             if let Err(error) = layout_binding.ensure_compatible_with_shader(reqs) {
645                 return Err(PipelineLayoutSupersetError::DescriptorRequirementsNotMet {
646                     set_num,
647                     binding_num,
648                     error,
649                 });
650             }
651         }
652 
653         // FIXME: check push constants
654         if let Some(range) = push_constant_range {
655             for own_range in self.push_constant_ranges.iter() {
656                 if range.stages.intersects(own_range.stages) &&       // check if it shares any stages
657                     (range.offset < own_range.offset || // our range must start before and end after the given range
658                         own_range.offset + own_range.size < range.offset + range.size)
659                 {
660                     return Err(PipelineLayoutSupersetError::PushConstantRange {
661                         first_range: *own_range,
662                         second_range: *range,
663                     });
664                 }
665             }
666         }
667 
668         Ok(())
669     }
670 }
671 
672 impl Drop for PipelineLayout {
673     #[inline]
drop(&mut self)674     fn drop(&mut self) {
675         unsafe {
676             let fns = self.device.fns();
677             (fns.v1_0.destroy_pipeline_layout)(self.device.handle(), self.handle, ptr::null());
678         }
679     }
680 }
681 
682 unsafe impl VulkanObject for PipelineLayout {
683     type Handle = ash::vk::PipelineLayout;
684 
685     #[inline]
handle(&self) -> Self::Handle686     fn handle(&self) -> Self::Handle {
687         self.handle
688     }
689 }
690 
691 unsafe impl DeviceOwned for PipelineLayout {
692     #[inline]
device(&self) -> &Arc<Device>693     fn device(&self) -> &Arc<Device> {
694         &self.device
695     }
696 }
697 
698 impl_id_counter!(PipelineLayout);
699 
700 /// Error that can happen when creating a pipeline layout.
701 #[derive(Clone, Debug, PartialEq, Eq)]
702 pub enum PipelineLayoutCreationError {
703     /// Not enough memory.
704     OomError(OomError),
705 
706     RequirementNotMet {
707         required_for: &'static str,
708         requires_one_of: RequiresOneOf,
709     },
710 
711     /// The number of elements in `set_layouts` is greater than the
712     /// [`max_bound_descriptor_sets`](crate::device::Properties::max_bound_descriptor_sets) limit.
713     MaxBoundDescriptorSetsExceeded { provided: u32, max_supported: u32 },
714 
715     /// The `set_layouts` contain more [`DescriptorType::Sampler`],
716     /// [`DescriptorType::CombinedImageSampler`] and [`DescriptorType::UniformTexelBuffer`]
717     /// descriptors than the
718     /// [`max_descriptor_set_samplers`](crate::device::Properties::max_descriptor_set_samplers)
719     /// limit.
720     MaxDescriptorSetSamplersExceeded { provided: u32, max_supported: u32 },
721 
722     /// The `set_layouts` contain more [`DescriptorType::UniformBuffer`] descriptors than the
723     /// [`max_descriptor_set_uniform_buffers`](crate::device::Properties::max_descriptor_set_uniform_buffers)
724     /// limit.
725     MaxDescriptorSetUniformBuffersExceeded { provided: u32, max_supported: u32 },
726 
727     /// The `set_layouts` contain more [`DescriptorType::UniformBufferDynamic`] descriptors than the
728     /// [`max_descriptor_set_uniform_buffers_dynamic`](crate::device::Properties::max_descriptor_set_uniform_buffers_dynamic)
729     /// limit.
730     MaxDescriptorSetUniformBuffersDynamicExceeded { provided: u32, max_supported: u32 },
731 
732     /// The `set_layouts` contain more [`DescriptorType::StorageBuffer`] descriptors than the
733     /// [`max_descriptor_set_storage_buffers`](crate::device::Properties::max_descriptor_set_storage_buffers)
734     /// limit.
735     MaxDescriptorSetStorageBuffersExceeded { provided: u32, max_supported: u32 },
736 
737     /// The `set_layouts` contain more [`DescriptorType::StorageBufferDynamic`] descriptors than the
738     /// [`max_descriptor_set_storage_buffers_dynamic`](crate::device::Properties::max_descriptor_set_storage_buffers_dynamic)
739     /// limit.
740     MaxDescriptorSetStorageBuffersDynamicExceeded { provided: u32, max_supported: u32 },
741 
742     /// The `set_layouts` contain more [`DescriptorType::SampledImage`] and
743     /// [`DescriptorType::CombinedImageSampler`] descriptors than the
744     /// [`max_descriptor_set_sampled_images`](crate::device::Properties::max_descriptor_set_sampled_images)
745     /// limit.
746     MaxDescriptorSetSampledImagesExceeded { provided: u32, max_supported: u32 },
747 
748     /// The `set_layouts` contain more [`DescriptorType::StorageImage`] and
749     /// [`DescriptorType::StorageTexelBuffer`] descriptors than the
750     /// [`max_descriptor_set_storage_images`](crate::device::Properties::max_descriptor_set_storage_images)
751     /// limit.
752     MaxDescriptorSetStorageImagesExceeded { provided: u32, max_supported: u32 },
753 
754     /// The `set_layouts` contain more [`DescriptorType::InputAttachment`] descriptors than the
755     /// [`max_descriptor_set_input_attachments`](crate::device::Properties::max_descriptor_set_input_attachments)
756     /// limit.
757     MaxDescriptorSetInputAttachmentsExceeded { provided: u32, max_supported: u32 },
758 
759     /// The `set_layouts` contain more bound resources in a single stage than the
760     /// [`max_per_stage_resources`](crate::device::Properties::max_per_stage_resources)
761     /// limit.
762     MaxPerStageResourcesExceeded { provided: u32, max_supported: u32 },
763 
764     /// The `set_layouts` contain more [`DescriptorType::Sampler`] and
765     /// [`DescriptorType::CombinedImageSampler`] descriptors in a single stage than the
766     /// [`max_per_stage_descriptor_samplers`](crate::device::Properties::max_per_stage_descriptor_samplers)
767     /// limit.
768     MaxPerStageDescriptorSamplersExceeded { provided: u32, max_supported: u32 },
769 
770     /// The `set_layouts` contain more [`DescriptorType::UniformBuffer`] and
771     /// [`DescriptorType::UniformBufferDynamic`] descriptors in a single stage than the
772     /// [`max_per_stage_descriptor_uniform_buffers`](crate::device::Properties::max_per_stage_descriptor_uniform_buffers)
773     /// limit.
774     MaxPerStageDescriptorUniformBuffersExceeded { provided: u32, max_supported: u32 },
775 
776     /// The `set_layouts` contain more [`DescriptorType::StorageBuffer`] and
777     /// [`DescriptorType::StorageBufferDynamic`] descriptors in a single stage than the
778     /// [`max_per_stage_descriptor_storage_buffers`](crate::device::Properties::max_per_stage_descriptor_storage_buffers)
779     /// limit.
780     MaxPerStageDescriptorStorageBuffersExceeded { provided: u32, max_supported: u32 },
781 
782     /// The `set_layouts` contain more [`DescriptorType::SampledImage`],
783     /// [`DescriptorType::CombinedImageSampler`] and [`DescriptorType::UniformTexelBuffer`]
784     /// descriptors in a single stage than the
785     /// [`max_per_stage_descriptor_sampled_images`](crate::device::Properties::max_per_stage_descriptor_sampled_images)
786     /// limit.
787     MaxPerStageDescriptorSampledImagesExceeded { provided: u32, max_supported: u32 },
788 
789     /// The `set_layouts` contain more [`DescriptorType::StorageImage`] and
790     /// [`DescriptorType::StorageTexelBuffer`] descriptors in a single stage than the
791     /// [`max_per_stage_descriptor_storage_images`](crate::device::Properties::max_per_stage_descriptor_storage_images)
792     /// limit.
793     MaxPerStageDescriptorStorageImagesExceeded { provided: u32, max_supported: u32 },
794 
795     /// The `set_layouts` contain more [`DescriptorType::InputAttachment`] descriptors in a single
796     /// stage than the
797     /// [`max_per_stage_descriptor_input_attachments`](crate::device::Properties::max_per_stage_descriptor_input_attachments)
798     /// limit.
799     MaxPerStageDescriptorInputAttachmentsExceeded { provided: u32, max_supported: u32 },
800 
801     /// An element in `push_constant_ranges` has an `offset + size` greater than the
802     /// [`max_push_constants_size`](crate::device::Properties::max_push_constants_size) limit.
803     MaxPushConstantsSizeExceeded { provided: u32, max_supported: u32 },
804 
805     /// A shader stage appears in multiple elements of `push_constant_ranges`.
806     PushConstantRangesStageMultiple,
807 
808     /// Multiple elements of `set_layouts` have `push_descriptor` enabled.
809     SetLayoutsPushDescriptorMultiple,
810 }
811 
812 impl Error for PipelineLayoutCreationError {
source(&self) -> Option<&(dyn Error + 'static)>813     fn source(&self) -> Option<&(dyn Error + 'static)> {
814         match self {
815             Self::OomError(err) => Some(err),
816             _ => None,
817         }
818     }
819 }
820 
821 impl Display for PipelineLayoutCreationError {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>822     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
823         match self {
824             Self::OomError(_) => write!(f, "not enough memory available"),
825             Self::RequirementNotMet {
826                 required_for,
827                 requires_one_of,
828             } => write!(
829                 f,
830                 "a requirement was not met for: {}; requires one of: {}",
831                 required_for, requires_one_of,
832             ),
833             Self::MaxBoundDescriptorSetsExceeded {
834                 provided,
835                 max_supported,
836             } => write!(
837                 f,
838                 "the number of elements in `set_layouts` ({}) is greater than the \
839                 `max_bound_descriptor_sets` limit ({})",
840                 provided, max_supported,
841             ),
842             Self::MaxDescriptorSetSamplersExceeded {
843                 provided,
844                 max_supported,
845             } => write!(
846                 f,
847                 "the `set_layouts` contain more `DescriptorType::Sampler` and \
848                 `DescriptorType::CombinedImageSampler` descriptors ({}) than the \
849                 `max_descriptor_set_samplers` limit ({})",
850                 provided, max_supported,
851             ),
852             Self::MaxDescriptorSetUniformBuffersExceeded {
853                 provided,
854                 max_supported,
855             } => write!(
856                 f,
857                 "the `set_layouts` contain more `DescriptorType::UniformBuffer` descriptors ({}) \
858                 than the `max_descriptor_set_uniform_buffers` limit ({})",
859                 provided, max_supported,
860             ),
861             Self::MaxDescriptorSetUniformBuffersDynamicExceeded {
862                 provided,
863                 max_supported,
864             } => write!(
865                 f,
866                 "the `set_layouts` contain more `DescriptorType::UniformBufferDynamic` descriptors \
867                 ({}) than the `max_descriptor_set_uniform_buffers_dynamic` limit ({})",
868                 provided, max_supported,
869             ),
870             Self::MaxDescriptorSetStorageBuffersExceeded {
871                 provided,
872                 max_supported,
873             } => write!(
874                 f,
875                 "the `set_layouts` contain more `DescriptorType::StorageBuffer` descriptors ({}) \
876                 than the `max_descriptor_set_storage_buffers` limit ({})",
877                 provided, max_supported,
878             ),
879             Self::MaxDescriptorSetStorageBuffersDynamicExceeded {
880                 provided,
881                 max_supported,
882             } => write!(
883                 f,
884                 "the `set_layouts` contain more `DescriptorType::StorageBufferDynamic` descriptors \
885                 ({}) than the `max_descriptor_set_storage_buffers_dynamic` limit ({})",
886                 provided, max_supported,
887             ),
888             Self::MaxDescriptorSetSampledImagesExceeded {
889                 provided,
890                 max_supported,
891             } => write!(
892                 f,
893                 "the `set_layouts` contain more `DescriptorType::SampledImage`, \
894                 `DescriptorType::CombinedImageSampler` and `DescriptorType::UniformTexelBuffer` \
895                 descriptors ({}) than the `max_descriptor_set_sampled_images` limit ({})",
896                 provided, max_supported,
897             ),
898             Self::MaxDescriptorSetStorageImagesExceeded {
899                 provided,
900                 max_supported,
901             } => write!(
902                 f,
903                 "the `set_layouts` contain more `DescriptorType::StorageImage` and \
904                 `DescriptorType::StorageTexelBuffer` descriptors ({}) than the \
905                 `max_descriptor_set_storage_images` limit ({})",
906                 provided, max_supported,
907             ),
908             Self::MaxDescriptorSetInputAttachmentsExceeded {
909                 provided,
910                 max_supported,
911             } => write!(
912                 f,
913                 "the `set_layouts` contain more `DescriptorType::InputAttachment` descriptors ({}) \
914                 than the `max_descriptor_set_input_attachments` limit ({})",
915                 provided, max_supported,
916             ),
917             Self::MaxPerStageResourcesExceeded {
918                 provided,
919                 max_supported,
920             } => write!(
921                 f,
922                 "the `set_layouts` contain more bound resources ({}) in a single stage than the \
923                 `max_per_stage_resources` limit ({})",
924                 provided, max_supported,
925             ),
926             Self::MaxPerStageDescriptorSamplersExceeded {
927                 provided,
928                 max_supported,
929             } => write!(
930                 f,
931                 "the `set_layouts` contain more `DescriptorType::Sampler` and \
932                 `DescriptorType::CombinedImageSampler` descriptors ({}) in a single stage than the \
933                 `max_per_stage_descriptor_set_samplers` limit ({})",
934                 provided, max_supported,
935             ),
936             Self::MaxPerStageDescriptorUniformBuffersExceeded {
937                 provided,
938                 max_supported,
939             } => write!(
940                 f,
941                 "the `set_layouts` contain more `DescriptorType::UniformBuffer` and \
942                 `DescriptorType::UniformBufferDynamic` descriptors ({}) in a single stage than the \
943                 `max_per_stage_descriptor_set_uniform_buffers` limit ({})",
944                 provided, max_supported,
945             ),
946             Self::MaxPerStageDescriptorStorageBuffersExceeded {
947                 provided,
948                 max_supported,
949             } => write!(
950                 f,
951                 "the `set_layouts` contain more `DescriptorType::StorageBuffer` and \
952                 `DescriptorType::StorageBufferDynamic` descriptors ({}) in a single stage than the \
953                 `max_per_stage_descriptor_set_storage_buffers` limit ({})",
954                 provided, max_supported,
955             ),
956             Self::MaxPerStageDescriptorSampledImagesExceeded {
957                 provided,
958                 max_supported,
959             } => write!(
960                 f,
961                 "the `set_layouts` contain more `DescriptorType::SampledImage`, \
962                 `DescriptorType::CombinedImageSampler` and `DescriptorType::UniformTexelBuffer` \
963                 descriptors ({}) in a single stage than the \
964                 `max_per_stage_descriptor_set_sampled_images` limit ({})",
965                 provided, max_supported,
966             ),
967             Self::MaxPerStageDescriptorStorageImagesExceeded {
968                 provided,
969                 max_supported,
970             } => write!(
971                 f,
972                 "the `set_layouts` contain more `DescriptorType::StorageImage` and \
973                 `DescriptorType::StorageTexelBuffer` descriptors ({}) in a single stage than the \
974                 `max_per_stage_descriptor_set_storage_images` limit ({})",
975                 provided, max_supported,
976             ),
977             Self::MaxPerStageDescriptorInputAttachmentsExceeded {
978                 provided,
979                 max_supported,
980             } => write!(
981                 f,
982                 "the `set_layouts` contain more `DescriptorType::InputAttachment` descriptors ({}) \
983                 in a single stage than the `max_per_stage_descriptor_set_input_attachments` limit \
984                 ({})",
985                 provided, max_supported,
986             ),
987             Self::MaxPushConstantsSizeExceeded {
988                 provided,
989                 max_supported,
990             } => write!(
991                 f,
992                 "an element in `push_constant_ranges` has an `offset + size` ({}) greater than the \
993                 `max_push_constants_size` limit ({})",
994                 provided, max_supported,
995             ),
996             Self::PushConstantRangesStageMultiple => write!(
997                 f,
998                 "a shader stage appears in multiple elements of `push_constant_ranges`",
999             ),
1000             Self::SetLayoutsPushDescriptorMultiple => write!(
1001                 f,
1002                 "multiple elements of `set_layouts` have `push_descriptor` enabled",
1003             ),
1004         }
1005     }
1006 }
1007 
1008 impl From<OomError> for PipelineLayoutCreationError {
from(err: OomError) -> PipelineLayoutCreationError1009     fn from(err: OomError) -> PipelineLayoutCreationError {
1010         PipelineLayoutCreationError::OomError(err)
1011     }
1012 }
1013 
1014 impl From<VulkanError> for PipelineLayoutCreationError {
from(err: VulkanError) -> PipelineLayoutCreationError1015     fn from(err: VulkanError) -> PipelineLayoutCreationError {
1016         match err {
1017             err @ VulkanError::OutOfHostMemory => {
1018                 PipelineLayoutCreationError::OomError(OomError::from(err))
1019             }
1020             err @ VulkanError::OutOfDeviceMemory => {
1021                 PipelineLayoutCreationError::OomError(OomError::from(err))
1022             }
1023             _ => panic!("unexpected error: {:?}", err),
1024         }
1025     }
1026 }
1027 
1028 impl From<RequirementNotMet> for PipelineLayoutCreationError {
from(err: RequirementNotMet) -> Self1029     fn from(err: RequirementNotMet) -> Self {
1030         Self::RequirementNotMet {
1031             required_for: err.required_for,
1032             requires_one_of: err.requires_one_of,
1033         }
1034     }
1035 }
1036 
1037 /// Error when checking whether a pipeline layout is a superset of another one.
1038 #[derive(Clone, Debug, PartialEq, Eq)]
1039 pub enum PipelineLayoutSupersetError {
1040     DescriptorMissing {
1041         set_num: u32,
1042         binding_num: u32,
1043     },
1044     DescriptorRequirementsNotMet {
1045         set_num: u32,
1046         binding_num: u32,
1047         error: DescriptorRequirementsNotMet,
1048     },
1049     PushConstantRange {
1050         first_range: PushConstantRange,
1051         second_range: PushConstantRange,
1052     },
1053 }
1054 
1055 impl Error for PipelineLayoutSupersetError {
source(&self) -> Option<&(dyn Error + 'static)>1056     fn source(&self) -> Option<&(dyn Error + 'static)> {
1057         match self {
1058             PipelineLayoutSupersetError::DescriptorRequirementsNotMet { error, .. } => Some(error),
1059             _ => None,
1060         }
1061     }
1062 }
1063 
1064 impl Display for PipelineLayoutSupersetError {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>1065     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
1066         match self {
1067             PipelineLayoutSupersetError::DescriptorRequirementsNotMet {
1068                 set_num,
1069                 binding_num,
1070                 ..
1071             } => write!(
1072                 f,
1073                 "the descriptor at set {} binding {} does not meet the requirements",
1074                 set_num, binding_num,
1075             ),
1076             PipelineLayoutSupersetError::DescriptorMissing {
1077                 set_num,
1078                 binding_num,
1079             } => write!(
1080                 f,
1081                 "a descriptor at set {} binding {} is required by the shaders, but is missing from \
1082                 the pipeline layout",
1083                 set_num, binding_num,
1084             ),
1085             PipelineLayoutSupersetError::PushConstantRange {
1086                 first_range,
1087                 second_range,
1088             } => {
1089                 writeln!(f, "our range did not completely encompass the other range")?;
1090                 writeln!(f, "    our stages: {:?}", first_range.stages)?;
1091                 writeln!(
1092                     f,
1093                     "    our range: {} - {}",
1094                     first_range.offset,
1095                     first_range.offset + first_range.size,
1096                 )?;
1097                 writeln!(f, "    other stages: {:?}", second_range.stages)?;
1098                 write!(
1099                     f,
1100                     "    other range: {} - {}",
1101                     second_range.offset,
1102                     second_range.offset + second_range.size,
1103                 )
1104             }
1105         }
1106     }
1107 }
1108 
1109 /// Parameters to create a new `PipelineLayout`.
1110 #[derive(Clone, Debug)]
1111 pub struct PipelineLayoutCreateInfo {
1112     /// The descriptor set layouts that should be part of the pipeline layout.
1113     ///
1114     /// They are provided in order of set number.
1115     ///
1116     /// The default value is empty.
1117     pub set_layouts: Vec<Arc<DescriptorSetLayout>>,
1118 
1119     /// The ranges of push constants that the pipeline will access.
1120     ///
1121     /// A shader stage can only appear in one element of the list, but it is possible to combine
1122     /// ranges for multiple shader stages if they are the same.
1123     ///
1124     /// The default value is empty.
1125     pub push_constant_ranges: Vec<PushConstantRange>,
1126 
1127     pub _ne: crate::NonExhaustive,
1128 }
1129 
1130 impl Default for PipelineLayoutCreateInfo {
1131     #[inline]
default() -> Self1132     fn default() -> Self {
1133         Self {
1134             set_layouts: Vec::new(),
1135             push_constant_ranges: Vec::new(),
1136             _ne: crate::NonExhaustive(()),
1137         }
1138     }
1139 }
1140 
1141 /// Description of a range of the push constants of a pipeline layout.
1142 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
1143 pub struct PushConstantRange {
1144     /// The stages which can access this range. A stage can access at most one push constant range.
1145     ///
1146     /// The default value is [`ShaderStages::empty()`], which must be overridden.
1147     pub stages: ShaderStages,
1148 
1149     /// Offset in bytes from the start of the push constants to this range.
1150     ///
1151     /// The value must be a multiple of 4.
1152     ///
1153     /// The default value is `0`.
1154     pub offset: u32,
1155 
1156     /// Size in bytes of the range.
1157     ///
1158     /// The value must be a multiple of 4, and not 0.
1159     ///
1160     /// The default value is `0`, which must be overridden.
1161     pub size: u32,
1162 }
1163 
1164 impl Default for PushConstantRange {
1165     #[inline]
default() -> Self1166     fn default() -> Self {
1167         Self {
1168             stages: ShaderStages::empty(),
1169             offset: 0,
1170             size: 0,
1171         }
1172     }
1173 }
1174 
1175 // Helper struct for the main function.
1176 #[derive(Default)]
1177 struct Counter {
1178     total: u32,
1179     compute: u32,
1180     vertex: u32,
1181     geometry: u32,
1182     tess_ctl: u32,
1183     tess_eval: u32,
1184     frag: u32,
1185 }
1186 
1187 impl Counter {
increment(&mut self, num: u32, stages: ShaderStages)1188     fn increment(&mut self, num: u32, stages: ShaderStages) {
1189         self.total += num;
1190         if stages.intersects(ShaderStages::COMPUTE) {
1191             self.compute += num;
1192         }
1193         if stages.intersects(ShaderStages::VERTEX) {
1194             self.vertex += num;
1195         }
1196         if stages.intersects(ShaderStages::TESSELLATION_CONTROL) {
1197             self.tess_ctl += num;
1198         }
1199         if stages.intersects(ShaderStages::TESSELLATION_EVALUATION) {
1200             self.tess_eval += num;
1201         }
1202         if stages.intersects(ShaderStages::GEOMETRY) {
1203             self.geometry += num;
1204         }
1205         if stages.intersects(ShaderStages::FRAGMENT) {
1206             self.frag += num;
1207         }
1208     }
1209 
max_per_stage(&self) -> u321210     fn max_per_stage(&self) -> u32 {
1211         [
1212             self.compute,
1213             self.vertex,
1214             self.tess_ctl,
1215             self.tess_eval,
1216             self.geometry,
1217             self.frag,
1218         ]
1219         .into_iter()
1220         .max()
1221         .unwrap_or(0)
1222     }
1223 }
1224 
1225 #[cfg(test)]
1226 mod tests {
1227 
1228     use super::PipelineLayout;
1229     use crate::{
1230         pipeline::layout::{PipelineLayoutCreateInfo, PushConstantRange},
1231         shader::ShaderStages,
1232     };
1233 
1234     #[test]
push_constant_ranges_disjoint()1235     fn push_constant_ranges_disjoint() {
1236         let test_cases = [
1237             // input:
1238             // - `0..12`, stage=fragment
1239             // - `0..40`, stage=vertex
1240             //
1241             // output:
1242             // - `0..12`, stage=fragment|vertex
1243             // - `12..40`, stage=vertex
1244             (
1245                 &[
1246                     PushConstantRange {
1247                         stages: ShaderStages::FRAGMENT,
1248                         offset: 0,
1249                         size: 12,
1250                     },
1251                     PushConstantRange {
1252                         stages: ShaderStages::VERTEX,
1253                         offset: 0,
1254                         size: 40,
1255                     },
1256                 ][..],
1257                 &[
1258                     PushConstantRange {
1259                         stages: ShaderStages::VERTEX | ShaderStages::FRAGMENT,
1260                         offset: 0,
1261                         size: 12,
1262                     },
1263                     PushConstantRange {
1264                         stages: ShaderStages::VERTEX,
1265                         offset: 12,
1266                         size: 28,
1267                     },
1268                 ][..],
1269             ),
1270             // input:
1271             // - `0..12`, stage=fragment
1272             // - `4..40`, stage=vertex
1273             //
1274             // output:
1275             // - `0..4`, stage=fragment
1276             // - `4..12`, stage=fragment|vertex
1277             // - `12..40`, stage=vertex
1278             (
1279                 &[
1280                     PushConstantRange {
1281                         stages: ShaderStages::FRAGMENT,
1282                         offset: 0,
1283                         size: 12,
1284                     },
1285                     PushConstantRange {
1286                         stages: ShaderStages::VERTEX,
1287                         offset: 4,
1288                         size: 36,
1289                     },
1290                 ][..],
1291                 &[
1292                     PushConstantRange {
1293                         stages: ShaderStages::FRAGMENT,
1294                         offset: 0,
1295                         size: 4,
1296                     },
1297                     PushConstantRange {
1298                         stages: ShaderStages::FRAGMENT | ShaderStages::VERTEX,
1299                         offset: 4,
1300                         size: 8,
1301                     },
1302                     PushConstantRange {
1303                         stages: ShaderStages::VERTEX,
1304                         offset: 12,
1305                         size: 28,
1306                     },
1307                 ][..],
1308             ),
1309             // input:
1310             // - `0..12`, stage=fragment
1311             // - `8..20`, stage=compute
1312             // - `4..16`, stage=vertex
1313             // - `8..32`, stage=tess_ctl
1314             //
1315             // output:
1316             // - `0..4`, stage=fragment
1317             // - `4..8`, stage=fragment|vertex
1318             // - `8..16`, stage=fragment|vertex|compute|tess_ctl
1319             // - `16..20`, stage=compute|tess_ctl
1320             // - `20..32` stage=tess_ctl
1321             (
1322                 &[
1323                     PushConstantRange {
1324                         stages: ShaderStages::FRAGMENT,
1325                         offset: 0,
1326                         size: 12,
1327                     },
1328                     PushConstantRange {
1329                         stages: ShaderStages::COMPUTE,
1330                         offset: 8,
1331                         size: 12,
1332                     },
1333                     PushConstantRange {
1334                         stages: ShaderStages::VERTEX,
1335                         offset: 4,
1336                         size: 12,
1337                     },
1338                     PushConstantRange {
1339                         stages: ShaderStages::TESSELLATION_CONTROL,
1340                         offset: 8,
1341                         size: 24,
1342                     },
1343                 ][..],
1344                 &[
1345                     PushConstantRange {
1346                         stages: ShaderStages::FRAGMENT,
1347                         offset: 0,
1348                         size: 4,
1349                     },
1350                     PushConstantRange {
1351                         stages: ShaderStages::FRAGMENT | ShaderStages::VERTEX,
1352                         offset: 4,
1353                         size: 4,
1354                     },
1355                     PushConstantRange {
1356                         stages: ShaderStages::VERTEX
1357                             | ShaderStages::FRAGMENT
1358                             | ShaderStages::COMPUTE
1359                             | ShaderStages::TESSELLATION_CONTROL,
1360                         offset: 8,
1361                         size: 4,
1362                     },
1363                     PushConstantRange {
1364                         stages: ShaderStages::VERTEX
1365                             | ShaderStages::COMPUTE
1366                             | ShaderStages::TESSELLATION_CONTROL,
1367                         offset: 12,
1368                         size: 4,
1369                     },
1370                     PushConstantRange {
1371                         stages: ShaderStages::COMPUTE | ShaderStages::TESSELLATION_CONTROL,
1372                         offset: 16,
1373                         size: 4,
1374                     },
1375                     PushConstantRange {
1376                         stages: ShaderStages::TESSELLATION_CONTROL,
1377                         offset: 20,
1378                         size: 12,
1379                     },
1380                 ][..],
1381             ),
1382         ];
1383 
1384         let (device, _) = gfx_dev_and_queue!();
1385 
1386         for (input, expected) in test_cases {
1387             let layout = PipelineLayout::new(
1388                 device.clone(),
1389                 PipelineLayoutCreateInfo {
1390                     push_constant_ranges: input.into(),
1391                     ..Default::default()
1392                 },
1393             )
1394             .unwrap();
1395 
1396             assert_eq!(layout.push_constant_ranges_disjoint.as_slice(), expected);
1397         }
1398     }
1399 }
1400 
1401 /* TODO: restore
1402 #[cfg(test)]
1403 mod tests {
1404     use std::iter;
1405     use std::sync::Arc;
1406     use descriptor::descriptor::ShaderStages;
1407     use descriptor::descriptor_set::DescriptorSetLayout;
1408     use descriptor::pipeline_layout::sys::PipelineLayout;
1409     use descriptor::pipeline_layout::sys::PipelineLayoutCreationError;
1410 
1411     #[test]
1412     fn empty() {
1413         let (device, _) = gfx_dev_and_queue!();
1414         let _layout = PipelineLayout::new(&device, iter::empty(), iter::empty()).unwrap();
1415     }
1416 
1417     #[test]
1418     fn wrong_device_panic() {
1419         let (device1, _) = gfx_dev_and_queue!();
1420         let (device2, _) = gfx_dev_and_queue!();
1421 
1422         let set = match DescriptorSetLayout::raw(device1, iter::empty()) {
1423             Ok(s) => Arc::new(s),
1424             Err(_) => return
1425         };
1426 
1427         assert_should_panic!({
1428             let _ = PipelineLayout::new(&device2, Some(&set), iter::empty());
1429         });
1430     }
1431 
1432     #[test]
1433     fn invalid_push_constant_stages() {
1434         let (device, _) = gfx_dev_and_queue!();
1435 
1436         let push_constant = (0, 8, ShaderStages::empty());
1437 
1438         match PipelineLayout::new(&device, iter::empty(), Some(push_constant)) {
1439             Err(PipelineLayoutCreationError::InvalidPushConstant) => (),
1440             _ => panic!()
1441         }
1442     }
1443 
1444     #[test]
1445     fn invalid_push_constant_size1() {
1446         let (device, _) = gfx_dev_and_queue!();
1447 
1448         let push_constant = (0, 0, ShaderStages::all_graphics());
1449 
1450         match PipelineLayout::new(&device, iter::empty(), Some(push_constant)) {
1451             Err(PipelineLayoutCreationError::InvalidPushConstant) => (),
1452             _ => panic!()
1453         }
1454     }
1455 
1456     #[test]
1457     fn invalid_push_constant_size2() {
1458         let (device, _) = gfx_dev_and_queue!();
1459 
1460         let push_constant = (0, 11, ShaderStages::all_graphics());
1461 
1462         match PipelineLayout::new(&device, iter::empty(), Some(push_constant)) {
1463             Err(PipelineLayoutCreationError::InvalidPushConstant) => (),
1464             _ => panic!()
1465         }
1466     }
1467 }
1468 */
1469