• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2022 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 use crate::{
11     buffer::{BufferContents, BufferUsage, Subbuffer},
12     command_buffer::{
13         allocator::CommandBufferAllocator,
14         auto::RenderPassStateType,
15         synced::{Command, SetOrPush, SyncCommandBufferBuilder},
16         sys::UnsafeCommandBufferBuilder,
17         AutoCommandBufferBuilder,
18     },
19     descriptor_set::{
20         check_descriptor_write, layout::DescriptorType, sys::UnsafeDescriptorSet,
21         DescriptorBindingResources, DescriptorSetResources, DescriptorSetUpdateError,
22         DescriptorSetWithOffsets, DescriptorSetsCollection, DescriptorWriteInfo,
23         WriteDescriptorSet,
24     },
25     device::{DeviceOwned, QueueFlags},
26     memory::{is_aligned, DeviceAlignment},
27     pipeline::{
28         graphics::{
29             input_assembly::{Index, IndexType},
30             render_pass::PipelineRenderPassType,
31             vertex_input::VertexBuffersCollection,
32         },
33         ComputePipeline, GraphicsPipeline, PipelineBindPoint, PipelineLayout,
34     },
35     shader::ShaderStages,
36     DeviceSize, RequirementNotMet, RequiresOneOf, VulkanObject,
37 };
38 use parking_lot::Mutex;
39 use smallvec::SmallVec;
40 use std::{
41     cmp::min,
42     error,
43     fmt::{Display, Error as FmtError, Formatter},
44     mem::{size_of, size_of_val},
45     ptr, slice,
46     sync::Arc,
47 };
48 
49 /// # Commands to bind or push state for pipeline execution commands.
50 ///
51 /// These commands require a queue with a pipeline type that uses the given state.
52 impl<L, A> AutoCommandBufferBuilder<L, A>
53 where
54     A: CommandBufferAllocator,
55 {
56     /// Binds descriptor sets for future dispatch or draw calls.
57     ///
58     /// # Panics
59     ///
60     /// - Panics if the queue family of the command buffer does not support `pipeline_bind_point`.
61     /// - Panics if the highest descriptor set slot being bound is not less than the number of sets
62     ///   in `pipeline_layout`.
63     /// - Panics if `self` and any element of `descriptor_sets` do not belong to the same device.
bind_descriptor_sets<S>( &mut self, pipeline_bind_point: PipelineBindPoint, pipeline_layout: Arc<PipelineLayout>, first_set: u32, descriptor_sets: S, ) -> &mut Self where S: DescriptorSetsCollection,64     pub fn bind_descriptor_sets<S>(
65         &mut self,
66         pipeline_bind_point: PipelineBindPoint,
67         pipeline_layout: Arc<PipelineLayout>,
68         first_set: u32,
69         descriptor_sets: S,
70     ) -> &mut Self
71     where
72         S: DescriptorSetsCollection,
73     {
74         let descriptor_sets = descriptor_sets.into_vec();
75         self.validate_bind_descriptor_sets(
76             pipeline_bind_point,
77             &pipeline_layout,
78             first_set,
79             &descriptor_sets,
80         )
81         .unwrap();
82 
83         unsafe {
84             let mut sets_binder = self.inner.bind_descriptor_sets();
85             for set in descriptor_sets.into_iter() {
86                 sets_binder.add(set);
87             }
88             sets_binder.submit(pipeline_bind_point, pipeline_layout, first_set);
89         }
90 
91         self
92     }
93 
validate_bind_descriptor_sets( &self, pipeline_bind_point: PipelineBindPoint, pipeline_layout: &PipelineLayout, first_set: u32, descriptor_sets: &[DescriptorSetWithOffsets], ) -> Result<(), BindPushError>94     fn validate_bind_descriptor_sets(
95         &self,
96         pipeline_bind_point: PipelineBindPoint,
97         pipeline_layout: &PipelineLayout,
98         first_set: u32,
99         descriptor_sets: &[DescriptorSetWithOffsets],
100     ) -> Result<(), BindPushError> {
101         // VUID-vkCmdBindDescriptorSets-pipelineBindPoint-parameter
102         pipeline_bind_point.validate_device(self.device())?;
103 
104         let queue_family_properties = self.queue_family_properties();
105 
106         // VUID-vkCmdBindDescriptorSets-commandBuffer-cmdpool
107         // VUID-vkCmdBindDescriptorSets-pipelineBindPoint-00361
108         match pipeline_bind_point {
109             PipelineBindPoint::Compute => {
110                 if !queue_family_properties
111                     .queue_flags
112                     .intersects(QueueFlags::COMPUTE)
113                 {
114                     return Err(BindPushError::NotSupportedByQueueFamily);
115                 }
116             }
117             PipelineBindPoint::Graphics => {
118                 if !queue_family_properties
119                     .queue_flags
120                     .intersects(QueueFlags::GRAPHICS)
121                 {
122                     return Err(BindPushError::NotSupportedByQueueFamily);
123                 }
124             }
125         }
126 
127         // VUID-vkCmdBindDescriptorSets-firstSet-00360
128         if first_set + descriptor_sets.len() as u32 > pipeline_layout.set_layouts().len() as u32 {
129             return Err(BindPushError::DescriptorSetOutOfRange {
130                 set_num: first_set + descriptor_sets.len() as u32,
131                 pipeline_layout_set_count: pipeline_layout.set_layouts().len() as u32,
132             });
133         }
134 
135         let properties = self.device().physical_device().properties();
136         let uniform_alignment = properties.min_uniform_buffer_offset_alignment;
137         let storage_alignment = properties.min_storage_buffer_offset_alignment;
138 
139         for (i, set) in descriptor_sets.iter().enumerate() {
140             let set_num = first_set + i as u32;
141             let (set, dynamic_offsets) = set.as_ref();
142 
143             // VUID-vkCmdBindDescriptorSets-commonparent
144             assert_eq!(self.device(), set.device());
145 
146             let set_layout = set.layout();
147             let pipeline_set_layout = &pipeline_layout.set_layouts()[set_num as usize];
148 
149             // VUID-vkCmdBindDescriptorSets-pDescriptorSets-00358
150             if !pipeline_set_layout.is_compatible_with(set_layout) {
151                 return Err(BindPushError::DescriptorSetNotCompatible { set_num });
152             }
153 
154             let mut dynamic_offsets_remaining = dynamic_offsets;
155             let mut required_dynamic_offset_count = 0;
156 
157             for (&binding_num, binding) in set_layout.bindings() {
158                 let required_alignment = match binding.descriptor_type {
159                     DescriptorType::UniformBufferDynamic => uniform_alignment,
160                     DescriptorType::StorageBufferDynamic => storage_alignment,
161                     _ => continue,
162                 };
163 
164                 let count = if binding.variable_descriptor_count {
165                     set.variable_descriptor_count()
166                 } else {
167                     binding.descriptor_count
168                 } as usize;
169 
170                 required_dynamic_offset_count += count;
171 
172                 if !dynamic_offsets_remaining.is_empty() {
173                     let split_index = min(count, dynamic_offsets_remaining.len());
174                     let dynamic_offsets = &dynamic_offsets_remaining[..split_index];
175                     dynamic_offsets_remaining = &dynamic_offsets_remaining[split_index..];
176 
177                     let elements = match set.resources().binding(binding_num) {
178                         Some(DescriptorBindingResources::Buffer(elements)) => elements.as_slice(),
179                         _ => unreachable!(),
180                     };
181 
182                     for (index, (&offset, element)) in
183                         dynamic_offsets.iter().zip(elements).enumerate()
184                     {
185                         // VUID-vkCmdBindDescriptorSets-pDynamicOffsets-01971
186                         // VUID-vkCmdBindDescriptorSets-pDynamicOffsets-01972
187                         if !is_aligned(offset as DeviceSize, required_alignment) {
188                             return Err(BindPushError::DynamicOffsetNotAligned {
189                                 set_num,
190                                 binding_num,
191                                 index: index as u32,
192                                 offset,
193                                 required_alignment,
194                             });
195                         }
196 
197                         if let Some((buffer, range)) = element {
198                             // VUID-vkCmdBindDescriptorSets-pDescriptorSets-01979
199                             if offset as DeviceSize + range.end > buffer.size() {
200                                 return Err(BindPushError::DynamicOffsetOutOfBufferBounds {
201                                     set_num,
202                                     binding_num,
203                                     index: index as u32,
204                                     offset,
205                                     range_end: range.end,
206                                     buffer_size: buffer.size(),
207                                 });
208                             }
209                         }
210                     }
211                 }
212             }
213 
214             // VUID-vkCmdBindDescriptorSets-dynamicOffsetCount-00359
215             if dynamic_offsets.len() != required_dynamic_offset_count {
216                 return Err(BindPushError::DynamicOffsetCountMismatch {
217                     set_num,
218                     provided_count: dynamic_offsets.len(),
219                     required_count: required_dynamic_offset_count,
220                 });
221             }
222         }
223 
224         Ok(())
225     }
226 
227     /// Binds an index buffer for future indexed draw calls.
228     ///
229     /// # Panics
230     ///
231     /// - Panics if the queue family of the command buffer does not support graphics operations.
232     /// - Panics if `self` and `index_buffer` do not belong to the same device.
233     /// - Panics if `index_buffer` does not have the [`BufferUsage::INDEX_BUFFER`] usage enabled.
234     /// - If the index buffer contains `u8` indices, panics if the [`index_type_uint8`] feature is
235     ///   not enabled on the device.
236     ///
237     /// [`BufferUsage::INDEX_BUFFER`]: crate::buffer::BufferUsage::INDEX_BUFFER
238     /// [`index_type_uint8`]: crate::device::Features::index_type_uint8
bind_index_buffer<I: Index>(&mut self, index_buffer: Subbuffer<[I]>) -> &mut Self239     pub fn bind_index_buffer<I: Index>(&mut self, index_buffer: Subbuffer<[I]>) -> &mut Self {
240         self.validate_bind_index_buffer(index_buffer.as_bytes(), I::ty())
241             .unwrap();
242 
243         unsafe {
244             self.inner
245                 .bind_index_buffer(index_buffer.into_bytes(), I::ty());
246         }
247 
248         self
249     }
250 
validate_bind_index_buffer( &self, index_buffer: &Subbuffer<[u8]>, index_type: IndexType, ) -> Result<(), BindPushError>251     fn validate_bind_index_buffer(
252         &self,
253         index_buffer: &Subbuffer<[u8]>,
254         index_type: IndexType,
255     ) -> Result<(), BindPushError> {
256         let queue_family_properties = self.queue_family_properties();
257 
258         // VUID-vkCmdBindIndexBuffer-commandBuffer-cmdpool
259         if !queue_family_properties
260             .queue_flags
261             .intersects(QueueFlags::GRAPHICS)
262         {
263             return Err(BindPushError::NotSupportedByQueueFamily);
264         }
265 
266         // VUID-vkCmdBindIndexBuffer-commonparent
267         assert_eq!(self.device(), index_buffer.device());
268 
269         // VUID-vkCmdBindIndexBuffer-buffer-00433
270         if !index_buffer
271             .buffer()
272             .usage()
273             .intersects(BufferUsage::INDEX_BUFFER)
274         {
275             return Err(BindPushError::IndexBufferMissingUsage);
276         }
277 
278         // VUID-vkCmdBindIndexBuffer-indexType-02765
279         if index_type == IndexType::U8 && !self.device().enabled_features().index_type_uint8 {
280             return Err(BindPushError::RequirementNotMet {
281                 required_for: "`index_type` is `IndexType::U8`",
282                 requires_one_of: RequiresOneOf {
283                     features: &["index_type_uint8"],
284                     ..Default::default()
285                 },
286             });
287         }
288 
289         // TODO:
290         // VUID-vkCmdBindIndexBuffer-offset-00432
291 
292         Ok(())
293     }
294 
295     /// Binds a compute pipeline for future dispatch calls.
296     ///
297     /// # Panics
298     ///
299     /// - Panics if the queue family of the command buffer does not support compute operations.
300     /// - Panics if `self` and `pipeline` do not belong to the same device.
bind_pipeline_compute(&mut self, pipeline: Arc<ComputePipeline>) -> &mut Self301     pub fn bind_pipeline_compute(&mut self, pipeline: Arc<ComputePipeline>) -> &mut Self {
302         self.validate_bind_pipeline_compute(&pipeline).unwrap();
303 
304         unsafe {
305             self.inner.bind_pipeline_compute(pipeline);
306         }
307 
308         self
309     }
310 
validate_bind_pipeline_compute( &self, pipeline: &ComputePipeline, ) -> Result<(), BindPushError>311     fn validate_bind_pipeline_compute(
312         &self,
313         pipeline: &ComputePipeline,
314     ) -> Result<(), BindPushError> {
315         let queue_family_properties = self.queue_family_properties();
316 
317         // VUID-vkCmdBindPipeline-pipelineBindPoint-00777
318         if !queue_family_properties
319             .queue_flags
320             .intersects(QueueFlags::COMPUTE)
321         {
322             return Err(BindPushError::NotSupportedByQueueFamily);
323         }
324 
325         // VUID-vkCmdBindPipeline-commonparent
326         assert_eq!(self.device(), pipeline.device());
327 
328         Ok(())
329     }
330 
331     /// Binds a graphics pipeline for future draw calls.
332     ///
333     /// # Panics
334     ///
335     /// - Panics if the queue family of the command buffer does not support graphics operations.
336     /// - Panics if `self` and `pipeline` do not belong to the same device.
bind_pipeline_graphics(&mut self, pipeline: Arc<GraphicsPipeline>) -> &mut Self337     pub fn bind_pipeline_graphics(&mut self, pipeline: Arc<GraphicsPipeline>) -> &mut Self {
338         self.validate_bind_pipeline_graphics(&pipeline).unwrap();
339 
340         unsafe {
341             self.inner.bind_pipeline_graphics(pipeline);
342         }
343 
344         self
345     }
346 
validate_bind_pipeline_graphics( &self, pipeline: &GraphicsPipeline, ) -> Result<(), BindPushError>347     fn validate_bind_pipeline_graphics(
348         &self,
349         pipeline: &GraphicsPipeline,
350     ) -> Result<(), BindPushError> {
351         let queue_family_properties = self.queue_family_properties();
352 
353         // VUID-vkCmdBindPipeline-pipelineBindPoint-00778
354         if !queue_family_properties
355             .queue_flags
356             .intersects(QueueFlags::GRAPHICS)
357         {
358             return Err(BindPushError::NotSupportedByQueueFamily);
359         }
360 
361         // VUID-vkCmdBindPipeline-commonparent
362         assert_eq!(self.device(), pipeline.device());
363 
364         if let Some(last_pipeline) = self
365             .render_pass_state
366             .as_ref()
367             .and_then(|render_pass_state| match &render_pass_state.render_pass {
368                 RenderPassStateType::BeginRendering(state) if state.pipeline_used => {
369                     self.state().pipeline_graphics()
370                 }
371                 _ => None,
372             })
373         {
374             if let (
375                 PipelineRenderPassType::BeginRendering(pipeline_rendering_info),
376                 PipelineRenderPassType::BeginRendering(last_pipeline_rendering_info),
377             ) = (pipeline.render_pass(), last_pipeline.render_pass())
378             {
379                 // VUID-vkCmdBindPipeline-pipeline-06195
380                 // VUID-vkCmdBindPipeline-pipeline-06196
381                 if pipeline_rendering_info.color_attachment_formats
382                     != last_pipeline_rendering_info.color_attachment_formats
383                 {
384                     return Err(BindPushError::PreviousPipelineColorAttachmentFormatMismatch);
385                 }
386 
387                 // VUID-vkCmdBindPipeline-pipeline-06197
388                 if pipeline_rendering_info.depth_attachment_format
389                     != last_pipeline_rendering_info.depth_attachment_format
390                 {
391                     return Err(BindPushError::PreviousPipelineDepthAttachmentFormatMismatch);
392                 }
393 
394                 // VUID-vkCmdBindPipeline-pipeline-06194
395                 if pipeline_rendering_info.stencil_attachment_format
396                     != last_pipeline_rendering_info.stencil_attachment_format
397                 {
398                     return Err(BindPushError::PreviousPipelineStencilAttachmentFormatMismatch);
399                 }
400             }
401         }
402 
403         // VUID-vkCmdBindPipeline-pipeline-00781
404         // TODO:
405 
406         Ok(())
407     }
408 
409     /// Binds vertex buffers for future draw calls.
410     ///
411     /// # Panics
412     ///
413     /// - Panics if the queue family of the command buffer does not support graphics operations.
414     /// - Panics if the highest vertex buffer binding being bound is greater than the
415     ///   [`max_vertex_input_bindings`] device property.
416     /// - Panics if `self` and any element of `vertex_buffers` do not belong to the same device.
417     /// - Panics if any element of `vertex_buffers` does not have the
418     ///   [`BufferUsage::VERTEX_BUFFER`] usage enabled.
419     ///
420     /// [`max_vertex_input_bindings`]: crate::device::Properties::max_vertex_input_bindings
421     /// [`BufferUsage::VERTEX_BUFFER`]: crate::buffer::BufferUsage::VERTEX_BUFFER
bind_vertex_buffers( &mut self, first_binding: u32, vertex_buffers: impl VertexBuffersCollection, ) -> &mut Self422     pub fn bind_vertex_buffers(
423         &mut self,
424         first_binding: u32,
425         vertex_buffers: impl VertexBuffersCollection,
426     ) -> &mut Self {
427         let vertex_buffers = vertex_buffers.into_vec();
428         self.validate_bind_vertex_buffers(first_binding, &vertex_buffers)
429             .unwrap();
430 
431         unsafe {
432             let mut binder = self.inner.bind_vertex_buffers();
433             for vb in vertex_buffers.into_iter() {
434                 binder.add(vb);
435             }
436             binder.submit(first_binding);
437         }
438 
439         self
440     }
441 
validate_bind_vertex_buffers( &self, first_binding: u32, vertex_buffers: &[Subbuffer<[u8]>], ) -> Result<(), BindPushError>442     fn validate_bind_vertex_buffers(
443         &self,
444         first_binding: u32,
445         vertex_buffers: &[Subbuffer<[u8]>],
446     ) -> Result<(), BindPushError> {
447         let queue_family_properties = self.queue_family_properties();
448 
449         // VUID-vkCmdBindVertexBuffers-commandBuffer-cmdpool
450         if !queue_family_properties
451             .queue_flags
452             .intersects(QueueFlags::GRAPHICS)
453         {
454             return Err(BindPushError::NotSupportedByQueueFamily);
455         }
456 
457         // VUID-vkCmdBindVertexBuffers-firstBinding-00624
458         // VUID-vkCmdBindVertexBuffers-firstBinding-00625
459         if first_binding + vertex_buffers.len() as u32
460             > self
461                 .device()
462                 .physical_device()
463                 .properties()
464                 .max_vertex_input_bindings
465         {
466             return Err(BindPushError::MaxVertexInputBindingsExceeded {
467                 _binding_count: first_binding + vertex_buffers.len() as u32,
468                 _max: self
469                     .device()
470                     .physical_device()
471                     .properties()
472                     .max_vertex_input_bindings,
473             });
474         }
475 
476         for buffer in vertex_buffers {
477             // VUID-vkCmdBindVertexBuffers-commonparent
478             assert_eq!(self.device(), buffer.device());
479 
480             // VUID-vkCmdBindVertexBuffers-pBuffers-00627
481             if !buffer
482                 .buffer()
483                 .usage()
484                 .intersects(BufferUsage::VERTEX_BUFFER)
485             {
486                 return Err(BindPushError::VertexBufferMissingUsage);
487             }
488         }
489 
490         Ok(())
491     }
492 
493     /// Sets push constants for future dispatch or draw calls.
494     ///
495     /// # Panics
496     ///
497     /// - Panics if `offset` is not a multiple of 4.
498     /// - Panics if the size of `push_constants` is not a multiple of 4.
499     /// - Panics if any of the bytes in `push_constants` do not fall within any of the pipeline
500     ///   layout's push constant ranges.
push_constants<Pc>( &mut self, pipeline_layout: Arc<PipelineLayout>, offset: u32, push_constants: Pc, ) -> &mut Self where Pc: BufferContents,501     pub fn push_constants<Pc>(
502         &mut self,
503         pipeline_layout: Arc<PipelineLayout>,
504         offset: u32,
505         push_constants: Pc,
506     ) -> &mut Self
507     where
508         Pc: BufferContents,
509     {
510         let size = size_of::<Pc>() as u32;
511 
512         if size == 0 {
513             return self;
514         }
515 
516         // SAFETY: `&push_constants` is a valid pointer, and the size of the struct is `size`,
517         //         thus, getting a slice of the whole struct is safe if its not modified.
518         let push_constants = unsafe {
519             slice::from_raw_parts(&push_constants as *const Pc as *const u8, size as usize)
520         };
521 
522         self.validate_push_constants(&pipeline_layout, offset, push_constants)
523             .unwrap();
524 
525         let mut current_offset = offset;
526         let mut remaining_size = size;
527         for range in pipeline_layout
528             .push_constant_ranges_disjoint()
529             .iter()
530             .skip_while(|range| range.offset + range.size <= offset)
531         {
532             // there is a gap between ranges, but the passed push_constants contains
533             // some bytes in this gap, exit the loop and report error
534             if range.offset > current_offset {
535                 break;
536             }
537 
538             // push the minimum of the whole remaining data, and the part until the end of this range
539             let push_size = remaining_size.min(range.offset + range.size - current_offset);
540             let data_offset = (current_offset - offset) as usize;
541             unsafe {
542                 self.inner.push_constants::<[u8]>(
543                     pipeline_layout.clone(),
544                     range.stages,
545                     current_offset,
546                     push_size,
547                     &push_constants[data_offset..(data_offset + push_size as usize)],
548                 );
549             }
550             current_offset += push_size;
551             remaining_size -= push_size;
552 
553             if remaining_size == 0 {
554                 break;
555             }
556         }
557 
558         debug_assert!(remaining_size == 0);
559 
560         self
561     }
562 
validate_push_constants( &self, pipeline_layout: &PipelineLayout, offset: u32, push_constants: &[u8], ) -> Result<(), BindPushError>563     fn validate_push_constants(
564         &self,
565         pipeline_layout: &PipelineLayout,
566         offset: u32,
567         push_constants: &[u8],
568     ) -> Result<(), BindPushError> {
569         if offset % 4 != 0 {
570             return Err(BindPushError::PushConstantsOffsetNotAligned);
571         }
572 
573         if push_constants.len() % 4 != 0 {
574             return Err(BindPushError::PushConstantsSizeNotAligned);
575         }
576 
577         let mut current_offset = offset;
578         let mut remaining_size = push_constants.len() as u32;
579         for range in pipeline_layout
580             .push_constant_ranges_disjoint()
581             .iter()
582             .skip_while(|range| range.offset + range.size <= offset)
583         {
584             // there is a gap between ranges, but the passed push_constants contains
585             // some bytes in this gap, exit the loop and report error
586             if range.offset > current_offset {
587                 break;
588             }
589 
590             // push the minimum of the whole remaining data, and the part until the end of this range
591             let push_size = remaining_size.min(range.offset + range.size - current_offset);
592             current_offset += push_size;
593             remaining_size -= push_size;
594 
595             if remaining_size == 0 {
596                 break;
597             }
598         }
599 
600         if remaining_size != 0 {
601             return Err(BindPushError::PushConstantsDataOutOfRange {
602                 offset: current_offset,
603             });
604         }
605 
606         Ok(())
607     }
608 
609     /// Pushes descriptor data directly into the command buffer for future dispatch or draw calls.
610     ///
611     /// # Panics
612     ///
613     /// - Panics if the queue family of the command buffer does not support `pipeline_bind_point`.
614     /// - Panics if the
615     ///   [`khr_push_descriptor`](crate::device::DeviceExtensions::khr_push_descriptor)
616     ///   extension is not enabled on the device.
617     /// - Panics if `set_num` is not less than the number of sets in `pipeline_layout`.
618     /// - Panics if an element of `descriptor_writes` is not compatible with `pipeline_layout`.
push_descriptor_set( &mut self, pipeline_bind_point: PipelineBindPoint, pipeline_layout: Arc<PipelineLayout>, set_num: u32, descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>, ) -> &mut Self619     pub fn push_descriptor_set(
620         &mut self,
621         pipeline_bind_point: PipelineBindPoint,
622         pipeline_layout: Arc<PipelineLayout>,
623         set_num: u32,
624         descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
625     ) -> &mut Self {
626         let descriptor_writes: SmallVec<[_; 8]> = descriptor_writes.into_iter().collect();
627         self.validate_push_descriptor_set(
628             pipeline_bind_point,
629             &pipeline_layout,
630             set_num,
631             &descriptor_writes,
632         )
633         .unwrap();
634 
635         unsafe {
636             self.inner.push_descriptor_set(
637                 pipeline_bind_point,
638                 pipeline_layout,
639                 set_num,
640                 descriptor_writes,
641             );
642         }
643 
644         self
645     }
646 
validate_push_descriptor_set( &self, pipeline_bind_point: PipelineBindPoint, pipeline_layout: &PipelineLayout, set_num: u32, descriptor_writes: &[WriteDescriptorSet], ) -> Result<(), BindPushError>647     fn validate_push_descriptor_set(
648         &self,
649         pipeline_bind_point: PipelineBindPoint,
650         pipeline_layout: &PipelineLayout,
651         set_num: u32,
652         descriptor_writes: &[WriteDescriptorSet],
653     ) -> Result<(), BindPushError> {
654         if !self.device().enabled_extensions().khr_push_descriptor {
655             return Err(BindPushError::RequirementNotMet {
656                 required_for: "`AutoCommandBufferBuilder::push_descriptor_set`",
657                 requires_one_of: RequiresOneOf {
658                     device_extensions: &["khr_push_descriptor"],
659                     ..Default::default()
660                 },
661             });
662         }
663 
664         // VUID-vkCmdPushDescriptorSetKHR-pipelineBindPoint-parameter
665         pipeline_bind_point.validate_device(self.device())?;
666 
667         let queue_family_properties = self.queue_family_properties();
668 
669         // VUID-vkCmdPushDescriptorSetKHR-commandBuffer-cmdpool
670         // VUID-vkCmdPushDescriptorSetKHR-pipelineBindPoint-00363
671         match pipeline_bind_point {
672             PipelineBindPoint::Compute => {
673                 if !queue_family_properties
674                     .queue_flags
675                     .intersects(QueueFlags::COMPUTE)
676                 {
677                     return Err(BindPushError::NotSupportedByQueueFamily);
678                 }
679             }
680             PipelineBindPoint::Graphics => {
681                 if !queue_family_properties
682                     .queue_flags
683                     .intersects(QueueFlags::GRAPHICS)
684                 {
685                     return Err(BindPushError::NotSupportedByQueueFamily);
686                 }
687             }
688         }
689 
690         // VUID-vkCmdPushDescriptorSetKHR-commonparent
691         assert_eq!(self.device(), pipeline_layout.device());
692 
693         // VUID-vkCmdPushDescriptorSetKHR-set-00364
694         if set_num as usize > pipeline_layout.set_layouts().len() {
695             return Err(BindPushError::DescriptorSetOutOfRange {
696                 set_num,
697                 pipeline_layout_set_count: pipeline_layout.set_layouts().len() as u32,
698             });
699         }
700 
701         let descriptor_set_layout = &pipeline_layout.set_layouts()[set_num as usize];
702 
703         // VUID-vkCmdPushDescriptorSetKHR-set-00365
704         if !descriptor_set_layout.push_descriptor() {
705             return Err(BindPushError::DescriptorSetNotPush { set_num });
706         }
707 
708         for write in descriptor_writes {
709             check_descriptor_write(write, descriptor_set_layout, 0)?;
710         }
711 
712         Ok(())
713     }
714 }
715 
716 impl SyncCommandBufferBuilder {
717     /// Starts the process of binding descriptor sets. Returns an intermediate struct which can be
718     /// used to add the sets.
719     #[inline]
bind_descriptor_sets(&mut self) -> SyncCommandBufferBuilderBindDescriptorSets<'_>720     pub fn bind_descriptor_sets(&mut self) -> SyncCommandBufferBuilderBindDescriptorSets<'_> {
721         SyncCommandBufferBuilderBindDescriptorSets {
722             builder: self,
723             descriptor_sets: SmallVec::new(),
724         }
725     }
726 
727     /// Calls `vkCmdBindIndexBuffer` on the builder.
728     #[inline]
bind_index_buffer(&mut self, buffer: Subbuffer<[u8]>, index_type: IndexType)729     pub unsafe fn bind_index_buffer(&mut self, buffer: Subbuffer<[u8]>, index_type: IndexType) {
730         struct Cmd {
731             buffer: Subbuffer<[u8]>,
732             index_type: IndexType,
733         }
734 
735         impl Command for Cmd {
736             fn name(&self) -> &'static str {
737                 "bind_index_buffer"
738             }
739 
740             unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
741                 out.bind_index_buffer(&self.buffer, self.index_type);
742             }
743         }
744 
745         self.current_state.index_buffer = Some((buffer.clone(), index_type));
746         self.commands.push(Box::new(Cmd { buffer, index_type }));
747     }
748 
749     /// Calls `vkCmdBindPipeline` on the builder with a compute pipeline.
750     #[inline]
bind_pipeline_compute(&mut self, pipeline: Arc<ComputePipeline>)751     pub unsafe fn bind_pipeline_compute(&mut self, pipeline: Arc<ComputePipeline>) {
752         struct Cmd {
753             pipeline: Arc<ComputePipeline>,
754         }
755 
756         impl Command for Cmd {
757             fn name(&self) -> &'static str {
758                 "bind_pipeline_compute"
759             }
760 
761             unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
762                 out.bind_pipeline_compute(&self.pipeline);
763             }
764         }
765 
766         self.current_state.pipeline_compute = Some(pipeline.clone());
767         self.commands.push(Box::new(Cmd { pipeline }));
768     }
769 
770     /// Calls `vkCmdBindPipeline` on the builder with a graphics pipeline.
771     #[inline]
bind_pipeline_graphics(&mut self, pipeline: Arc<GraphicsPipeline>)772     pub unsafe fn bind_pipeline_graphics(&mut self, pipeline: Arc<GraphicsPipeline>) {
773         struct Cmd {
774             pipeline: Arc<GraphicsPipeline>,
775         }
776 
777         impl Command for Cmd {
778             fn name(&self) -> &'static str {
779                 "bind_pipeline_graphics"
780             }
781 
782             unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
783                 out.bind_pipeline_graphics(&self.pipeline);
784             }
785         }
786 
787         // Reset any states that are fixed in the new pipeline. The pipeline bind command will
788         // overwrite these states.
789         self.current_state.reset_dynamic_states(
790             pipeline
791                 .dynamic_states()
792                 .filter(|(_, d)| !d) // not dynamic
793                 .map(|(s, _)| s),
794         );
795         self.current_state.pipeline_graphics = Some(pipeline.clone());
796         self.commands.push(Box::new(Cmd { pipeline }));
797     }
798 
799     /// Starts the process of binding vertex buffers. Returns an intermediate struct which can be
800     /// used to add the buffers.
801     #[inline]
bind_vertex_buffers(&mut self) -> SyncCommandBufferBuilderBindVertexBuffer<'_>802     pub fn bind_vertex_buffers(&mut self) -> SyncCommandBufferBuilderBindVertexBuffer<'_> {
803         SyncCommandBufferBuilderBindVertexBuffer {
804             builder: self,
805             inner: UnsafeCommandBufferBuilderBindVertexBuffer::new(),
806             buffers: SmallVec::new(),
807         }
808     }
809 
810     /// Calls `vkCmdPushConstants` on the builder.
push_constants<D>( &mut self, pipeline_layout: Arc<PipelineLayout>, stages: ShaderStages, offset: u32, size: u32, data: &D, ) where D: ?Sized + Send + Sync + 'static,811     pub unsafe fn push_constants<D>(
812         &mut self,
813         pipeline_layout: Arc<PipelineLayout>,
814         stages: ShaderStages,
815         offset: u32,
816         size: u32,
817         data: &D,
818     ) where
819         D: ?Sized + Send + Sync + 'static,
820     {
821         struct Cmd {
822             pipeline_layout: Arc<PipelineLayout>,
823             stages: ShaderStages,
824             offset: u32,
825             size: u32,
826             data: Box<[u8]>,
827         }
828 
829         impl Command for Cmd {
830             fn name(&self) -> &'static str {
831                 "push_constants"
832             }
833 
834             unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
835                 out.push_constants::<[u8]>(
836                     &self.pipeline_layout,
837                     self.stages,
838                     self.offset,
839                     self.size,
840                     &self.data,
841                 );
842             }
843         }
844 
845         debug_assert!(size_of_val(data) >= size as usize);
846 
847         let mut out = Vec::with_capacity(size as usize);
848         ptr::copy::<u8>(
849             data as *const D as *const u8,
850             out.as_mut_ptr(),
851             size as usize,
852         );
853         out.set_len(size as usize);
854 
855         self.commands.push(Box::new(Cmd {
856             pipeline_layout: pipeline_layout.clone(),
857             stages,
858             offset,
859             size,
860             data: out.into(),
861         }));
862 
863         // TODO: Push constant invalidations.
864         // The Vulkan spec currently is unclear about this, so Vulkano currently just marks
865         // push constants as set, and never unsets them. See:
866         // https://github.com/KhronosGroup/Vulkan-Docs/issues/1485
867         // https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/2711
868         self.current_state
869             .push_constants
870             .insert(offset..offset + size);
871         self.current_state.push_constants_pipeline_layout = Some(pipeline_layout);
872     }
873 
874     /// Calls `vkCmdPushDescriptorSetKHR` on the builder.
push_descriptor_set( &mut self, pipeline_bind_point: PipelineBindPoint, pipeline_layout: Arc<PipelineLayout>, set_num: u32, descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>, )875     pub unsafe fn push_descriptor_set(
876         &mut self,
877         pipeline_bind_point: PipelineBindPoint,
878         pipeline_layout: Arc<PipelineLayout>,
879         set_num: u32,
880         descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
881     ) {
882         struct Cmd {
883             pipeline_bind_point: PipelineBindPoint,
884             pipeline_layout: Arc<PipelineLayout>,
885             set_num: u32,
886             descriptor_writes: SmallVec<[WriteDescriptorSet; 8]>,
887         }
888 
889         impl Command for Cmd {
890             fn name(&self) -> &'static str {
891                 "push_descriptor_set"
892             }
893 
894             unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
895                 out.push_descriptor_set(
896                     self.pipeline_bind_point,
897                     &self.pipeline_layout,
898                     self.set_num,
899                     &self.descriptor_writes,
900                 );
901             }
902         }
903 
904         let descriptor_writes: SmallVec<[WriteDescriptorSet; 8]> =
905             descriptor_writes.into_iter().collect();
906 
907         let state = self.current_state.invalidate_descriptor_sets(
908             pipeline_bind_point,
909             pipeline_layout.clone(),
910             set_num,
911             1,
912         );
913         let layout = state.pipeline_layout.set_layouts()[set_num as usize].as_ref();
914         debug_assert!(layout.push_descriptor());
915 
916         let set_resources = match state
917             .descriptor_sets
918             .entry(set_num)
919             .or_insert_with(|| SetOrPush::Push(DescriptorSetResources::new(layout, 0)))
920         {
921             SetOrPush::Push(set_resources) => set_resources,
922             _ => unreachable!(),
923         };
924 
925         for write in &descriptor_writes {
926             set_resources.update(write);
927         }
928 
929         self.commands.push(Box::new(Cmd {
930             pipeline_bind_point,
931             pipeline_layout,
932             set_num,
933             descriptor_writes,
934         }));
935     }
936 }
937 
938 pub struct SyncCommandBufferBuilderBindDescriptorSets<'b> {
939     builder: &'b mut SyncCommandBufferBuilder,
940     descriptor_sets: SmallVec<[DescriptorSetWithOffsets; 12]>,
941 }
942 
943 impl<'b> SyncCommandBufferBuilderBindDescriptorSets<'b> {
944     /// Adds a descriptor set to the list.
add(&mut self, descriptor_set: impl Into<DescriptorSetWithOffsets>)945     pub fn add(&mut self, descriptor_set: impl Into<DescriptorSetWithOffsets>) {
946         self.descriptor_sets.push(descriptor_set.into());
947     }
948 
949     #[inline]
submit( self, pipeline_bind_point: PipelineBindPoint, pipeline_layout: Arc<PipelineLayout>, first_set: u32, )950     pub unsafe fn submit(
951         self,
952         pipeline_bind_point: PipelineBindPoint,
953         pipeline_layout: Arc<PipelineLayout>,
954         first_set: u32,
955     ) {
956         if self.descriptor_sets.is_empty() {
957             return;
958         }
959 
960         struct Cmd {
961             descriptor_sets: SmallVec<[DescriptorSetWithOffsets; 12]>,
962             pipeline_bind_point: PipelineBindPoint,
963             pipeline_layout: Arc<PipelineLayout>,
964             first_set: u32,
965         }
966 
967         impl Command for Cmd {
968             fn name(&self) -> &'static str {
969                 "bind_descriptor_sets"
970             }
971 
972             unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
973                 let descriptor_sets = self.descriptor_sets.iter().map(|x| x.as_ref().0.inner());
974                 let dynamic_offsets = self
975                     .descriptor_sets
976                     .iter()
977                     .flat_map(|x| x.as_ref().1.iter().copied());
978 
979                 out.bind_descriptor_sets(
980                     self.pipeline_bind_point,
981                     &self.pipeline_layout,
982                     self.first_set,
983                     descriptor_sets,
984                     dynamic_offsets,
985                 );
986             }
987         }
988 
989         let state = self.builder.current_state.invalidate_descriptor_sets(
990             pipeline_bind_point,
991             pipeline_layout.clone(),
992             first_set,
993             self.descriptor_sets.len() as u32,
994         );
995 
996         for (set_num, set) in self.descriptor_sets.iter().enumerate() {
997             state
998                 .descriptor_sets
999                 .insert(first_set + set_num as u32, SetOrPush::Set(set.clone()));
1000         }
1001 
1002         self.builder.commands.push(Box::new(Cmd {
1003             descriptor_sets: self.descriptor_sets,
1004             pipeline_bind_point,
1005             pipeline_layout,
1006             first_set,
1007         }));
1008     }
1009 }
1010 
1011 /// Prototype for a `vkCmdBindVertexBuffers`.
1012 pub struct SyncCommandBufferBuilderBindVertexBuffer<'a> {
1013     builder: &'a mut SyncCommandBufferBuilder,
1014     inner: UnsafeCommandBufferBuilderBindVertexBuffer,
1015     buffers: SmallVec<[Subbuffer<[u8]>; 4]>,
1016 }
1017 
1018 impl<'a> SyncCommandBufferBuilderBindVertexBuffer<'a> {
1019     /// Adds a buffer to the list.
1020     #[inline]
add(&mut self, buffer: Subbuffer<[u8]>)1021     pub fn add(&mut self, buffer: Subbuffer<[u8]>) {
1022         self.inner.add(&buffer);
1023         self.buffers.push(buffer);
1024     }
1025 
1026     #[inline]
submit(self, first_set: u32)1027     pub unsafe fn submit(self, first_set: u32) {
1028         struct Cmd {
1029             first_set: u32,
1030             inner: Mutex<Option<UnsafeCommandBufferBuilderBindVertexBuffer>>,
1031             _buffers: SmallVec<[Subbuffer<[u8]>; 4]>,
1032         }
1033 
1034         impl Command for Cmd {
1035             fn name(&self) -> &'static str {
1036                 "bind_vertex_buffers"
1037             }
1038 
1039             unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
1040                 out.bind_vertex_buffers(self.first_set, self.inner.lock().take().unwrap());
1041             }
1042         }
1043 
1044         for (i, buffer) in self.buffers.iter().enumerate() {
1045             self.builder
1046                 .current_state
1047                 .vertex_buffers
1048                 .insert(first_set + i as u32, buffer.clone());
1049         }
1050 
1051         self.builder.commands.push(Box::new(Cmd {
1052             first_set,
1053             inner: Mutex::new(Some(self.inner)),
1054             _buffers: self.buffers,
1055         }));
1056     }
1057 }
1058 
1059 impl UnsafeCommandBufferBuilder {
1060     /// Calls `vkCmdBindDescriptorSets` on the builder.
1061     ///
1062     /// Does nothing if the list of descriptor sets is empty, as it would be a no-op and isn't a
1063     /// valid usage of the command anyway.
1064     #[inline]
bind_descriptor_sets<'s>( &mut self, pipeline_bind_point: PipelineBindPoint, pipeline_layout: &PipelineLayout, first_set: u32, sets: impl IntoIterator<Item = &'s UnsafeDescriptorSet>, dynamic_offsets: impl IntoIterator<Item = u32>, )1065     pub unsafe fn bind_descriptor_sets<'s>(
1066         &mut self,
1067         pipeline_bind_point: PipelineBindPoint,
1068         pipeline_layout: &PipelineLayout,
1069         first_set: u32,
1070         sets: impl IntoIterator<Item = &'s UnsafeDescriptorSet>,
1071         dynamic_offsets: impl IntoIterator<Item = u32>,
1072     ) {
1073         let fns = self.device.fns();
1074 
1075         let sets: SmallVec<[_; 12]> = sets.into_iter().map(|s| s.handle()).collect();
1076         if sets.is_empty() {
1077             return;
1078         }
1079         let dynamic_offsets: SmallVec<[u32; 32]> = dynamic_offsets.into_iter().collect();
1080 
1081         let num_bindings = sets.len() as u32;
1082         debug_assert!(first_set + num_bindings <= pipeline_layout.set_layouts().len() as u32);
1083 
1084         (fns.v1_0.cmd_bind_descriptor_sets)(
1085             self.handle,
1086             pipeline_bind_point.into(),
1087             pipeline_layout.handle(),
1088             first_set,
1089             num_bindings,
1090             sets.as_ptr(),
1091             dynamic_offsets.len() as u32,
1092             dynamic_offsets.as_ptr(),
1093         );
1094     }
1095 
1096     /// Calls `vkCmdBindIndexBuffer` on the builder.
1097     #[inline]
bind_index_buffer(&mut self, buffer: &Subbuffer<[u8]>, index_type: IndexType)1098     pub unsafe fn bind_index_buffer(&mut self, buffer: &Subbuffer<[u8]>, index_type: IndexType) {
1099         let fns = self.device.fns();
1100 
1101         debug_assert!(buffer.offset() < buffer.buffer().size());
1102         debug_assert!(buffer
1103             .buffer()
1104             .usage()
1105             .intersects(BufferUsage::INDEX_BUFFER));
1106 
1107         (fns.v1_0.cmd_bind_index_buffer)(
1108             self.handle,
1109             buffer.buffer().handle(),
1110             buffer.offset(),
1111             index_type.into(),
1112         );
1113     }
1114 
1115     /// Calls `vkCmdBindPipeline` on the builder with a compute pipeline.
1116     #[inline]
bind_pipeline_compute(&mut self, pipeline: &ComputePipeline)1117     pub unsafe fn bind_pipeline_compute(&mut self, pipeline: &ComputePipeline) {
1118         let fns = self.device.fns();
1119         (fns.v1_0.cmd_bind_pipeline)(
1120             self.handle,
1121             ash::vk::PipelineBindPoint::COMPUTE,
1122             pipeline.handle(),
1123         );
1124     }
1125 
1126     /// Calls `vkCmdBindPipeline` on the builder with a graphics pipeline.
1127     #[inline]
bind_pipeline_graphics(&mut self, pipeline: &GraphicsPipeline)1128     pub unsafe fn bind_pipeline_graphics(&mut self, pipeline: &GraphicsPipeline) {
1129         let fns = self.device.fns();
1130         (fns.v1_0.cmd_bind_pipeline)(
1131             self.handle,
1132             ash::vk::PipelineBindPoint::GRAPHICS,
1133             pipeline.handle(),
1134         );
1135     }
1136 
1137     /// Calls `vkCmdBindVertexBuffers` on the builder.
1138     ///
1139     /// Does nothing if the list of buffers is empty, as it would be a no-op and isn't a valid
1140     /// usage of the command anyway.
1141     // TODO: vkCmdBindVertexBuffers2EXT
1142     #[inline]
bind_vertex_buffers( &mut self, first_binding: u32, params: UnsafeCommandBufferBuilderBindVertexBuffer, )1143     pub unsafe fn bind_vertex_buffers(
1144         &mut self,
1145         first_binding: u32,
1146         params: UnsafeCommandBufferBuilderBindVertexBuffer,
1147     ) {
1148         debug_assert_eq!(params.raw_buffers.len(), params.offsets.len());
1149 
1150         if params.raw_buffers.is_empty() {
1151             return;
1152         }
1153 
1154         let fns = self.device.fns();
1155 
1156         let num_bindings = params.raw_buffers.len() as u32;
1157 
1158         debug_assert!({
1159             let max_bindings = self
1160                 .device
1161                 .physical_device()
1162                 .properties()
1163                 .max_vertex_input_bindings;
1164             first_binding + num_bindings <= max_bindings
1165         });
1166 
1167         (fns.v1_0.cmd_bind_vertex_buffers)(
1168             self.handle,
1169             first_binding,
1170             num_bindings,
1171             params.raw_buffers.as_ptr(),
1172             params.offsets.as_ptr(),
1173         );
1174     }
1175 
1176     /// Calls `vkCmdPushConstants` on the builder.
push_constants<D>( &mut self, pipeline_layout: &PipelineLayout, stages: ShaderStages, offset: u32, size: u32, data: &D, ) where D: BufferContents + ?Sized,1177     pub unsafe fn push_constants<D>(
1178         &mut self,
1179         pipeline_layout: &PipelineLayout,
1180         stages: ShaderStages,
1181         offset: u32,
1182         size: u32,
1183         data: &D,
1184     ) where
1185         D: BufferContents + ?Sized,
1186     {
1187         let fns = self.device.fns();
1188 
1189         debug_assert!(!stages.is_empty());
1190         debug_assert!(size > 0);
1191         debug_assert_eq!(size % 4, 0);
1192         debug_assert_eq!(offset % 4, 0);
1193         debug_assert!(size_of_val(data) >= size as usize);
1194 
1195         (fns.v1_0.cmd_push_constants)(
1196             self.handle,
1197             pipeline_layout.handle(),
1198             stages.into(),
1199             offset,
1200             size,
1201             data as *const _ as *const _,
1202         );
1203     }
1204 
1205     /// Calls `vkCmdPushDescriptorSetKHR` on the builder.
1206     ///
1207     /// If the list is empty then the command is automatically ignored.
push_descriptor_set<'a>( &mut self, pipeline_bind_point: PipelineBindPoint, pipeline_layout: &PipelineLayout, set_num: u32, descriptor_writes: impl IntoIterator<Item = &'a WriteDescriptorSet>, )1208     pub unsafe fn push_descriptor_set<'a>(
1209         &mut self,
1210         pipeline_bind_point: PipelineBindPoint,
1211         pipeline_layout: &PipelineLayout,
1212         set_num: u32,
1213         descriptor_writes: impl IntoIterator<Item = &'a WriteDescriptorSet>,
1214     ) {
1215         debug_assert!(self.device.enabled_extensions().khr_push_descriptor);
1216 
1217         let (infos, mut writes): (SmallVec<[_; 8]>, SmallVec<[_; 8]>) = descriptor_writes
1218             .into_iter()
1219             .map(|write| {
1220                 let binding =
1221                     &pipeline_layout.set_layouts()[set_num as usize].bindings()[&write.binding()];
1222 
1223                 (
1224                     write.to_vulkan_info(binding.descriptor_type),
1225                     write.to_vulkan(ash::vk::DescriptorSet::null(), binding.descriptor_type),
1226                 )
1227             })
1228             .unzip();
1229 
1230         if writes.is_empty() {
1231             return;
1232         }
1233 
1234         // Set the info pointers separately.
1235         for (info, write) in infos.iter().zip(writes.iter_mut()) {
1236             match info {
1237                 DescriptorWriteInfo::Image(info) => {
1238                     write.descriptor_count = info.len() as u32;
1239                     write.p_image_info = info.as_ptr();
1240                 }
1241                 DescriptorWriteInfo::Buffer(info) => {
1242                     write.descriptor_count = info.len() as u32;
1243                     write.p_buffer_info = info.as_ptr();
1244                 }
1245                 DescriptorWriteInfo::BufferView(info) => {
1246                     write.descriptor_count = info.len() as u32;
1247                     write.p_texel_buffer_view = info.as_ptr();
1248                 }
1249             }
1250 
1251             debug_assert!(write.descriptor_count != 0);
1252         }
1253 
1254         let fns = self.device.fns();
1255 
1256         (fns.khr_push_descriptor.cmd_push_descriptor_set_khr)(
1257             self.handle,
1258             pipeline_bind_point.into(),
1259             pipeline_layout.handle(),
1260             set_num,
1261             writes.len() as u32,
1262             writes.as_ptr(),
1263         );
1264     }
1265 }
1266 
1267 /// Prototype for a `vkCmdBindVertexBuffers`.
1268 #[derive(Debug)]
1269 pub struct UnsafeCommandBufferBuilderBindVertexBuffer {
1270     // Raw handles of the buffers to bind.
1271     pub raw_buffers: SmallVec<[ash::vk::Buffer; 4]>,
1272     // Raw offsets of the buffers to bind.
1273     pub offsets: SmallVec<[DeviceSize; 4]>,
1274 }
1275 
1276 impl UnsafeCommandBufferBuilderBindVertexBuffer {
1277     /// Builds a new empty list.
1278     #[inline]
new() -> UnsafeCommandBufferBuilderBindVertexBuffer1279     pub fn new() -> UnsafeCommandBufferBuilderBindVertexBuffer {
1280         UnsafeCommandBufferBuilderBindVertexBuffer {
1281             raw_buffers: SmallVec::new(),
1282             offsets: SmallVec::new(),
1283         }
1284     }
1285 
1286     /// Adds a buffer to the list.
1287     #[inline]
add(&mut self, subbuffer: &Subbuffer<[u8]>)1288     pub fn add(&mut self, subbuffer: &Subbuffer<[u8]>) {
1289         debug_assert!(subbuffer
1290             .buffer()
1291             .usage()
1292             .intersects(BufferUsage::VERTEX_BUFFER));
1293         self.raw_buffers.push(subbuffer.buffer().handle());
1294         self.offsets.push(subbuffer.offset());
1295     }
1296 }
1297 
1298 #[derive(Clone, Debug)]
1299 pub(in super::super) enum BindPushError {
1300     DescriptorSetUpdateError(DescriptorSetUpdateError),
1301 
1302     RequirementNotMet {
1303         required_for: &'static str,
1304         requires_one_of: RequiresOneOf,
1305     },
1306 
1307     /// The element of `descriptor_sets` being bound to a slot is not compatible with the
1308     /// corresponding slot in `pipeline_layout`.
1309     DescriptorSetNotCompatible {
1310         set_num: u32,
1311     },
1312 
1313     /// The descriptor set number being pushed is not defined for push descriptor sets in the
1314     /// pipeline layout.
1315     DescriptorSetNotPush {
1316         set_num: u32,
1317     },
1318 
1319     /// The highest descriptor set slot being bound is greater than the number of sets in
1320     /// `pipeline_layout`.
1321     DescriptorSetOutOfRange {
1322         set_num: u32,
1323         pipeline_layout_set_count: u32,
1324     },
1325 
1326     /// In an element of `descriptor_sets`, the number of provided dynamic offsets does not match
1327     /// the number required by the descriptor set.
1328     DynamicOffsetCountMismatch {
1329         set_num: u32,
1330         provided_count: usize,
1331         required_count: usize,
1332     },
1333 
1334     /// In an element of `descriptor_sets`, a provided dynamic offset
1335     /// is not a multiple of the value of the [`min_uniform_buffer_offset_alignment`] or
1336     /// [`min_storage_buffer_offset_alignment`]  property.
1337     ///
1338     /// min_uniform_buffer_offset_alignment: crate::device::Properties::min_uniform_buffer_offset_alignment
1339     /// min_storage_buffer_offset_alignment: crate::device::Properties::min_storage_buffer_offset_alignment
1340     DynamicOffsetNotAligned {
1341         set_num: u32,
1342         binding_num: u32,
1343         index: u32,
1344         offset: u32,
1345         required_alignment: DeviceAlignment,
1346     },
1347 
1348     /// In an element of `descriptor_sets`, a provided dynamic offset, when added to the end of the
1349     /// buffer range bound to the descriptor set, is greater than the size of the buffer.
1350     DynamicOffsetOutOfBufferBounds {
1351         set_num: u32,
1352         binding_num: u32,
1353         index: u32,
1354         offset: u32,
1355         range_end: DeviceSize,
1356         buffer_size: DeviceSize,
1357     },
1358 
1359     /// An index buffer is missing the `index_buffer` usage.
1360     IndexBufferMissingUsage,
1361 
1362     /// The `max_vertex_input_bindings` limit has been exceeded.
1363     MaxVertexInputBindingsExceeded {
1364         _binding_count: u32,
1365         _max: u32,
1366     },
1367 
1368     /// The queue family doesn't allow this operation.
1369     NotSupportedByQueueFamily,
1370 
1371     /// The newly set pipeline has color attachment formats that do not match the
1372     /// previously used pipeline.
1373     PreviousPipelineColorAttachmentFormatMismatch,
1374 
1375     /// The newly set pipeline has a depth attachment format that does not match the
1376     /// previously used pipeline.
1377     PreviousPipelineDepthAttachmentFormatMismatch,
1378 
1379     /// The newly set pipeline has a stencil attachment format that does not match the
1380     /// previously used pipeline.
1381     PreviousPipelineStencilAttachmentFormatMismatch,
1382 
1383     /// The push constants data to be written at an offset is not included in any push constant
1384     /// range of the pipeline layout.
1385     PushConstantsDataOutOfRange {
1386         offset: u32,
1387     },
1388 
1389     /// The push constants offset is not a multiple of 4.
1390     PushConstantsOffsetNotAligned,
1391 
1392     /// The push constants size is not a multiple of 4.
1393     PushConstantsSizeNotAligned,
1394 
1395     /// A vertex buffer is missing the `vertex_buffer` usage.
1396     VertexBufferMissingUsage,
1397 }
1398 
1399 impl error::Error for BindPushError {
source(&self) -> Option<&(dyn error::Error + 'static)>1400     fn source(&self) -> Option<&(dyn error::Error + 'static)> {
1401         match self {
1402             BindPushError::DescriptorSetUpdateError(err) => Some(err),
1403             _ => None,
1404         }
1405     }
1406 }
1407 
1408 impl Display for BindPushError {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>1409     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
1410         match self {
1411             Self::RequirementNotMet {
1412                 required_for,
1413                 requires_one_of,
1414             } => write!(
1415                 f,
1416                 "a requirement was not met for: {}; requires one of: {}",
1417                 required_for, requires_one_of,
1418             ),
1419             Self::DescriptorSetUpdateError(_) => write!(f, "a DescriptorSetUpdateError"),
1420             Self::DescriptorSetNotCompatible { set_num } => write!(
1421                 f,
1422                 "the element of `descriptor_sets` being bound to slot {} is not compatible with \
1423                 the corresponding slot in `pipeline_layout`",
1424                 set_num,
1425             ),
1426             Self::DescriptorSetNotPush { set_num } => write!(
1427                 f,
1428                 "the descriptor set number being pushed ({}) is not defined for push descriptor \
1429                 sets in the pipeline layout",
1430                 set_num,
1431             ),
1432             Self::DescriptorSetOutOfRange {
1433                 set_num,
1434                 pipeline_layout_set_count,
1435             } => write!(
1436                 f,
1437                 "the highest descriptor set slot being bound ({}) is greater than the number of \
1438                 sets in `pipeline_layout` ({})",
1439                 set_num, pipeline_layout_set_count,
1440             ),
1441             Self::DynamicOffsetCountMismatch {
1442                 set_num,
1443                 provided_count,
1444                 required_count,
1445             } => write!(
1446                 f,
1447                 "in the element of `descriptor_sets` being bound to slot {}, the number of \
1448                 provided dynamic offsets ({}) does not match the number required by the \
1449                 descriptor set ({})",
1450                 set_num, provided_count, required_count,
1451             ),
1452             Self::DynamicOffsetNotAligned {
1453                 set_num,
1454                 binding_num,
1455                 index,
1456                 offset,
1457                 required_alignment,
1458             } => write!(
1459                 f,
1460                 "in the element of `descriptor_sets` being bound to slot {}, the dynamic offset \
1461                 provided for binding {} index {} ({}) is not a multiple of the value of the \
1462                 `min_uniform_buffer_offset_alignment` or `min_storage_buffer_offset_alignment` \
1463                 property ({:?})",
1464                 set_num, binding_num, index, offset, required_alignment,
1465             ),
1466             Self::DynamicOffsetOutOfBufferBounds {
1467                 set_num,
1468                 binding_num,
1469                 index,
1470                 offset,
1471                 range_end,
1472                 buffer_size,
1473             } => write!(
1474                 f,
1475                 "in the element of `descriptor_sets` being bound to slot {}, the dynamic offset \
1476                 provided for binding {} index {} ({}), when added to the end of the buffer range \
1477                 bound to the descriptor set ({}), is greater than the size of the buffer ({})",
1478                 set_num, binding_num, index, offset, range_end, buffer_size,
1479             ),
1480             Self::IndexBufferMissingUsage => {
1481                 write!(f, "an index buffer is missing the `index_buffer` usage")
1482             }
1483             Self::MaxVertexInputBindingsExceeded { .. } => {
1484                 write!(f, "the `max_vertex_input_bindings` limit has been exceeded")
1485             }
1486             Self::NotSupportedByQueueFamily => {
1487                 write!(f, "the queue family doesn't allow this operation")
1488             }
1489             Self::PreviousPipelineColorAttachmentFormatMismatch => write!(
1490                 f,
1491                 "the newly set pipeline has color attachment formats that do not match the \
1492                 previously used pipeline",
1493             ),
1494             Self::PreviousPipelineDepthAttachmentFormatMismatch => write!(
1495                 f,
1496                 "the newly set pipeline has a depth attachment format that does not match the \
1497                 previously used pipeline",
1498             ),
1499             Self::PreviousPipelineStencilAttachmentFormatMismatch => write!(
1500                 f,
1501                 "the newly set pipeline has a stencil attachment format that does not match the \
1502                 previously used pipeline",
1503             ),
1504             Self::PushConstantsDataOutOfRange { offset } => write!(
1505                 f,
1506                 "the push constants data to be written at offset {} is not included in any push \
1507                 constant range of the pipeline layout",
1508                 offset,
1509             ),
1510             Self::PushConstantsOffsetNotAligned => {
1511                 write!(f, "the push constants offset is not a multiple of 4")
1512             }
1513             Self::PushConstantsSizeNotAligned => {
1514                 write!(f, "the push constants size is not a multiple of 4")
1515             }
1516             Self::VertexBufferMissingUsage => {
1517                 write!(f, "a vertex buffer is missing the `vertex_buffer` usage")
1518             }
1519         }
1520     }
1521 }
1522 
1523 impl From<DescriptorSetUpdateError> for BindPushError {
from(err: DescriptorSetUpdateError) -> Self1524     fn from(err: DescriptorSetUpdateError) -> Self {
1525         Self::DescriptorSetUpdateError(err)
1526     }
1527 }
1528 
1529 impl From<RequirementNotMet> for BindPushError {
from(err: RequirementNotMet) -> Self1530     fn from(err: RequirementNotMet) -> Self {
1531         Self::RequirementNotMet {
1532             required_for: err.required_for,
1533             requires_one_of: err.requires_one_of,
1534         }
1535     }
1536 }
1537