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::{view::BufferView, BufferUsage, Subbuffer},
12     command_buffer::{
13         allocator::CommandBufferAllocator,
14         auto::{RenderPassState, RenderPassStateType},
15         synced::{Command, Resource, SyncCommandBufferBuilder, SyncCommandBufferBuilderError},
16         sys::UnsafeCommandBufferBuilder,
17         AutoCommandBufferBuilder, DispatchIndirectCommand, DrawIndexedIndirectCommand,
18         DrawIndirectCommand, ResourceInCommand, ResourceUseRef, SubpassContents,
19     },
20     descriptor_set::{layout::DescriptorType, DescriptorBindingResources},
21     device::{DeviceOwned, QueueFlags},
22     format::{Format, FormatFeatures},
23     image::{
24         view::ImageViewType, ImageAccess, ImageAspects, ImageSubresourceRange, ImageViewAbstract,
25         SampleCount,
26     },
27     pipeline::{
28         graphics::{
29             input_assembly::{PrimitiveTopology, PrimitiveTopologyClass},
30             render_pass::PipelineRenderPassType,
31             vertex_input::VertexInputRate,
32         },
33         DynamicState, GraphicsPipeline, PartialStateMode, Pipeline, PipelineLayout,
34     },
35     sampler::{Sampler, SamplerImageViewIncompatibleError},
36     shader::{DescriptorBindingRequirements, ShaderScalarType, ShaderStage},
37     sync::{AccessFlags, PipelineMemoryAccess, PipelineStages},
38     DeviceSize, RequiresOneOf, VulkanObject,
39 };
40 use std::{
41     cmp::min,
42     error::Error,
43     fmt::{Display, Error as FmtError, Formatter},
44     mem::size_of,
45     ops::Range,
46     sync::Arc,
47 };
48 
49 /// # Commands to execute a bound pipeline.
50 ///
51 /// Dispatch commands require a compute queue, draw commands require a graphics queue.
52 impl<L, A> AutoCommandBufferBuilder<L, A>
53 where
54     A: CommandBufferAllocator,
55 {
56     /// Perform a single compute operation using a compute pipeline.
57     ///
58     /// A compute pipeline must have been bound using
59     /// [`bind_pipeline_compute`](Self::bind_pipeline_compute). Any resources used by the compute
60     /// pipeline, such as descriptor sets, must have been set beforehand.
dispatch( &mut self, group_counts: [u32; 3], ) -> Result<&mut Self, PipelineExecutionError>61     pub fn dispatch(
62         &mut self,
63         group_counts: [u32; 3],
64     ) -> Result<&mut Self, PipelineExecutionError> {
65         self.validate_dispatch(group_counts)?;
66 
67         unsafe {
68             self.inner.dispatch(group_counts)?;
69         }
70 
71         Ok(self)
72     }
73 
validate_dispatch(&self, group_counts: [u32; 3]) -> Result<(), PipelineExecutionError>74     fn validate_dispatch(&self, group_counts: [u32; 3]) -> Result<(), PipelineExecutionError> {
75         let queue_family_properties = self.queue_family_properties();
76 
77         // VUID-vkCmdDispatch-commandBuffer-cmdpool
78         if !queue_family_properties
79             .queue_flags
80             .intersects(QueueFlags::COMPUTE)
81         {
82             return Err(PipelineExecutionError::NotSupportedByQueueFamily);
83         }
84 
85         // VUID-vkCmdDispatch-renderpass
86         if self.render_pass_state.is_some() {
87             return Err(PipelineExecutionError::ForbiddenInsideRenderPass);
88         }
89 
90         // VUID-vkCmdDispatch-None-02700
91         let pipeline = match self.state().pipeline_compute() {
92             Some(x) => x.as_ref(),
93             None => return Err(PipelineExecutionError::PipelineNotBound),
94         };
95 
96         self.validate_pipeline_descriptor_sets(pipeline)?;
97         self.validate_pipeline_push_constants(pipeline.layout())?;
98 
99         let max = self
100             .device()
101             .physical_device()
102             .properties()
103             .max_compute_work_group_count;
104 
105         // VUID-vkCmdDispatch-groupCountX-00386
106         // VUID-vkCmdDispatch-groupCountY-00387
107         // VUID-vkCmdDispatch-groupCountZ-00388
108         if group_counts[0] > max[0] || group_counts[1] > max[1] || group_counts[2] > max[2] {
109             return Err(PipelineExecutionError::MaxComputeWorkGroupCountExceeded {
110                 requested: group_counts,
111                 max,
112             });
113         }
114 
115         Ok(())
116     }
117 
118     /// Perform multiple compute operations using a compute pipeline. One dispatch is performed for
119     /// each [`DispatchIndirectCommand`] struct in `indirect_buffer`.
120     ///
121     /// A compute pipeline must have been bound using
122     /// [`bind_pipeline_compute`](Self::bind_pipeline_compute). Any resources used by the compute
123     /// pipeline, such as descriptor sets, must have been set beforehand.
dispatch_indirect( &mut self, indirect_buffer: Subbuffer<[DispatchIndirectCommand]>, ) -> Result<&mut Self, PipelineExecutionError>124     pub fn dispatch_indirect(
125         &mut self,
126         indirect_buffer: Subbuffer<[DispatchIndirectCommand]>,
127     ) -> Result<&mut Self, PipelineExecutionError> {
128         self.validate_dispatch_indirect(indirect_buffer.as_bytes())?;
129 
130         unsafe {
131             self.inner.dispatch_indirect(indirect_buffer)?;
132         }
133 
134         Ok(self)
135     }
136 
validate_dispatch_indirect( &self, indirect_buffer: &Subbuffer<[u8]>, ) -> Result<(), PipelineExecutionError>137     fn validate_dispatch_indirect(
138         &self,
139         indirect_buffer: &Subbuffer<[u8]>,
140     ) -> Result<(), PipelineExecutionError> {
141         let queue_family_properties = self.queue_family_properties();
142 
143         // VUID-vkCmdDispatchIndirect-commandBuffer-cmdpool
144         if !queue_family_properties
145             .queue_flags
146             .intersects(QueueFlags::COMPUTE)
147         {
148             return Err(PipelineExecutionError::NotSupportedByQueueFamily);
149         }
150 
151         // VUID-vkCmdDispatchIndirect-renderpass
152         if self.render_pass_state.is_some() {
153             return Err(PipelineExecutionError::ForbiddenInsideRenderPass);
154         }
155 
156         // VUID-vkCmdDispatchIndirect-None-02700
157         let pipeline = match self.state().pipeline_compute() {
158             Some(x) => x.as_ref(),
159             None => return Err(PipelineExecutionError::PipelineNotBound),
160         };
161 
162         self.validate_pipeline_descriptor_sets(pipeline)?;
163         self.validate_pipeline_push_constants(pipeline.layout())?;
164         self.validate_indirect_buffer(indirect_buffer)?;
165 
166         Ok(())
167     }
168 
169     /// Perform a single draw operation using a graphics pipeline.
170     ///
171     /// The parameters specify the first vertex and the number of vertices to draw, and the first
172     /// instance and number of instances. For non-instanced drawing, specify `instance_count` as 1
173     /// and `first_instance` as 0.
174     ///
175     /// A graphics pipeline must have been bound using
176     /// [`bind_pipeline_graphics`](Self::bind_pipeline_graphics). Any resources used by the graphics
177     /// pipeline, such as descriptor sets, vertex buffers and dynamic state, must have been set
178     /// beforehand. If the bound graphics pipeline uses vertex buffers, then the provided vertex and
179     /// instance ranges must be in range of the bound vertex buffers.
draw( &mut self, vertex_count: u32, instance_count: u32, first_vertex: u32, first_instance: u32, ) -> Result<&mut Self, PipelineExecutionError>180     pub fn draw(
181         &mut self,
182         vertex_count: u32,
183         instance_count: u32,
184         first_vertex: u32,
185         first_instance: u32,
186     ) -> Result<&mut Self, PipelineExecutionError> {
187         self.validate_draw(vertex_count, instance_count, first_vertex, first_instance)?;
188 
189         unsafe {
190             self.inner
191                 .draw(vertex_count, instance_count, first_vertex, first_instance)?;
192         }
193 
194         if let RenderPassStateType::BeginRendering(state) =
195             &mut self.render_pass_state.as_mut().unwrap().render_pass
196         {
197             state.pipeline_used = true;
198         }
199 
200         Ok(self)
201     }
202 
validate_draw( &self, vertex_count: u32, instance_count: u32, first_vertex: u32, first_instance: u32, ) -> Result<(), PipelineExecutionError>203     fn validate_draw(
204         &self,
205         vertex_count: u32,
206         instance_count: u32,
207         first_vertex: u32,
208         first_instance: u32,
209     ) -> Result<(), PipelineExecutionError> {
210         // VUID-vkCmdDraw-renderpass
211         let render_pass_state = self
212             .render_pass_state
213             .as_ref()
214             .ok_or(PipelineExecutionError::ForbiddenOutsideRenderPass)?;
215 
216         // VUID-vkCmdDraw-None-02700
217         let pipeline = match self.state().pipeline_graphics() {
218             Some(x) => x.as_ref(),
219             None => return Err(PipelineExecutionError::PipelineNotBound),
220         };
221 
222         self.validate_pipeline_descriptor_sets(pipeline)?;
223         self.validate_pipeline_push_constants(pipeline.layout())?;
224         self.validate_pipeline_graphics_dynamic_state(pipeline)?;
225         self.validate_pipeline_graphics_render_pass(pipeline, render_pass_state)?;
226         self.validate_pipeline_graphics_vertex_buffers(
227             pipeline,
228             Some((first_vertex, vertex_count)),
229             Some((first_instance, instance_count)),
230         )?;
231 
232         Ok(())
233     }
234 
235     /// Perform multiple draw operations using a graphics pipeline.
236     ///
237     /// One draw is performed for each [`DrawIndirectCommand`] struct in `indirect_buffer`.
238     /// The maximum number of draw commands in the buffer is limited by the
239     /// [`max_draw_indirect_count`](crate::device::Properties::max_draw_indirect_count) limit.
240     /// This limit is 1 unless the
241     /// [`multi_draw_indirect`](crate::device::Features::multi_draw_indirect) feature has been
242     /// enabled.
243     ///
244     /// A graphics pipeline must have been bound using
245     /// [`bind_pipeline_graphics`](Self::bind_pipeline_graphics). Any resources used by the graphics
246     /// pipeline, such as descriptor sets, vertex buffers and dynamic state, must have been set
247     /// beforehand. If the bound graphics pipeline uses vertex buffers, then the vertex and instance
248     /// ranges of each `DrawIndirectCommand` in the indirect buffer must be in range of the bound
249     /// vertex buffers.
draw_indirect( &mut self, indirect_buffer: Subbuffer<[DrawIndirectCommand]>, ) -> Result<&mut Self, PipelineExecutionError>250     pub fn draw_indirect(
251         &mut self,
252         indirect_buffer: Subbuffer<[DrawIndirectCommand]>,
253     ) -> Result<&mut Self, PipelineExecutionError> {
254         let draw_count = indirect_buffer.len() as u32;
255         let stride = size_of::<DrawIndirectCommand>() as u32;
256         self.validate_draw_indirect(indirect_buffer.as_bytes(), draw_count, stride)?;
257 
258         unsafe {
259             self.inner
260                 .draw_indirect(indirect_buffer, draw_count, stride)?;
261         }
262 
263         if let RenderPassStateType::BeginRendering(state) =
264             &mut self.render_pass_state.as_mut().unwrap().render_pass
265         {
266             state.pipeline_used = true;
267         }
268 
269         Ok(self)
270     }
271 
validate_draw_indirect( &self, indirect_buffer: &Subbuffer<[u8]>, draw_count: u32, _stride: u32, ) -> Result<(), PipelineExecutionError>272     fn validate_draw_indirect(
273         &self,
274         indirect_buffer: &Subbuffer<[u8]>,
275         draw_count: u32,
276         _stride: u32,
277     ) -> Result<(), PipelineExecutionError> {
278         // VUID-vkCmdDrawIndirect-renderpass
279         let render_pass_state = self
280             .render_pass_state
281             .as_ref()
282             .ok_or(PipelineExecutionError::ForbiddenOutsideRenderPass)?;
283 
284         // VUID-vkCmdDrawIndirect-None-02700
285         let pipeline = match self.state().pipeline_graphics() {
286             Some(x) => x.as_ref(),
287             None => return Err(PipelineExecutionError::PipelineNotBound),
288         };
289 
290         self.validate_pipeline_descriptor_sets(pipeline)?;
291         self.validate_pipeline_push_constants(pipeline.layout())?;
292         self.validate_pipeline_graphics_dynamic_state(pipeline)?;
293         self.validate_pipeline_graphics_render_pass(pipeline, render_pass_state)?;
294         self.validate_pipeline_graphics_vertex_buffers(pipeline, None, None)?;
295 
296         self.validate_indirect_buffer(indirect_buffer)?;
297 
298         // VUID-vkCmdDrawIndirect-drawCount-02718
299         if draw_count > 1 && !self.device().enabled_features().multi_draw_indirect {
300             return Err(PipelineExecutionError::RequirementNotMet {
301                 required_for: "`draw_count` is greater than `1`",
302                 requires_one_of: RequiresOneOf {
303                     features: &["multi_draw_indirect"],
304                     ..Default::default()
305                 },
306             });
307         }
308 
309         let max = self
310             .device()
311             .physical_device()
312             .properties()
313             .max_draw_indirect_count;
314 
315         // VUID-vkCmdDrawIndirect-drawCount-02719
316         if draw_count > max {
317             return Err(PipelineExecutionError::MaxDrawIndirectCountExceeded {
318                 provided: draw_count,
319                 max,
320             });
321         }
322 
323         Ok(())
324     }
325 
326     /// Perform a single draw operation using a graphics pipeline, using an index buffer.
327     ///
328     /// The parameters specify the first index and the number of indices in the index buffer that
329     /// should be used, and the first instance and number of instances. For non-instanced drawing,
330     /// specify `instance_count` as 1 and `first_instance` as 0. The `vertex_offset` is a constant
331     /// value that should be added to each index in the index buffer to produce the final vertex
332     /// number to be used.
333     ///
334     /// An index buffer must have been bound using
335     /// [`bind_index_buffer`](Self::bind_index_buffer), and the provided index range must be in
336     /// range of the bound index buffer.
337     ///
338     /// A graphics pipeline must have been bound using
339     /// [`bind_pipeline_graphics`](Self::bind_pipeline_graphics). Any resources used by the graphics
340     /// pipeline, such as descriptor sets, vertex buffers and dynamic state, must have been set
341     /// beforehand. If the bound graphics pipeline uses vertex buffers, then the provided instance
342     /// range must be in range of the bound vertex buffers. The vertex indices in the index buffer
343     /// must be in range of the bound vertex buffers.
draw_indexed( &mut self, index_count: u32, instance_count: u32, first_index: u32, vertex_offset: i32, first_instance: u32, ) -> Result<&mut Self, PipelineExecutionError>344     pub fn draw_indexed(
345         &mut self,
346         index_count: u32,
347         instance_count: u32,
348         first_index: u32,
349         vertex_offset: i32,
350         first_instance: u32,
351     ) -> Result<&mut Self, PipelineExecutionError> {
352         self.validate_draw_indexed(
353             index_count,
354             instance_count,
355             first_index,
356             vertex_offset,
357             first_instance,
358         )?;
359 
360         unsafe {
361             self.inner.draw_indexed(
362                 index_count,
363                 instance_count,
364                 first_index,
365                 vertex_offset,
366                 first_instance,
367             )?;
368         }
369 
370         if let RenderPassStateType::BeginRendering(state) =
371             &mut self.render_pass_state.as_mut().unwrap().render_pass
372         {
373             state.pipeline_used = true;
374         }
375 
376         Ok(self)
377     }
378 
validate_draw_indexed( &self, index_count: u32, instance_count: u32, first_index: u32, _vertex_offset: i32, first_instance: u32, ) -> Result<(), PipelineExecutionError>379     fn validate_draw_indexed(
380         &self,
381         index_count: u32,
382         instance_count: u32,
383         first_index: u32,
384         _vertex_offset: i32,
385         first_instance: u32,
386     ) -> Result<(), PipelineExecutionError> {
387         // TODO: how to handle an index out of range of the vertex buffers?
388 
389         // VUID-vkCmdDrawIndexed-renderpass
390         let render_pass_state = self
391             .render_pass_state
392             .as_ref()
393             .ok_or(PipelineExecutionError::ForbiddenOutsideRenderPass)?;
394 
395         // VUID-vkCmdDrawIndexed-None-02700
396         let pipeline = match self.state().pipeline_graphics() {
397             Some(x) => x.as_ref(),
398             None => return Err(PipelineExecutionError::PipelineNotBound),
399         };
400 
401         self.validate_pipeline_descriptor_sets(pipeline)?;
402         self.validate_pipeline_push_constants(pipeline.layout())?;
403         self.validate_pipeline_graphics_dynamic_state(pipeline)?;
404         self.validate_pipeline_graphics_render_pass(pipeline, render_pass_state)?;
405         self.validate_pipeline_graphics_vertex_buffers(
406             pipeline,
407             None,
408             Some((first_instance, instance_count)),
409         )?;
410 
411         self.validate_index_buffer(Some((first_index, index_count)))?;
412 
413         Ok(())
414     }
415 
416     /// Perform multiple draw operations using a graphics pipeline, using an index buffer.
417     ///
418     /// One draw is performed for each [`DrawIndexedIndirectCommand`] struct in `indirect_buffer`.
419     /// The maximum number of draw commands in the buffer is limited by the
420     /// [`max_draw_indirect_count`](crate::device::Properties::max_draw_indirect_count) limit.
421     /// This limit is 1 unless the
422     /// [`multi_draw_indirect`](crate::device::Features::multi_draw_indirect) feature has been
423     /// enabled.
424     ///
425     /// An index buffer must have been bound using
426     /// [`bind_index_buffer`](Self::bind_index_buffer), and the index ranges of each
427     /// `DrawIndexedIndirectCommand` in the indirect buffer must be in range of the bound index
428     /// buffer.
429     ///
430     /// A graphics pipeline must have been bound using
431     /// [`bind_pipeline_graphics`](Self::bind_pipeline_graphics). Any resources used by the graphics
432     /// pipeline, such as descriptor sets, vertex buffers and dynamic state, must have been set
433     /// beforehand. If the bound graphics pipeline uses vertex buffers, then the instance ranges of
434     /// each `DrawIndexedIndirectCommand` in the indirect buffer must be in range of the bound
435     /// vertex buffers.
draw_indexed_indirect( &mut self, indirect_buffer: Subbuffer<[DrawIndexedIndirectCommand]>, ) -> Result<&mut Self, PipelineExecutionError>436     pub fn draw_indexed_indirect(
437         &mut self,
438         indirect_buffer: Subbuffer<[DrawIndexedIndirectCommand]>,
439     ) -> Result<&mut Self, PipelineExecutionError> {
440         let draw_count = indirect_buffer.len() as u32;
441         let stride = size_of::<DrawIndexedIndirectCommand>() as u32;
442         self.validate_draw_indexed_indirect(indirect_buffer.as_bytes(), draw_count, stride)?;
443 
444         unsafe {
445             self.inner
446                 .draw_indexed_indirect(indirect_buffer, draw_count, stride)?;
447         }
448 
449         if let RenderPassStateType::BeginRendering(state) =
450             &mut self.render_pass_state.as_mut().unwrap().render_pass
451         {
452             state.pipeline_used = true;
453         }
454 
455         Ok(self)
456     }
457 
validate_draw_indexed_indirect( &self, indirect_buffer: &Subbuffer<[u8]>, draw_count: u32, _stride: u32, ) -> Result<(), PipelineExecutionError>458     fn validate_draw_indexed_indirect(
459         &self,
460         indirect_buffer: &Subbuffer<[u8]>,
461         draw_count: u32,
462         _stride: u32,
463     ) -> Result<(), PipelineExecutionError> {
464         // VUID-vkCmdDrawIndexedIndirect-renderpass
465         let render_pass_state = self
466             .render_pass_state
467             .as_ref()
468             .ok_or(PipelineExecutionError::ForbiddenOutsideRenderPass)?;
469 
470         // VUID-vkCmdDrawIndexedIndirect-None-02700
471         let pipeline = match self.state().pipeline_graphics() {
472             Some(x) => x.as_ref(),
473             None => return Err(PipelineExecutionError::PipelineNotBound),
474         };
475 
476         self.validate_pipeline_descriptor_sets(pipeline)?;
477         self.validate_pipeline_push_constants(pipeline.layout())?;
478         self.validate_pipeline_graphics_dynamic_state(pipeline)?;
479         self.validate_pipeline_graphics_render_pass(pipeline, render_pass_state)?;
480         self.validate_pipeline_graphics_vertex_buffers(pipeline, None, None)?;
481 
482         self.validate_index_buffer(None)?;
483         self.validate_indirect_buffer(indirect_buffer)?;
484 
485         // VUID-vkCmdDrawIndexedIndirect-drawCount-02718
486         if draw_count > 1 && !self.device().enabled_features().multi_draw_indirect {
487             return Err(PipelineExecutionError::RequirementNotMet {
488                 required_for: "`draw_count` is greater than `1`",
489                 requires_one_of: RequiresOneOf {
490                     features: &["multi_draw_indirect"],
491                     ..Default::default()
492                 },
493             });
494         }
495 
496         let max = self
497             .device()
498             .physical_device()
499             .properties()
500             .max_draw_indirect_count;
501 
502         // VUID-vkCmdDrawIndexedIndirect-drawCount-02719
503         if draw_count > max {
504             return Err(PipelineExecutionError::MaxDrawIndirectCountExceeded {
505                 provided: draw_count,
506                 max,
507             });
508         }
509 
510         Ok(())
511     }
512 
validate_index_buffer( &self, indices: Option<(u32, u32)>, ) -> Result<(), PipelineExecutionError>513     fn validate_index_buffer(
514         &self,
515         indices: Option<(u32, u32)>,
516     ) -> Result<(), PipelineExecutionError> {
517         let current_state = self.state();
518 
519         // VUID?
520         let (index_buffer, index_type) = match current_state.index_buffer() {
521             Some(x) => x,
522             None => return Err(PipelineExecutionError::IndexBufferNotBound),
523         };
524 
525         if let Some((first_index, index_count)) = indices {
526             let max_index_count = (index_buffer.size() / index_type.size()) as u32;
527 
528             // // VUID-vkCmdDrawIndexed-firstIndex-04932
529             if first_index + index_count > max_index_count {
530                 return Err(PipelineExecutionError::IndexBufferRangeOutOfBounds {
531                     highest_index: first_index + index_count,
532                     max_index_count,
533                 });
534             }
535         }
536 
537         Ok(())
538     }
539 
validate_indirect_buffer( &self, buffer: &Subbuffer<[u8]>, ) -> Result<(), PipelineExecutionError>540     fn validate_indirect_buffer(
541         &self,
542         buffer: &Subbuffer<[u8]>,
543     ) -> Result<(), PipelineExecutionError> {
544         // VUID-vkCmdDispatchIndirect-commonparent
545         assert_eq!(self.device(), buffer.device());
546 
547         // VUID-vkCmdDispatchIndirect-buffer-02709
548         if !buffer
549             .buffer()
550             .usage()
551             .intersects(BufferUsage::INDIRECT_BUFFER)
552         {
553             return Err(PipelineExecutionError::IndirectBufferMissingUsage);
554         }
555 
556         // VUID-vkCmdDispatchIndirect-offset-02710
557         // TODO:
558 
559         Ok(())
560     }
561 
validate_pipeline_descriptor_sets<Pl: Pipeline>( &self, pipeline: &Pl, ) -> Result<(), PipelineExecutionError>562     fn validate_pipeline_descriptor_sets<Pl: Pipeline>(
563         &self,
564         pipeline: &Pl,
565     ) -> Result<(), PipelineExecutionError> {
566         fn validate_resources<T>(
567             set_num: u32,
568             binding_num: u32,
569             binding_reqs: &DescriptorBindingRequirements,
570             elements: &[Option<T>],
571             mut extra_check: impl FnMut(u32, &T) -> Result<(), DescriptorResourceInvalidError>,
572         ) -> Result<(), PipelineExecutionError> {
573             let elements_to_check = if let Some(descriptor_count) = binding_reqs.descriptor_count {
574                 // The shader has a fixed-sized array, so it will never access more than
575                 // the first `descriptor_count` elements.
576                 elements.get(..descriptor_count as usize).ok_or({
577                     // There are less than `descriptor_count` elements in `elements`
578                     PipelineExecutionError::DescriptorResourceInvalid {
579                         set_num,
580                         binding_num,
581                         index: elements.len() as u32,
582                         error: DescriptorResourceInvalidError::Missing,
583                     }
584                 })?
585             } else {
586                 // The shader has a runtime-sized array, so any element could potentially
587                 // be accessed. We must check them all.
588                 elements
589             };
590 
591             for (index, element) in elements_to_check.iter().enumerate() {
592                 let index = index as u32;
593 
594                 // VUID-vkCmdDispatch-None-02699
595                 let element = match element {
596                     Some(x) => x,
597                     None => {
598                         return Err(PipelineExecutionError::DescriptorResourceInvalid {
599                             set_num,
600                             binding_num,
601                             index,
602                             error: DescriptorResourceInvalidError::Missing,
603                         })
604                     }
605                 };
606 
607                 if let Err(error) = extra_check(index, element) {
608                     return Err(PipelineExecutionError::DescriptorResourceInvalid {
609                         set_num,
610                         binding_num,
611                         index,
612                         error,
613                     });
614                 }
615             }
616 
617             Ok(())
618         }
619 
620         if pipeline.num_used_descriptor_sets() == 0 {
621             return Ok(());
622         }
623 
624         let current_state = self.state();
625 
626         // VUID-vkCmdDispatch-None-02697
627         let bindings_pipeline_layout =
628             match current_state.descriptor_sets_pipeline_layout(pipeline.bind_point()) {
629                 Some(x) => x,
630                 None => return Err(PipelineExecutionError::PipelineLayoutNotCompatible),
631             };
632 
633         // VUID-vkCmdDispatch-None-02697
634         if !pipeline.layout().is_compatible_with(
635             bindings_pipeline_layout,
636             pipeline.num_used_descriptor_sets(),
637         ) {
638             return Err(PipelineExecutionError::PipelineLayoutNotCompatible);
639         }
640 
641         for (&(set_num, binding_num), binding_reqs) in pipeline.descriptor_binding_requirements() {
642             let layout_binding =
643                 &pipeline.layout().set_layouts()[set_num as usize].bindings()[&binding_num];
644 
645             let check_buffer =
646                 |_index: u32, (_buffer, _range): &(Subbuffer<[u8]>, Range<DeviceSize>)| Ok(());
647 
648             let check_buffer_view = |index: u32, buffer_view: &Arc<BufferView>| {
649                 for desc_reqs in (binding_reqs.descriptors.get(&Some(index)).into_iter())
650                     .chain(binding_reqs.descriptors.get(&None))
651                 {
652                     if layout_binding.descriptor_type == DescriptorType::StorageTexelBuffer {
653                         // VUID-vkCmdDispatch-OpTypeImage-06423
654                         if binding_reqs.image_format.is_none()
655                             && !desc_reqs.memory_write.is_empty()
656                             && !buffer_view
657                                 .format_features()
658                                 .intersects(FormatFeatures::STORAGE_WRITE_WITHOUT_FORMAT)
659                         {
660                             return Err(DescriptorResourceInvalidError::StorageWriteWithoutFormatNotSupported);
661                         }
662 
663                         // VUID-vkCmdDispatch-OpTypeImage-06424
664                         if binding_reqs.image_format.is_none()
665                             && !desc_reqs.memory_read.is_empty()
666                             && !buffer_view
667                                 .format_features()
668                                 .intersects(FormatFeatures::STORAGE_READ_WITHOUT_FORMAT)
669                         {
670                             return Err(DescriptorResourceInvalidError::StorageReadWithoutFormatNotSupported);
671                         }
672                     }
673                 }
674 
675                 Ok(())
676             };
677 
678             let check_image_view_common = |index: u32, image_view: &Arc<dyn ImageViewAbstract>| {
679                 for desc_reqs in (binding_reqs.descriptors.get(&Some(index)).into_iter())
680                     .chain(binding_reqs.descriptors.get(&None))
681                 {
682                     // VUID-vkCmdDispatch-None-02691
683                     if desc_reqs.storage_image_atomic
684                         && !image_view
685                             .format_features()
686                             .intersects(FormatFeatures::STORAGE_IMAGE_ATOMIC)
687                     {
688                         return Err(DescriptorResourceInvalidError::StorageImageAtomicNotSupported);
689                     }
690 
691                     if layout_binding.descriptor_type == DescriptorType::StorageImage {
692                         // VUID-vkCmdDispatch-OpTypeImage-06423
693                         if binding_reqs.image_format.is_none()
694                             && !desc_reqs.memory_write.is_empty()
695                             && !image_view
696                                 .format_features()
697                                 .intersects(FormatFeatures::STORAGE_WRITE_WITHOUT_FORMAT)
698                         {
699                             return Err(
700                             DescriptorResourceInvalidError::StorageWriteWithoutFormatNotSupported,
701                         );
702                         }
703 
704                         // VUID-vkCmdDispatch-OpTypeImage-06424
705                         if binding_reqs.image_format.is_none()
706                             && !desc_reqs.memory_read.is_empty()
707                             && !image_view
708                                 .format_features()
709                                 .intersects(FormatFeatures::STORAGE_READ_WITHOUT_FORMAT)
710                         {
711                             return Err(
712                             DescriptorResourceInvalidError::StorageReadWithoutFormatNotSupported,
713                         );
714                         }
715                     }
716                 }
717 
718                 /*
719                    Instruction/Sampler/Image View Validation
720                    https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap16.html#textures-input-validation
721                 */
722 
723                 // The SPIR-V Image Format is not compatible with the image view’s format.
724                 if let Some(format) = binding_reqs.image_format {
725                     if image_view.format() != Some(format) {
726                         return Err(DescriptorResourceInvalidError::ImageViewFormatMismatch {
727                             required: format,
728                             provided: image_view.format(),
729                         });
730                     }
731                 }
732 
733                 // Rules for viewType
734                 if let Some(image_view_type) = binding_reqs.image_view_type {
735                     if image_view.view_type() != image_view_type {
736                         return Err(DescriptorResourceInvalidError::ImageViewTypeMismatch {
737                             required: image_view_type,
738                             provided: image_view.view_type(),
739                         });
740                     }
741                 }
742 
743                 // - If the image was created with VkImageCreateInfo::samples equal to
744                 //   VK_SAMPLE_COUNT_1_BIT, the instruction must have MS = 0.
745                 // - If the image was created with VkImageCreateInfo::samples not equal to
746                 //   VK_SAMPLE_COUNT_1_BIT, the instruction must have MS = 1.
747                 if binding_reqs.image_multisampled
748                     != (image_view.image().samples() != SampleCount::Sample1)
749                 {
750                     return Err(
751                         DescriptorResourceInvalidError::ImageViewMultisampledMismatch {
752                             required: binding_reqs.image_multisampled,
753                             provided: image_view.image().samples() != SampleCount::Sample1,
754                         },
755                     );
756                 }
757 
758                 // - If the Sampled Type of the OpTypeImage does not match the numeric format of the
759                 //   image, as shown in the SPIR-V Sampled Type column of the
760                 //   Interpretation of Numeric Format table.
761                 // - If the signedness of any read or sample operation does not match the signedness of
762                 //   the image’s format.
763                 if let Some(scalar_type) = binding_reqs.image_scalar_type {
764                     let aspects = image_view.subresource_range().aspects;
765                     let view_scalar_type = ShaderScalarType::from(
766                         if aspects.intersects(
767                             ImageAspects::COLOR
768                                 | ImageAspects::PLANE_0
769                                 | ImageAspects::PLANE_1
770                                 | ImageAspects::PLANE_2,
771                         ) {
772                             image_view.format().unwrap().type_color().unwrap()
773                         } else if aspects.intersects(ImageAspects::DEPTH) {
774                             image_view.format().unwrap().type_depth().unwrap()
775                         } else if aspects.intersects(ImageAspects::STENCIL) {
776                             image_view.format().unwrap().type_stencil().unwrap()
777                         } else {
778                             // Per `ImageViewBuilder::aspects` and
779                             // VUID-VkDescriptorImageInfo-imageView-01976
780                             unreachable!()
781                         },
782                     );
783 
784                     if scalar_type != view_scalar_type {
785                         return Err(
786                             DescriptorResourceInvalidError::ImageViewScalarTypeMismatch {
787                                 required: scalar_type,
788                                 provided: view_scalar_type,
789                             },
790                         );
791                     }
792                 }
793 
794                 Ok(())
795             };
796 
797             let check_sampler_common = |index: u32, sampler: &Arc<Sampler>| {
798                 for desc_reqs in (binding_reqs.descriptors.get(&Some(index)).into_iter())
799                     .chain(binding_reqs.descriptors.get(&None))
800                 {
801                     // VUID-vkCmdDispatch-None-02703
802                     // VUID-vkCmdDispatch-None-02704
803                     if desc_reqs.sampler_no_unnormalized_coordinates
804                         && sampler.unnormalized_coordinates()
805                     {
806                         return Err(
807                         DescriptorResourceInvalidError::SamplerUnnormalizedCoordinatesNotAllowed,
808                     );
809                     }
810 
811                     // - OpImageFetch, OpImageSparseFetch, OpImage*Gather, and OpImageSparse*Gather must not
812                     //   be used with a sampler that enables sampler Y′CBCR conversion.
813                     // - The ConstOffset and Offset operands must not be used with a sampler that enables
814                     //   sampler Y′CBCR conversion.
815                     if desc_reqs.sampler_no_ycbcr_conversion
816                         && sampler.sampler_ycbcr_conversion().is_some()
817                     {
818                         return Err(
819                             DescriptorResourceInvalidError::SamplerYcbcrConversionNotAllowed,
820                         );
821                     }
822 
823                     /*
824                         Instruction/Sampler/Image View Validation
825                         https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap16.html#textures-input-validation
826                     */
827 
828                     // - The SPIR-V instruction is one of the OpImage*Dref* instructions and the sampler
829                     //   compareEnable is VK_FALSE
830                     // - The SPIR-V instruction is not one of the OpImage*Dref* instructions and the sampler
831                     //   compareEnable is VK_TRUE
832                     if desc_reqs.sampler_compare != sampler.compare().is_some() {
833                         return Err(DescriptorResourceInvalidError::SamplerCompareMismatch {
834                             required: desc_reqs.sampler_compare,
835                             provided: sampler.compare().is_some(),
836                         });
837                     }
838                 }
839 
840                 Ok(())
841             };
842 
843             let check_image_view = |index: u32, image_view: &Arc<dyn ImageViewAbstract>| {
844                 check_image_view_common(index, image_view)?;
845 
846                 if let Some(sampler) = layout_binding.immutable_samplers.get(index as usize) {
847                     check_sampler_common(index, sampler)?;
848                 }
849 
850                 Ok(())
851             };
852 
853             let check_image_view_sampler =
854                 |index: u32, (image_view, sampler): &(Arc<dyn ImageViewAbstract>, Arc<Sampler>)| {
855                     check_image_view_common(index, image_view)?;
856                     check_sampler_common(index, sampler)?;
857 
858                     Ok(())
859                 };
860 
861             let check_sampler = |index: u32, sampler: &Arc<Sampler>| {
862                 check_sampler_common(index, sampler)?;
863 
864                 for desc_reqs in (binding_reqs.descriptors.get(&Some(index)).into_iter())
865                     .chain(binding_reqs.descriptors.get(&None))
866                 {
867                     // Check sampler-image compatibility. Only done for separate samplers;
868                     // combined image samplers are checked when updating the descriptor set.
869 
870                     // If the image view isn't actually present in the resources, then just skip it.
871                     // It will be caught later by check_resources.
872                     let iter = desc_reqs.sampler_with_images.iter().filter_map(|id| {
873                         current_state
874                             .descriptor_set(pipeline.bind_point(), id.set)
875                             .and_then(|set| set.resources().binding(id.binding))
876                             .and_then(|res| match res {
877                                 DescriptorBindingResources::ImageView(elements) => elements
878                                     .get(id.index as usize)
879                                     .and_then(|opt| opt.as_ref().map(|opt| (id, opt))),
880                                 _ => None,
881                             })
882                     });
883 
884                     for (id, image_view) in iter {
885                         if let Err(error) = sampler.check_can_sample(image_view.as_ref()) {
886                             return Err(
887                                 DescriptorResourceInvalidError::SamplerImageViewIncompatible {
888                                     image_view_set_num: id.set,
889                                     image_view_binding_num: id.binding,
890                                     image_view_index: id.index,
891                                     error,
892                                 },
893                             );
894                         }
895                     }
896                 }
897 
898                 Ok(())
899             };
900 
901             let check_none = |index: u32, _: &()| {
902                 if let Some(sampler) = layout_binding.immutable_samplers.get(index as usize) {
903                     check_sampler(index, sampler)?;
904                 }
905 
906                 Ok(())
907             };
908 
909             let set_resources = match current_state.descriptor_set(pipeline.bind_point(), set_num) {
910                 Some(x) => x.resources(),
911                 None => return Err(PipelineExecutionError::DescriptorSetNotBound { set_num }),
912             };
913 
914             let binding_resources = set_resources.binding(binding_num).unwrap();
915 
916             match binding_resources {
917                 DescriptorBindingResources::None(elements) => {
918                     validate_resources(set_num, binding_num, binding_reqs, elements, check_none)?;
919                 }
920                 DescriptorBindingResources::Buffer(elements) => {
921                     validate_resources(set_num, binding_num, binding_reqs, elements, check_buffer)?;
922                 }
923                 DescriptorBindingResources::BufferView(elements) => {
924                     validate_resources(
925                         set_num,
926                         binding_num,
927                         binding_reqs,
928                         elements,
929                         check_buffer_view,
930                     )?;
931                 }
932                 DescriptorBindingResources::ImageView(elements) => {
933                     validate_resources(
934                         set_num,
935                         binding_num,
936                         binding_reqs,
937                         elements,
938                         check_image_view,
939                     )?;
940                 }
941                 DescriptorBindingResources::ImageViewSampler(elements) => {
942                     validate_resources(
943                         set_num,
944                         binding_num,
945                         binding_reqs,
946                         elements,
947                         check_image_view_sampler,
948                     )?;
949                 }
950                 DescriptorBindingResources::Sampler(elements) => {
951                     validate_resources(
952                         set_num,
953                         binding_num,
954                         binding_reqs,
955                         elements,
956                         check_sampler,
957                     )?;
958                 }
959             }
960         }
961 
962         Ok(())
963     }
964 
validate_pipeline_push_constants( &self, pipeline_layout: &PipelineLayout, ) -> Result<(), PipelineExecutionError>965     fn validate_pipeline_push_constants(
966         &self,
967         pipeline_layout: &PipelineLayout,
968     ) -> Result<(), PipelineExecutionError> {
969         if pipeline_layout.push_constant_ranges().is_empty()
970             || self.device().enabled_features().maintenance4
971         {
972             return Ok(());
973         }
974 
975         let current_state = self.state();
976 
977         // VUID-vkCmdDispatch-maintenance4-06425
978         let constants_pipeline_layout = match current_state.push_constants_pipeline_layout() {
979             Some(x) => x,
980             None => return Err(PipelineExecutionError::PushConstantsMissing),
981         };
982 
983         // VUID-vkCmdDispatch-maintenance4-06425
984         if pipeline_layout.handle() != constants_pipeline_layout.handle()
985             && pipeline_layout.push_constant_ranges()
986                 != constants_pipeline_layout.push_constant_ranges()
987         {
988             return Err(PipelineExecutionError::PushConstantsNotCompatible);
989         }
990 
991         let set_bytes = current_state.push_constants();
992 
993         // VUID-vkCmdDispatch-maintenance4-06425
994         if !pipeline_layout
995             .push_constant_ranges()
996             .iter()
997             .all(|pc_range| set_bytes.contains(pc_range.offset..pc_range.offset + pc_range.size))
998         {
999             return Err(PipelineExecutionError::PushConstantsMissing);
1000         }
1001 
1002         Ok(())
1003     }
1004 
validate_pipeline_graphics_dynamic_state( &self, pipeline: &GraphicsPipeline, ) -> Result<(), PipelineExecutionError>1005     fn validate_pipeline_graphics_dynamic_state(
1006         &self,
1007         pipeline: &GraphicsPipeline,
1008     ) -> Result<(), PipelineExecutionError> {
1009         let device = pipeline.device();
1010         let current_state = self.state();
1011 
1012         // VUID-vkCmdDraw-commandBuffer-02701
1013         for dynamic_state in pipeline
1014             .dynamic_states()
1015             .filter(|(_, d)| *d)
1016             .map(|(s, _)| s)
1017         {
1018             match dynamic_state {
1019                 DynamicState::BlendConstants => {
1020                     // VUID?
1021                     if current_state.blend_constants().is_none() {
1022                         return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1023                     }
1024                 }
1025                 DynamicState::ColorWriteEnable => {
1026                     // VUID-vkCmdDraw-attachmentCount-06667
1027                     let enables = if let Some(enables) = current_state.color_write_enable() {
1028                         enables
1029                     } else {
1030                         return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1031                     };
1032 
1033                     // VUID-vkCmdDraw-attachmentCount-06667
1034                     if enables.len() < pipeline.color_blend_state().unwrap().attachments.len() {
1035                         return Err(
1036                             PipelineExecutionError::DynamicColorWriteEnableNotEnoughValues {
1037                                 color_write_enable_count: enables.len() as u32,
1038                                 attachment_count: pipeline
1039                                     .color_blend_state()
1040                                     .unwrap()
1041                                     .attachments
1042                                     .len() as u32,
1043                             },
1044                         );
1045                     }
1046                 }
1047                 DynamicState::CullMode => {
1048                     // VUID?
1049                     if current_state.cull_mode().is_none() {
1050                         return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1051                     }
1052                 }
1053                 DynamicState::DepthBias => {
1054                     // VUID?
1055                     if current_state.depth_bias().is_none() {
1056                         return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1057                     }
1058                 }
1059                 DynamicState::DepthBiasEnable => {
1060                     // VUID-vkCmdDraw-None-04877
1061                     if current_state.depth_bias_enable().is_none() {
1062                         return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1063                     }
1064                 }
1065                 DynamicState::DepthBounds => {
1066                     // VUID?
1067                     if current_state.depth_bounds().is_none() {
1068                         return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1069                     }
1070                 }
1071                 DynamicState::DepthBoundsTestEnable => {
1072                     // VUID?
1073                     if current_state.depth_bounds_test_enable().is_none() {
1074                         return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1075                     }
1076                 }
1077                 DynamicState::DepthCompareOp => {
1078                     // VUID?
1079                     if current_state.depth_compare_op().is_none() {
1080                         return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1081                     }
1082                 }
1083                 DynamicState::DepthTestEnable => {
1084                     // VUID?
1085                     if current_state.depth_test_enable().is_none() {
1086                         return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1087                     }
1088                 }
1089                 DynamicState::DepthWriteEnable => {
1090                     // VUID?
1091                     if current_state.depth_write_enable().is_none() {
1092                         return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1093                     }
1094 
1095                     // TODO: Check if the depth buffer is writable
1096                 }
1097                 DynamicState::DiscardRectangle => {
1098                     let discard_rectangle_count =
1099                         match pipeline.discard_rectangle_state().unwrap().rectangles {
1100                             PartialStateMode::Dynamic(count) => count,
1101                             _ => unreachable!(),
1102                         };
1103 
1104                     for num in 0..discard_rectangle_count {
1105                         // VUID?
1106                         if current_state.discard_rectangle(num).is_none() {
1107                             return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1108                         }
1109                     }
1110                 }
1111                 DynamicState::ExclusiveScissor => todo!(),
1112                 DynamicState::FragmentShadingRate => todo!(),
1113                 DynamicState::FrontFace => {
1114                     // VUID?
1115                     if current_state.front_face().is_none() {
1116                         return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1117                     }
1118                 }
1119                 DynamicState::LineStipple => {
1120                     // VUID?
1121                     if current_state.line_stipple().is_none() {
1122                         return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1123                     }
1124                 }
1125                 DynamicState::LineWidth => {
1126                     // VUID?
1127                     if current_state.line_width().is_none() {
1128                         return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1129                     }
1130                 }
1131                 DynamicState::LogicOp => {
1132                     // VUID-vkCmdDraw-logicOp-04878
1133                     if current_state.logic_op().is_none() {
1134                         return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1135                     }
1136                 }
1137                 DynamicState::PatchControlPoints => {
1138                     // VUID-vkCmdDraw-None-04875
1139                     if current_state.patch_control_points().is_none() {
1140                         return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1141                     }
1142                 }
1143                 DynamicState::PrimitiveRestartEnable => {
1144                     // VUID-vkCmdDraw-None-04879
1145                     let primitive_restart_enable =
1146                         if let Some(enable) = current_state.primitive_restart_enable() {
1147                             enable
1148                         } else {
1149                             return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1150                         };
1151 
1152                     if primitive_restart_enable {
1153                         let topology = match pipeline.input_assembly_state().topology {
1154                             PartialStateMode::Fixed(topology) => topology,
1155                             PartialStateMode::Dynamic(_) => {
1156                                 if let Some(topology) = current_state.primitive_topology() {
1157                                     topology
1158                                 } else {
1159                                     return Err(PipelineExecutionError::DynamicStateNotSet {
1160                                         dynamic_state: DynamicState::PrimitiveTopology,
1161                                     });
1162                                 }
1163                             }
1164                         };
1165 
1166                         match topology {
1167                             PrimitiveTopology::PointList
1168                             | PrimitiveTopology::LineList
1169                             | PrimitiveTopology::TriangleList
1170                             | PrimitiveTopology::LineListWithAdjacency
1171                             | PrimitiveTopology::TriangleListWithAdjacency => {
1172                                 // VUID?
1173                                 if !device.enabled_features().primitive_topology_list_restart {
1174                                     return Err(PipelineExecutionError::RequirementNotMet {
1175                                         required_for: "The bound pipeline sets \
1176                                             `DynamicState::PrimitiveRestartEnable` and the \
1177                                             current primitive topology is \
1178                                             `PrimitiveTopology::*List`",
1179                                         requires_one_of: RequiresOneOf {
1180                                             features: &["primitive_topology_list_restart"],
1181                                             ..Default::default()
1182                                         },
1183                                     });
1184                                 }
1185                             }
1186                             PrimitiveTopology::PatchList => {
1187                                 // VUID?
1188                                 if !device
1189                                     .enabled_features()
1190                                     .primitive_topology_patch_list_restart
1191                                 {
1192                                     return Err(PipelineExecutionError::RequirementNotMet {
1193                                         required_for: "The bound pipeline sets \
1194                                             `DynamicState::PrimitiveRestartEnable` and the \
1195                                             current primitive topology is \
1196                                             `PrimitiveTopology::PatchList`",
1197                                         requires_one_of: RequiresOneOf {
1198                                             features: &["primitive_topology_patch_list_restart"],
1199                                             ..Default::default()
1200                                         },
1201                                     });
1202                                 }
1203                             }
1204                             _ => (),
1205                         }
1206                     }
1207                 }
1208                 DynamicState::PrimitiveTopology => {
1209                     // VUID-vkCmdDraw-primitiveTopology-03420
1210                     let topology = if let Some(topology) = current_state.primitive_topology() {
1211                         topology
1212                     } else {
1213                         return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1214                     };
1215 
1216                     if pipeline.shader(ShaderStage::TessellationControl).is_some() {
1217                         // VUID?
1218                         if !matches!(topology, PrimitiveTopology::PatchList) {
1219                             return Err(PipelineExecutionError::DynamicPrimitiveTopologyInvalid {
1220                                 topology,
1221                             });
1222                         }
1223                     } else {
1224                         // VUID?
1225                         if matches!(topology, PrimitiveTopology::PatchList) {
1226                             return Err(PipelineExecutionError::DynamicPrimitiveTopologyInvalid {
1227                                 topology,
1228                             });
1229                         }
1230                     }
1231 
1232                     let required_topology_class = match pipeline.input_assembly_state().topology {
1233                         PartialStateMode::Dynamic(topology_class) => topology_class,
1234                         _ => unreachable!(),
1235                     };
1236 
1237                     // VUID-vkCmdDraw-primitiveTopology-03420
1238                     if topology.class() != required_topology_class {
1239                         return Err(
1240                             PipelineExecutionError::DynamicPrimitiveTopologyClassMismatch {
1241                                 provided_class: topology.class(),
1242                                 required_class: required_topology_class,
1243                             },
1244                         );
1245                     }
1246 
1247                     // TODO: check that the topology matches the geometry shader
1248                 }
1249                 DynamicState::RasterizerDiscardEnable => {
1250                     // VUID-vkCmdDraw-None-04876
1251                     if current_state.rasterizer_discard_enable().is_none() {
1252                         return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1253                     }
1254                 }
1255                 DynamicState::RayTracingPipelineStackSize => unreachable!(
1256                     "RayTracingPipelineStackSize dynamic state should not occur on a graphics pipeline"
1257                 ),
1258                 DynamicState::SampleLocations => todo!(),
1259                 DynamicState::Scissor => {
1260                     for num in 0..pipeline.viewport_state().unwrap().count().unwrap() {
1261                         // VUID?
1262                         if current_state.scissor(num).is_none() {
1263                             return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1264                         }
1265                     }
1266                 }
1267                 DynamicState::ScissorWithCount => {
1268                     // VUID-vkCmdDraw-scissorCount-03418
1269                     // VUID-vkCmdDraw-viewportCount-03419
1270                     let scissor_count = if let Some(scissors) = current_state.scissor_with_count() {
1271                         scissors.len() as u32
1272                     } else {
1273                         return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1274                     };
1275 
1276                     // Check if the counts match, but only if the viewport count is fixed.
1277                     // If the viewport count is also dynamic, then the
1278                     // DynamicState::ViewportWithCount match arm will handle it.
1279                     if let Some(viewport_count) = pipeline.viewport_state().unwrap().count() {
1280                         // VUID-vkCmdDraw-scissorCount-03418
1281                         if viewport_count != scissor_count {
1282                             return Err(
1283                                 PipelineExecutionError::DynamicViewportScissorCountMismatch {
1284                                     viewport_count,
1285                                     scissor_count,
1286                                 },
1287                             );
1288                         }
1289                     }
1290                 }
1291                 DynamicState::StencilCompareMask => {
1292                     let state = current_state.stencil_compare_mask();
1293 
1294                     // VUID?
1295                     if state.front.is_none() || state.back.is_none() {
1296                         return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1297                     }
1298                 }
1299                 DynamicState::StencilOp => {
1300                     let state = current_state.stencil_op();
1301 
1302                     // VUID?
1303                     if state.front.is_none() || state.back.is_none() {
1304                         return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1305                     }
1306                 }
1307                 DynamicState::StencilReference => {
1308                     let state = current_state.stencil_reference();
1309 
1310                     // VUID?
1311                     if state.front.is_none() || state.back.is_none() {
1312                         return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1313                     }
1314                 }
1315                 DynamicState::StencilTestEnable => {
1316                     // VUID?
1317                     if current_state.stencil_test_enable().is_none() {
1318                         return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1319                     }
1320 
1321                     // TODO: Check if the stencil buffer is writable
1322                 }
1323                 DynamicState::StencilWriteMask => {
1324                     let state = current_state.stencil_write_mask();
1325 
1326                     // VUID?
1327                     if state.front.is_none() || state.back.is_none() {
1328                         return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1329                     }
1330                 }
1331                 DynamicState::VertexInput => todo!(),
1332                 DynamicState::VertexInputBindingStride => todo!(),
1333                 DynamicState::Viewport => {
1334                     for num in 0..pipeline.viewport_state().unwrap().count().unwrap() {
1335                         // VUID?
1336                         if current_state.viewport(num).is_none() {
1337                             return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1338                         }
1339                     }
1340                 }
1341                 DynamicState::ViewportCoarseSampleOrder => todo!(),
1342                 DynamicState::ViewportShadingRatePalette => todo!(),
1343                 DynamicState::ViewportWithCount => {
1344                     // VUID-vkCmdDraw-viewportCount-03417
1345                     let viewport_count = if let Some(viewports) = current_state.viewport_with_count() {
1346                         viewports.len() as u32
1347                     } else {
1348                         return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1349                     };
1350 
1351                     let scissor_count = if let Some(scissor_count) =
1352                         pipeline.viewport_state().unwrap().count()
1353                     {
1354                         // The scissor count is fixed.
1355                         scissor_count
1356                     } else {
1357                         // VUID-vkCmdDraw-viewportCount-03419
1358                         // The scissor count is also dynamic.
1359                         if let Some(scissors) = current_state.scissor_with_count() {
1360                             scissors.len() as u32
1361                         } else {
1362                             return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
1363                         }
1364                     };
1365 
1366                     // VUID-vkCmdDraw-viewportCount-03417
1367                     // VUID-vkCmdDraw-viewportCount-03419
1368                     if viewport_count != scissor_count {
1369                         return Err(
1370                             PipelineExecutionError::DynamicViewportScissorCountMismatch {
1371                                 viewport_count,
1372                                 scissor_count,
1373                             },
1374                         );
1375                     }
1376 
1377                     // TODO: VUID-vkCmdDrawIndexed-primitiveFragmentShadingRateWithMultipleViewports-04552
1378                     // If the primitiveFragmentShadingRateWithMultipleViewports limit is not supported,
1379                     // the bound graphics pipeline was created with the
1380                     // VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT dynamic state enabled, and any of the
1381                     // shader stages of the bound graphics pipeline write to the PrimitiveShadingRateKHR
1382                     // built-in, then vkCmdSetViewportWithCountEXT must have been called in the current
1383                     // command buffer prior to this drawing command, and the viewportCount parameter of
1384                     // vkCmdSetViewportWithCountEXT must be 1
1385                 }
1386                 DynamicState::ViewportWScaling => todo!(),
1387                 DynamicState::TessellationDomainOrigin => todo!(),
1388                 DynamicState::DepthClampEnable => todo!(),
1389                 DynamicState::PolygonMode => todo!(),
1390                 DynamicState::RasterizationSamples => todo!(),
1391                 DynamicState::SampleMask => todo!(),
1392                 DynamicState::AlphaToCoverageEnable => todo!(),
1393                 DynamicState::AlphaToOneEnable => todo!(),
1394                 DynamicState::LogicOpEnable => todo!(),
1395                 DynamicState::ColorBlendEnable => todo!(),
1396                 DynamicState::ColorBlendEquation => todo!(),
1397                 DynamicState::ColorWriteMask => todo!(),
1398                 DynamicState::RasterizationStream => todo!(),
1399                 DynamicState::ConservativeRasterizationMode => todo!(),
1400                 DynamicState::ExtraPrimitiveOverestimationSize => todo!(),
1401                 DynamicState::DepthClipEnable => todo!(),
1402                 DynamicState::SampleLocationsEnable => todo!(),
1403                 DynamicState::ColorBlendAdvanced => todo!(),
1404                 DynamicState::ProvokingVertexMode => todo!(),
1405                 DynamicState::LineRasterizationMode => todo!(),
1406                 DynamicState::LineStippleEnable => todo!(),
1407                 DynamicState::DepthClipNegativeOneToOne => todo!(),
1408                 DynamicState::ViewportWScalingEnable => todo!(),
1409                 DynamicState::ViewportSwizzle => todo!(),
1410                 DynamicState::CoverageToColorEnable => todo!(),
1411                 DynamicState::CoverageToColorLocation => todo!(),
1412                 DynamicState::CoverageModulationMode => todo!(),
1413                 DynamicState::CoverageModulationTableEnable => todo!(),
1414                 DynamicState::CoverageModulationTable => todo!(),
1415                 DynamicState::ShadingRateImageEnable => todo!(),
1416                 DynamicState::RepresentativeFragmentTestEnable => todo!(),
1417                 DynamicState::CoverageReductionMode => todo!(),
1418             }
1419         }
1420 
1421         Ok(())
1422     }
1423 
validate_pipeline_graphics_render_pass( &self, pipeline: &GraphicsPipeline, render_pass_state: &RenderPassState, ) -> Result<(), PipelineExecutionError>1424     fn validate_pipeline_graphics_render_pass(
1425         &self,
1426         pipeline: &GraphicsPipeline,
1427         render_pass_state: &RenderPassState,
1428     ) -> Result<(), PipelineExecutionError> {
1429         // VUID?
1430         if render_pass_state.contents != SubpassContents::Inline {
1431             return Err(PipelineExecutionError::ForbiddenWithSubpassContents {
1432                 subpass_contents: render_pass_state.contents,
1433             });
1434         }
1435 
1436         match (&render_pass_state.render_pass, pipeline.render_pass()) {
1437             (
1438                 RenderPassStateType::BeginRenderPass(state),
1439                 PipelineRenderPassType::BeginRenderPass(pipeline_subpass),
1440             ) => {
1441                 // VUID-vkCmdDraw-renderPass-02684
1442                 if !pipeline_subpass
1443                     .render_pass()
1444                     .is_compatible_with(state.subpass.render_pass())
1445                 {
1446                     return Err(PipelineExecutionError::PipelineRenderPassNotCompatible);
1447                 }
1448 
1449                 // VUID-vkCmdDraw-subpass-02685
1450                 if pipeline_subpass.index() != state.subpass.index() {
1451                     return Err(PipelineExecutionError::PipelineSubpassMismatch {
1452                         pipeline: pipeline_subpass.index(),
1453                         current: state.subpass.index(),
1454                     });
1455                 }
1456             }
1457             (
1458                 RenderPassStateType::BeginRendering(current_rendering_info),
1459                 PipelineRenderPassType::BeginRendering(pipeline_rendering_info),
1460             ) => {
1461                 // VUID-vkCmdDraw-viewMask-06178
1462                 if pipeline_rendering_info.view_mask != render_pass_state.view_mask {
1463                     return Err(PipelineExecutionError::PipelineViewMaskMismatch {
1464                         pipeline_view_mask: pipeline_rendering_info.view_mask,
1465                         required_view_mask: render_pass_state.view_mask,
1466                     });
1467                 }
1468 
1469                 // VUID-vkCmdDraw-colorAttachmentCount-06179
1470                 if pipeline_rendering_info.color_attachment_formats.len()
1471                     != current_rendering_info.color_attachment_formats.len()
1472                 {
1473                     return Err(
1474                         PipelineExecutionError::PipelineColorAttachmentCountMismatch {
1475                             pipeline_count: pipeline_rendering_info.color_attachment_formats.len()
1476                                 as u32,
1477                             required_count: current_rendering_info.color_attachment_formats.len()
1478                                 as u32,
1479                         },
1480                     );
1481                 }
1482 
1483                 for (color_attachment_index, required_format, pipeline_format) in
1484                     current_rendering_info
1485                         .color_attachment_formats
1486                         .iter()
1487                         .zip(
1488                             pipeline_rendering_info
1489                                 .color_attachment_formats
1490                                 .iter()
1491                                 .copied(),
1492                         )
1493                         .enumerate()
1494                         .filter_map(|(i, (r, p))| r.map(|r| (i as u32, r, p)))
1495                 {
1496                     // VUID-vkCmdDraw-colorAttachmentCount-06180
1497                     if Some(required_format) != pipeline_format {
1498                         return Err(
1499                             PipelineExecutionError::PipelineColorAttachmentFormatMismatch {
1500                                 color_attachment_index,
1501                                 pipeline_format,
1502                                 required_format,
1503                             },
1504                         );
1505                     }
1506                 }
1507 
1508                 if let Some((required_format, pipeline_format)) = current_rendering_info
1509                     .depth_attachment_format
1510                     .map(|r| (r, pipeline_rendering_info.depth_attachment_format))
1511                 {
1512                     // VUID-vkCmdDraw-pDepthAttachment-06181
1513                     if Some(required_format) != pipeline_format {
1514                         return Err(
1515                             PipelineExecutionError::PipelineDepthAttachmentFormatMismatch {
1516                                 pipeline_format,
1517                                 required_format,
1518                             },
1519                         );
1520                     }
1521                 }
1522 
1523                 if let Some((required_format, pipeline_format)) = current_rendering_info
1524                     .stencil_attachment_format
1525                     .map(|r| (r, pipeline_rendering_info.stencil_attachment_format))
1526                 {
1527                     // VUID-vkCmdDraw-pStencilAttachment-06182
1528                     if Some(required_format) != pipeline_format {
1529                         return Err(
1530                             PipelineExecutionError::PipelineStencilAttachmentFormatMismatch {
1531                                 pipeline_format,
1532                                 required_format,
1533                             },
1534                         );
1535                     }
1536                 }
1537 
1538                 // VUID-vkCmdDraw-imageView-06172
1539                 // VUID-vkCmdDraw-imageView-06173
1540                 // VUID-vkCmdDraw-imageView-06174
1541                 // VUID-vkCmdDraw-imageView-06175
1542                 // VUID-vkCmdDraw-imageView-06176
1543                 // VUID-vkCmdDraw-imageView-06177
1544                 // TODO:
1545             }
1546             _ => return Err(PipelineExecutionError::PipelineRenderPassTypeMismatch),
1547         }
1548 
1549         // VUID-vkCmdDraw-None-02686
1550         // TODO:
1551 
1552         Ok(())
1553     }
1554 
validate_pipeline_graphics_vertex_buffers( &self, pipeline: &GraphicsPipeline, vertices: Option<(u32, u32)>, instances: Option<(u32, u32)>, ) -> Result<(), PipelineExecutionError>1555     fn validate_pipeline_graphics_vertex_buffers(
1556         &self,
1557         pipeline: &GraphicsPipeline,
1558         vertices: Option<(u32, u32)>,
1559         instances: Option<(u32, u32)>,
1560     ) -> Result<(), PipelineExecutionError> {
1561         let vertex_input = pipeline.vertex_input_state();
1562         let mut vertices_in_buffers: Option<u64> = None;
1563         let mut instances_in_buffers: Option<u64> = None;
1564         let current_state = self.state();
1565 
1566         for (&binding_num, binding_desc) in &vertex_input.bindings {
1567             // VUID-vkCmdDraw-None-04007
1568             let vertex_buffer = match current_state.vertex_buffer(binding_num) {
1569                 Some(x) => x,
1570                 None => return Err(PipelineExecutionError::VertexBufferNotBound { binding_num }),
1571             };
1572 
1573             let mut num_elements = vertex_buffer.size() / binding_desc.stride as u64;
1574 
1575             match binding_desc.input_rate {
1576                 VertexInputRate::Vertex => {
1577                     vertices_in_buffers = Some(if let Some(x) = vertices_in_buffers {
1578                         min(x, num_elements)
1579                     } else {
1580                         num_elements
1581                     });
1582                 }
1583                 VertexInputRate::Instance { divisor } => {
1584                     if divisor == 0 {
1585                         // A divisor of 0 means the same instance data is used for all instances,
1586                         // so we can draw any number of instances from a single element.
1587                         // The buffer must contain at least one element though.
1588                         if num_elements != 0 {
1589                             num_elements = u64::MAX;
1590                         }
1591                     } else {
1592                         // If divisor is e.g. 2, we use only half the amount of data from the source
1593                         // buffer, so the number of instances that can be drawn is twice as large.
1594                         num_elements = num_elements.saturating_mul(divisor as u64);
1595                     }
1596 
1597                     instances_in_buffers = Some(if let Some(x) = instances_in_buffers {
1598                         min(x, num_elements)
1599                     } else {
1600                         num_elements
1601                     });
1602                 }
1603             };
1604         }
1605 
1606         if let Some((first_vertex, vertex_count)) = vertices {
1607             let vertices_needed = first_vertex as u64 + vertex_count as u64;
1608 
1609             if let Some(vertices_in_buffers) = vertices_in_buffers {
1610                 // VUID-vkCmdDraw-None-02721
1611                 if vertices_needed > vertices_in_buffers {
1612                     return Err(PipelineExecutionError::VertexBufferVertexRangeOutOfBounds {
1613                         vertices_needed,
1614                         vertices_in_buffers,
1615                     });
1616                 }
1617             }
1618         }
1619 
1620         if let Some((first_instance, instance_count)) = instances {
1621             let instances_needed = first_instance as u64 + instance_count as u64;
1622 
1623             if let Some(instances_in_buffers) = instances_in_buffers {
1624                 // VUID-vkCmdDraw-None-02721
1625                 if instances_needed > instances_in_buffers {
1626                     return Err(
1627                         PipelineExecutionError::VertexBufferInstanceRangeOutOfBounds {
1628                             instances_needed,
1629                             instances_in_buffers,
1630                         },
1631                     );
1632                 }
1633             }
1634 
1635             let view_mask = match pipeline.render_pass() {
1636                 PipelineRenderPassType::BeginRenderPass(subpass) => {
1637                     subpass.render_pass().views_used()
1638                 }
1639                 PipelineRenderPassType::BeginRendering(rendering_info) => rendering_info.view_mask,
1640             };
1641 
1642             if view_mask != 0 {
1643                 let max = pipeline
1644                     .device()
1645                     .physical_device()
1646                     .properties()
1647                     .max_multiview_instance_index
1648                     .unwrap_or(0);
1649 
1650                 let highest_instance = instances_needed.saturating_sub(1);
1651 
1652                 // VUID-vkCmdDraw-maxMultiviewInstanceIndex-02688
1653                 if highest_instance > max as u64 {
1654                     return Err(PipelineExecutionError::MaxMultiviewInstanceIndexExceeded {
1655                         highest_instance,
1656                         max,
1657                     });
1658                 }
1659             }
1660         }
1661 
1662         Ok(())
1663     }
1664 }
1665 
1666 impl SyncCommandBufferBuilder {
1667     /// Calls `vkCmdDispatch` on the builder.
1668     #[inline]
dispatch( &mut self, group_counts: [u32; 3], ) -> Result<(), SyncCommandBufferBuilderError>1669     pub unsafe fn dispatch(
1670         &mut self,
1671         group_counts: [u32; 3],
1672     ) -> Result<(), SyncCommandBufferBuilderError> {
1673         struct Cmd {
1674             group_counts: [u32; 3],
1675         }
1676 
1677         impl Command for Cmd {
name(&self) -> &'static str1678             fn name(&self) -> &'static str {
1679                 "dispatch"
1680             }
1681 
send(&self, out: &mut UnsafeCommandBufferBuilder)1682             unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
1683                 out.dispatch(self.group_counts);
1684             }
1685         }
1686 
1687         let command_index = self.commands.len();
1688         let command_name = "dispatch";
1689         let pipeline = self
1690             .current_state
1691             .pipeline_compute
1692             .as_ref()
1693             .unwrap()
1694             .as_ref();
1695 
1696         let mut resources = Vec::new();
1697         self.add_descriptor_sets(&mut resources, command_index, command_name, pipeline);
1698 
1699         for resource in &resources {
1700             self.check_resource_conflicts(resource)?;
1701         }
1702 
1703         self.commands.push(Box::new(Cmd { group_counts }));
1704 
1705         for resource in resources {
1706             self.add_resource(resource);
1707         }
1708 
1709         Ok(())
1710     }
1711 
1712     /// Calls `vkCmdDispatchIndirect` on the builder.
1713     #[inline]
dispatch_indirect( &mut self, indirect_buffer: Subbuffer<[DispatchIndirectCommand]>, ) -> Result<(), SyncCommandBufferBuilderError>1714     pub unsafe fn dispatch_indirect(
1715         &mut self,
1716         indirect_buffer: Subbuffer<[DispatchIndirectCommand]>,
1717     ) -> Result<(), SyncCommandBufferBuilderError> {
1718         struct Cmd {
1719             indirect_buffer: Subbuffer<[DispatchIndirectCommand]>,
1720         }
1721 
1722         impl Command for Cmd {
1723             fn name(&self) -> &'static str {
1724                 "dispatch_indirect"
1725             }
1726 
1727             unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
1728                 out.dispatch_indirect(&self.indirect_buffer);
1729             }
1730         }
1731 
1732         let command_index = self.commands.len();
1733         let command_name = "dispatch_indirect";
1734         let pipeline = self
1735             .current_state
1736             .pipeline_compute
1737             .as_ref()
1738             .unwrap()
1739             .as_ref();
1740 
1741         let mut resources = Vec::new();
1742         self.add_descriptor_sets(&mut resources, command_index, command_name, pipeline);
1743         self.add_indirect_buffer(
1744             &mut resources,
1745             command_index,
1746             command_name,
1747             indirect_buffer.as_bytes(),
1748         );
1749 
1750         for resource in &resources {
1751             self.check_resource_conflicts(resource)?;
1752         }
1753 
1754         self.commands.push(Box::new(Cmd { indirect_buffer }));
1755 
1756         for resource in resources {
1757             self.add_resource(resource);
1758         }
1759 
1760         Ok(())
1761     }
1762 
1763     /// Calls `vkCmdDraw` on the builder.
1764     #[inline]
draw( &mut self, vertex_count: u32, instance_count: u32, first_vertex: u32, first_instance: u32, ) -> Result<(), SyncCommandBufferBuilderError>1765     pub unsafe fn draw(
1766         &mut self,
1767         vertex_count: u32,
1768         instance_count: u32,
1769         first_vertex: u32,
1770         first_instance: u32,
1771     ) -> Result<(), SyncCommandBufferBuilderError> {
1772         struct Cmd {
1773             vertex_count: u32,
1774             instance_count: u32,
1775             first_vertex: u32,
1776             first_instance: u32,
1777         }
1778 
1779         impl Command for Cmd {
1780             fn name(&self) -> &'static str {
1781                 "draw"
1782             }
1783 
1784             unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
1785                 out.draw(
1786                     self.vertex_count,
1787                     self.instance_count,
1788                     self.first_vertex,
1789                     self.first_instance,
1790                 );
1791             }
1792         }
1793 
1794         let command_index = self.commands.len();
1795         let command_name = "draw";
1796         let pipeline = self
1797             .current_state
1798             .pipeline_graphics
1799             .as_ref()
1800             .unwrap()
1801             .as_ref();
1802 
1803         let mut resources = Vec::new();
1804         self.add_descriptor_sets(&mut resources, command_index, command_name, pipeline);
1805         self.add_vertex_buffers(&mut resources, command_index, command_name, pipeline);
1806 
1807         for resource in &resources {
1808             self.check_resource_conflicts(resource)?;
1809         }
1810 
1811         self.commands.push(Box::new(Cmd {
1812             vertex_count,
1813             instance_count,
1814             first_vertex,
1815             first_instance,
1816         }));
1817 
1818         for resource in resources {
1819             self.add_resource(resource);
1820         }
1821 
1822         Ok(())
1823     }
1824 
1825     /// Calls `vkCmdDrawIndexed` on the builder.
1826     #[inline]
draw_indexed( &mut self, index_count: u32, instance_count: u32, first_index: u32, vertex_offset: i32, first_instance: u32, ) -> Result<(), SyncCommandBufferBuilderError>1827     pub unsafe fn draw_indexed(
1828         &mut self,
1829         index_count: u32,
1830         instance_count: u32,
1831         first_index: u32,
1832         vertex_offset: i32,
1833         first_instance: u32,
1834     ) -> Result<(), SyncCommandBufferBuilderError> {
1835         struct Cmd {
1836             index_count: u32,
1837             instance_count: u32,
1838             first_index: u32,
1839             vertex_offset: i32,
1840             first_instance: u32,
1841         }
1842 
1843         impl Command for Cmd {
1844             fn name(&self) -> &'static str {
1845                 "draw_indexed"
1846             }
1847 
1848             unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
1849                 out.draw_indexed(
1850                     self.index_count,
1851                     self.instance_count,
1852                     self.first_index,
1853                     self.vertex_offset,
1854                     self.first_instance,
1855                 );
1856             }
1857         }
1858 
1859         let command_index = self.commands.len();
1860         let command_name = "draw_indexed";
1861         let pipeline = self
1862             .current_state
1863             .pipeline_graphics
1864             .as_ref()
1865             .unwrap()
1866             .as_ref();
1867 
1868         let mut resources = Vec::new();
1869         self.add_descriptor_sets(&mut resources, command_index, command_name, pipeline);
1870         self.add_vertex_buffers(&mut resources, command_index, command_name, pipeline);
1871         self.add_index_buffer(&mut resources, command_index, command_name);
1872 
1873         for resource in &resources {
1874             self.check_resource_conflicts(resource)?;
1875         }
1876 
1877         self.commands.push(Box::new(Cmd {
1878             index_count,
1879             instance_count,
1880             first_index,
1881             vertex_offset,
1882             first_instance,
1883         }));
1884 
1885         for resource in resources {
1886             self.add_resource(resource);
1887         }
1888 
1889         Ok(())
1890     }
1891 
1892     /// Calls `vkCmdDrawIndirect` on the builder.
1893     #[inline]
draw_indirect( &mut self, indirect_buffer: Subbuffer<[DrawIndirectCommand]>, draw_count: u32, stride: u32, ) -> Result<(), SyncCommandBufferBuilderError>1894     pub unsafe fn draw_indirect(
1895         &mut self,
1896         indirect_buffer: Subbuffer<[DrawIndirectCommand]>,
1897         draw_count: u32,
1898         stride: u32,
1899     ) -> Result<(), SyncCommandBufferBuilderError> {
1900         struct Cmd {
1901             indirect_buffer: Subbuffer<[DrawIndirectCommand]>,
1902             draw_count: u32,
1903             stride: u32,
1904         }
1905 
1906         impl Command for Cmd {
1907             fn name(&self) -> &'static str {
1908                 "draw_indirect"
1909             }
1910 
1911             unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
1912                 out.draw_indirect(&self.indirect_buffer, self.draw_count, self.stride);
1913             }
1914         }
1915 
1916         let command_index = self.commands.len();
1917         let command_name = "draw_indirect";
1918         let pipeline = self
1919             .current_state
1920             .pipeline_graphics
1921             .as_ref()
1922             .unwrap()
1923             .as_ref();
1924 
1925         let mut resources = Vec::new();
1926         self.add_descriptor_sets(&mut resources, command_index, command_name, pipeline);
1927         self.add_vertex_buffers(&mut resources, command_index, command_name, pipeline);
1928         self.add_indirect_buffer(
1929             &mut resources,
1930             command_index,
1931             command_name,
1932             indirect_buffer.as_bytes(),
1933         );
1934 
1935         for resource in &resources {
1936             self.check_resource_conflicts(resource)?;
1937         }
1938 
1939         self.commands.push(Box::new(Cmd {
1940             indirect_buffer,
1941             draw_count,
1942             stride,
1943         }));
1944 
1945         for resource in resources {
1946             self.add_resource(resource);
1947         }
1948 
1949         Ok(())
1950     }
1951 
1952     /// Calls `vkCmdDrawIndexedIndirect` on the builder.
1953     #[inline]
draw_indexed_indirect( &mut self, indirect_buffer: Subbuffer<[DrawIndexedIndirectCommand]>, draw_count: u32, stride: u32, ) -> Result<(), SyncCommandBufferBuilderError>1954     pub unsafe fn draw_indexed_indirect(
1955         &mut self,
1956         indirect_buffer: Subbuffer<[DrawIndexedIndirectCommand]>,
1957         draw_count: u32,
1958         stride: u32,
1959     ) -> Result<(), SyncCommandBufferBuilderError> {
1960         struct Cmd {
1961             indirect_buffer: Subbuffer<[DrawIndexedIndirectCommand]>,
1962             draw_count: u32,
1963             stride: u32,
1964         }
1965 
1966         impl Command for Cmd {
1967             fn name(&self) -> &'static str {
1968                 "draw_indexed_indirect"
1969             }
1970 
1971             unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
1972                 out.draw_indexed_indirect(&self.indirect_buffer, self.draw_count, self.stride);
1973             }
1974         }
1975 
1976         let command_index = self.commands.len();
1977         let command_name = "draw_indexed_indirect";
1978         let pipeline = self
1979             .current_state
1980             .pipeline_graphics
1981             .as_ref()
1982             .unwrap()
1983             .as_ref();
1984 
1985         let mut resources = Vec::new();
1986         self.add_descriptor_sets(&mut resources, command_index, command_name, pipeline);
1987         self.add_vertex_buffers(&mut resources, command_index, command_name, pipeline);
1988         self.add_index_buffer(&mut resources, command_index, command_name);
1989         self.add_indirect_buffer(
1990             &mut resources,
1991             command_index,
1992             command_name,
1993             indirect_buffer.as_bytes(),
1994         );
1995 
1996         for resource in &resources {
1997             self.check_resource_conflicts(resource)?;
1998         }
1999 
2000         self.commands.push(Box::new(Cmd {
2001             indirect_buffer,
2002             draw_count,
2003             stride,
2004         }));
2005 
2006         for resource in resources {
2007             self.add_resource(resource);
2008         }
2009 
2010         Ok(())
2011     }
2012 
add_descriptor_sets<Pl: Pipeline>( &self, resources: &mut Vec<(ResourceUseRef, Resource)>, command_index: usize, command_name: &'static str, pipeline: &Pl, )2013     fn add_descriptor_sets<Pl: Pipeline>(
2014         &self,
2015         resources: &mut Vec<(ResourceUseRef, Resource)>,
2016         command_index: usize,
2017         command_name: &'static str,
2018         pipeline: &Pl,
2019     ) {
2020         let descriptor_sets_state = match self
2021             .current_state
2022             .descriptor_sets
2023             .get(&pipeline.bind_point())
2024         {
2025             Some(x) => x,
2026             None => return,
2027         };
2028 
2029         for (&(set, binding), binding_reqs) in pipeline.descriptor_binding_requirements() {
2030             // TODO: Can things be refactored so that the pipeline layout isn't needed at all?
2031             let descriptor_type = descriptor_sets_state.pipeline_layout.set_layouts()[set as usize]
2032                 .bindings()[&binding]
2033                 .descriptor_type;
2034 
2035             let (access_read, access_write) = match descriptor_type {
2036                 DescriptorType::Sampler => continue,
2037                 DescriptorType::InputAttachment => {
2038                     // FIXME: This is tricky. Since we read from the input attachment
2039                     // and this input attachment is being written in an earlier pass,
2040                     // vulkano will think that it needs to put a pipeline barrier and will
2041                     // return a `Conflict` error. For now as a work-around we simply ignore
2042                     // input attachments.
2043                     continue;
2044                 }
2045                 DescriptorType::CombinedImageSampler
2046                 | DescriptorType::SampledImage
2047                 | DescriptorType::UniformTexelBuffer => (Some(AccessFlags::SHADER_READ), None),
2048                 DescriptorType::StorageImage
2049                 | DescriptorType::StorageTexelBuffer
2050                 | DescriptorType::StorageBuffer
2051                 | DescriptorType::StorageBufferDynamic => (
2052                     Some(AccessFlags::SHADER_READ),
2053                     Some(AccessFlags::SHADER_WRITE),
2054                 ),
2055                 DescriptorType::UniformBuffer | DescriptorType::UniformBufferDynamic => {
2056                     (Some(AccessFlags::UNIFORM_READ), None)
2057                 }
2058             };
2059 
2060             let memory_iter = move |index: u32| {
2061                 let mut stages_read = PipelineStages::empty();
2062                 let mut stages_write = PipelineStages::empty();
2063 
2064                 for desc_reqs in (binding_reqs.descriptors.get(&Some(index)).into_iter())
2065                     .chain(binding_reqs.descriptors.get(&None))
2066                 {
2067                     stages_read |= desc_reqs.memory_read.into();
2068                     stages_write |= desc_reqs.memory_write.into();
2069                 }
2070 
2071                 let memory_read = (!stages_read.is_empty()).then(|| PipelineMemoryAccess {
2072                     stages: stages_read,
2073                     access: access_read.unwrap(),
2074                     exclusive: false,
2075                 });
2076                 let memory_write = (!stages_write.is_empty()).then(|| PipelineMemoryAccess {
2077                     stages: stages_write,
2078                     access: access_write.unwrap(),
2079                     exclusive: true,
2080                 });
2081 
2082                 [memory_read, memory_write].into_iter().flatten()
2083             };
2084             let buffer_resource =
2085                 |(index, buffer, range): (u32, Subbuffer<[u8]>, Range<DeviceSize>)| {
2086                     memory_iter(index).map(move |memory| {
2087                         (
2088                             ResourceUseRef {
2089                                 command_index,
2090                                 command_name,
2091                                 resource_in_command: ResourceInCommand::DescriptorSet {
2092                                     set,
2093                                     binding,
2094                                     index,
2095                                 },
2096                                 secondary_use_ref: None,
2097                             },
2098                             Resource::Buffer {
2099                                 buffer: buffer.clone(),
2100                                 range: range.clone(),
2101                                 memory,
2102                             },
2103                         )
2104                     })
2105                 };
2106             let image_resource = |(index, image, subresource_range): (
2107                 u32,
2108                 Arc<dyn ImageAccess>,
2109                 ImageSubresourceRange,
2110             )| {
2111                 let layout = image
2112                     .descriptor_layouts()
2113                     .expect("descriptor_layouts must return Some when used in an image view")
2114                     .layout_for(descriptor_type);
2115 
2116                 memory_iter(index).map(move |memory| {
2117                     (
2118                         ResourceUseRef {
2119                             command_index,
2120                             command_name,
2121                             resource_in_command: ResourceInCommand::DescriptorSet {
2122                                 set,
2123                                 binding,
2124                                 index,
2125                             },
2126                             secondary_use_ref: None,
2127                         },
2128                         Resource::Image {
2129                             image: image.clone(),
2130                             subresource_range: subresource_range.clone(),
2131                             memory,
2132                             start_layout: layout,
2133                             end_layout: layout,
2134                         },
2135                     )
2136                 })
2137             };
2138 
2139             let descriptor_set_state = &descriptor_sets_state.descriptor_sets[&set];
2140 
2141             match descriptor_set_state.resources().binding(binding).unwrap() {
2142                 DescriptorBindingResources::None(_) => continue,
2143                 DescriptorBindingResources::Buffer(elements) => {
2144                     if matches!(
2145                         descriptor_type,
2146                         DescriptorType::UniformBufferDynamic | DescriptorType::StorageBufferDynamic
2147                     ) {
2148                         let dynamic_offsets = descriptor_set_state.dynamic_offsets();
2149                         resources.extend(
2150                             (elements.iter().enumerate())
2151                                 .filter_map(|(index, element)| {
2152                                     element.as_ref().map(|(buffer, range)| {
2153                                         let dynamic_offset = dynamic_offsets[index] as DeviceSize;
2154 
2155                                         (
2156                                             index as u32,
2157                                             buffer.clone(),
2158                                             dynamic_offset + range.start
2159                                                 ..dynamic_offset + range.end,
2160                                         )
2161                                     })
2162                                 })
2163                                 .flat_map(buffer_resource),
2164                         );
2165                     } else {
2166                         resources.extend(
2167                             (elements.iter().enumerate())
2168                                 .filter_map(|(index, element)| {
2169                                     element.as_ref().map(|(buffer, range)| {
2170                                         (index as u32, buffer.clone(), range.clone())
2171                                     })
2172                                 })
2173                                 .flat_map(buffer_resource),
2174                         );
2175                     }
2176                 }
2177                 DescriptorBindingResources::BufferView(elements) => {
2178                     resources.extend(
2179                         (elements.iter().enumerate())
2180                             .filter_map(|(index, element)| {
2181                                 element.as_ref().map(|buffer_view| {
2182                                     (
2183                                         index as u32,
2184                                         buffer_view.buffer().clone(),
2185                                         buffer_view.range(),
2186                                     )
2187                                 })
2188                             })
2189                             .flat_map(buffer_resource),
2190                     );
2191                 }
2192                 DescriptorBindingResources::ImageView(elements) => {
2193                     resources.extend(
2194                         (elements.iter().enumerate())
2195                             .filter_map(|(index, element)| {
2196                                 element.as_ref().map(|image_view| {
2197                                     (
2198                                         index as u32,
2199                                         image_view.image(),
2200                                         image_view.subresource_range().clone(),
2201                                     )
2202                                 })
2203                             })
2204                             .flat_map(image_resource),
2205                     );
2206                 }
2207                 DescriptorBindingResources::ImageViewSampler(elements) => {
2208                     resources.extend(
2209                         (elements.iter().enumerate())
2210                             .filter_map(|(index, element)| {
2211                                 element.as_ref().map(|(image_view, _)| {
2212                                     (
2213                                         index as u32,
2214                                         image_view.image(),
2215                                         image_view.subresource_range().clone(),
2216                                     )
2217                                 })
2218                             })
2219                             .flat_map(image_resource),
2220                     );
2221                 }
2222                 DescriptorBindingResources::Sampler(_) => (),
2223             }
2224         }
2225     }
2226 
add_vertex_buffers( &self, resources: &mut Vec<(ResourceUseRef, Resource)>, command_index: usize, command_name: &'static str, pipeline: &GraphicsPipeline, )2227     fn add_vertex_buffers(
2228         &self,
2229         resources: &mut Vec<(ResourceUseRef, Resource)>,
2230         command_index: usize,
2231         command_name: &'static str,
2232         pipeline: &GraphicsPipeline,
2233     ) {
2234         resources.extend(
2235             pipeline
2236                 .vertex_input_state()
2237                 .bindings
2238                 .iter()
2239                 .map(|(&binding, _)| {
2240                     let vertex_buffer = &self.current_state.vertex_buffers[&binding];
2241                     (
2242                         ResourceUseRef {
2243                             command_index,
2244                             command_name,
2245                             resource_in_command: ResourceInCommand::VertexBuffer { binding },
2246                             secondary_use_ref: None,
2247                         },
2248                         Resource::Buffer {
2249                             buffer: vertex_buffer.clone(),
2250                             range: 0..vertex_buffer.size(), // TODO:
2251                             memory: PipelineMemoryAccess {
2252                                 stages: PipelineStages::VERTEX_INPUT,
2253                                 access: AccessFlags::VERTEX_ATTRIBUTE_READ,
2254                                 exclusive: false,
2255                             },
2256                         },
2257                     )
2258                 }),
2259         );
2260     }
2261 
add_index_buffer( &self, resources: &mut Vec<(ResourceUseRef, Resource)>, command_index: usize, command_name: &'static str, )2262     fn add_index_buffer(
2263         &self,
2264         resources: &mut Vec<(ResourceUseRef, Resource)>,
2265         command_index: usize,
2266         command_name: &'static str,
2267     ) {
2268         let index_buffer = &self.current_state.index_buffer.as_ref().unwrap().0;
2269         resources.push((
2270             ResourceUseRef {
2271                 command_index,
2272                 command_name,
2273                 resource_in_command: ResourceInCommand::IndexBuffer,
2274                 secondary_use_ref: None,
2275             },
2276             Resource::Buffer {
2277                 buffer: index_buffer.clone(),
2278                 range: 0..index_buffer.size(), // TODO:
2279                 memory: PipelineMemoryAccess {
2280                     stages: PipelineStages::VERTEX_INPUT,
2281                     access: AccessFlags::INDEX_READ,
2282                     exclusive: false,
2283                 },
2284             },
2285         ));
2286     }
2287 
add_indirect_buffer( &self, resources: &mut Vec<(ResourceUseRef, Resource)>, command_index: usize, command_name: &'static str, indirect_buffer: &Subbuffer<[u8]>, )2288     fn add_indirect_buffer(
2289         &self,
2290         resources: &mut Vec<(ResourceUseRef, Resource)>,
2291         command_index: usize,
2292         command_name: &'static str,
2293         indirect_buffer: &Subbuffer<[u8]>,
2294     ) {
2295         resources.push((
2296             ResourceUseRef {
2297                 command_index,
2298                 command_name,
2299                 resource_in_command: ResourceInCommand::IndirectBuffer,
2300                 secondary_use_ref: None,
2301             },
2302             Resource::Buffer {
2303                 buffer: indirect_buffer.clone(),
2304                 range: 0..indirect_buffer.size(), // TODO:
2305                 memory: PipelineMemoryAccess {
2306                     stages: PipelineStages::DRAW_INDIRECT,
2307                     access: AccessFlags::INDIRECT_COMMAND_READ,
2308                     exclusive: false,
2309                 },
2310             },
2311         ));
2312     }
2313 }
2314 
2315 impl UnsafeCommandBufferBuilder {
2316     /// Calls `vkCmdDispatch` on the builder.
2317     #[inline]
dispatch(&mut self, group_counts: [u32; 3])2318     pub unsafe fn dispatch(&mut self, group_counts: [u32; 3]) {
2319         debug_assert!({
2320             let max_group_counts = self
2321                 .device
2322                 .physical_device()
2323                 .properties()
2324                 .max_compute_work_group_count;
2325             group_counts[0] <= max_group_counts[0]
2326                 && group_counts[1] <= max_group_counts[1]
2327                 && group_counts[2] <= max_group_counts[2]
2328         });
2329 
2330         let fns = self.device.fns();
2331         (fns.v1_0.cmd_dispatch)(
2332             self.handle,
2333             group_counts[0],
2334             group_counts[1],
2335             group_counts[2],
2336         );
2337     }
2338 
2339     /// Calls `vkCmdDispatchIndirect` on the builder.
2340     #[inline]
dispatch_indirect(&mut self, buffer: &Subbuffer<[DispatchIndirectCommand]>)2341     pub unsafe fn dispatch_indirect(&mut self, buffer: &Subbuffer<[DispatchIndirectCommand]>) {
2342         let fns = self.device.fns();
2343 
2344         debug_assert!(buffer.offset() < buffer.buffer().size());
2345         debug_assert!(buffer
2346             .buffer()
2347             .usage()
2348             .intersects(BufferUsage::INDIRECT_BUFFER));
2349         debug_assert_eq!(buffer.offset() % 4, 0);
2350 
2351         (fns.v1_0.cmd_dispatch_indirect)(self.handle, buffer.buffer().handle(), buffer.offset());
2352     }
2353 
2354     /// Calls `vkCmdDraw` on the builder.
2355     #[inline]
draw( &mut self, vertex_count: u32, instance_count: u32, first_vertex: u32, first_instance: u32, )2356     pub unsafe fn draw(
2357         &mut self,
2358         vertex_count: u32,
2359         instance_count: u32,
2360         first_vertex: u32,
2361         first_instance: u32,
2362     ) {
2363         let fns = self.device.fns();
2364         (fns.v1_0.cmd_draw)(
2365             self.handle,
2366             vertex_count,
2367             instance_count,
2368             first_vertex,
2369             first_instance,
2370         );
2371     }
2372 
2373     /// Calls `vkCmdDrawIndexed` on the builder.
2374     #[inline]
draw_indexed( &mut self, index_count: u32, instance_count: u32, first_index: u32, vertex_offset: i32, first_instance: u32, )2375     pub unsafe fn draw_indexed(
2376         &mut self,
2377         index_count: u32,
2378         instance_count: u32,
2379         first_index: u32,
2380         vertex_offset: i32,
2381         first_instance: u32,
2382     ) {
2383         let fns = self.device.fns();
2384         (fns.v1_0.cmd_draw_indexed)(
2385             self.handle,
2386             index_count,
2387             instance_count,
2388             first_index,
2389             vertex_offset,
2390             first_instance,
2391         );
2392     }
2393 
2394     /// Calls `vkCmdDrawIndirect` on the builder.
2395     #[inline]
draw_indirect( &mut self, buffer: &Subbuffer<[DrawIndirectCommand]>, draw_count: u32, stride: u32, )2396     pub unsafe fn draw_indirect(
2397         &mut self,
2398         buffer: &Subbuffer<[DrawIndirectCommand]>,
2399         draw_count: u32,
2400         stride: u32,
2401     ) {
2402         let fns = self.device.fns();
2403 
2404         debug_assert!(
2405             draw_count == 0
2406                 || ((stride % 4) == 0)
2407                     && stride as usize >= size_of::<ash::vk::DrawIndirectCommand>()
2408         );
2409 
2410         debug_assert!(buffer.offset() < buffer.buffer().size());
2411         debug_assert!(buffer
2412             .buffer()
2413             .usage()
2414             .intersects(BufferUsage::INDIRECT_BUFFER));
2415 
2416         (fns.v1_0.cmd_draw_indirect)(
2417             self.handle,
2418             buffer.buffer().handle(),
2419             buffer.offset(),
2420             draw_count,
2421             stride,
2422         );
2423     }
2424 
2425     /// Calls `vkCmdDrawIndexedIndirect` on the builder.
2426     #[inline]
draw_indexed_indirect( &mut self, buffer: &Subbuffer<[DrawIndexedIndirectCommand]>, draw_count: u32, stride: u32, )2427     pub unsafe fn draw_indexed_indirect(
2428         &mut self,
2429         buffer: &Subbuffer<[DrawIndexedIndirectCommand]>,
2430         draw_count: u32,
2431         stride: u32,
2432     ) {
2433         let fns = self.device.fns();
2434 
2435         debug_assert!(buffer.offset() < buffer.buffer().size());
2436         debug_assert!(buffer
2437             .buffer()
2438             .usage()
2439             .intersects(BufferUsage::INDIRECT_BUFFER));
2440 
2441         (fns.v1_0.cmd_draw_indexed_indirect)(
2442             self.handle,
2443             buffer.buffer().handle(),
2444             buffer.offset(),
2445             draw_count,
2446             stride,
2447         );
2448     }
2449 }
2450 
2451 /// Error that can happen when recording a bound pipeline execution command.
2452 #[derive(Debug, Clone)]
2453 pub enum PipelineExecutionError {
2454     SyncCommandBufferBuilderError(SyncCommandBufferBuilderError),
2455 
2456     RequirementNotMet {
2457         required_for: &'static str,
2458         requires_one_of: RequiresOneOf,
2459     },
2460 
2461     /// The resource bound to a descriptor set binding at a particular index is not compatible
2462     /// with the requirements of the pipeline and shaders.
2463     DescriptorResourceInvalid {
2464         set_num: u32,
2465         binding_num: u32,
2466         index: u32,
2467         error: DescriptorResourceInvalidError,
2468     },
2469 
2470     /// The pipeline layout requires a descriptor set bound to a set number, but none was bound.
2471     DescriptorSetNotBound {
2472         set_num: u32,
2473     },
2474 
2475     /// The bound pipeline uses a dynamic color write enable setting, but the number of provided
2476     /// enable values is less than the number of attachments in the current render subpass.
2477     DynamicColorWriteEnableNotEnoughValues {
2478         color_write_enable_count: u32,
2479         attachment_count: u32,
2480     },
2481 
2482     /// The bound pipeline uses a dynamic primitive topology, but the provided topology is of a
2483     /// different topology class than what the pipeline requires.
2484     DynamicPrimitiveTopologyClassMismatch {
2485         provided_class: PrimitiveTopologyClass,
2486         required_class: PrimitiveTopologyClass,
2487     },
2488 
2489     /// The bound pipeline uses a dynamic primitive topology, but the provided topology is not
2490     /// compatible with the shader stages in the pipeline.
2491     DynamicPrimitiveTopologyInvalid {
2492         topology: PrimitiveTopology,
2493     },
2494 
2495     /// The pipeline requires a particular dynamic state, but this state was not set.
2496     DynamicStateNotSet {
2497         dynamic_state: DynamicState,
2498     },
2499 
2500     /// The bound pipeline uses a dynamic scissor and/or viewport count, but the scissor count
2501     /// does not match the viewport count.
2502     DynamicViewportScissorCountMismatch {
2503         viewport_count: u32,
2504         scissor_count: u32,
2505     },
2506 
2507     /// Operation forbidden inside a render pass.
2508     ForbiddenInsideRenderPass,
2509 
2510     /// Operation forbidden outside a render pass.
2511     ForbiddenOutsideRenderPass,
2512 
2513     /// Operation forbidden inside a render subpass with the specified contents.
2514     ForbiddenWithSubpassContents {
2515         subpass_contents: SubpassContents,
2516     },
2517 
2518     /// An indexed draw command was recorded, but no index buffer was bound.
2519     IndexBufferNotBound,
2520 
2521     /// The highest index to be drawn exceeds the available number of indices in the bound index
2522     /// buffer.
2523     IndexBufferRangeOutOfBounds {
2524         highest_index: u32,
2525         max_index_count: u32,
2526     },
2527 
2528     /// The `indirect_buffer` usage was not enabled on the indirect buffer.
2529     IndirectBufferMissingUsage,
2530 
2531     /// The `max_compute_work_group_count` limit has been exceeded.
2532     MaxComputeWorkGroupCountExceeded {
2533         requested: [u32; 3],
2534         max: [u32; 3],
2535     },
2536 
2537     /// The `max_draw_indirect_count` limit has been exceeded.
2538     MaxDrawIndirectCountExceeded {
2539         provided: u32,
2540         max: u32,
2541     },
2542 
2543     /// The `max_multiview_instance_index` limit has been exceeded.
2544     MaxMultiviewInstanceIndexExceeded {
2545         highest_instance: u64,
2546         max: u32,
2547     },
2548 
2549     /// The queue family doesn't allow this operation.
2550     NotSupportedByQueueFamily,
2551 
2552     /// The color attachment count in the bound pipeline does not match the count of the current
2553     /// render pass.
2554     PipelineColorAttachmentCountMismatch {
2555         pipeline_count: u32,
2556         required_count: u32,
2557     },
2558 
2559     /// The format of a color attachment in the bound pipeline does not match the format of the
2560     /// corresponding color attachment in the current render pass.
2561     PipelineColorAttachmentFormatMismatch {
2562         color_attachment_index: u32,
2563         pipeline_format: Option<Format>,
2564         required_format: Format,
2565     },
2566 
2567     /// The format of the depth attachment in the bound pipeline does not match the format of the
2568     /// depth attachment in the current render pass.
2569     PipelineDepthAttachmentFormatMismatch {
2570         pipeline_format: Option<Format>,
2571         required_format: Format,
2572     },
2573 
2574     /// The bound pipeline is not compatible with the layout used to bind the descriptor sets.
2575     PipelineLayoutNotCompatible,
2576 
2577     /// No pipeline was bound to the bind point used by the operation.
2578     PipelineNotBound,
2579 
2580     /// The bound graphics pipeline uses a render pass that is not compatible with the currently
2581     /// active render pass.
2582     PipelineRenderPassNotCompatible,
2583 
2584     /// The bound graphics pipeline uses a render pass of a different type than the currently
2585     /// active render pass.
2586     PipelineRenderPassTypeMismatch,
2587 
2588     /// The bound graphics pipeline uses a render subpass index that doesn't match the currently
2589     /// active subpass index.
2590     PipelineSubpassMismatch {
2591         pipeline: u32,
2592         current: u32,
2593     },
2594 
2595     /// The format of the stencil attachment in the bound pipeline does not match the format of the
2596     /// stencil attachment in the current render pass.
2597     PipelineStencilAttachmentFormatMismatch {
2598         pipeline_format: Option<Format>,
2599         required_format: Format,
2600     },
2601 
2602     /// The view mask of the bound pipeline does not match the view mask of the current render pass.
2603     PipelineViewMaskMismatch {
2604         pipeline_view_mask: u32,
2605         required_view_mask: u32,
2606     },
2607 
2608     /// The push constants are not compatible with the pipeline layout.
2609     PushConstantsNotCompatible,
2610 
2611     /// Not all push constants used by the pipeline have been set.
2612     PushConstantsMissing,
2613 
2614     /// The bound graphics pipeline requires a vertex buffer bound to a binding number, but none
2615     /// was bound.
2616     VertexBufferNotBound {
2617         binding_num: u32,
2618     },
2619 
2620     /// The number of instances to be drawn exceeds the available number of indices in the
2621     /// bound vertex buffers used by the pipeline.
2622     VertexBufferInstanceRangeOutOfBounds {
2623         instances_needed: u64,
2624         instances_in_buffers: u64,
2625     },
2626 
2627     /// The number of vertices to be drawn exceeds the lowest available number of vertices in the
2628     /// bound vertex buffers used by the pipeline.
2629     VertexBufferVertexRangeOutOfBounds {
2630         vertices_needed: u64,
2631         vertices_in_buffers: u64,
2632     },
2633 }
2634 
2635 impl Error for PipelineExecutionError {
source(&self) -> Option<&(dyn Error + 'static)>2636     fn source(&self) -> Option<&(dyn Error + 'static)> {
2637         match self {
2638             Self::SyncCommandBufferBuilderError(err) => Some(err),
2639             Self::DescriptorResourceInvalid { error, .. } => Some(error),
2640             _ => None,
2641         }
2642     }
2643 }
2644 
2645 impl Display for PipelineExecutionError {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>2646     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
2647         match self {
2648             Self::SyncCommandBufferBuilderError(_) => write!(f, "a SyncCommandBufferBuilderError"),
2649             Self::RequirementNotMet {
2650                 required_for,
2651                 requires_one_of,
2652             } => write!(
2653                 f,
2654                 "a requirement was not met for: {}; requires one of: {}",
2655                 required_for, requires_one_of,
2656             ),
2657             Self::DescriptorResourceInvalid {
2658                 set_num,
2659                 binding_num,
2660                 index,
2661                 ..
2662             } => write!(
2663                 f,
2664                 "the resource bound to descriptor set {} binding {} at index {} is not compatible \
2665                 with the requirements of the pipeline and shaders",
2666                 set_num, binding_num, index,
2667             ),
2668             Self::DescriptorSetNotBound { set_num } => write!(
2669                 f,
2670                 "the pipeline layout requires a descriptor set bound to set number {}, but none \
2671                 was bound",
2672                 set_num,
2673             ),
2674             Self::DynamicColorWriteEnableNotEnoughValues {
2675                 color_write_enable_count,
2676                 attachment_count,
2677             } => write!(
2678                 f,
2679                 "the bound pipeline uses a dynamic color write enable setting, but the number of \
2680                 provided enable values ({}) is less than the number of attachments in the current \
2681                 render subpass ({})",
2682                 color_write_enable_count, attachment_count,
2683             ),
2684             Self::DynamicPrimitiveTopologyClassMismatch {
2685                 provided_class,
2686                 required_class,
2687             } => write!(
2688                 f,
2689                 "The bound pipeline uses a dynamic primitive topology, but the provided topology \
2690                 is of a different topology class ({:?}) than what the pipeline requires ({:?})",
2691                 provided_class, required_class,
2692             ),
2693             Self::DynamicPrimitiveTopologyInvalid { topology } => write!(
2694                 f,
2695                 "the bound pipeline uses a dynamic primitive topology, but the provided topology \
2696                 ({:?}) is not compatible with the shader stages in the pipeline",
2697                 topology,
2698             ),
2699             Self::DynamicStateNotSet { dynamic_state } => write!(
2700                 f,
2701                 "the pipeline requires the dynamic state {:?}, but this state was not set",
2702                 dynamic_state,
2703             ),
2704             Self::DynamicViewportScissorCountMismatch {
2705                 viewport_count,
2706                 scissor_count,
2707             } => write!(
2708                 f,
2709                 "the bound pipeline uses a dynamic scissor and/or viewport count, but the scissor \
2710                 count ({}) does not match the viewport count ({})",
2711                 scissor_count, viewport_count,
2712             ),
2713             Self::ForbiddenInsideRenderPass => {
2714                 write!(f, "operation forbidden inside a render pass")
2715             }
2716             Self::ForbiddenOutsideRenderPass => {
2717                 write!(f, "operation forbidden outside a render pass")
2718             }
2719             Self::ForbiddenWithSubpassContents { subpass_contents } => write!(
2720                 f,
2721                 "operation forbidden inside a render subpass with contents {:?}",
2722                 subpass_contents,
2723             ),
2724             Self::IndexBufferNotBound => write!(
2725                 f,
2726                 "an indexed draw command was recorded, but no index buffer was bound",
2727             ),
2728             Self::IndexBufferRangeOutOfBounds {
2729                 highest_index,
2730                 max_index_count,
2731             } => write!(
2732                 f,
2733                 "the highest index to be drawn ({}) exceeds the available number of indices in the \
2734                 bound index buffer ({})",
2735                 highest_index, max_index_count,
2736             ),
2737             Self::IndirectBufferMissingUsage => write!(
2738                 f,
2739                 "the `indirect_buffer` usage was not enabled on the indirect buffer",
2740             ),
2741             Self::MaxComputeWorkGroupCountExceeded { .. } => write!(
2742                 f,
2743                 "the `max_compute_work_group_count` limit has been exceeded",
2744             ),
2745             Self::MaxDrawIndirectCountExceeded { .. } => {
2746                 write!(f, "the `max_draw_indirect_count` limit has been exceeded")
2747             }
2748             Self::MaxMultiviewInstanceIndexExceeded { .. } => write!(
2749                 f,
2750                 "the `max_multiview_instance_index` limit has been exceeded",
2751             ),
2752             Self::NotSupportedByQueueFamily => {
2753                 write!(f, "the queue family doesn't allow this operation")
2754             }
2755             Self::PipelineColorAttachmentCountMismatch {
2756                 pipeline_count,
2757                 required_count,
2758             } => write!(
2759                 f,
2760                 "the color attachment count in the bound pipeline ({}) does not match the count of \
2761                 the current render pass ({})",
2762                 pipeline_count, required_count,
2763             ),
2764             Self::PipelineColorAttachmentFormatMismatch {
2765                 color_attachment_index,
2766                 pipeline_format,
2767                 required_format,
2768             } => write!(
2769                 f,
2770                 "the format of color attachment {} in the bound pipeline ({:?}) does not match the \
2771                 format of the corresponding color attachment in the current render pass ({:?})",
2772                 color_attachment_index, pipeline_format, required_format,
2773             ),
2774             Self::PipelineDepthAttachmentFormatMismatch {
2775                 pipeline_format,
2776                 required_format,
2777             } => write!(
2778                 f,
2779                 "the format of the depth attachment in the bound pipeline ({:?}) does not match \
2780                 the format of the depth attachment in the current render pass ({:?})",
2781                 pipeline_format, required_format,
2782             ),
2783             Self::PipelineLayoutNotCompatible => write!(
2784                 f,
2785                 "the bound pipeline is not compatible with the layout used to bind the descriptor \
2786                 sets",
2787             ),
2788             Self::PipelineNotBound => write!(
2789                 f,
2790                 "no pipeline was bound to the bind point used by the operation",
2791             ),
2792             Self::PipelineRenderPassNotCompatible => write!(
2793                 f,
2794                 "the bound graphics pipeline uses a render pass that is not compatible with the \
2795                 currently active render pass",
2796             ),
2797             Self::PipelineRenderPassTypeMismatch => write!(
2798                 f,
2799                 "the bound graphics pipeline uses a render pass of a different type than the \
2800                 currently active render pass",
2801             ),
2802             Self::PipelineSubpassMismatch { pipeline, current } => write!(
2803                 f,
2804                 "the bound graphics pipeline uses a render subpass index ({}) that doesn't match \
2805                 the currently active subpass index ({})",
2806                 pipeline, current,
2807             ),
2808             Self::PipelineStencilAttachmentFormatMismatch {
2809                 pipeline_format,
2810                 required_format,
2811             } => write!(
2812                 f,
2813                 "the format of the stencil attachment in the bound pipeline ({:?}) does not match \
2814                 the format of the stencil attachment in the current render pass ({:?})",
2815                 pipeline_format, required_format,
2816             ),
2817             Self::PipelineViewMaskMismatch {
2818                 pipeline_view_mask,
2819                 required_view_mask,
2820             } => write!(
2821                 f,
2822                 "the view mask of the bound pipeline ({}) does not match the view mask of the \
2823                 current render pass ({})",
2824                 pipeline_view_mask, required_view_mask,
2825             ),
2826             Self::PushConstantsNotCompatible => write!(
2827                 f,
2828                 "the push constants are not compatible with the pipeline layout",
2829             ),
2830             Self::PushConstantsMissing => write!(
2831                 f,
2832                 "not all push constants used by the pipeline have been set",
2833             ),
2834             Self::VertexBufferNotBound { binding_num } => write!(
2835                 f,
2836                 "the bound graphics pipeline requires a vertex buffer bound to binding number {}, \
2837                 but none was bound",
2838                 binding_num,
2839             ),
2840             Self::VertexBufferInstanceRangeOutOfBounds {
2841                 instances_needed,
2842                 instances_in_buffers,
2843             } => write!(
2844                 f,
2845                 "the number of instances to be drawn ({}) exceeds the available number of \
2846                 instances in the bound vertex buffers ({}) used by the pipeline",
2847                 instances_needed, instances_in_buffers,
2848             ),
2849             Self::VertexBufferVertexRangeOutOfBounds {
2850                 vertices_needed,
2851                 vertices_in_buffers,
2852             } => write!(
2853                 f,
2854                 "the number of vertices to be drawn ({}) exceeds the available number of vertices \
2855                 in the bound vertex buffers ({}) used by the pipeline",
2856                 vertices_needed, vertices_in_buffers,
2857             ),
2858         }
2859     }
2860 }
2861 
2862 impl From<SyncCommandBufferBuilderError> for PipelineExecutionError {
from(err: SyncCommandBufferBuilderError) -> Self2863     fn from(err: SyncCommandBufferBuilderError) -> Self {
2864         Self::SyncCommandBufferBuilderError(err)
2865     }
2866 }
2867 
2868 #[derive(Clone, Copy, Debug)]
2869 pub enum DescriptorResourceInvalidError {
2870     ImageViewFormatMismatch {
2871         required: Format,
2872         provided: Option<Format>,
2873     },
2874     ImageViewMultisampledMismatch {
2875         required: bool,
2876         provided: bool,
2877     },
2878     ImageViewScalarTypeMismatch {
2879         required: ShaderScalarType,
2880         provided: ShaderScalarType,
2881     },
2882     ImageViewTypeMismatch {
2883         required: ImageViewType,
2884         provided: ImageViewType,
2885     },
2886     Missing,
2887     SamplerCompareMismatch {
2888         required: bool,
2889         provided: bool,
2890     },
2891     SamplerImageViewIncompatible {
2892         image_view_set_num: u32,
2893         image_view_binding_num: u32,
2894         image_view_index: u32,
2895         error: SamplerImageViewIncompatibleError,
2896     },
2897     SamplerUnnormalizedCoordinatesNotAllowed,
2898     SamplerYcbcrConversionNotAllowed,
2899     StorageImageAtomicNotSupported,
2900     StorageReadWithoutFormatNotSupported,
2901     StorageWriteWithoutFormatNotSupported,
2902 }
2903 
2904 impl Error for DescriptorResourceInvalidError {
source(&self) -> Option<&(dyn Error + 'static)>2905     fn source(&self) -> Option<&(dyn Error + 'static)> {
2906         match self {
2907             Self::SamplerImageViewIncompatible { error, .. } => Some(error),
2908             _ => None,
2909         }
2910     }
2911 }
2912 
2913 impl Display for DescriptorResourceInvalidError {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>2914     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
2915         match self {
2916             Self::ImageViewFormatMismatch { provided, required } => write!(
2917                 f,
2918                 "the format of the bound image view ({:?}) does not match what the pipeline \
2919                 requires ({:?})",
2920                 provided, required,
2921             ),
2922             Self::ImageViewMultisampledMismatch { provided, required } => write!(
2923                 f,
2924                 "the multisampling of the bound image ({}) does not match what the pipeline \
2925                 requires ({})",
2926                 provided, required,
2927             ),
2928             Self::ImageViewScalarTypeMismatch { provided, required } => write!(
2929                 f,
2930                 "the scalar type of the format and aspect of the bound image view ({:?}) does not \
2931                 match what the pipeline requires ({:?})",
2932                 provided, required,
2933             ),
2934             Self::ImageViewTypeMismatch { provided, required } => write!(
2935                 f,
2936                 "the image view type of the bound image view ({:?}) does not match what the \
2937                 pipeline requires ({:?})",
2938                 provided, required,
2939             ),
2940             Self::Missing => write!(f, "no resource was bound"),
2941             Self::SamplerImageViewIncompatible { .. } => write!(
2942                 f,
2943                 "the bound sampler samples an image view that is not compatible with that sampler",
2944             ),
2945             Self::SamplerCompareMismatch { provided, required } => write!(
2946                 f,
2947                 "the depth comparison state of the bound sampler ({}) does not match what the \
2948                 pipeline requires ({})",
2949                 provided, required,
2950             ),
2951             Self::SamplerUnnormalizedCoordinatesNotAllowed => write!(
2952                 f,
2953                 "the bound sampler is required to have unnormalized coordinates disabled",
2954             ),
2955             Self::SamplerYcbcrConversionNotAllowed => write!(
2956                 f,
2957                 "the bound sampler is required to have no attached sampler YCbCr conversion",
2958             ),
2959             Self::StorageImageAtomicNotSupported => write!(
2960                 f,
2961                 "the bound image view does not support the `storage_image_atomic` format feature",
2962             ),
2963             Self::StorageReadWithoutFormatNotSupported => write!(
2964                 f,
2965                 "the bound image view or buffer view does not support the \
2966                 `storage_read_without_format` format feature",
2967             ),
2968             Self::StorageWriteWithoutFormatNotSupported => write!(
2969                 f,
2970                 "the bound image view or buffer view does not support the \
2971                 `storage_write_without_format` format feature",
2972             ),
2973         }
2974     }
2975 }
2976