• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2022 The vulkano developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
6 // at your option. All files in the project carrying such
7 // notice may not be copied, modified, or distributed except
8 // according to those terms.
9 
10 use super::CommandBufferBuilder;
11 use crate::{
12     command_buffer::{
13         allocator::CommandBufferAllocator, commands::dynamic_state::SetDynamicStateError,
14     },
15     device::{DeviceOwned, QueueFlags},
16     pipeline::{
17         graphics::{
18             color_blend::LogicOp,
19             depth_stencil::{CompareOp, StencilFaces, StencilOp, StencilOps},
20             input_assembly::PrimitiveTopology,
21             rasterization::{CullMode, DepthBias, FrontFace, LineStipple},
22             viewport::{Scissor, Viewport},
23         },
24         DynamicState,
25     },
26     RequiresOneOf, Version, VulkanObject,
27 };
28 use smallvec::SmallVec;
29 use std::ops::RangeInclusive;
30 
31 impl<L, A> CommandBufferBuilder<L, A>
32 where
33     A: CommandBufferAllocator,
34 {
35     // Helper function for dynamic state setting.
36     #[inline]
validate_pipeline_fixed_state( &self, state: DynamicState, ) -> Result<(), SetDynamicStateError>37     fn validate_pipeline_fixed_state(
38         &self,
39         state: DynamicState,
40     ) -> Result<(), SetDynamicStateError> {
41         // VUID-vkCmdDispatch-None-02859
42         if self
43             .builder_state
44             .pipeline_graphics
45             .as_ref()
46             .map_or(false, |pipeline| {
47                 matches!(pipeline.dynamic_state(state), Some(false))
48             })
49         {
50             return Err(SetDynamicStateError::PipelineHasFixedState);
51         }
52 
53         Ok(())
54     }
55 
56     /// Sets the dynamic blend constants for future draw calls.
57     ///
58     /// # Panics
59     ///
60     /// - Panics if the queue family of the command buffer does not support graphics operations.
61     /// - Panics if the currently bound graphics pipeline already contains this state internally.
62     #[inline]
set_blend_constants(&mut self, constants: [f32; 4]) -> &mut Self63     pub fn set_blend_constants(&mut self, constants: [f32; 4]) -> &mut Self {
64         self.validate_set_blend_constants(constants).unwrap();
65 
66         unsafe { self.set_blend_constants_unchecked(constants) }
67     }
68 
validate_set_blend_constants( &self, _constants: [f32; 4], ) -> Result<(), SetDynamicStateError>69     fn validate_set_blend_constants(
70         &self,
71         _constants: [f32; 4],
72     ) -> Result<(), SetDynamicStateError> {
73         self.validate_pipeline_fixed_state(DynamicState::BlendConstants)?;
74 
75         let queue_family_properties = self.queue_family_properties();
76 
77         // VUID-vkCmdSetBlendConstants-commandBuffer-cmdpool
78         if !queue_family_properties
79             .queue_flags
80             .intersects(QueueFlags::GRAPHICS)
81         {
82             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
83         }
84 
85         Ok(())
86     }
87 
88     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_blend_constants_unchecked(&mut self, constants: [f32; 4]) -> &mut Self89     pub unsafe fn set_blend_constants_unchecked(&mut self, constants: [f32; 4]) -> &mut Self {
90         let fns = self.device().fns();
91         (fns.v1_0.cmd_set_blend_constants)(self.handle(), &constants);
92 
93         self.builder_state.blend_constants = Some(constants);
94 
95         self.next_command_index += 1;
96         self
97     }
98 
99     /// Sets whether dynamic color writes should be enabled for each attachment in the
100     /// framebuffer.
101     ///
102     /// # Panics
103     ///
104     /// - Panics if the queue family of the command buffer does not support graphics operations.
105     /// - Panics if the [`color_write_enable`] feature is not enabled on the device.
106     /// - Panics if the currently bound graphics pipeline already contains this state internally.
107     /// - If there is a graphics pipeline with color blend state bound, `enables.len()` must equal
108     ///   [`attachments.len()`].
109     ///
110     /// [`color_write_enable`]: crate::device::Features::color_write_enable
111     /// [`attachments.len()`]: crate::pipeline::graphics::color_blend::ColorBlendState::attachments
112     #[inline]
set_color_write_enable<I>(&mut self, enables: I) -> &mut Self where I: IntoIterator<Item = bool>, I::IntoIter: ExactSizeIterator,113     pub fn set_color_write_enable<I>(&mut self, enables: I) -> &mut Self
114     where
115         I: IntoIterator<Item = bool>,
116         I::IntoIter: ExactSizeIterator,
117     {
118         let enables = enables.into_iter();
119         self.validate_set_color_write_enable(&enables).unwrap();
120 
121         unsafe { self.set_color_write_enable_unchecked(enables) }
122     }
123 
validate_set_color_write_enable( &self, enables: &impl ExactSizeIterator, ) -> Result<(), SetDynamicStateError>124     fn validate_set_color_write_enable(
125         &self,
126         enables: &impl ExactSizeIterator,
127     ) -> Result<(), SetDynamicStateError> {
128         self.validate_pipeline_fixed_state(DynamicState::ColorWriteEnable)?;
129 
130         let queue_family_properties = self.queue_family_properties();
131 
132         // VUID-vkCmdSetColorWriteEnableEXT-commandBuffer-cmdpool
133         if !queue_family_properties
134             .queue_flags
135             .intersects(QueueFlags::GRAPHICS)
136         {
137             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
138         }
139 
140         // VUID-vkCmdSetColorWriteEnableEXT-None-04803
141         if !self.device().enabled_features().color_write_enable {
142             return Err(SetDynamicStateError::RequirementNotMet {
143                 required_for: "`CommandBufferBuilder::set_color_write_enable`",
144                 requires_one_of: RequiresOneOf {
145                     device_extensions: &["ext_color_write_enable"],
146                     ..Default::default()
147                 },
148             });
149         }
150 
151         if let Some(color_blend_state) = self
152             .builder_state
153             .pipeline_graphics
154             .as_ref()
155             .and_then(|pipeline| pipeline.color_blend_state())
156         {
157             // VUID-vkCmdSetColorWriteEnableEXT-attachmentCount-06656
158             // Indirectly checked
159             if enables.len() != color_blend_state.attachments.len() {
160                 return Err(
161                     SetDynamicStateError::PipelineColorBlendAttachmentCountMismatch {
162                         provided_count: enables.len() as u32,
163                         required_count: color_blend_state.attachments.len() as u32,
164                     },
165                 );
166             }
167         }
168 
169         Ok(())
170     }
171 
172     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_color_write_enable_unchecked( &mut self, enables: impl IntoIterator<Item = bool>, ) -> &mut Self173     pub unsafe fn set_color_write_enable_unchecked(
174         &mut self,
175         enables: impl IntoIterator<Item = bool>,
176     ) -> &mut Self {
177         let enables: SmallVec<[bool; 4]> = enables.into_iter().collect();
178 
179         if enables.is_empty() {
180             return self;
181         }
182 
183         debug_assert!(self.device().enabled_extensions().ext_color_write_enable);
184         let enables_vk = enables
185             .iter()
186             .copied()
187             .map(ash::vk::Bool32::from)
188             .collect::<SmallVec<[_; 4]>>();
189 
190         let fns = self.device().fns();
191         (fns.ext_color_write_enable.cmd_set_color_write_enable_ext)(
192             self.handle(),
193             enables_vk.len() as u32,
194             enables_vk.as_ptr(),
195         );
196 
197         self.builder_state.color_write_enable = Some(enables);
198 
199         self.next_command_index += 1;
200         self
201     }
202 
203     /// Sets the dynamic cull mode for future draw calls.
204     ///
205     /// # Panics
206     ///
207     /// - Panics if the queue family of the command buffer does not support graphics operations.
208     /// - Panics if the device API version is less than 1.3 and the [`extended_dynamic_state`]
209     ///   feature is not enabled on the device.
210     /// - Panics if the currently bound graphics pipeline already contains this state internally.
211     ///
212     /// [`extended_dynamic_state`]: crate::device::Features::extended_dynamic_state
213     #[inline]
set_cull_mode(&mut self, cull_mode: CullMode) -> &mut Self214     pub fn set_cull_mode(&mut self, cull_mode: CullMode) -> &mut Self {
215         self.validate_set_cull_mode(cull_mode).unwrap();
216 
217         unsafe { self.set_cull_mode_unchecked(cull_mode) }
218     }
219 
validate_set_cull_mode(&self, cull_mode: CullMode) -> Result<(), SetDynamicStateError>220     fn validate_set_cull_mode(&self, cull_mode: CullMode) -> Result<(), SetDynamicStateError> {
221         self.validate_pipeline_fixed_state(DynamicState::CullMode)?;
222 
223         // VUID-vkCmdSetCullMode-cullMode-parameter
224         cull_mode.validate_device(self.device())?;
225 
226         let queue_family_properties = self.queue_family_properties();
227 
228         // VUID-vkCmdSetCullMode-commandBuffer-cmdpool
229         if !queue_family_properties
230             .queue_flags
231             .intersects(QueueFlags::GRAPHICS)
232         {
233             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
234         }
235 
236         // VUID-vkCmdSetCullMode-None-03384
237         if !(self.device().api_version() >= Version::V1_3
238             || self.device().enabled_features().extended_dynamic_state)
239         {
240             return Err(SetDynamicStateError::RequirementNotMet {
241                 required_for: "`CommandBufferBuilder::set_cull_mode`",
242                 requires_one_of: RequiresOneOf {
243                     api_version: Some(Version::V1_3),
244                     features: &["extended_dynamic_state"],
245                     ..Default::default()
246                 },
247             });
248         }
249 
250         Ok(())
251     }
252 
253     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_cull_mode_unchecked(&mut self, cull_mode: CullMode) -> &mut Self254     pub unsafe fn set_cull_mode_unchecked(&mut self, cull_mode: CullMode) -> &mut Self {
255         let fns = self.device().fns();
256 
257         if self.device().api_version() >= Version::V1_3 {
258             (fns.v1_3.cmd_set_cull_mode)(self.handle(), cull_mode.into());
259         } else {
260             debug_assert!(
261                 self.device()
262                     .enabled_extensions()
263                     .ext_extended_dynamic_state
264             );
265             (fns.ext_extended_dynamic_state.cmd_set_cull_mode_ext)(self.handle(), cull_mode.into());
266         }
267 
268         self.builder_state.cull_mode = Some(cull_mode);
269 
270         self.next_command_index += 1;
271         self
272     }
273 
274     /// Sets the dynamic depth bias values for future draw calls.
275     ///
276     /// # Panics
277     ///
278     /// - Panics if the queue family of the command buffer does not support graphics operations.
279     /// - Panics if the currently bound graphics pipeline already contains this state internally.
280     /// - If the [`depth_bias_clamp`] feature is not enabled on the device, panics if `clamp` is
281     ///   not 0.0.
282     ///
283     /// [`depth_bias_clamp`]: crate::device::Features::depth_bias_clamp
284     #[inline]
set_depth_bias( &mut self, constant_factor: f32, clamp: f32, slope_factor: f32, ) -> &mut Self285     pub fn set_depth_bias(
286         &mut self,
287         constant_factor: f32,
288         clamp: f32,
289         slope_factor: f32,
290     ) -> &mut Self {
291         self.validate_set_depth_bias(constant_factor, clamp, slope_factor)
292             .unwrap();
293 
294         unsafe { self.set_depth_bias_unchecked(constant_factor, clamp, slope_factor) }
295     }
296 
validate_set_depth_bias( &self, _constant_factor: f32, clamp: f32, _slope_factor: f32, ) -> Result<(), SetDynamicStateError>297     fn validate_set_depth_bias(
298         &self,
299         _constant_factor: f32,
300         clamp: f32,
301         _slope_factor: f32,
302     ) -> Result<(), SetDynamicStateError> {
303         self.validate_pipeline_fixed_state(DynamicState::DepthBias)?;
304 
305         let queue_family_properties = self.queue_family_properties();
306 
307         // VUID-vkCmdSetDepthBias-commandBuffer-cmdpool
308         if !queue_family_properties
309             .queue_flags
310             .intersects(QueueFlags::GRAPHICS)
311         {
312             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
313         }
314 
315         // VUID-vkCmdSetDepthBias-depthBiasClamp-00790
316         if clamp != 0.0 && !self.device().enabled_features().depth_bias_clamp {
317             return Err(SetDynamicStateError::RequirementNotMet {
318                 required_for: "`clamp` is not `0.0`",
319                 requires_one_of: RequiresOneOf {
320                     features: &["depth_bias_clamp"],
321                     ..Default::default()
322                 },
323             });
324         }
325 
326         Ok(())
327     }
328 
329     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_depth_bias_unchecked( &mut self, constant_factor: f32, clamp: f32, slope_factor: f32, ) -> &mut Self330     pub unsafe fn set_depth_bias_unchecked(
331         &mut self,
332         constant_factor: f32,
333         clamp: f32,
334         slope_factor: f32,
335     ) -> &mut Self {
336         let fns = self.device().fns();
337         (fns.v1_0.cmd_set_depth_bias)(self.handle(), constant_factor, clamp, slope_factor);
338 
339         self.builder_state.depth_bias = Some(DepthBias {
340             constant_factor,
341             clamp,
342             slope_factor,
343         });
344 
345         self.next_command_index += 1;
346         self
347     }
348 
349     /// Sets whether dynamic depth bias is enabled for future draw calls.
350     ///
351     /// # Panics
352     ///
353     /// - Panics if the queue family of the command buffer does not support graphics operations.
354     /// - Panics if the device API version is less than 1.3 and the [`extended_dynamic_state2`]
355     ///   feature is not enabled on the device.
356     /// - Panics if the currently bound graphics pipeline already contains this state internally.
357     ///
358     /// [`extended_dynamic_state2`]: crate::device::Features::extended_dynamic_state2
359     #[inline]
set_depth_bias_enable(&mut self, enable: bool) -> &mut Self360     pub fn set_depth_bias_enable(&mut self, enable: bool) -> &mut Self {
361         self.validate_set_depth_bias_enable(enable).unwrap();
362 
363         unsafe { self.set_depth_bias_enable_unchecked(enable) }
364     }
365 
validate_set_depth_bias_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError>366     fn validate_set_depth_bias_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError> {
367         self.validate_pipeline_fixed_state(DynamicState::DepthBiasEnable)?;
368 
369         let queue_family_properties = self.queue_family_properties();
370 
371         // VUID-vkCmdSetDepthBiasEnable-commandBuffer-cmdpool
372         if !queue_family_properties
373             .queue_flags
374             .intersects(QueueFlags::GRAPHICS)
375         {
376             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
377         }
378 
379         // VUID-vkCmdSetDepthBiasEnable-None-04872
380         if !(self.device().api_version() >= Version::V1_3
381             || self.device().enabled_features().extended_dynamic_state2)
382         {
383             return Err(SetDynamicStateError::RequirementNotMet {
384                 required_for: "`CommandBufferBuilder::set_depth_bias_enable`",
385                 requires_one_of: RequiresOneOf {
386                     api_version: Some(Version::V1_3),
387                     features: &["extended_dynamic_state2"],
388                     ..Default::default()
389                 },
390             });
391         }
392 
393         Ok(())
394     }
395 
396     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_depth_bias_enable_unchecked(&mut self, enable: bool) -> &mut Self397     pub unsafe fn set_depth_bias_enable_unchecked(&mut self, enable: bool) -> &mut Self {
398         let fns = self.device().fns();
399 
400         if self.device().api_version() >= Version::V1_3 {
401             (fns.v1_3.cmd_set_depth_bias_enable)(self.handle(), enable.into());
402         } else {
403             debug_assert!(
404                 self.device()
405                     .enabled_extensions()
406                     .ext_extended_dynamic_state2
407             );
408             (fns.ext_extended_dynamic_state2
409                 .cmd_set_depth_bias_enable_ext)(self.handle(), enable.into());
410         }
411 
412         self.builder_state.depth_bias_enable = Some(enable);
413 
414         self.next_command_index += 1;
415         self
416     }
417 
418     /// Sets the dynamic depth bounds for future draw calls.
419     ///
420     /// # Panics
421     ///
422     /// - Panics if the queue family of the command buffer does not support graphics operations.
423     /// - Panics if the currently bound graphics pipeline already contains this state internally.
424     /// - If the [`ext_depth_range_unrestricted`] extension is not enabled on the device, panics if
425     ///   the start and end of `bounds` are not between 0.0 and 1.0 inclusive.
426     ///
427     /// [`ext_depth_range_unrestricted`]: crate::device::DeviceExtensions::ext_depth_range_unrestricted
set_depth_bounds(&mut self, bounds: RangeInclusive<f32>) -> &mut Self428     pub fn set_depth_bounds(&mut self, bounds: RangeInclusive<f32>) -> &mut Self {
429         self.validate_set_depth_bounds(bounds.clone()).unwrap();
430 
431         unsafe { self.set_depth_bounds_unchecked(bounds) }
432     }
433 
validate_set_depth_bounds( &self, bounds: RangeInclusive<f32>, ) -> Result<(), SetDynamicStateError>434     fn validate_set_depth_bounds(
435         &self,
436         bounds: RangeInclusive<f32>,
437     ) -> Result<(), SetDynamicStateError> {
438         self.validate_pipeline_fixed_state(DynamicState::DepthBounds)?;
439 
440         let queue_family_properties = self.queue_family_properties();
441 
442         // VUID-vkCmdSetDepthBounds-commandBuffer-cmdpool
443         if !queue_family_properties
444             .queue_flags
445             .intersects(QueueFlags::GRAPHICS)
446         {
447             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
448         }
449 
450         // VUID-vkCmdSetDepthBounds-minDepthBounds-00600
451         // VUID-vkCmdSetDepthBounds-maxDepthBounds-00601
452         if !self
453             .device()
454             .enabled_extensions()
455             .ext_depth_range_unrestricted
456             && !((0.0..=1.0).contains(bounds.start()) && (0.0..=1.0).contains(bounds.end()))
457         {
458             return Err(SetDynamicStateError::RequirementNotMet {
459                 required_for: "`bounds` is not between `0.0` and `1.0` inclusive",
460                 requires_one_of: RequiresOneOf {
461                     device_extensions: &["ext_depth_range_unrestricted"],
462                     ..Default::default()
463                 },
464             });
465         }
466 
467         Ok(())
468     }
469 
470     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_depth_bounds_unchecked(&mut self, bounds: RangeInclusive<f32>) -> &mut Self471     pub unsafe fn set_depth_bounds_unchecked(&mut self, bounds: RangeInclusive<f32>) -> &mut Self {
472         let fns = self.device().fns();
473         (fns.v1_0.cmd_set_depth_bounds)(self.handle(), *bounds.start(), *bounds.end());
474 
475         self.builder_state.depth_bounds = Some(bounds);
476 
477         self.next_command_index += 1;
478         self
479     }
480 
481     /// Sets whether dynamic depth bounds testing is enabled for future draw calls.
482     ///
483     /// # Panics
484     ///
485     /// - Panics if the queue family of the command buffer does not support graphics operations.
486     /// - Panics if the device API version is less than 1.3 and the [`extended_dynamic_state`]
487     ///   feature is not enabled on the device.
488     /// - Panics if the currently bound graphics pipeline already contains this state internally.
489     ///
490     /// [`extended_dynamic_state`]: crate::device::Features::extended_dynamic_state
491     #[inline]
set_depth_bounds_test_enable(&mut self, enable: bool) -> &mut Self492     pub fn set_depth_bounds_test_enable(&mut self, enable: bool) -> &mut Self {
493         self.validate_set_depth_bounds_test_enable(enable).unwrap();
494 
495         unsafe { self.set_depth_bounds_test_enable_unchecked(enable) }
496     }
497 
validate_set_depth_bounds_test_enable( &self, _enable: bool, ) -> Result<(), SetDynamicStateError>498     fn validate_set_depth_bounds_test_enable(
499         &self,
500         _enable: bool,
501     ) -> Result<(), SetDynamicStateError> {
502         self.validate_pipeline_fixed_state(DynamicState::DepthBoundsTestEnable)?;
503 
504         let queue_family_properties = self.queue_family_properties();
505 
506         // VUID-vkCmdSetDepthBoundsTestEnable-commandBuffer-cmdpool
507         if !queue_family_properties
508             .queue_flags
509             .intersects(QueueFlags::GRAPHICS)
510         {
511             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
512         }
513 
514         // VUID-vkCmdSetDepthBoundsTestEnable-None-03349
515         if !(self.device().api_version() >= Version::V1_3
516             || self.device().enabled_features().extended_dynamic_state)
517         {
518             return Err(SetDynamicStateError::RequirementNotMet {
519                 required_for: "`CommandBufferBuilder::set_depth_bounds_test_enable`",
520                 requires_one_of: RequiresOneOf {
521                     api_version: Some(Version::V1_3),
522                     features: &["extended_dynamic_state"],
523                     ..Default::default()
524                 },
525             });
526         }
527 
528         Ok(())
529     }
530 
531     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_depth_bounds_test_enable_unchecked(&mut self, enable: bool) -> &mut Self532     pub unsafe fn set_depth_bounds_test_enable_unchecked(&mut self, enable: bool) -> &mut Self {
533         let fns = self.device().fns();
534 
535         if self.device().api_version() >= Version::V1_3 {
536             (fns.v1_3.cmd_set_depth_bounds_test_enable)(self.handle(), enable.into());
537         } else {
538             debug_assert!(
539                 self.device()
540                     .enabled_extensions()
541                     .ext_extended_dynamic_state
542             );
543             (fns.ext_extended_dynamic_state
544                 .cmd_set_depth_bounds_test_enable_ext)(self.handle(), enable.into());
545         }
546 
547         self.builder_state.depth_bounds_test_enable = Some(enable);
548 
549         self.next_command_index += 1;
550         self
551     }
552 
553     /// Sets the dynamic depth compare op for future draw calls.
554     ///
555     /// # Panics
556     ///
557     /// - Panics if the queue family of the command buffer does not support graphics operations.
558     /// - Panics if the device API version is less than 1.3 and the
559     ///   [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
560     ///   not enabled on the device.
561     /// - Panics if the currently bound graphics pipeline already contains this state internally.
562     #[inline]
set_depth_compare_op(&mut self, compare_op: CompareOp) -> &mut Self563     pub fn set_depth_compare_op(&mut self, compare_op: CompareOp) -> &mut Self {
564         self.validate_set_depth_compare_op(compare_op).unwrap();
565 
566         unsafe { self.set_depth_compare_op_unchecked(compare_op) }
567     }
568 
validate_set_depth_compare_op( &self, compare_op: CompareOp, ) -> Result<(), SetDynamicStateError>569     fn validate_set_depth_compare_op(
570         &self,
571         compare_op: CompareOp,
572     ) -> Result<(), SetDynamicStateError> {
573         self.validate_pipeline_fixed_state(DynamicState::DepthCompareOp)?;
574 
575         // VUID-vkCmdSetDepthCompareOp-depthCompareOp-parameter
576         compare_op.validate_device(self.device())?;
577 
578         let queue_family_properties = self.queue_family_properties();
579 
580         // VUID-vkCmdSetDepthCompareOp-commandBuffer-cmdpool
581         if !queue_family_properties
582             .queue_flags
583             .intersects(QueueFlags::GRAPHICS)
584         {
585             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
586         }
587 
588         // VUID-vkCmdSetDepthCompareOp-None-03353
589         if !(self.device().api_version() >= Version::V1_3
590             || self.device().enabled_features().extended_dynamic_state)
591         {
592             return Err(SetDynamicStateError::RequirementNotMet {
593                 required_for: "`CommandBufferBuilder::set_depth_compare_op`",
594                 requires_one_of: RequiresOneOf {
595                     api_version: Some(Version::V1_3),
596                     features: &["extended_dynamic_state"],
597                     ..Default::default()
598                 },
599             });
600         }
601 
602         Ok(())
603     }
604 
605     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_depth_compare_op_unchecked(&mut self, compare_op: CompareOp) -> &mut Self606     pub unsafe fn set_depth_compare_op_unchecked(&mut self, compare_op: CompareOp) -> &mut Self {
607         let fns = self.device().fns();
608 
609         if self.device().api_version() >= Version::V1_3 {
610             (fns.v1_3.cmd_set_depth_compare_op)(self.handle(), compare_op.into());
611         } else {
612             debug_assert!(
613                 self.device()
614                     .enabled_extensions()
615                     .ext_extended_dynamic_state
616             );
617             (fns.ext_extended_dynamic_state.cmd_set_depth_compare_op_ext)(
618                 self.handle(),
619                 compare_op.into(),
620             );
621         }
622 
623         self.builder_state.depth_compare_op = Some(compare_op);
624 
625         self.next_command_index += 1;
626         self
627     }
628 
629     /// Sets whether dynamic depth testing is enabled for future draw calls.
630     ///
631     /// # Panics
632     ///
633     /// - Panics if the queue family of the command buffer does not support graphics operations.
634     /// - Panics if the device API version is less than 1.3 and the
635     ///   [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
636     ///   not enabled on the device.
637     /// - Panics if the currently bound graphics pipeline already contains this state internally.
638     #[inline]
set_depth_test_enable(&mut self, enable: bool) -> &mut Self639     pub fn set_depth_test_enable(&mut self, enable: bool) -> &mut Self {
640         self.validate_set_depth_test_enable(enable).unwrap();
641 
642         unsafe { self.set_depth_test_enable_unchecked(enable) }
643     }
644 
validate_set_depth_test_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError>645     fn validate_set_depth_test_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError> {
646         self.validate_pipeline_fixed_state(DynamicState::DepthTestEnable)?;
647 
648         let queue_family_properties = self.queue_family_properties();
649 
650         // VUID-vkCmdSetDepthTestEnable-commandBuffer-cmdpool
651         if !queue_family_properties
652             .queue_flags
653             .intersects(QueueFlags::GRAPHICS)
654         {
655             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
656         }
657 
658         // VUID-vkCmdSetDepthTestEnable-None-03352
659         if !(self.device().api_version() >= Version::V1_3
660             || self.device().enabled_features().extended_dynamic_state)
661         {
662             return Err(SetDynamicStateError::RequirementNotMet {
663                 required_for: "`CommandBufferBuilder::set_depth_test_enable`",
664                 requires_one_of: RequiresOneOf {
665                     api_version: Some(Version::V1_3),
666                     features: &["extended_dynamic_state"],
667                     ..Default::default()
668                 },
669             });
670         }
671 
672         Ok(())
673     }
674 
675     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_depth_test_enable_unchecked(&mut self, enable: bool) -> &mut Self676     pub unsafe fn set_depth_test_enable_unchecked(&mut self, enable: bool) -> &mut Self {
677         let fns = self.device().fns();
678 
679         if self.device().api_version() >= Version::V1_3 {
680             (fns.v1_3.cmd_set_depth_test_enable)(self.handle(), enable.into());
681         } else {
682             debug_assert!(
683                 self.device()
684                     .enabled_extensions()
685                     .ext_extended_dynamic_state
686             );
687             (fns.ext_extended_dynamic_state.cmd_set_depth_test_enable_ext)(
688                 self.handle(),
689                 enable.into(),
690             );
691         }
692 
693         self.builder_state.depth_test_enable = Some(enable);
694 
695         self.next_command_index += 1;
696         self
697     }
698 
699     /// Sets whether dynamic depth write is enabled for future draw calls.
700     ///
701     /// # Panics
702     ///
703     /// - Panics if the queue family of the command buffer does not support graphics operations.
704     /// - Panics if the device API version is less than 1.3 and the
705     ///   [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
706     ///   not enabled on the device.
707     /// - Panics if the currently bound graphics pipeline already contains this state internally.
708     #[inline]
set_depth_write_enable(&mut self, enable: bool) -> &mut Self709     pub fn set_depth_write_enable(&mut self, enable: bool) -> &mut Self {
710         self.validate_set_depth_write_enable(enable).unwrap();
711 
712         unsafe { self.set_depth_write_enable_unchecked(enable) }
713     }
714 
validate_set_depth_write_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError>715     fn validate_set_depth_write_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError> {
716         self.validate_pipeline_fixed_state(DynamicState::DepthWriteEnable)?;
717 
718         let queue_family_properties = self.queue_family_properties();
719 
720         // VUID-vkCmdSetDepthWriteEnable-commandBuffer-cmdpool
721         if !queue_family_properties
722             .queue_flags
723             .intersects(QueueFlags::GRAPHICS)
724         {
725             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
726         }
727 
728         // VUID-vkCmdSetDepthWriteEnable-None-03354
729         if !(self.device().api_version() >= Version::V1_3
730             || self.device().enabled_features().extended_dynamic_state)
731         {
732             return Err(SetDynamicStateError::RequirementNotMet {
733                 required_for: "`CommandBufferBuilder::set_depth_write_enable`",
734                 requires_one_of: RequiresOneOf {
735                     api_version: Some(Version::V1_3),
736                     features: &["extended_dynamic_state"],
737                     ..Default::default()
738                 },
739             });
740         }
741 
742         Ok(())
743     }
744 
745     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_depth_write_enable_unchecked(&mut self, enable: bool) -> &mut Self746     pub unsafe fn set_depth_write_enable_unchecked(&mut self, enable: bool) -> &mut Self {
747         let fns = self.device().fns();
748 
749         if self.device().api_version() >= Version::V1_3 {
750             (fns.v1_3.cmd_set_depth_write_enable)(self.handle(), enable.into());
751         } else {
752             debug_assert!(
753                 self.device()
754                     .enabled_extensions()
755                     .ext_extended_dynamic_state
756             );
757             (fns.ext_extended_dynamic_state
758                 .cmd_set_depth_write_enable_ext)(self.handle(), enable.into());
759         }
760 
761         self.builder_state.depth_write_enable = Some(enable);
762 
763         self.next_command_index += 1;
764         self
765     }
766 
767     /// Sets the dynamic discard rectangles for future draw calls.
768     ///
769     /// # Panics
770     ///
771     /// - Panics if the queue family of the command buffer does not support graphics operations.
772     /// - Panics if the
773     ///   [`ext_discard_rectangles`](crate::device::DeviceExtensions::ext_discard_rectangles)
774     ///   extension is not enabled on the device.
775     /// - Panics if the currently bound graphics pipeline already contains this state internally.
776     /// - Panics if the highest discard rectangle slot being set is greater than the
777     ///   [`max_discard_rectangles`](crate::device::Properties::max_discard_rectangles) device
778     ///   property.
set_discard_rectangle( &mut self, first_rectangle: u32, rectangles: impl IntoIterator<Item = Scissor>, ) -> &mut Self779     pub fn set_discard_rectangle(
780         &mut self,
781         first_rectangle: u32,
782         rectangles: impl IntoIterator<Item = Scissor>,
783     ) -> &mut Self {
784         let rectangles: SmallVec<[Scissor; 2]> = rectangles.into_iter().collect();
785         self.validate_set_discard_rectangle(first_rectangle, &rectangles)
786             .unwrap();
787 
788         unsafe { self.set_discard_rectangle_unchecked(first_rectangle, rectangles) }
789     }
790 
validate_set_discard_rectangle( &self, first_rectangle: u32, rectangles: &[Scissor], ) -> Result<(), SetDynamicStateError>791     fn validate_set_discard_rectangle(
792         &self,
793         first_rectangle: u32,
794         rectangles: &[Scissor],
795     ) -> Result<(), SetDynamicStateError> {
796         self.validate_pipeline_fixed_state(DynamicState::DiscardRectangle)?;
797 
798         let queue_family_properties = self.queue_family_properties();
799 
800         // VUID-vkCmdSetDiscardRectangle-commandBuffer-cmdpool
801         if !queue_family_properties
802             .queue_flags
803             .intersects(QueueFlags::GRAPHICS)
804         {
805             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
806         }
807 
808         if self.device().enabled_extensions().ext_discard_rectangles {
809             return Err(SetDynamicStateError::RequirementNotMet {
810                 required_for: "`CommandBufferBuilder::set_discard_rectangle`",
811                 requires_one_of: RequiresOneOf {
812                     device_extensions: &["ext_discard_rectangles"],
813                     ..Default::default()
814                 },
815             });
816         }
817 
818         // VUID-vkCmdSetDiscardRectangleEXT-firstDiscardRectangle-00585
819         if first_rectangle + rectangles.len() as u32
820             > self
821                 .device()
822                 .physical_device()
823                 .properties()
824                 .max_discard_rectangles
825                 .unwrap()
826         {
827             return Err(SetDynamicStateError::MaxDiscardRectanglesExceeded {
828                 provided: first_rectangle + rectangles.len() as u32,
829                 max: self
830                     .device()
831                     .physical_device()
832                     .properties()
833                     .max_discard_rectangles
834                     .unwrap(),
835             });
836         }
837 
838         Ok(())
839     }
840 
841     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_discard_rectangle_unchecked( &mut self, first_rectangle: u32, rectangles: impl IntoIterator<Item = Scissor>, ) -> &mut Self842     pub unsafe fn set_discard_rectangle_unchecked(
843         &mut self,
844         first_rectangle: u32,
845         rectangles: impl IntoIterator<Item = Scissor>,
846     ) -> &mut Self {
847         let rectangles: SmallVec<[Scissor; 2]> = rectangles.into_iter().collect();
848 
849         if rectangles.is_empty() {
850             return self;
851         }
852 
853         debug_assert!(self.device().enabled_extensions().ext_discard_rectangles);
854 
855         let rectangles_vk = rectangles
856             .iter()
857             .copied()
858             .map(ash::vk::Rect2D::from)
859             .collect::<SmallVec<[_; 2]>>();
860 
861         debug_assert!(
862             first_rectangle + rectangles.len() as u32
863                 <= self
864                     .device()
865                     .physical_device()
866                     .properties()
867                     .max_discard_rectangles
868                     .unwrap()
869         );
870 
871         let fns = self.device().fns();
872         (fns.ext_discard_rectangles.cmd_set_discard_rectangle_ext)(
873             self.handle(),
874             first_rectangle,
875             rectangles_vk.len() as u32,
876             rectangles_vk.as_ptr(),
877         );
878 
879         for (num, rectangle) in rectangles.iter().enumerate() {
880             let num = num as u32 + first_rectangle;
881             self.builder_state.discard_rectangle.insert(num, *rectangle);
882         }
883 
884         self.next_command_index += 1;
885         self
886     }
887 
888     /// Sets the dynamic front face for future draw calls.
889     ///
890     /// # Panics
891     ///
892     /// - Panics if the queue family of the command buffer does not support graphics operations.
893     /// - Panics if the device API version is less than 1.3 and the
894     ///   [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
895     ///   not enabled on the device.
896     /// - Panics if the currently bound graphics pipeline already contains this state internally.
897     #[inline]
set_front_face(&mut self, face: FrontFace) -> &mut Self898     pub fn set_front_face(&mut self, face: FrontFace) -> &mut Self {
899         self.validate_set_front_face(face).unwrap();
900 
901         unsafe { self.set_front_face_unchecked(face) }
902     }
903 
validate_set_front_face(&self, face: FrontFace) -> Result<(), SetDynamicStateError>904     fn validate_set_front_face(&self, face: FrontFace) -> Result<(), SetDynamicStateError> {
905         self.validate_pipeline_fixed_state(DynamicState::FrontFace)?;
906 
907         // VUID-vkCmdSetFrontFace-frontFace-parameter
908         face.validate_device(self.device())?;
909 
910         let queue_family_properties = self.queue_family_properties();
911 
912         // VUID-vkCmdSetFrontFace-commandBuffer-cmdpool
913         if !queue_family_properties
914             .queue_flags
915             .intersects(QueueFlags::GRAPHICS)
916         {
917             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
918         }
919 
920         // VUID-vkCmdSetFrontFace-None-03383
921         if !(self.device().api_version() >= Version::V1_3
922             || self.device().enabled_features().extended_dynamic_state)
923         {
924             return Err(SetDynamicStateError::RequirementNotMet {
925                 required_for: "`CommandBufferBuilder::set_front_face`",
926                 requires_one_of: RequiresOneOf {
927                     api_version: Some(Version::V1_3),
928                     features: &["extended_dynamic_state"],
929                     ..Default::default()
930                 },
931             });
932         }
933 
934         Ok(())
935     }
936 
937     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_front_face_unchecked(&mut self, face: FrontFace) -> &mut Self938     pub unsafe fn set_front_face_unchecked(&mut self, face: FrontFace) -> &mut Self {
939         let fns = self.device().fns();
940 
941         if self.device().api_version() >= Version::V1_3 {
942             (fns.v1_3.cmd_set_front_face)(self.handle(), face.into());
943         } else {
944             debug_assert!(
945                 self.device()
946                     .enabled_extensions()
947                     .ext_extended_dynamic_state
948             );
949             (fns.ext_extended_dynamic_state.cmd_set_front_face_ext)(self.handle(), face.into());
950         }
951 
952         self.builder_state.front_face = Some(face);
953 
954         self.next_command_index += 1;
955         self
956     }
957 
958     /// Sets the dynamic line stipple values for future draw calls.
959     ///
960     /// # Panics
961     ///
962     /// - Panics if the queue family of the command buffer does not support graphics operations.
963     /// - Panics if the [`ext_line_rasterization`](crate::device::DeviceExtensions::ext_line_rasterization)
964     ///   extension is not enabled on the device.
965     /// - Panics if the currently bound graphics pipeline already contains this state internally.
966     /// - Panics if `factor` is not between 1 and 256 inclusive.
967     #[inline]
set_line_stipple(&mut self, factor: u32, pattern: u16) -> &mut Self968     pub fn set_line_stipple(&mut self, factor: u32, pattern: u16) -> &mut Self {
969         self.validate_set_line_stipple(factor, pattern).unwrap();
970 
971         unsafe { self.set_line_stipple_unchecked(factor, pattern) }
972     }
973 
validate_set_line_stipple( &self, factor: u32, _pattern: u16, ) -> Result<(), SetDynamicStateError>974     fn validate_set_line_stipple(
975         &self,
976         factor: u32,
977         _pattern: u16,
978     ) -> Result<(), SetDynamicStateError> {
979         self.validate_pipeline_fixed_state(DynamicState::LineStipple)?;
980 
981         let queue_family_properties = self.queue_family_properties();
982 
983         // VUID-vkCmdSetLineStippleEXT-commandBuffer-cmdpool
984         if !queue_family_properties
985             .queue_flags
986             .intersects(QueueFlags::GRAPHICS)
987         {
988             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
989         }
990 
991         if !self.device().enabled_extensions().ext_line_rasterization {
992             return Err(SetDynamicStateError::RequirementNotMet {
993                 required_for: "`CommandBufferBuilder::set_line_stipple`",
994                 requires_one_of: RequiresOneOf {
995                     device_extensions: &["ext_line_rasterization"],
996                     ..Default::default()
997                 },
998             });
999         }
1000 
1001         // VUID-vkCmdSetLineStippleEXT-lineStippleFactor-02776
1002         if !(1..=256).contains(&factor) {
1003             return Err(SetDynamicStateError::FactorOutOfRange);
1004         }
1005 
1006         Ok(())
1007     }
1008 
1009     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_line_stipple_unchecked(&mut self, factor: u32, pattern: u16) -> &mut Self1010     pub unsafe fn set_line_stipple_unchecked(&mut self, factor: u32, pattern: u16) -> &mut Self {
1011         debug_assert!(self.device().enabled_extensions().ext_line_rasterization);
1012         let fns = self.device().fns();
1013         (fns.ext_line_rasterization.cmd_set_line_stipple_ext)(self.handle(), factor, pattern);
1014 
1015         self.builder_state.line_stipple = Some(LineStipple { factor, pattern });
1016 
1017         self.next_command_index += 1;
1018         self
1019     }
1020 
1021     /// Sets the dynamic line width for future draw calls.
1022     ///
1023     /// # Panics
1024     ///
1025     /// - Panics if the queue family of the command buffer does not support graphics operations.
1026     /// - Panics if the currently bound graphics pipeline already contains this state internally.
1027     /// - If the [`wide_lines`](crate::device::Features::wide_lines) feature is not enabled, panics
1028     ///   if `line_width` is not 1.0.
set_line_width(&mut self, line_width: f32) -> &mut Self1029     pub fn set_line_width(&mut self, line_width: f32) -> &mut Self {
1030         self.validate_set_line_width(line_width).unwrap();
1031 
1032         unsafe { self.set_line_width_unchecked(line_width) }
1033     }
1034 
validate_set_line_width(&self, line_width: f32) -> Result<(), SetDynamicStateError>1035     fn validate_set_line_width(&self, line_width: f32) -> Result<(), SetDynamicStateError> {
1036         self.validate_pipeline_fixed_state(DynamicState::LineWidth)?;
1037 
1038         let queue_family_properties = self.queue_family_properties();
1039 
1040         // VUID-vkCmdSetLineWidth-commandBuffer-cmdpool
1041         if !queue_family_properties
1042             .queue_flags
1043             .intersects(QueueFlags::GRAPHICS)
1044         {
1045             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
1046         }
1047 
1048         // VUID-vkCmdSetLineWidth-lineWidth-00788
1049         if !self.device().enabled_features().wide_lines && line_width != 1.0 {
1050             return Err(SetDynamicStateError::RequirementNotMet {
1051                 required_for: "`line_width` is not `1.0`",
1052                 requires_one_of: RequiresOneOf {
1053                     features: &["wide_lines"],
1054                     ..Default::default()
1055                 },
1056             });
1057         }
1058 
1059         Ok(())
1060     }
1061 
1062     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_line_width_unchecked(&mut self, line_width: f32) -> &mut Self1063     pub unsafe fn set_line_width_unchecked(&mut self, line_width: f32) -> &mut Self {
1064         let fns = self.device().fns();
1065         (fns.v1_0.cmd_set_line_width)(self.handle(), line_width);
1066 
1067         self.builder_state.line_width = Some(line_width);
1068 
1069         self.next_command_index += 1;
1070         self
1071     }
1072 
1073     /// Sets the dynamic logic op for future draw calls.
1074     ///
1075     /// # Panics
1076     ///
1077     /// - Panics if the queue family of the command buffer does not support graphics operations.
1078     /// - Panics if the
1079     ///   [`extended_dynamic_state2_logic_op`](crate::device::Features::extended_dynamic_state2_logic_op)
1080     ///   feature is not enabled on the device.
1081     /// - Panics if the currently bound graphics pipeline already contains this state internally.
1082     #[inline]
set_logic_op(&mut self, logic_op: LogicOp) -> &mut Self1083     pub fn set_logic_op(&mut self, logic_op: LogicOp) -> &mut Self {
1084         self.validate_set_logic_op(logic_op).unwrap();
1085 
1086         unsafe { self.set_logic_op_unchecked(logic_op) }
1087     }
1088 
validate_set_logic_op(&self, logic_op: LogicOp) -> Result<(), SetDynamicStateError>1089     fn validate_set_logic_op(&self, logic_op: LogicOp) -> Result<(), SetDynamicStateError> {
1090         self.validate_pipeline_fixed_state(DynamicState::LogicOp)?;
1091 
1092         // VUID-vkCmdSetLogicOpEXT-logicOp-parameter
1093         logic_op.validate_device(self.device())?;
1094 
1095         let queue_family_properties = self.queue_family_properties();
1096 
1097         // VUID-vkCmdSetLogicOpEXT-commandBuffer-cmdpool
1098         if !queue_family_properties
1099             .queue_flags
1100             .intersects(QueueFlags::GRAPHICS)
1101         {
1102             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
1103         }
1104 
1105         // VUID-vkCmdSetLogicOpEXT-None-04867
1106         if !self
1107             .device()
1108             .enabled_features()
1109             .extended_dynamic_state2_logic_op
1110         {
1111             return Err(SetDynamicStateError::RequirementNotMet {
1112                 required_for: "`CommandBufferBuilder::set_logic_op`",
1113                 requires_one_of: RequiresOneOf {
1114                     features: &["extended_dynamic_state2_logic_op"],
1115                     ..Default::default()
1116                 },
1117             });
1118         }
1119 
1120         Ok(())
1121     }
1122 
1123     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_logic_op_unchecked(&mut self, logic_op: LogicOp) -> &mut Self1124     pub unsafe fn set_logic_op_unchecked(&mut self, logic_op: LogicOp) -> &mut Self {
1125         debug_assert!(
1126             self.device()
1127                 .enabled_extensions()
1128                 .ext_extended_dynamic_state2
1129         );
1130         debug_assert!(
1131             self.device()
1132                 .enabled_features()
1133                 .extended_dynamic_state2_logic_op
1134         );
1135         let fns = self.device().fns();
1136         (fns.ext_extended_dynamic_state2.cmd_set_logic_op_ext)(self.handle(), logic_op.into());
1137 
1138         self.builder_state.logic_op = Some(logic_op);
1139 
1140         self.next_command_index += 1;
1141         self
1142     }
1143 
1144     /// Sets the dynamic number of patch control points for future draw calls.
1145     ///
1146     /// # Panics
1147     ///
1148     /// - Panics if the queue family of the command buffer does not support graphics operations.
1149     /// - Panics if the
1150     ///   [`extended_dynamic_state2_patch_control_points`](crate::device::Features::extended_dynamic_state2_patch_control_points)
1151     ///   feature is not enabled on the device.
1152     /// - Panics if the currently bound graphics pipeline already contains this state internally.
1153     /// - Panics if `num` is 0.
1154     /// - Panics if `num` is greater than the
1155     ///   [`max_tessellation_patch_size`](crate::device::Properties::max_tessellation_patch_size)
1156     ///   property of the device.
1157     #[inline]
set_patch_control_points(&mut self, num: u32) -> &mut Self1158     pub fn set_patch_control_points(&mut self, num: u32) -> &mut Self {
1159         self.validate_set_patch_control_points(num).unwrap();
1160 
1161         unsafe { self.set_patch_control_points_unchecked(num) }
1162     }
1163 
validate_set_patch_control_points(&self, num: u32) -> Result<(), SetDynamicStateError>1164     fn validate_set_patch_control_points(&self, num: u32) -> Result<(), SetDynamicStateError> {
1165         self.validate_pipeline_fixed_state(DynamicState::PatchControlPoints)?;
1166 
1167         let queue_family_properties = self.queue_family_properties();
1168 
1169         // VUID-vkCmdSetPatchControlPointsEXT-commandBuffer-cmdpool
1170         if !queue_family_properties
1171             .queue_flags
1172             .intersects(QueueFlags::GRAPHICS)
1173         {
1174             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
1175         }
1176 
1177         // VUID-vkCmdSetPatchControlPointsEXT-None-04873
1178         if !self
1179             .device()
1180             .enabled_features()
1181             .extended_dynamic_state2_patch_control_points
1182         {
1183             return Err(SetDynamicStateError::RequirementNotMet {
1184                 required_for: "`CommandBufferBuilder::set_patch_control_points`",
1185                 requires_one_of: RequiresOneOf {
1186                     features: &["extended_dynamic_state2_patch_control_points"],
1187                     ..Default::default()
1188                 },
1189             });
1190         }
1191 
1192         // VUID-vkCmdSetPatchControlPointsEXT-patchControlPoints-04874
1193         assert!(num > 0, "num must be greater than 0");
1194 
1195         // VUID-vkCmdSetPatchControlPointsEXT-patchControlPoints-04874
1196         if num
1197             > self
1198                 .device()
1199                 .physical_device()
1200                 .properties()
1201                 .max_tessellation_patch_size
1202         {
1203             return Err(SetDynamicStateError::MaxTessellationPatchSizeExceeded {
1204                 provided: num,
1205                 max: self
1206                     .device()
1207                     .physical_device()
1208                     .properties()
1209                     .max_tessellation_patch_size,
1210             });
1211         }
1212 
1213         Ok(())
1214     }
1215 
1216     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_patch_control_points_unchecked(&mut self, num: u32) -> &mut Self1217     pub unsafe fn set_patch_control_points_unchecked(&mut self, num: u32) -> &mut Self {
1218         debug_assert!(
1219             self.device()
1220                 .enabled_extensions()
1221                 .ext_extended_dynamic_state2
1222         );
1223         let fns = self.device().fns();
1224         (fns.ext_extended_dynamic_state2
1225             .cmd_set_patch_control_points_ext)(self.handle(), num);
1226 
1227         self.builder_state.patch_control_points = Some(num);
1228 
1229         self.next_command_index += 1;
1230         self
1231     }
1232 
1233     /// Sets whether dynamic primitive restart is enabled for future draw calls.
1234     ///
1235     /// # Panics
1236     ///
1237     /// - Panics if the queue family of the command buffer does not support graphics operations.
1238     /// - Panics if the device API version is less than 1.3 and the
1239     ///   [`extended_dynamic_state2`](crate::device::Features::extended_dynamic_state2) feature is
1240     ///   not enabled on the device.
1241     /// - Panics if the currently bound graphics pipeline already contains this state internally.
1242     #[inline]
set_primitive_restart_enable(&mut self, enable: bool) -> &mut Self1243     pub fn set_primitive_restart_enable(&mut self, enable: bool) -> &mut Self {
1244         self.validate_set_primitive_restart_enable(enable).unwrap();
1245 
1246         unsafe { self.set_primitive_restart_enable_unchecked(enable) }
1247     }
1248 
validate_set_primitive_restart_enable( &self, _enable: bool, ) -> Result<(), SetDynamicStateError>1249     fn validate_set_primitive_restart_enable(
1250         &self,
1251         _enable: bool,
1252     ) -> Result<(), SetDynamicStateError> {
1253         self.validate_pipeline_fixed_state(DynamicState::PrimitiveRestartEnable)?;
1254 
1255         let queue_family_properties = self.queue_family_properties();
1256 
1257         // VUID-vkCmdSetPrimitiveRestartEnable-commandBuffer-cmdpool
1258         if !queue_family_properties
1259             .queue_flags
1260             .intersects(QueueFlags::GRAPHICS)
1261         {
1262             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
1263         }
1264 
1265         // VUID-vkCmdSetPrimitiveRestartEnable-None-04866
1266         if !(self.device().api_version() >= Version::V1_3
1267             || self.device().enabled_features().extended_dynamic_state2)
1268         {
1269             return Err(SetDynamicStateError::RequirementNotMet {
1270                 required_for: "`CommandBufferBuilder::set_primitive_restart_enable`",
1271                 requires_one_of: RequiresOneOf {
1272                     api_version: Some(Version::V1_3),
1273                     features: &["extended_dynamic_state2"],
1274                     ..Default::default()
1275                 },
1276             });
1277         }
1278 
1279         Ok(())
1280     }
1281 
1282     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_primitive_restart_enable_unchecked(&mut self, enable: bool) -> &mut Self1283     pub unsafe fn set_primitive_restart_enable_unchecked(&mut self, enable: bool) -> &mut Self {
1284         let fns = self.device().fns();
1285 
1286         if self.device().api_version() >= Version::V1_3 {
1287             (fns.v1_3.cmd_set_primitive_restart_enable)(self.handle(), enable.into());
1288         } else {
1289             debug_assert!(
1290                 self.device()
1291                     .enabled_extensions()
1292                     .ext_extended_dynamic_state2
1293             );
1294             (fns.ext_extended_dynamic_state2
1295                 .cmd_set_primitive_restart_enable_ext)(self.handle(), enable.into());
1296         }
1297 
1298         self.builder_state.primitive_restart_enable = Some(enable);
1299 
1300         self.next_command_index += 1;
1301         self
1302     }
1303 
1304     /// Sets the dynamic primitive topology for future draw calls.
1305     ///
1306     /// # Panics
1307     ///
1308     /// - Panics if the queue family of the command buffer does not support graphics operations.
1309     /// - Panics if the device API version is less than 1.3 and the
1310     ///   [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
1311     ///   not enabled on the device.
1312     /// - Panics if the currently bound graphics pipeline already contains this state internally.
1313     /// - If the [`geometry_shader`](crate::device::Features::geometry_shader) feature is not
1314     ///   enabled, panics if `topology` is a `WithAdjacency` topology.
1315     /// - If the [`tessellation_shader`](crate::device::Features::tessellation_shader) feature is
1316     ///   not enabled, panics if `topology` is `PatchList`.
1317     #[inline]
set_primitive_topology(&mut self, topology: PrimitiveTopology) -> &mut Self1318     pub fn set_primitive_topology(&mut self, topology: PrimitiveTopology) -> &mut Self {
1319         self.validate_set_primitive_topology(topology).unwrap();
1320 
1321         unsafe { self.set_primitive_topology_unchecked(topology) }
1322     }
1323 
validate_set_primitive_topology( &self, topology: PrimitiveTopology, ) -> Result<(), SetDynamicStateError>1324     fn validate_set_primitive_topology(
1325         &self,
1326         topology: PrimitiveTopology,
1327     ) -> Result<(), SetDynamicStateError> {
1328         self.validate_pipeline_fixed_state(DynamicState::PrimitiveTopology)?;
1329 
1330         // VUID-vkCmdSetPrimitiveTopology-primitiveTopology-parameter
1331         topology.validate_device(self.device())?;
1332 
1333         let queue_family_properties = self.queue_family_properties();
1334 
1335         // VUID-vkCmdSetPrimitiveTopology-commandBuffer-cmdpool
1336         if !queue_family_properties
1337             .queue_flags
1338             .intersects(QueueFlags::GRAPHICS)
1339         {
1340             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
1341         }
1342 
1343         // VUID-vkCmdSetPrimitiveTopology-None-03347
1344         if !(self.device().api_version() >= Version::V1_3
1345             || self.device().enabled_features().extended_dynamic_state)
1346         {
1347             return Err(SetDynamicStateError::RequirementNotMet {
1348                 required_for: "`CommandBufferBuilder::set_primitive_topology`",
1349                 requires_one_of: RequiresOneOf {
1350                     api_version: Some(Version::V1_3),
1351                     features: &["extended_dynamic_state"],
1352                     ..Default::default()
1353                 },
1354             });
1355         }
1356 
1357         // VUID?
1358         // Since these requirements exist for fixed state when creating the pipeline,
1359         // I assume they exist for dynamic state as well.
1360         match topology {
1361             PrimitiveTopology::TriangleFan => {
1362                 if self.device().enabled_extensions().khr_portability_subset
1363                     && !self.device().enabled_features().triangle_fans
1364                 {
1365                     return Err(SetDynamicStateError::RequirementNotMet {
1366                         required_for: "this device is a portability subset device, and `topology` \
1367                             is `PrimitiveTopology::TriangleFan`",
1368                         requires_one_of: RequiresOneOf {
1369                             features: &["triangle_fans"],
1370                             ..Default::default()
1371                         },
1372                     });
1373                 }
1374             }
1375             PrimitiveTopology::LineListWithAdjacency
1376             | PrimitiveTopology::LineStripWithAdjacency
1377             | PrimitiveTopology::TriangleListWithAdjacency
1378             | PrimitiveTopology::TriangleStripWithAdjacency => {
1379                 if !self.device().enabled_features().geometry_shader {
1380                     return Err(SetDynamicStateError::RequirementNotMet {
1381                         required_for: "`topology` is `PrimitiveTopology::*WithAdjacency`",
1382                         requires_one_of: RequiresOneOf {
1383                             features: &["geometry_shader"],
1384                             ..Default::default()
1385                         },
1386                     });
1387                 }
1388             }
1389             PrimitiveTopology::PatchList => {
1390                 if !self.device().enabled_features().tessellation_shader {
1391                     return Err(SetDynamicStateError::RequirementNotMet {
1392                         required_for: "`topology` is `PrimitiveTopology::PatchList`",
1393                         requires_one_of: RequiresOneOf {
1394                             features: &["tessellation_shader"],
1395                             ..Default::default()
1396                         },
1397                     });
1398                 }
1399             }
1400             _ => (),
1401         }
1402 
1403         Ok(())
1404     }
1405 
1406     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_primitive_topology_unchecked( &mut self, topology: PrimitiveTopology, ) -> &mut Self1407     pub unsafe fn set_primitive_topology_unchecked(
1408         &mut self,
1409         topology: PrimitiveTopology,
1410     ) -> &mut Self {
1411         let fns = self.device().fns();
1412 
1413         if self.device().api_version() >= Version::V1_3 {
1414             (fns.v1_3.cmd_set_primitive_topology)(self.handle(), topology.into());
1415         } else {
1416             debug_assert!(
1417                 self.device()
1418                     .enabled_extensions()
1419                     .ext_extended_dynamic_state
1420             );
1421             (fns.ext_extended_dynamic_state
1422                 .cmd_set_primitive_topology_ext)(self.handle(), topology.into());
1423         }
1424 
1425         self.builder_state.primitive_topology = Some(topology);
1426 
1427         self.next_command_index += 1;
1428         self
1429     }
1430 
1431     /// Sets whether dynamic rasterizer discard is enabled for future draw calls.
1432     ///
1433     /// # Panics
1434     ///
1435     /// - Panics if the queue family of the command buffer does not support graphics operations.
1436     /// - Panics if the device API version is less than 1.3 and the
1437     ///   [`extended_dynamic_state2`](crate::device::Features::extended_dynamic_state2) feature is
1438     ///   not enabled on the device.
1439     /// - Panics if the currently bound graphics pipeline already contains this state internally.
1440     #[inline]
set_rasterizer_discard_enable(&mut self, enable: bool) -> &mut Self1441     pub fn set_rasterizer_discard_enable(&mut self, enable: bool) -> &mut Self {
1442         self.validate_set_rasterizer_discard_enable(enable).unwrap();
1443 
1444         unsafe { self.set_rasterizer_discard_enable_unchecked(enable) }
1445     }
1446 
validate_set_rasterizer_discard_enable( &self, _enable: bool, ) -> Result<(), SetDynamicStateError>1447     fn validate_set_rasterizer_discard_enable(
1448         &self,
1449         _enable: bool,
1450     ) -> Result<(), SetDynamicStateError> {
1451         self.validate_pipeline_fixed_state(DynamicState::RasterizerDiscardEnable)?;
1452 
1453         let queue_family_properties = self.queue_family_properties();
1454 
1455         // VUID-vkCmdSetRasterizerDiscardEnable-commandBuffer-cmdpool
1456         if !queue_family_properties
1457             .queue_flags
1458             .intersects(QueueFlags::GRAPHICS)
1459         {
1460             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
1461         }
1462 
1463         // VUID-vkCmdSetRasterizerDiscardEnable-None-04871
1464         if !(self.device().api_version() >= Version::V1_3
1465             || self.device().enabled_features().extended_dynamic_state2)
1466         {
1467             return Err(SetDynamicStateError::RequirementNotMet {
1468                 required_for: "`CommandBufferBuilder::set_rasterizer_discard_enable`",
1469                 requires_one_of: RequiresOneOf {
1470                     api_version: Some(Version::V1_3),
1471                     features: &["extended_dynamic_state2"],
1472                     ..Default::default()
1473                 },
1474             });
1475         }
1476 
1477         Ok(())
1478     }
1479 
1480     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_rasterizer_discard_enable_unchecked(&mut self, enable: bool) -> &mut Self1481     pub unsafe fn set_rasterizer_discard_enable_unchecked(&mut self, enable: bool) -> &mut Self {
1482         let fns = self.device().fns();
1483 
1484         if self.device().api_version() >= Version::V1_3 {
1485             (fns.v1_3.cmd_set_rasterizer_discard_enable)(self.handle(), enable.into());
1486         } else {
1487             debug_assert!(
1488                 self.device()
1489                     .enabled_extensions()
1490                     .ext_extended_dynamic_state2
1491             );
1492             (fns.ext_extended_dynamic_state2
1493                 .cmd_set_rasterizer_discard_enable_ext)(self.handle(), enable.into());
1494         }
1495 
1496         self.builder_state.rasterizer_discard_enable = Some(enable);
1497 
1498         self.next_command_index += 1;
1499         self
1500     }
1501 
1502     /// Sets the dynamic scissors for future draw calls.
1503     ///
1504     /// # Panics
1505     ///
1506     /// - Panics if the queue family of the command buffer does not support graphics operations.
1507     /// - Panics if the currently bound graphics pipeline already contains this state internally.
1508     /// - Panics if the highest scissor slot being set is greater than the
1509     ///   [`max_viewports`](crate::device::Properties::max_viewports) device property.
1510     /// - If the [`multi_viewport`](crate::device::Features::multi_viewport) feature is not enabled,
1511     ///   panics if `first_scissor` is not 0, or if more than 1 scissor is provided.
1512     #[inline]
set_scissor( &mut self, first_scissor: u32, scissors: impl IntoIterator<Item = Scissor>, ) -> &mut Self1513     pub fn set_scissor(
1514         &mut self,
1515         first_scissor: u32,
1516         scissors: impl IntoIterator<Item = Scissor>,
1517     ) -> &mut Self {
1518         let scissors: SmallVec<[Scissor; 2]> = scissors.into_iter().collect();
1519         self.validate_set_scissor(first_scissor, &scissors).unwrap();
1520 
1521         unsafe { self.set_scissor_unchecked(first_scissor, scissors) }
1522     }
1523 
validate_set_scissor( &self, first_scissor: u32, scissors: &[Scissor], ) -> Result<(), SetDynamicStateError>1524     fn validate_set_scissor(
1525         &self,
1526         first_scissor: u32,
1527         scissors: &[Scissor],
1528     ) -> Result<(), SetDynamicStateError> {
1529         self.validate_pipeline_fixed_state(DynamicState::Scissor)?;
1530 
1531         let queue_family_properties = self.queue_family_properties();
1532 
1533         // VUID-vkCmdSetScissor-commandBuffer-cmdpool
1534         if !queue_family_properties
1535             .queue_flags
1536             .intersects(QueueFlags::GRAPHICS)
1537         {
1538             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
1539         }
1540 
1541         // VUID-vkCmdSetScissor-firstScissor-00592
1542         if first_scissor + scissors.len() as u32
1543             > self.device().physical_device().properties().max_viewports
1544         {
1545             return Err(SetDynamicStateError::MaxViewportsExceeded {
1546                 provided: first_scissor + scissors.len() as u32,
1547                 max: self.device().physical_device().properties().max_viewports,
1548             });
1549         }
1550 
1551         if !self.device().enabled_features().multi_viewport {
1552             // VUID-vkCmdSetScissor-firstScissor-00593
1553             if first_scissor != 0 {
1554                 return Err(SetDynamicStateError::RequirementNotMet {
1555                     required_for: "`first_scissor` is not `0`",
1556                     requires_one_of: RequiresOneOf {
1557                         features: &["multi_viewport"],
1558                         ..Default::default()
1559                     },
1560                 });
1561             }
1562 
1563             // VUID-vkCmdSetScissor-scissorCount-00594
1564             if scissors.len() > 1 {
1565                 return Err(SetDynamicStateError::RequirementNotMet {
1566                     required_for: "`scissors.len()` is greater than `1`",
1567                     requires_one_of: RequiresOneOf {
1568                         features: &["multi_viewport"],
1569                         ..Default::default()
1570                     },
1571                 });
1572             }
1573         }
1574 
1575         Ok(())
1576     }
1577 
1578     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_scissor_unchecked( &mut self, first_scissor: u32, scissors: impl IntoIterator<Item = Scissor>, ) -> &mut Self1579     pub unsafe fn set_scissor_unchecked(
1580         &mut self,
1581         first_scissor: u32,
1582         scissors: impl IntoIterator<Item = Scissor>,
1583     ) -> &mut Self {
1584         let scissors: SmallVec<[Scissor; 2]> = scissors.into_iter().collect();
1585 
1586         if scissors.is_empty() {
1587             return self;
1588         }
1589 
1590         let scissors_vk = scissors
1591             .iter()
1592             .copied()
1593             .map(ash::vk::Rect2D::from)
1594             .collect::<SmallVec<[_; 2]>>();
1595 
1596         let fns = self.device().fns();
1597         (fns.v1_0.cmd_set_scissor)(
1598             self.handle(),
1599             first_scissor,
1600             scissors_vk.len() as u32,
1601             scissors_vk.as_ptr(),
1602         );
1603 
1604         for (num, scissor) in scissors.iter().enumerate() {
1605             let num = num as u32 + first_scissor;
1606             self.builder_state.scissor.insert(num, *scissor);
1607         }
1608 
1609         self.next_command_index += 1;
1610         self
1611     }
1612 
1613     /// Sets the dynamic scissors with count for future draw calls.
1614     ///
1615     /// # Panics
1616     ///
1617     /// - Panics if the queue family of the command buffer does not support graphics operations.
1618     /// - Panics if the device API version is less than 1.3 and the
1619     ///   [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
1620     ///   not enabled on the device.
1621     /// - Panics if the currently bound graphics pipeline already contains this state internally.
1622     /// - Panics if the highest scissor slot being set is greater than the
1623     ///   [`max_viewports`](crate::device::Properties::max_viewports) device property.
1624     /// - If the [`multi_viewport`](crate::device::Features::multi_viewport) feature is not enabled,
1625     ///   panics if more than 1 scissor is provided.
1626     #[inline]
set_scissor_with_count( &mut self, scissors: impl IntoIterator<Item = Scissor>, ) -> &mut Self1627     pub fn set_scissor_with_count(
1628         &mut self,
1629         scissors: impl IntoIterator<Item = Scissor>,
1630     ) -> &mut Self {
1631         let scissors: SmallVec<[Scissor; 2]> = scissors.into_iter().collect();
1632         self.validate_set_scissor_with_count(&scissors).unwrap();
1633 
1634         unsafe { self.set_scissor_with_count_unchecked(scissors) }
1635     }
1636 
validate_set_scissor_with_count( &self, scissors: &[Scissor], ) -> Result<(), SetDynamicStateError>1637     fn validate_set_scissor_with_count(
1638         &self,
1639         scissors: &[Scissor],
1640     ) -> Result<(), SetDynamicStateError> {
1641         self.validate_pipeline_fixed_state(DynamicState::ScissorWithCount)?;
1642 
1643         let queue_family_properties = self.queue_family_properties();
1644 
1645         // VUID-vkCmdSetScissorWithCount-commandBuffer-cmdpool
1646         if !queue_family_properties
1647             .queue_flags
1648             .intersects(QueueFlags::GRAPHICS)
1649         {
1650             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
1651         }
1652 
1653         // VUID-vkCmdSetScissorWithCount-None-03396
1654         if !(self.device().api_version() >= Version::V1_3
1655             || self.device().enabled_features().extended_dynamic_state)
1656         {
1657             return Err(SetDynamicStateError::RequirementNotMet {
1658                 required_for: "`CommandBufferBuilder::set_scissor_with_count`",
1659                 requires_one_of: RequiresOneOf {
1660                     api_version: Some(Version::V1_3),
1661                     features: &["extended_dynamic_state"],
1662                     ..Default::default()
1663                 },
1664             });
1665         }
1666 
1667         // VUID-vkCmdSetScissorWithCount-scissorCount-03397
1668         if scissors.len() as u32 > self.device().physical_device().properties().max_viewports {
1669             return Err(SetDynamicStateError::MaxViewportsExceeded {
1670                 provided: scissors.len() as u32,
1671                 max: self.device().physical_device().properties().max_viewports,
1672             });
1673         }
1674 
1675         // VUID-vkCmdSetScissorWithCount-scissorCount-03398
1676         if !self.device().enabled_features().multi_viewport && scissors.len() > 1 {
1677             return Err(SetDynamicStateError::RequirementNotMet {
1678                 required_for: "`scissors.len()` is greater than `1`",
1679                 requires_one_of: RequiresOneOf {
1680                     features: &["multi_viewport"],
1681                     ..Default::default()
1682                 },
1683             });
1684         }
1685 
1686         Ok(())
1687     }
1688 
1689     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_scissor_with_count_unchecked( &mut self, scissors: impl IntoIterator<Item = Scissor>, ) -> &mut Self1690     pub unsafe fn set_scissor_with_count_unchecked(
1691         &mut self,
1692         scissors: impl IntoIterator<Item = Scissor>,
1693     ) -> &mut Self {
1694         let scissors: SmallVec<[Scissor; 2]> = scissors.into_iter().collect();
1695 
1696         if scissors.is_empty() {
1697             return self;
1698         }
1699 
1700         let scissors_vk = scissors
1701             .iter()
1702             .copied()
1703             .map(ash::vk::Rect2D::from)
1704             .collect::<SmallVec<[_; 2]>>();
1705 
1706         let fns = self.device().fns();
1707 
1708         if self.device().api_version() >= Version::V1_3 {
1709             (fns.v1_3.cmd_set_scissor_with_count)(
1710                 self.handle(),
1711                 scissors_vk.len() as u32,
1712                 scissors_vk.as_ptr(),
1713             );
1714         } else {
1715             debug_assert!(
1716                 self.device()
1717                     .enabled_extensions()
1718                     .ext_extended_dynamic_state
1719             );
1720             (fns.ext_extended_dynamic_state
1721                 .cmd_set_scissor_with_count_ext)(
1722                 self.handle(),
1723                 scissors_vk.len() as u32,
1724                 scissors_vk.as_ptr(),
1725             );
1726         }
1727 
1728         self.builder_state.scissor_with_count = Some(scissors);
1729 
1730         self.next_command_index += 1;
1731         self
1732     }
1733 
1734     /// Sets the dynamic stencil compare mask on one or both faces for future draw calls.
1735     ///
1736     /// # Panics
1737     ///
1738     /// - Panics if the queue family of the command buffer does not support graphics operations.
1739     /// - Panics if the currently bound graphics pipeline already contains this state internally.
set_stencil_compare_mask( &mut self, faces: StencilFaces, compare_mask: u32, ) -> &mut Self1740     pub fn set_stencil_compare_mask(
1741         &mut self,
1742         faces: StencilFaces,
1743         compare_mask: u32,
1744     ) -> &mut Self {
1745         self.validate_set_stencil_compare_mask(faces, compare_mask)
1746             .unwrap();
1747 
1748         unsafe { self.set_stencil_compare_mask_unchecked(faces, compare_mask) }
1749     }
1750 
validate_set_stencil_compare_mask( &self, faces: StencilFaces, _compare_mask: u32, ) -> Result<(), SetDynamicStateError>1751     fn validate_set_stencil_compare_mask(
1752         &self,
1753         faces: StencilFaces,
1754         _compare_mask: u32,
1755     ) -> Result<(), SetDynamicStateError> {
1756         self.validate_pipeline_fixed_state(DynamicState::StencilCompareMask)?;
1757 
1758         // VUID-vkCmdSetStencilCompareMask-faceMask-parameter
1759         faces.validate_device(self.device())?;
1760 
1761         let queue_family_properties = self.queue_family_properties();
1762 
1763         // VUID-vkCmdSetStencilCompareMask-commandBuffer-cmdpool
1764         if !queue_family_properties
1765             .queue_flags
1766             .intersects(QueueFlags::GRAPHICS)
1767         {
1768             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
1769         }
1770 
1771         Ok(())
1772     }
1773 
1774     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_stencil_compare_mask_unchecked( &mut self, faces: StencilFaces, compare_mask: u32, ) -> &mut Self1775     pub unsafe fn set_stencil_compare_mask_unchecked(
1776         &mut self,
1777         faces: StencilFaces,
1778         compare_mask: u32,
1779     ) -> &mut Self {
1780         let fns = self.device().fns();
1781         (fns.v1_0.cmd_set_stencil_compare_mask)(self.handle(), faces.into(), compare_mask);
1782 
1783         let faces = ash::vk::StencilFaceFlags::from(faces);
1784 
1785         if faces.intersects(ash::vk::StencilFaceFlags::FRONT) {
1786             self.builder_state.stencil_compare_mask.front = Some(compare_mask);
1787         }
1788 
1789         if faces.intersects(ash::vk::StencilFaceFlags::BACK) {
1790             self.builder_state.stencil_compare_mask.back = Some(compare_mask);
1791         }
1792 
1793         self.next_command_index += 1;
1794         self
1795     }
1796 
1797     /// Sets the dynamic stencil ops on one or both faces for future draw calls.
1798     ///
1799     /// # Panics
1800     ///
1801     /// - Panics if the queue family of the command buffer does not support graphics operations.
1802     /// - Panics if the device API version is less than 1.3 and the
1803     ///   [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
1804     ///   not enabled on the device.
1805     /// - Panics if the currently bound graphics pipeline already contains this state internally.
1806     #[inline]
set_stencil_op( &mut self, faces: StencilFaces, fail_op: StencilOp, pass_op: StencilOp, depth_fail_op: StencilOp, compare_op: CompareOp, ) -> &mut Self1807     pub fn set_stencil_op(
1808         &mut self,
1809         faces: StencilFaces,
1810         fail_op: StencilOp,
1811         pass_op: StencilOp,
1812         depth_fail_op: StencilOp,
1813         compare_op: CompareOp,
1814     ) -> &mut Self {
1815         self.validate_set_stencil_op(faces, fail_op, pass_op, depth_fail_op, compare_op)
1816             .unwrap();
1817 
1818         unsafe { self.set_stencil_op_unchecked(faces, fail_op, pass_op, depth_fail_op, compare_op) }
1819     }
1820 
validate_set_stencil_op( &self, faces: StencilFaces, fail_op: StencilOp, pass_op: StencilOp, depth_fail_op: StencilOp, compare_op: CompareOp, ) -> Result<(), SetDynamicStateError>1821     fn validate_set_stencil_op(
1822         &self,
1823         faces: StencilFaces,
1824         fail_op: StencilOp,
1825         pass_op: StencilOp,
1826         depth_fail_op: StencilOp,
1827         compare_op: CompareOp,
1828     ) -> Result<(), SetDynamicStateError> {
1829         self.validate_pipeline_fixed_state(DynamicState::StencilOp)?;
1830 
1831         // VUID-vkCmdSetStencilOp-faceMask-parameter
1832         faces.validate_device(self.device())?;
1833 
1834         // VUID-vkCmdSetStencilOp-failOp-parameter
1835         fail_op.validate_device(self.device())?;
1836 
1837         // VUID-vkCmdSetStencilOp-passOp-parameter
1838         pass_op.validate_device(self.device())?;
1839 
1840         // VUID-vkCmdSetStencilOp-depthFailOp-parameter
1841         depth_fail_op.validate_device(self.device())?;
1842 
1843         // VUID-vkCmdSetStencilOp-compareOp-parameter
1844         compare_op.validate_device(self.device())?;
1845 
1846         let queue_family_properties = self.queue_family_properties();
1847 
1848         // VUID-vkCmdSetStencilOp-commandBuffer-cmdpool
1849         if !queue_family_properties
1850             .queue_flags
1851             .intersects(QueueFlags::GRAPHICS)
1852         {
1853             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
1854         }
1855 
1856         // VUID-vkCmdSetStencilOp-None-03351
1857         if !(self.device().api_version() >= Version::V1_3
1858             || self.device().enabled_features().extended_dynamic_state)
1859         {
1860             return Err(SetDynamicStateError::RequirementNotMet {
1861                 required_for: "`CommandBufferBuilder::set_stencil_op`",
1862                 requires_one_of: RequiresOneOf {
1863                     api_version: Some(Version::V1_3),
1864                     features: &["extended_dynamic_state"],
1865                     ..Default::default()
1866                 },
1867             });
1868         }
1869 
1870         Ok(())
1871     }
1872 
1873     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_stencil_op_unchecked( &mut self, faces: StencilFaces, fail_op: StencilOp, pass_op: StencilOp, depth_fail_op: StencilOp, compare_op: CompareOp, ) -> &mut Self1874     pub unsafe fn set_stencil_op_unchecked(
1875         &mut self,
1876         faces: StencilFaces,
1877         fail_op: StencilOp,
1878         pass_op: StencilOp,
1879         depth_fail_op: StencilOp,
1880         compare_op: CompareOp,
1881     ) -> &mut Self {
1882         let fns = self.device().fns();
1883 
1884         if self.device().api_version() >= Version::V1_3 {
1885             (fns.v1_3.cmd_set_stencil_op)(
1886                 self.handle(),
1887                 faces.into(),
1888                 fail_op.into(),
1889                 pass_op.into(),
1890                 depth_fail_op.into(),
1891                 compare_op.into(),
1892             );
1893         } else {
1894             debug_assert!(
1895                 self.device()
1896                     .enabled_extensions()
1897                     .ext_extended_dynamic_state
1898             );
1899             (fns.ext_extended_dynamic_state.cmd_set_stencil_op_ext)(
1900                 self.handle(),
1901                 faces.into(),
1902                 fail_op.into(),
1903                 pass_op.into(),
1904                 depth_fail_op.into(),
1905                 compare_op.into(),
1906             );
1907         }
1908 
1909         let faces = ash::vk::StencilFaceFlags::from(faces);
1910 
1911         if faces.intersects(ash::vk::StencilFaceFlags::FRONT) {
1912             self.builder_state.stencil_op.front = Some(StencilOps {
1913                 fail_op,
1914                 pass_op,
1915                 depth_fail_op,
1916                 compare_op,
1917             });
1918         }
1919 
1920         if faces.intersects(ash::vk::StencilFaceFlags::BACK) {
1921             self.builder_state.stencil_op.back = Some(StencilOps {
1922                 fail_op,
1923                 pass_op,
1924                 depth_fail_op,
1925                 compare_op,
1926             });
1927         }
1928 
1929         self.next_command_index += 1;
1930         self
1931     }
1932 
1933     /// Sets the dynamic stencil reference on one or both faces for future draw calls.
1934     ///
1935     /// # Panics
1936     ///
1937     /// - Panics if the queue family of the command buffer does not support graphics operations.
1938     /// - Panics if the currently bound graphics pipeline already contains this state internally.
set_stencil_reference(&mut self, faces: StencilFaces, reference: u32) -> &mut Self1939     pub fn set_stencil_reference(&mut self, faces: StencilFaces, reference: u32) -> &mut Self {
1940         self.validate_set_stencil_reference(faces, reference)
1941             .unwrap();
1942 
1943         unsafe { self.set_stencil_reference_unchecked(faces, reference) }
1944     }
1945 
validate_set_stencil_reference( &self, faces: StencilFaces, _reference: u32, ) -> Result<(), SetDynamicStateError>1946     fn validate_set_stencil_reference(
1947         &self,
1948         faces: StencilFaces,
1949         _reference: u32,
1950     ) -> Result<(), SetDynamicStateError> {
1951         self.validate_pipeline_fixed_state(DynamicState::StencilReference)?;
1952 
1953         // VUID-vkCmdSetStencilReference-faceMask-parameter
1954         faces.validate_device(self.device())?;
1955 
1956         let queue_family_properties = self.queue_family_properties();
1957 
1958         // VUID-vkCmdSetStencilReference-commandBuffer-cmdpool
1959         if !queue_family_properties
1960             .queue_flags
1961             .intersects(QueueFlags::GRAPHICS)
1962         {
1963             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
1964         }
1965 
1966         Ok(())
1967     }
1968 
1969     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_stencil_reference_unchecked( &mut self, faces: StencilFaces, reference: u32, ) -> &mut Self1970     pub unsafe fn set_stencil_reference_unchecked(
1971         &mut self,
1972         faces: StencilFaces,
1973         reference: u32,
1974     ) -> &mut Self {
1975         let fns = self.device().fns();
1976         (fns.v1_0.cmd_set_stencil_reference)(self.handle(), faces.into(), reference);
1977 
1978         let faces = ash::vk::StencilFaceFlags::from(faces);
1979 
1980         if faces.intersects(ash::vk::StencilFaceFlags::FRONT) {
1981             self.builder_state.stencil_reference.front = Some(reference);
1982         }
1983 
1984         if faces.intersects(ash::vk::StencilFaceFlags::BACK) {
1985             self.builder_state.stencil_reference.back = Some(reference);
1986         }
1987 
1988         self.next_command_index += 1;
1989         self
1990     }
1991 
1992     /// Sets whether dynamic stencil testing is enabled for future draw calls.
1993     ///
1994     /// # Panics
1995     ///
1996     /// - Panics if the queue family of the command buffer does not support graphics operations.
1997     /// - Panics if the device API version is less than 1.3 and the
1998     ///   [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
1999     ///   not enabled on the device.
2000     /// - Panics if the currently bound graphics pipeline already contains this state internally.
2001     #[inline]
set_stencil_test_enable(&mut self, enable: bool) -> &mut Self2002     pub fn set_stencil_test_enable(&mut self, enable: bool) -> &mut Self {
2003         self.validate_set_stencil_test_enable(enable).unwrap();
2004 
2005         unsafe { self.set_stencil_test_enable_unchecked(enable) }
2006     }
2007 
validate_set_stencil_test_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError>2008     fn validate_set_stencil_test_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError> {
2009         self.validate_pipeline_fixed_state(DynamicState::StencilTestEnable)?;
2010 
2011         let queue_family_properties = self.queue_family_properties();
2012 
2013         // VUID-vkCmdSetStencilTestEnable-commandBuffer-cmdpool
2014         if !queue_family_properties
2015             .queue_flags
2016             .intersects(QueueFlags::GRAPHICS)
2017         {
2018             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
2019         }
2020 
2021         // VUID-vkCmdSetStencilTestEnable-None-03350
2022         if !(self.device().api_version() >= Version::V1_3
2023             || self.device().enabled_features().extended_dynamic_state)
2024         {
2025             return Err(SetDynamicStateError::RequirementNotMet {
2026                 required_for: "`CommandBufferBuilder::set_stencil_test_enable`",
2027                 requires_one_of: RequiresOneOf {
2028                     api_version: Some(Version::V1_3),
2029                     features: &["extended_dynamic_state"],
2030                     ..Default::default()
2031                 },
2032             });
2033         }
2034 
2035         Ok(())
2036     }
2037 
2038     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_stencil_test_enable_unchecked(&mut self, enable: bool) -> &mut Self2039     pub unsafe fn set_stencil_test_enable_unchecked(&mut self, enable: bool) -> &mut Self {
2040         let fns = self.device().fns();
2041 
2042         if self.device().api_version() >= Version::V1_3 {
2043             (fns.v1_3.cmd_set_stencil_test_enable)(self.handle(), enable.into());
2044         } else {
2045             debug_assert!(
2046                 self.device()
2047                     .enabled_extensions()
2048                     .ext_extended_dynamic_state
2049             );
2050             (fns.ext_extended_dynamic_state
2051                 .cmd_set_stencil_test_enable_ext)(self.handle(), enable.into());
2052         }
2053 
2054         self.builder_state.stencil_test_enable = Some(enable);
2055 
2056         self.next_command_index += 1;
2057         self
2058     }
2059 
2060     /// Sets the dynamic stencil write mask on one or both faces for future draw calls.
2061     ///
2062     /// # Panics
2063     ///
2064     /// - Panics if the queue family of the command buffer does not support graphics operations.
2065     /// - Panics if the currently bound graphics pipeline already contains this state internally.
set_stencil_write_mask(&mut self, faces: StencilFaces, write_mask: u32) -> &mut Self2066     pub fn set_stencil_write_mask(&mut self, faces: StencilFaces, write_mask: u32) -> &mut Self {
2067         self.validate_set_stencil_write_mask(faces, write_mask)
2068             .unwrap();
2069 
2070         unsafe { self.set_stencil_write_mask_unchecked(faces, write_mask) }
2071     }
2072 
validate_set_stencil_write_mask( &self, faces: StencilFaces, _write_mask: u32, ) -> Result<(), SetDynamicStateError>2073     fn validate_set_stencil_write_mask(
2074         &self,
2075         faces: StencilFaces,
2076         _write_mask: u32,
2077     ) -> Result<(), SetDynamicStateError> {
2078         self.validate_pipeline_fixed_state(DynamicState::StencilWriteMask)?;
2079 
2080         // VUID-vkCmdSetStencilWriteMask-faceMask-parameter
2081         faces.validate_device(self.device())?;
2082 
2083         let queue_family_properties = self.queue_family_properties();
2084 
2085         // VUID-vkCmdSetStencilWriteMask-commandBuffer-cmdpool
2086         if !queue_family_properties
2087             .queue_flags
2088             .intersects(QueueFlags::GRAPHICS)
2089         {
2090             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
2091         }
2092 
2093         Ok(())
2094     }
2095 
2096     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_stencil_write_mask_unchecked( &mut self, faces: StencilFaces, write_mask: u32, ) -> &mut Self2097     pub unsafe fn set_stencil_write_mask_unchecked(
2098         &mut self,
2099         faces: StencilFaces,
2100         write_mask: u32,
2101     ) -> &mut Self {
2102         let fns = self.device().fns();
2103         (fns.v1_0.cmd_set_stencil_write_mask)(self.handle(), faces.into(), write_mask);
2104 
2105         let faces = ash::vk::StencilFaceFlags::from(faces);
2106 
2107         if faces.intersects(ash::vk::StencilFaceFlags::FRONT) {
2108             self.builder_state.stencil_write_mask.front = Some(write_mask);
2109         }
2110 
2111         if faces.intersects(ash::vk::StencilFaceFlags::BACK) {
2112             self.builder_state.stencil_write_mask.back = Some(write_mask);
2113         }
2114 
2115         self.next_command_index += 1;
2116         self
2117     }
2118 
2119     /// Sets the dynamic viewports for future draw calls.
2120     ///
2121     /// # Panics
2122     ///
2123     /// - Panics if the queue family of the command buffer does not support graphics operations.
2124     /// - Panics if the currently bound graphics pipeline already contains this state internally.
2125     /// - Panics if the highest viewport slot being set is greater than the
2126     ///   [`max_viewports`](crate::device::Properties::max_viewports) device property.
2127     /// - If the [`multi_viewport`](crate::device::Features::multi_viewport) feature is not enabled,
2128     ///   panics if `first_viewport` is not 0, or if more than 1 viewport is provided.
set_viewport( &mut self, first_viewport: u32, viewports: impl IntoIterator<Item = Viewport>, ) -> &mut Self2129     pub fn set_viewport(
2130         &mut self,
2131         first_viewport: u32,
2132         viewports: impl IntoIterator<Item = Viewport>,
2133     ) -> &mut Self {
2134         let viewports: SmallVec<[Viewport; 2]> = viewports.into_iter().collect();
2135         self.validate_set_viewport(first_viewport, &viewports)
2136             .unwrap();
2137 
2138         unsafe { self.set_viewport_unchecked(first_viewport, viewports) }
2139     }
2140 
validate_set_viewport( &self, first_viewport: u32, viewports: &[Viewport], ) -> Result<(), SetDynamicStateError>2141     fn validate_set_viewport(
2142         &self,
2143         first_viewport: u32,
2144         viewports: &[Viewport],
2145     ) -> Result<(), SetDynamicStateError> {
2146         self.validate_pipeline_fixed_state(DynamicState::Viewport)?;
2147 
2148         let queue_family_properties = self.queue_family_properties();
2149 
2150         // VUID-vkCmdSetViewport-commandBuffer-cmdpool
2151         if !queue_family_properties
2152             .queue_flags
2153             .intersects(QueueFlags::GRAPHICS)
2154         {
2155             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
2156         }
2157 
2158         // VUID-vkCmdSetViewport-firstViewport-01223
2159         if first_viewport + viewports.len() as u32
2160             > self.device().physical_device().properties().max_viewports
2161         {
2162             return Err(SetDynamicStateError::MaxViewportsExceeded {
2163                 provided: first_viewport + viewports.len() as u32,
2164                 max: self.device().physical_device().properties().max_viewports,
2165             });
2166         }
2167 
2168         if !self.device().enabled_features().multi_viewport {
2169             // VUID-vkCmdSetViewport-firstViewport-01224
2170             if first_viewport != 0 {
2171                 return Err(SetDynamicStateError::RequirementNotMet {
2172                     required_for: "`first_scissors` is not `0`",
2173                     requires_one_of: RequiresOneOf {
2174                         features: &["multi_viewport"],
2175                         ..Default::default()
2176                     },
2177                 });
2178             }
2179 
2180             // VUID-vkCmdSetViewport-viewportCount-01225
2181             if viewports.len() > 1 {
2182                 return Err(SetDynamicStateError::RequirementNotMet {
2183                     required_for: "`viewports.len()` is greater than `1`",
2184                     requires_one_of: RequiresOneOf {
2185                         features: &["multi_viewport"],
2186                         ..Default::default()
2187                     },
2188                 });
2189             }
2190         }
2191 
2192         Ok(())
2193     }
2194 
2195     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_viewport_unchecked( &mut self, first_viewport: u32, viewports: impl IntoIterator<Item = Viewport>, ) -> &mut Self2196     pub unsafe fn set_viewport_unchecked(
2197         &mut self,
2198         first_viewport: u32,
2199         viewports: impl IntoIterator<Item = Viewport>,
2200     ) -> &mut Self {
2201         let viewports: SmallVec<[Viewport; 2]> = viewports.into_iter().collect();
2202 
2203         if viewports.is_empty() {
2204             return self;
2205         }
2206 
2207         let viewports_vk = viewports
2208             .iter()
2209             .cloned()
2210             .map(ash::vk::Viewport::from)
2211             .collect::<SmallVec<[_; 2]>>();
2212 
2213         let fns = self.device().fns();
2214         (fns.v1_0.cmd_set_viewport)(
2215             self.handle(),
2216             first_viewport,
2217             viewports_vk.len() as u32,
2218             viewports_vk.as_ptr(),
2219         );
2220 
2221         for (num, viewport) in viewports.iter().enumerate() {
2222             let num = num as u32 + first_viewport;
2223             self.builder_state.viewport.insert(num, viewport.clone());
2224         }
2225 
2226         self.next_command_index += 1;
2227         self
2228     }
2229 
2230     /// Sets the dynamic viewports with count for future draw calls.
2231     ///
2232     /// # Panics
2233     ///
2234     /// - Panics if the queue family of the command buffer does not support graphics operations.
2235     /// - Panics if the device API version is less than 1.3 and the
2236     ///   [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
2237     ///   not enabled on the device.
2238     /// - Panics if the currently bound graphics pipeline already contains this state internally.
2239     /// - Panics if the highest viewport slot being set is greater than the
2240     ///   [`max_viewports`](crate::device::Properties::max_viewports) device property.
2241     /// - If the [`multi_viewport`](crate::device::Features::multi_viewport) feature is not enabled,
2242     ///   panics if more than 1 viewport is provided.
2243     #[inline]
set_viewport_with_count( &mut self, viewports: impl IntoIterator<Item = Viewport>, ) -> &mut Self2244     pub fn set_viewport_with_count(
2245         &mut self,
2246         viewports: impl IntoIterator<Item = Viewport>,
2247     ) -> &mut Self {
2248         let viewports: SmallVec<[Viewport; 2]> = viewports.into_iter().collect();
2249         self.validate_set_viewport_with_count(&viewports).unwrap();
2250 
2251         unsafe { self.set_viewport_with_count_unchecked(viewports) }
2252     }
2253 
validate_set_viewport_with_count( &self, viewports: &[Viewport], ) -> Result<(), SetDynamicStateError>2254     fn validate_set_viewport_with_count(
2255         &self,
2256         viewports: &[Viewport],
2257     ) -> Result<(), SetDynamicStateError> {
2258         self.validate_pipeline_fixed_state(DynamicState::ViewportWithCount)?;
2259 
2260         let queue_family_properties = self.queue_family_properties();
2261 
2262         // VUID-vkCmdSetViewportWithCount-commandBuffer-cmdpool
2263         if !queue_family_properties
2264             .queue_flags
2265             .intersects(QueueFlags::GRAPHICS)
2266         {
2267             return Err(SetDynamicStateError::NotSupportedByQueueFamily);
2268         }
2269 
2270         // VUID-vkCmdSetViewportWithCount-None-03393
2271         if !(self.device().api_version() >= Version::V1_3
2272             || self.device().enabled_features().extended_dynamic_state)
2273         {
2274             return Err(SetDynamicStateError::RequirementNotMet {
2275                 required_for: "`CommandBufferBuilder::set_viewport_with_count`",
2276                 requires_one_of: RequiresOneOf {
2277                     api_version: Some(Version::V1_3),
2278                     features: &["extended_dynamic_state"],
2279                     ..Default::default()
2280                 },
2281             });
2282         }
2283 
2284         // VUID-vkCmdSetViewportWithCount-viewportCount-03394
2285         if viewports.len() as u32 > self.device().physical_device().properties().max_viewports {
2286             return Err(SetDynamicStateError::MaxViewportsExceeded {
2287                 provided: viewports.len() as u32,
2288                 max: self.device().physical_device().properties().max_viewports,
2289             });
2290         }
2291 
2292         // VUID-vkCmdSetViewportWithCount-viewportCount-03395
2293         if !self.device().enabled_features().multi_viewport && viewports.len() > 1 {
2294             return Err(SetDynamicStateError::RequirementNotMet {
2295                 required_for: "`viewports.len()` is greater than `1`",
2296                 requires_one_of: RequiresOneOf {
2297                     features: &["multi_viewport"],
2298                     ..Default::default()
2299                 },
2300             });
2301         }
2302 
2303         Ok(())
2304     }
2305 
2306     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
set_viewport_with_count_unchecked( &mut self, viewports: impl IntoIterator<Item = Viewport>, ) -> &mut Self2307     pub unsafe fn set_viewport_with_count_unchecked(
2308         &mut self,
2309         viewports: impl IntoIterator<Item = Viewport>,
2310     ) -> &mut Self {
2311         let viewports: SmallVec<[Viewport; 2]> = viewports.into_iter().collect();
2312 
2313         if viewports.is_empty() {
2314             return self;
2315         }
2316 
2317         let viewports_vk = viewports
2318             .iter()
2319             .cloned()
2320             .map(ash::vk::Viewport::from)
2321             .collect::<SmallVec<[_; 2]>>();
2322 
2323         let fns = self.device().fns();
2324 
2325         if self.device().api_version() >= Version::V1_3 {
2326             (fns.v1_3.cmd_set_viewport_with_count)(
2327                 self.handle(),
2328                 viewports_vk.len() as u32,
2329                 viewports_vk.as_ptr(),
2330             );
2331         } else {
2332             debug_assert!(
2333                 self.device()
2334                     .enabled_extensions()
2335                     .ext_extended_dynamic_state
2336             );
2337             (fns.ext_extended_dynamic_state
2338                 .cmd_set_viewport_with_count_ext)(
2339                 self.handle(),
2340                 viewports_vk.len() as u32,
2341                 viewports_vk.as_ptr(),
2342             );
2343         }
2344 
2345         self.builder_state.viewport_with_count = Some(viewports);
2346 
2347         self.next_command_index += 1;
2348         self
2349     }
2350 }
2351