vulkano/command_buffer/commands/
dynamic_state.rs

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
10use crate::{
11    command_buffer::{
12        allocator::CommandBufferAllocator, sys::UnsafeCommandBufferBuilder,
13        AutoCommandBufferBuilder,
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, DepthBiasState, FrontFace, LineStipple},
22            viewport::{Scissor, Viewport},
23        },
24        DynamicState,
25    },
26    Requires, RequiresAllOf, RequiresOneOf, ValidationError, Version, VulkanObject,
27};
28use smallvec::SmallVec;
29use std::ops::RangeInclusive;
30
31/// # Commands to set dynamic state for pipelines.
32///
33/// These commands require a queue with a pipeline type that uses the given state.
34impl<L, A> AutoCommandBufferBuilder<L, A>
35where
36    A: CommandBufferAllocator,
37{
38    // Helper function for dynamic state setting.
39    fn validate_graphics_pipeline_fixed_state(
40        &self,
41        state: DynamicState,
42    ) -> Result<(), Box<ValidationError>> {
43        if self
44            .builder_state
45            .pipeline_graphics
46            .as_ref()
47            .map_or(false, |pipeline| pipeline.fixed_state().contains(&state))
48        {
49            return Err(Box::new(ValidationError {
50                problem: "the state for this value in the currently bound graphics pipeline \
51                    is fixed, and cannot be set"
52                    .into(),
53                vuids: &["VUID-vkCmdDispatch-None-08608", "VUID-vkCmdDraw-None-08608"],
54                ..Default::default()
55            }));
56        }
57
58        Ok(())
59    }
60
61    /// Sets the dynamic blend constants for future draw calls.
62    pub fn set_blend_constants(
63        &mut self,
64        constants: [f32; 4],
65    ) -> Result<&mut Self, Box<ValidationError>> {
66        self.validate_set_blend_constants(constants)?;
67
68        unsafe { Ok(self.set_blend_constants_unchecked(constants)) }
69    }
70
71    fn validate_set_blend_constants(
72        &self,
73        constants: [f32; 4],
74    ) -> Result<(), Box<ValidationError>> {
75        self.inner.validate_set_blend_constants(constants)?;
76
77        self.validate_graphics_pipeline_fixed_state(DynamicState::BlendConstants)?;
78
79        Ok(())
80    }
81
82    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
83    pub unsafe fn set_blend_constants_unchecked(&mut self, constants: [f32; 4]) -> &mut Self {
84        self.builder_state.blend_constants = Some(constants);
85        self.add_command(
86            "set_blend_constants",
87            Default::default(),
88            move |out: &mut UnsafeCommandBufferBuilder<A>| {
89                out.set_blend_constants_unchecked(constants);
90            },
91        );
92
93        self
94    }
95
96    /// Sets whether dynamic color writes should be enabled for each attachment in the
97    /// framebuffer.
98    pub fn set_color_write_enable(
99        &mut self,
100        enables: SmallVec<[bool; 4]>,
101    ) -> Result<&mut Self, Box<ValidationError>> {
102        self.validate_set_color_write_enable(&enables)?;
103
104        unsafe { Ok(self.set_color_write_enable_unchecked(enables)) }
105    }
106
107    fn validate_set_color_write_enable(
108        &self,
109        enables: &[bool],
110    ) -> Result<(), Box<ValidationError>> {
111        self.inner.validate_set_color_write_enable(enables)?;
112
113        self.validate_graphics_pipeline_fixed_state(DynamicState::ColorWriteEnable)?;
114
115        if let Some(color_blend_state) = self
116            .builder_state
117            .pipeline_graphics
118            .as_ref()
119            .and_then(|pipeline| pipeline.color_blend_state())
120        {
121            // Indirectly checked
122            if enables.len() != color_blend_state.attachments.len() {
123                return Err(Box::new(ValidationError {
124                    problem: "the length of `enables` does not match the number of \
125                        color attachments in the subpass of the currently bound graphics pipeline"
126                        .into(),
127                    vuids: &["VUID-vkCmdSetColorWriteEnableEXT-attachmentCount-06656"],
128                    ..Default::default()
129                }));
130            }
131        }
132
133        Ok(())
134    }
135
136    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
137    pub unsafe fn set_color_write_enable_unchecked(
138        &mut self,
139        enables: SmallVec<[bool; 4]>,
140    ) -> &mut Self {
141        self.builder_state.color_write_enable = Some(enables.clone());
142        self.add_command(
143            "set_color_write_enable",
144            Default::default(),
145            move |out: &mut UnsafeCommandBufferBuilder<A>| {
146                out.set_color_write_enable_unchecked(&enables);
147            },
148        );
149
150        self
151    }
152
153    /// Sets the dynamic cull mode for future draw calls.
154    pub fn set_cull_mode(
155        &mut self,
156        cull_mode: CullMode,
157    ) -> Result<&mut Self, Box<ValidationError>> {
158        self.validate_set_cull_mode(cull_mode)?;
159
160        unsafe { Ok(self.set_cull_mode_unchecked(cull_mode)) }
161    }
162
163    fn validate_set_cull_mode(&self, cull_mode: CullMode) -> Result<(), Box<ValidationError>> {
164        self.inner.validate_set_cull_mode(cull_mode)?;
165
166        self.validate_graphics_pipeline_fixed_state(DynamicState::CullMode)?;
167
168        Ok(())
169    }
170
171    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
172    pub unsafe fn set_cull_mode_unchecked(&mut self, cull_mode: CullMode) -> &mut Self {
173        self.builder_state.cull_mode = Some(cull_mode);
174        self.add_command(
175            "set_cull_mode",
176            Default::default(),
177            move |out: &mut UnsafeCommandBufferBuilder<A>| {
178                out.set_cull_mode_unchecked(cull_mode);
179            },
180        );
181
182        self
183    }
184
185    /// Sets the dynamic depth bias values for future draw calls.
186    pub fn set_depth_bias(
187        &mut self,
188        constant_factor: f32,
189        clamp: f32,
190        slope_factor: f32,
191    ) -> Result<&mut Self, Box<ValidationError>> {
192        self.validate_set_depth_bias(constant_factor, clamp, slope_factor)?;
193
194        unsafe { Ok(self.set_depth_bias_unchecked(constant_factor, clamp, slope_factor)) }
195    }
196
197    fn validate_set_depth_bias(
198        &self,
199        constant_factor: f32,
200        clamp: f32,
201        slope_factor: f32,
202    ) -> Result<(), Box<ValidationError>> {
203        self.inner
204            .validate_set_depth_bias(constant_factor, clamp, slope_factor)?;
205
206        self.validate_graphics_pipeline_fixed_state(DynamicState::DepthBias)?;
207
208        Ok(())
209    }
210
211    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
212    pub unsafe fn set_depth_bias_unchecked(
213        &mut self,
214        constant_factor: f32,
215        clamp: f32,
216        slope_factor: f32,
217    ) -> &mut Self {
218        self.builder_state.depth_bias = Some(DepthBiasState {
219            constant_factor,
220            clamp,
221            slope_factor,
222        });
223        self.add_command(
224            "set_depth_bias",
225            Default::default(),
226            move |out: &mut UnsafeCommandBufferBuilder<A>| {
227                out.set_depth_bias_unchecked(constant_factor, clamp, slope_factor);
228            },
229        );
230
231        self
232    }
233
234    /// Sets whether dynamic depth bias is enabled for future draw calls.
235    pub fn set_depth_bias_enable(
236        &mut self,
237        enable: bool,
238    ) -> Result<&mut Self, Box<ValidationError>> {
239        self.validate_set_depth_bias_enable(enable)?;
240
241        unsafe { Ok(self.set_depth_bias_enable_unchecked(enable)) }
242    }
243
244    fn validate_set_depth_bias_enable(&self, enable: bool) -> Result<(), Box<ValidationError>> {
245        self.inner.validate_set_depth_bias_enable(enable)?;
246
247        self.validate_graphics_pipeline_fixed_state(DynamicState::DepthBiasEnable)?;
248
249        Ok(())
250    }
251
252    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
253    pub unsafe fn set_depth_bias_enable_unchecked(&mut self, enable: bool) -> &mut Self {
254        self.builder_state.depth_bias_enable = Some(enable);
255        self.add_command(
256            "set_depth_bias_enable",
257            Default::default(),
258            move |out: &mut UnsafeCommandBufferBuilder<A>| {
259                out.set_depth_bias_enable_unchecked(enable);
260            },
261        );
262
263        self
264    }
265
266    /// Sets the dynamic depth bounds for future draw calls.
267    pub fn set_depth_bounds(
268        &mut self,
269        bounds: RangeInclusive<f32>,
270    ) -> Result<&mut Self, Box<ValidationError>> {
271        self.validate_set_depth_bounds(bounds.clone())?;
272
273        unsafe { Ok(self.set_depth_bounds_unchecked(bounds)) }
274    }
275
276    fn validate_set_depth_bounds(
277        &self,
278        bounds: RangeInclusive<f32>,
279    ) -> Result<(), Box<ValidationError>> {
280        self.inner.validate_set_depth_bounds(bounds)?;
281
282        self.validate_graphics_pipeline_fixed_state(DynamicState::DepthBounds)?;
283
284        Ok(())
285    }
286
287    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
288    pub unsafe fn set_depth_bounds_unchecked(&mut self, bounds: RangeInclusive<f32>) -> &mut Self {
289        self.builder_state.depth_bounds = Some(bounds.clone());
290        self.add_command(
291            "set_depth_bounds",
292            Default::default(),
293            move |out: &mut UnsafeCommandBufferBuilder<A>| {
294                out.set_depth_bounds_unchecked(bounds.clone());
295            },
296        );
297
298        self
299    }
300
301    /// Sets whether dynamic depth bounds testing is enabled for future draw calls.
302    pub fn set_depth_bounds_test_enable(
303        &mut self,
304        enable: bool,
305    ) -> Result<&mut Self, Box<ValidationError>> {
306        self.validate_set_depth_bounds_test_enable(enable)?;
307
308        unsafe { Ok(self.set_depth_bounds_test_enable_unchecked(enable)) }
309    }
310
311    fn validate_set_depth_bounds_test_enable(
312        &self,
313        enable: bool,
314    ) -> Result<(), Box<ValidationError>> {
315        self.inner.validate_set_depth_bounds_test_enable(enable)?;
316
317        self.validate_graphics_pipeline_fixed_state(DynamicState::DepthBoundsTestEnable)?;
318
319        Ok(())
320    }
321
322    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
323    pub unsafe fn set_depth_bounds_test_enable_unchecked(&mut self, enable: bool) -> &mut Self {
324        self.builder_state.depth_bounds_test_enable = Some(enable);
325        self.add_command(
326            "set_depth_bounds_test_enable",
327            Default::default(),
328            move |out: &mut UnsafeCommandBufferBuilder<A>| {
329                out.set_depth_bounds_test_enable_unchecked(enable);
330            },
331        );
332
333        self
334    }
335
336    /// Sets the dynamic depth compare op for future draw calls.
337    pub fn set_depth_compare_op(
338        &mut self,
339        compare_op: CompareOp,
340    ) -> Result<&mut Self, Box<ValidationError>> {
341        self.validate_set_depth_compare_op(compare_op)?;
342
343        unsafe { Ok(self.set_depth_compare_op_unchecked(compare_op)) }
344    }
345
346    fn validate_set_depth_compare_op(
347        &self,
348        compare_op: CompareOp,
349    ) -> Result<(), Box<ValidationError>> {
350        self.inner.validate_set_depth_compare_op(compare_op)?;
351
352        self.validate_graphics_pipeline_fixed_state(DynamicState::DepthCompareOp)?;
353
354        Ok(())
355    }
356
357    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
358    pub unsafe fn set_depth_compare_op_unchecked(&mut self, compare_op: CompareOp) -> &mut Self {
359        self.builder_state.depth_compare_op = Some(compare_op);
360        self.add_command(
361            "set_depth_compare_op",
362            Default::default(),
363            move |out: &mut UnsafeCommandBufferBuilder<A>| {
364                out.set_depth_compare_op_unchecked(compare_op);
365            },
366        );
367
368        self
369    }
370
371    /// Sets whether dynamic depth testing is enabled for future draw calls.
372    pub fn set_depth_test_enable(
373        &mut self,
374        enable: bool,
375    ) -> Result<&mut Self, Box<ValidationError>> {
376        self.validate_set_depth_test_enable(enable)?;
377
378        unsafe { Ok(self.set_depth_test_enable_unchecked(enable)) }
379    }
380
381    fn validate_set_depth_test_enable(&self, enable: bool) -> Result<(), Box<ValidationError>> {
382        self.inner.validate_set_depth_test_enable(enable)?;
383
384        self.validate_graphics_pipeline_fixed_state(DynamicState::DepthTestEnable)?;
385
386        Ok(())
387    }
388
389    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
390    pub unsafe fn set_depth_test_enable_unchecked(&mut self, enable: bool) -> &mut Self {
391        self.builder_state.depth_test_enable = Some(enable);
392        self.add_command(
393            "set_depth_test_enable",
394            Default::default(),
395            move |out: &mut UnsafeCommandBufferBuilder<A>| {
396                out.set_depth_test_enable_unchecked(enable);
397            },
398        );
399
400        self
401    }
402
403    /// Sets whether dynamic depth write is enabled for future draw calls.
404    pub fn set_depth_write_enable(
405        &mut self,
406        enable: bool,
407    ) -> Result<&mut Self, Box<ValidationError>> {
408        self.validate_set_depth_write_enable(enable)?;
409
410        unsafe { Ok(self.set_depth_write_enable_unchecked(enable)) }
411    }
412
413    fn validate_set_depth_write_enable(&self, enable: bool) -> Result<(), Box<ValidationError>> {
414        self.inner.validate_set_depth_write_enable(enable)?;
415
416        self.validate_graphics_pipeline_fixed_state(DynamicState::DepthWriteEnable)?;
417
418        Ok(())
419    }
420
421    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
422    pub unsafe fn set_depth_write_enable_unchecked(&mut self, enable: bool) -> &mut Self {
423        self.builder_state.depth_write_enable = Some(enable);
424        self.add_command(
425            "set_depth_write_enable",
426            Default::default(),
427            move |out: &mut UnsafeCommandBufferBuilder<A>| {
428                out.set_depth_write_enable_unchecked(enable);
429            },
430        );
431
432        self
433    }
434
435    /// Sets the dynamic discard rectangles for future draw calls.
436    pub fn set_discard_rectangle(
437        &mut self,
438        first_rectangle: u32,
439        rectangles: SmallVec<[Scissor; 2]>,
440    ) -> Result<&mut Self, Box<ValidationError>> {
441        self.validate_set_discard_rectangle(first_rectangle, &rectangles)?;
442
443        unsafe { Ok(self.set_discard_rectangle_unchecked(first_rectangle, rectangles)) }
444    }
445
446    fn validate_set_discard_rectangle(
447        &self,
448        first_rectangle: u32,
449        rectangles: &[Scissor],
450    ) -> Result<(), Box<ValidationError>> {
451        self.inner
452            .validate_set_discard_rectangle(first_rectangle, rectangles)?;
453
454        self.validate_graphics_pipeline_fixed_state(DynamicState::DiscardRectangle)?;
455
456        Ok(())
457    }
458
459    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
460    pub unsafe fn set_discard_rectangle_unchecked(
461        &mut self,
462        first_rectangle: u32,
463        rectangles: SmallVec<[Scissor; 2]>,
464    ) -> &mut Self {
465        for (num, rectangle) in rectangles.iter().enumerate() {
466            let num = num as u32 + first_rectangle;
467            self.builder_state.discard_rectangle.insert(num, *rectangle);
468        }
469
470        self.add_command(
471            "set_discard_rectangle",
472            Default::default(),
473            move |out: &mut UnsafeCommandBufferBuilder<A>| {
474                out.set_discard_rectangle_unchecked(first_rectangle, &rectangles);
475            },
476        );
477
478        self
479    }
480
481    /// Sets the dynamic front face for future draw calls.
482    pub fn set_front_face(&mut self, face: FrontFace) -> Result<&mut Self, Box<ValidationError>> {
483        self.validate_set_front_face(face)?;
484
485        unsafe { Ok(self.set_front_face_unchecked(face)) }
486    }
487
488    fn validate_set_front_face(&self, face: FrontFace) -> Result<(), Box<ValidationError>> {
489        self.inner.validate_set_front_face(face)?;
490
491        self.validate_graphics_pipeline_fixed_state(DynamicState::FrontFace)?;
492
493        Ok(())
494    }
495
496    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
497    pub unsafe fn set_front_face_unchecked(&mut self, face: FrontFace) -> &mut Self {
498        self.builder_state.front_face = Some(face);
499        self.add_command(
500            "set_front_face",
501            Default::default(),
502            move |out: &mut UnsafeCommandBufferBuilder<A>| {
503                out.set_front_face_unchecked(face);
504            },
505        );
506
507        self
508    }
509
510    /// Sets the dynamic line stipple values for future draw calls.
511    pub fn set_line_stipple(
512        &mut self,
513        factor: u32,
514        pattern: u16,
515    ) -> Result<&mut Self, Box<ValidationError>> {
516        self.validate_set_line_stipple(factor, pattern)?;
517
518        unsafe { Ok(self.set_line_stipple_unchecked(factor, pattern)) }
519    }
520
521    fn validate_set_line_stipple(
522        &self,
523        factor: u32,
524        pattern: u16,
525    ) -> Result<(), Box<ValidationError>> {
526        self.inner.validate_set_line_stipple(factor, pattern)?;
527
528        self.validate_graphics_pipeline_fixed_state(DynamicState::LineStipple)?;
529
530        Ok(())
531    }
532
533    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
534    pub unsafe fn set_line_stipple_unchecked(&mut self, factor: u32, pattern: u16) -> &mut Self {
535        self.builder_state.line_stipple = Some(LineStipple { factor, pattern });
536        self.add_command(
537            "set_line_stipple",
538            Default::default(),
539            move |out: &mut UnsafeCommandBufferBuilder<A>| {
540                out.set_line_stipple_unchecked(factor, pattern);
541            },
542        );
543
544        self
545    }
546
547    /// Sets the dynamic line width for future draw calls.
548    pub fn set_line_width(&mut self, line_width: f32) -> Result<&mut Self, Box<ValidationError>> {
549        self.validate_set_line_width(line_width)?;
550
551        unsafe { Ok(self.set_line_width_unchecked(line_width)) }
552    }
553
554    fn validate_set_line_width(&self, line_width: f32) -> Result<(), Box<ValidationError>> {
555        self.inner.validate_set_line_width(line_width)?;
556
557        self.validate_graphics_pipeline_fixed_state(DynamicState::LineWidth)?;
558
559        Ok(())
560    }
561
562    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
563    pub unsafe fn set_line_width_unchecked(&mut self, line_width: f32) -> &mut Self {
564        self.builder_state.line_width = Some(line_width);
565        self.add_command(
566            "set_line_width",
567            Default::default(),
568            move |out: &mut UnsafeCommandBufferBuilder<A>| {
569                out.set_line_width_unchecked(line_width);
570            },
571        );
572
573        self
574    }
575
576    /// Sets the dynamic logic op for future draw calls.
577    pub fn set_logic_op(&mut self, logic_op: LogicOp) -> Result<&mut Self, Box<ValidationError>> {
578        self.validate_set_logic_op(logic_op)?;
579
580        unsafe { Ok(self.set_logic_op_unchecked(logic_op)) }
581    }
582
583    fn validate_set_logic_op(&self, logic_op: LogicOp) -> Result<(), Box<ValidationError>> {
584        self.inner.validate_set_logic_op(logic_op)?;
585
586        self.validate_graphics_pipeline_fixed_state(DynamicState::LogicOp)?;
587
588        Ok(())
589    }
590
591    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
592    pub unsafe fn set_logic_op_unchecked(&mut self, logic_op: LogicOp) -> &mut Self {
593        self.builder_state.logic_op = Some(logic_op);
594        self.add_command(
595            "set_logic_op",
596            Default::default(),
597            move |out: &mut UnsafeCommandBufferBuilder<A>| {
598                out.set_logic_op_unchecked(logic_op);
599            },
600        );
601
602        self
603    }
604
605    /// Sets the dynamic number of patch control points for future draw calls.
606    pub fn set_patch_control_points(
607        &mut self,
608        num: u32,
609    ) -> Result<&mut Self, Box<ValidationError>> {
610        self.validate_set_patch_control_points(num)?;
611
612        unsafe { Ok(self.set_patch_control_points_unchecked(num)) }
613    }
614
615    fn validate_set_patch_control_points(&self, num: u32) -> Result<(), Box<ValidationError>> {
616        self.inner.validate_set_patch_control_points(num)?;
617
618        self.validate_graphics_pipeline_fixed_state(DynamicState::PatchControlPoints)?;
619
620        Ok(())
621    }
622
623    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
624    pub unsafe fn set_patch_control_points_unchecked(&mut self, num: u32) -> &mut Self {
625        self.builder_state.patch_control_points = Some(num);
626        self.add_command(
627            "set_patch_control_points",
628            Default::default(),
629            move |out: &mut UnsafeCommandBufferBuilder<A>| {
630                out.set_patch_control_points_unchecked(num);
631            },
632        );
633
634        self
635    }
636
637    /// Sets whether dynamic primitive restart is enabled for future draw calls.
638    pub fn set_primitive_restart_enable(
639        &mut self,
640        enable: bool,
641    ) -> Result<&mut Self, Box<ValidationError>> {
642        self.validate_set_primitive_restart_enable(enable)?;
643
644        unsafe { Ok(self.set_primitive_restart_enable_unchecked(enable)) }
645    }
646
647    fn validate_set_primitive_restart_enable(
648        &self,
649        enable: bool,
650    ) -> Result<(), Box<ValidationError>> {
651        self.inner.validate_set_primitive_restart_enable(enable)?;
652
653        self.validate_graphics_pipeline_fixed_state(DynamicState::PrimitiveRestartEnable)?;
654
655        Ok(())
656    }
657
658    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
659    pub unsafe fn set_primitive_restart_enable_unchecked(&mut self, enable: bool) -> &mut Self {
660        self.builder_state.primitive_restart_enable = Some(enable);
661        self.add_command(
662            "set_primitive_restart_enable",
663            Default::default(),
664            move |out: &mut UnsafeCommandBufferBuilder<A>| {
665                out.set_primitive_restart_enable_unchecked(enable);
666            },
667        );
668
669        self
670    }
671
672    /// Sets the dynamic primitive topology for future draw calls.
673    pub fn set_primitive_topology(
674        &mut self,
675        topology: PrimitiveTopology,
676    ) -> Result<&mut Self, Box<ValidationError>> {
677        self.validate_set_primitive_topology(topology)?;
678
679        unsafe { Ok(self.set_primitive_topology_unchecked(topology)) }
680    }
681
682    fn validate_set_primitive_topology(
683        &self,
684        topology: PrimitiveTopology,
685    ) -> Result<(), Box<ValidationError>> {
686        self.inner.validate_set_primitive_topology(topology)?;
687
688        self.validate_graphics_pipeline_fixed_state(DynamicState::PrimitiveTopology)?;
689
690        Ok(())
691    }
692
693    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
694    pub unsafe fn set_primitive_topology_unchecked(
695        &mut self,
696        topology: PrimitiveTopology,
697    ) -> &mut Self {
698        self.builder_state.primitive_topology = Some(topology);
699        self.add_command(
700            "set_primitive_topology",
701            Default::default(),
702            move |out: &mut UnsafeCommandBufferBuilder<A>| {
703                out.set_primitive_topology_unchecked(topology);
704            },
705        );
706
707        self
708    }
709
710    /// Sets whether dynamic rasterizer discard is enabled for future draw calls.
711    pub fn set_rasterizer_discard_enable(
712        &mut self,
713        enable: bool,
714    ) -> Result<&mut Self, Box<ValidationError>> {
715        self.validate_set_rasterizer_discard_enable(enable)?;
716
717        unsafe { Ok(self.set_rasterizer_discard_enable_unchecked(enable)) }
718    }
719
720    fn validate_set_rasterizer_discard_enable(
721        &self,
722        enable: bool,
723    ) -> Result<(), Box<ValidationError>> {
724        self.inner.validate_set_rasterizer_discard_enable(enable)?;
725
726        self.validate_graphics_pipeline_fixed_state(DynamicState::RasterizerDiscardEnable)?;
727
728        Ok(())
729    }
730
731    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
732    pub unsafe fn set_rasterizer_discard_enable_unchecked(&mut self, enable: bool) -> &mut Self {
733        self.builder_state.rasterizer_discard_enable = Some(enable);
734        self.add_command(
735            "set_rasterizer_discard_enable",
736            Default::default(),
737            move |out: &mut UnsafeCommandBufferBuilder<A>| {
738                out.set_rasterizer_discard_enable_unchecked(enable);
739            },
740        );
741
742        self
743    }
744
745    /// Sets the dynamic scissors for future draw calls.
746    pub fn set_scissor(
747        &mut self,
748        first_scissor: u32,
749        scissors: SmallVec<[Scissor; 2]>,
750    ) -> Result<&mut Self, Box<ValidationError>> {
751        self.validate_set_scissor(first_scissor, &scissors)?;
752
753        unsafe { Ok(self.set_scissor_unchecked(first_scissor, scissors)) }
754    }
755
756    fn validate_set_scissor(
757        &self,
758        first_scissor: u32,
759        scissors: &[Scissor],
760    ) -> Result<(), Box<ValidationError>> {
761        self.inner.validate_set_scissor(first_scissor, scissors)?;
762
763        self.validate_graphics_pipeline_fixed_state(DynamicState::Scissor)?;
764
765        Ok(())
766    }
767
768    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
769    pub unsafe fn set_scissor_unchecked(
770        &mut self,
771        first_scissor: u32,
772        scissors: SmallVec<[Scissor; 2]>,
773    ) -> &mut Self {
774        let scissors: SmallVec<[Scissor; 2]> = scissors.into_iter().collect();
775
776        for (num, scissor) in scissors.iter().enumerate() {
777            let num = num as u32 + first_scissor;
778            self.builder_state.scissor.insert(num, *scissor);
779        }
780
781        self.add_command(
782            "set_scissor",
783            Default::default(),
784            move |out: &mut UnsafeCommandBufferBuilder<A>| {
785                out.set_scissor_unchecked(first_scissor, &scissors);
786            },
787        );
788
789        self
790    }
791
792    /// Sets the dynamic scissors with count for future draw calls.
793    pub fn set_scissor_with_count(
794        &mut self,
795        scissors: SmallVec<[Scissor; 2]>,
796    ) -> Result<&mut Self, Box<ValidationError>> {
797        self.validate_set_scissor_with_count(&scissors)?;
798
799        unsafe { Ok(self.set_scissor_with_count_unchecked(scissors)) }
800    }
801
802    fn validate_set_scissor_with_count(
803        &self,
804        scissors: &[Scissor],
805    ) -> Result<(), Box<ValidationError>> {
806        self.inner.validate_set_scissor_with_count(scissors)?;
807
808        self.validate_graphics_pipeline_fixed_state(DynamicState::ScissorWithCount)?;
809
810        Ok(())
811    }
812
813    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
814    pub unsafe fn set_scissor_with_count_unchecked(
815        &mut self,
816        scissors: SmallVec<[Scissor; 2]>,
817    ) -> &mut Self {
818        self.builder_state.scissor_with_count = Some(scissors.clone());
819        self.add_command(
820            "set_scissor_with_count",
821            Default::default(),
822            move |out: &mut UnsafeCommandBufferBuilder<A>| {
823                out.set_scissor_with_count_unchecked(&scissors);
824            },
825        );
826
827        self
828    }
829
830    /// Sets the dynamic stencil compare mask on one or both faces for future draw calls.
831    pub fn set_stencil_compare_mask(
832        &mut self,
833        faces: StencilFaces,
834        compare_mask: u32,
835    ) -> Result<&mut Self, Box<ValidationError>> {
836        self.validate_set_stencil_compare_mask(faces, compare_mask)?;
837
838        unsafe { Ok(self.set_stencil_compare_mask_unchecked(faces, compare_mask)) }
839    }
840
841    fn validate_set_stencil_compare_mask(
842        &self,
843        faces: StencilFaces,
844        compare_mask: u32,
845    ) -> Result<(), Box<ValidationError>> {
846        self.inner
847            .validate_set_stencil_compare_mask(faces, compare_mask)?;
848
849        self.validate_graphics_pipeline_fixed_state(DynamicState::StencilCompareMask)?;
850
851        Ok(())
852    }
853
854    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
855    pub unsafe fn set_stencil_compare_mask_unchecked(
856        &mut self,
857        faces: StencilFaces,
858        compare_mask: u32,
859    ) -> &mut Self {
860        let faces_vk = ash::vk::StencilFaceFlags::from(faces);
861
862        if faces_vk.intersects(ash::vk::StencilFaceFlags::FRONT) {
863            self.builder_state.stencil_compare_mask.front = Some(compare_mask);
864        }
865
866        if faces_vk.intersects(ash::vk::StencilFaceFlags::BACK) {
867            self.builder_state.stencil_compare_mask.back = Some(compare_mask);
868        }
869
870        self.add_command(
871            "set_stencil_compare_mask",
872            Default::default(),
873            move |out: &mut UnsafeCommandBufferBuilder<A>| {
874                out.set_stencil_compare_mask_unchecked(faces, compare_mask);
875            },
876        );
877
878        self
879    }
880
881    /// Sets the dynamic stencil ops on one or both faces for future draw calls.
882    pub fn set_stencil_op(
883        &mut self,
884        faces: StencilFaces,
885        fail_op: StencilOp,
886        pass_op: StencilOp,
887        depth_fail_op: StencilOp,
888        compare_op: CompareOp,
889    ) -> Result<&mut Self, Box<ValidationError>> {
890        self.validate_set_stencil_op(faces, fail_op, pass_op, depth_fail_op, compare_op)?;
891
892        unsafe {
893            Ok(self.set_stencil_op_unchecked(faces, fail_op, pass_op, depth_fail_op, compare_op))
894        }
895    }
896
897    fn validate_set_stencil_op(
898        &self,
899        faces: StencilFaces,
900        fail_op: StencilOp,
901        pass_op: StencilOp,
902        depth_fail_op: StencilOp,
903        compare_op: CompareOp,
904    ) -> Result<(), Box<ValidationError>> {
905        self.inner
906            .validate_set_stencil_op(faces, fail_op, pass_op, depth_fail_op, compare_op)?;
907
908        self.validate_graphics_pipeline_fixed_state(DynamicState::StencilOp)?;
909
910        Ok(())
911    }
912
913    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
914    pub unsafe fn set_stencil_op_unchecked(
915        &mut self,
916        faces: StencilFaces,
917        fail_op: StencilOp,
918        pass_op: StencilOp,
919        depth_fail_op: StencilOp,
920        compare_op: CompareOp,
921    ) -> &mut Self {
922        let faces_vk = ash::vk::StencilFaceFlags::from(faces);
923
924        if faces_vk.intersects(ash::vk::StencilFaceFlags::FRONT) {
925            self.builder_state.stencil_op.front = Some(StencilOps {
926                fail_op,
927                pass_op,
928                depth_fail_op,
929                compare_op,
930            });
931        }
932
933        if faces_vk.intersects(ash::vk::StencilFaceFlags::BACK) {
934            self.builder_state.stencil_op.back = Some(StencilOps {
935                fail_op,
936                pass_op,
937                depth_fail_op,
938                compare_op,
939            });
940        }
941
942        self.add_command(
943            "set_stencil_op",
944            Default::default(),
945            move |out: &mut UnsafeCommandBufferBuilder<A>| {
946                out.set_stencil_op_unchecked(faces, fail_op, pass_op, depth_fail_op, compare_op);
947            },
948        );
949
950        self
951    }
952
953    /// Sets the dynamic stencil reference on one or both faces for future draw calls.
954    pub fn set_stencil_reference(
955        &mut self,
956        faces: StencilFaces,
957        reference: u32,
958    ) -> Result<&mut Self, Box<ValidationError>> {
959        self.validate_set_stencil_reference(faces, reference)?;
960
961        unsafe { Ok(self.set_stencil_reference_unchecked(faces, reference)) }
962    }
963
964    fn validate_set_stencil_reference(
965        &self,
966        faces: StencilFaces,
967        reference: u32,
968    ) -> Result<(), Box<ValidationError>> {
969        self.inner
970            .validate_set_stencil_reference(faces, reference)?;
971
972        self.validate_graphics_pipeline_fixed_state(DynamicState::StencilReference)?;
973
974        Ok(())
975    }
976
977    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
978    pub unsafe fn set_stencil_reference_unchecked(
979        &mut self,
980        faces: StencilFaces,
981        reference: u32,
982    ) -> &mut Self {
983        let faces_vk = ash::vk::StencilFaceFlags::from(faces);
984
985        if faces_vk.intersects(ash::vk::StencilFaceFlags::FRONT) {
986            self.builder_state.stencil_reference.front = Some(reference);
987        }
988
989        if faces_vk.intersects(ash::vk::StencilFaceFlags::BACK) {
990            self.builder_state.stencil_reference.back = Some(reference);
991        }
992
993        self.add_command(
994            "set_stencil_reference",
995            Default::default(),
996            move |out: &mut UnsafeCommandBufferBuilder<A>| {
997                out.set_stencil_reference_unchecked(faces, reference);
998            },
999        );
1000
1001        self
1002    }
1003
1004    /// Sets whether dynamic stencil testing is enabled for future draw calls.
1005    pub fn set_stencil_test_enable(
1006        &mut self,
1007        enable: bool,
1008    ) -> Result<&mut Self, Box<ValidationError>> {
1009        self.validate_set_stencil_test_enable(enable)?;
1010
1011        unsafe { Ok(self.set_stencil_test_enable_unchecked(enable)) }
1012    }
1013
1014    fn validate_set_stencil_test_enable(&self, enable: bool) -> Result<(), Box<ValidationError>> {
1015        self.inner.validate_set_stencil_test_enable(enable)?;
1016
1017        self.validate_graphics_pipeline_fixed_state(DynamicState::StencilTestEnable)?;
1018
1019        Ok(())
1020    }
1021
1022    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1023    pub unsafe fn set_stencil_test_enable_unchecked(&mut self, enable: bool) -> &mut Self {
1024        self.builder_state.stencil_test_enable = Some(enable);
1025        self.add_command(
1026            "set_stencil_test_enable",
1027            Default::default(),
1028            move |out: &mut UnsafeCommandBufferBuilder<A>| {
1029                out.set_stencil_test_enable_unchecked(enable);
1030            },
1031        );
1032
1033        self
1034    }
1035
1036    /// Sets the dynamic stencil write mask on one or both faces for future draw calls.
1037    pub fn set_stencil_write_mask(
1038        &mut self,
1039        faces: StencilFaces,
1040        write_mask: u32,
1041    ) -> Result<&mut Self, Box<ValidationError>> {
1042        self.validate_set_stencil_write_mask(faces, write_mask)?;
1043
1044        unsafe { Ok(self.set_stencil_write_mask_unchecked(faces, write_mask)) }
1045    }
1046
1047    fn validate_set_stencil_write_mask(
1048        &self,
1049        faces: StencilFaces,
1050        write_mask: u32,
1051    ) -> Result<(), Box<ValidationError>> {
1052        self.inner
1053            .validate_set_stencil_write_mask(faces, write_mask)?;
1054
1055        self.validate_graphics_pipeline_fixed_state(DynamicState::StencilWriteMask)?;
1056
1057        Ok(())
1058    }
1059
1060    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1061    pub unsafe fn set_stencil_write_mask_unchecked(
1062        &mut self,
1063        faces: StencilFaces,
1064        write_mask: u32,
1065    ) -> &mut Self {
1066        let faces_vk = ash::vk::StencilFaceFlags::from(faces);
1067
1068        if faces_vk.intersects(ash::vk::StencilFaceFlags::FRONT) {
1069            self.builder_state.stencil_write_mask.front = Some(write_mask);
1070        }
1071
1072        if faces_vk.intersects(ash::vk::StencilFaceFlags::BACK) {
1073            self.builder_state.stencil_write_mask.back = Some(write_mask);
1074        }
1075
1076        self.add_command(
1077            "set_stencil_write_mask",
1078            Default::default(),
1079            move |out: &mut UnsafeCommandBufferBuilder<A>| {
1080                out.set_stencil_write_mask_unchecked(faces, write_mask);
1081            },
1082        );
1083
1084        self
1085    }
1086
1087    /// Sets the dynamic viewports for future draw calls.
1088    pub fn set_viewport(
1089        &mut self,
1090        first_viewport: u32,
1091        viewports: SmallVec<[Viewport; 2]>,
1092    ) -> Result<&mut Self, Box<ValidationError>> {
1093        self.validate_set_viewport(first_viewport, &viewports)?;
1094
1095        unsafe { Ok(self.set_viewport_unchecked(first_viewport, viewports)) }
1096    }
1097
1098    fn validate_set_viewport(
1099        &self,
1100        first_viewport: u32,
1101        viewports: &[Viewport],
1102    ) -> Result<(), Box<ValidationError>> {
1103        self.inner
1104            .validate_set_viewport(first_viewport, viewports)?;
1105
1106        self.validate_graphics_pipeline_fixed_state(DynamicState::Viewport)?;
1107
1108        Ok(())
1109    }
1110
1111    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1112    pub unsafe fn set_viewport_unchecked(
1113        &mut self,
1114        first_viewport: u32,
1115        viewports: SmallVec<[Viewport; 2]>,
1116    ) -> &mut Self {
1117        for (num, viewport) in viewports.iter().enumerate() {
1118            let num = num as u32 + first_viewport;
1119            self.builder_state.viewport.insert(num, viewport.clone());
1120        }
1121
1122        self.add_command(
1123            "set_viewport",
1124            Default::default(),
1125            move |out: &mut UnsafeCommandBufferBuilder<A>| {
1126                out.set_viewport_unchecked(first_viewport, &viewports);
1127            },
1128        );
1129
1130        self
1131    }
1132
1133    /// Sets the dynamic viewports with count for future draw calls.
1134    pub fn set_viewport_with_count(
1135        &mut self,
1136        viewports: SmallVec<[Viewport; 2]>,
1137    ) -> Result<&mut Self, Box<ValidationError>> {
1138        self.validate_set_viewport_with_count(&viewports)?;
1139
1140        unsafe { Ok(self.set_viewport_with_count_unchecked(viewports)) }
1141    }
1142
1143    fn validate_set_viewport_with_count(
1144        &self,
1145        viewports: &[Viewport],
1146    ) -> Result<(), Box<ValidationError>> {
1147        self.inner.validate_set_viewport_with_count(viewports)?;
1148
1149        self.validate_graphics_pipeline_fixed_state(DynamicState::ViewportWithCount)?;
1150
1151        Ok(())
1152    }
1153
1154    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1155    pub unsafe fn set_viewport_with_count_unchecked(
1156        &mut self,
1157        viewports: SmallVec<[Viewport; 2]>,
1158    ) -> &mut Self {
1159        self.builder_state.viewport_with_count = Some(viewports.clone());
1160        self.add_command(
1161            "set_viewport",
1162            Default::default(),
1163            move |out: &mut UnsafeCommandBufferBuilder<A>| {
1164                out.set_viewport_with_count_unchecked(&viewports);
1165            },
1166        );
1167
1168        self
1169    }
1170}
1171
1172impl<A> UnsafeCommandBufferBuilder<A>
1173where
1174    A: CommandBufferAllocator,
1175{
1176    pub unsafe fn set_blend_constants(
1177        &mut self,
1178        constants: [f32; 4],
1179    ) -> Result<&mut Self, Box<ValidationError>> {
1180        self.validate_set_blend_constants(constants)?;
1181
1182        Ok(self.set_blend_constants_unchecked(constants))
1183    }
1184
1185    fn validate_set_blend_constants(
1186        &self,
1187        _constants: [f32; 4],
1188    ) -> Result<(), Box<ValidationError>> {
1189        if !self
1190            .queue_family_properties()
1191            .queue_flags
1192            .intersects(QueueFlags::GRAPHICS)
1193        {
1194            return Err(Box::new(ValidationError {
1195                problem: "the queue family of the command buffer does not support \
1196                    graphics operations"
1197                    .into(),
1198                vuids: &["VUID-vkCmdSetBlendConstants-commandBuffer-cmdpool"],
1199                ..Default::default()
1200            }));
1201        }
1202
1203        Ok(())
1204    }
1205
1206    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1207    pub unsafe fn set_blend_constants_unchecked(&mut self, constants: [f32; 4]) -> &mut Self {
1208        let fns = self.device().fns();
1209        (fns.v1_0.cmd_set_blend_constants)(self.handle(), &constants);
1210
1211        self
1212    }
1213
1214    pub unsafe fn set_color_write_enable(
1215        &mut self,
1216        enables: &[bool],
1217    ) -> Result<&mut Self, Box<ValidationError>> {
1218        self.validate_set_color_write_enable(enables)?;
1219
1220        Ok(self.set_color_write_enable_unchecked(enables))
1221    }
1222
1223    fn validate_set_color_write_enable(
1224        &self,
1225        _enables: &[bool],
1226    ) -> Result<(), Box<ValidationError>> {
1227        if !self.device().enabled_features().color_write_enable {
1228            return Err(Box::new(ValidationError {
1229                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
1230                    "ext_color_write_enable",
1231                )])]),
1232                vuids: &["VUID-vkCmdSetColorWriteEnableEXT-None-04803"],
1233                ..Default::default()
1234            }));
1235        }
1236
1237        if !self
1238            .queue_family_properties()
1239            .queue_flags
1240            .intersects(QueueFlags::GRAPHICS)
1241        {
1242            return Err(Box::new(ValidationError {
1243                problem: "the queue family of the command buffer does not support \
1244                    graphics operations"
1245                    .into(),
1246                vuids: &["VUID-vkCmdSetColorWriteEnableEXT-commandBuffer-cmdpool"],
1247                ..Default::default()
1248            }));
1249        }
1250
1251        Ok(())
1252    }
1253
1254    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1255    pub unsafe fn set_color_write_enable_unchecked(&mut self, enables: &[bool]) -> &mut Self {
1256        let enables = enables
1257            .iter()
1258            .copied()
1259            .map(|v| v as ash::vk::Bool32)
1260            .collect::<SmallVec<[_; 4]>>();
1261
1262        if enables.is_empty() {
1263            return self;
1264        }
1265
1266        let fns = self.device().fns();
1267        (fns.ext_color_write_enable.cmd_set_color_write_enable_ext)(
1268            self.handle(),
1269            enables.len() as u32,
1270            enables.as_ptr(),
1271        );
1272
1273        self
1274    }
1275
1276    pub unsafe fn set_cull_mode(
1277        &mut self,
1278        cull_mode: CullMode,
1279    ) -> Result<&mut Self, Box<ValidationError>> {
1280        self.validate_set_cull_mode(cull_mode)?;
1281
1282        Ok(self.set_cull_mode_unchecked(cull_mode))
1283    }
1284
1285    fn validate_set_cull_mode(&self, cull_mode: CullMode) -> Result<(), Box<ValidationError>> {
1286        if !(self.device().api_version() >= Version::V1_3
1287            || self.device().enabled_features().extended_dynamic_state)
1288        {
1289            return Err(Box::new(ValidationError {
1290                requires_one_of: RequiresOneOf(&[
1291                    RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]),
1292                    RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]),
1293                ]),
1294                vuids: &["VUID-vkCmdSetCullMode-None-03384"],
1295                ..Default::default()
1296            }));
1297        }
1298
1299        if !self
1300            .queue_family_properties()
1301            .queue_flags
1302            .intersects(QueueFlags::GRAPHICS)
1303        {
1304            return Err(Box::new(ValidationError {
1305                problem: "the queue family of the command buffer does not support \
1306                    graphics operations"
1307                    .into(),
1308                vuids: &["VUID-vkCmdSetCullMode-commandBuffer-cmdpool"],
1309                ..Default::default()
1310            }));
1311        }
1312
1313        cull_mode.validate_device(self.device()).map_err(|err| {
1314            err.add_context("cull_mode")
1315                .set_vuids(&["VUID-vkCmdSetCullMode-cullMode-parameter"])
1316        })?;
1317
1318        Ok(())
1319    }
1320
1321    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1322    pub unsafe fn set_cull_mode_unchecked(&mut self, cull_mode: CullMode) -> &mut Self {
1323        let fns = self.device().fns();
1324
1325        if self.device().api_version() >= Version::V1_3 {
1326            (fns.v1_3.cmd_set_cull_mode)(self.handle(), cull_mode.into());
1327        } else {
1328            (fns.ext_extended_dynamic_state.cmd_set_cull_mode_ext)(self.handle(), cull_mode.into());
1329        }
1330
1331        self
1332    }
1333
1334    pub unsafe fn set_depth_bias(
1335        &mut self,
1336        constant_factor: f32,
1337        clamp: f32,
1338        slope_factor: f32,
1339    ) -> Result<&mut Self, Box<ValidationError>> {
1340        self.validate_set_depth_bias(constant_factor, clamp, slope_factor)?;
1341
1342        Ok(self.set_depth_bias_unchecked(constant_factor, clamp, slope_factor))
1343    }
1344
1345    fn validate_set_depth_bias(
1346        &self,
1347        _constant_factor: f32,
1348        clamp: f32,
1349        _slope_factor: f32,
1350    ) -> Result<(), Box<ValidationError>> {
1351        if !self
1352            .queue_family_properties()
1353            .queue_flags
1354            .intersects(QueueFlags::GRAPHICS)
1355        {
1356            return Err(Box::new(ValidationError {
1357                problem: "the queue family of the command buffer does not support \
1358                    graphics operations"
1359                    .into(),
1360                vuids: &["VUID-vkCmdSetDepthBias-commandBuffer-cmdpool"],
1361                ..Default::default()
1362            }));
1363        }
1364
1365        if clamp != 0.0 && !self.device().enabled_features().depth_bias_clamp {
1366            return Err(Box::new(ValidationError {
1367                context: "clamp".into(),
1368                problem: "is not `0.0`".into(),
1369                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
1370                    "depth_bias_clamp",
1371                )])]),
1372                vuids: &["VUID-vkCmdSetDepthBias-depthBiasClamp-00790"],
1373            }));
1374        }
1375
1376        Ok(())
1377    }
1378
1379    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1380    pub unsafe fn set_depth_bias_unchecked(
1381        &mut self,
1382        constant_factor: f32,
1383        clamp: f32,
1384        slope_factor: f32,
1385    ) -> &mut Self {
1386        let fns = self.device().fns();
1387        (fns.v1_0.cmd_set_depth_bias)(self.handle(), constant_factor, clamp, slope_factor);
1388
1389        self
1390    }
1391
1392    pub unsafe fn set_depth_bias_enable(
1393        &mut self,
1394        enable: bool,
1395    ) -> Result<&mut Self, Box<ValidationError>> {
1396        self.validate_set_depth_bias_enable(enable)?;
1397
1398        Ok(self.set_depth_bias_enable_unchecked(enable))
1399    }
1400
1401    fn validate_set_depth_bias_enable(&self, _enable: bool) -> Result<(), Box<ValidationError>> {
1402        if !(self.device().api_version() >= Version::V1_3
1403            || self.device().enabled_features().extended_dynamic_state2)
1404        {
1405            return Err(Box::new(ValidationError {
1406                requires_one_of: RequiresOneOf(&[
1407                    RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]),
1408                    RequiresAllOf(&[Requires::Feature("extended_dynamic_state2")]),
1409                ]),
1410                vuids: &["VUID-vkCmdSetDepthBiasEnable-None-04872"],
1411                ..Default::default()
1412            }));
1413        }
1414
1415        if !self
1416            .queue_family_properties()
1417            .queue_flags
1418            .intersects(QueueFlags::GRAPHICS)
1419        {
1420            return Err(Box::new(ValidationError {
1421                problem: "the queue family of the command buffer does not support \
1422                    graphics operations"
1423                    .into(),
1424                vuids: &["VUID-vkCmdSetDepthBiasEnable-commandBuffer-cmdpool"],
1425                ..Default::default()
1426            }));
1427        }
1428
1429        Ok(())
1430    }
1431
1432    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1433    pub unsafe fn set_depth_bias_enable_unchecked(&mut self, enable: bool) -> &mut Self {
1434        let fns = self.device().fns();
1435
1436        if self.device().api_version() >= Version::V1_3 {
1437            (fns.v1_3.cmd_set_depth_bias_enable)(self.handle(), enable.into());
1438        } else {
1439            (fns.ext_extended_dynamic_state2
1440                .cmd_set_depth_bias_enable_ext)(self.handle(), enable.into());
1441        }
1442
1443        self
1444    }
1445
1446    pub unsafe fn set_depth_bounds(
1447        &mut self,
1448        bounds: RangeInclusive<f32>,
1449    ) -> Result<&mut Self, Box<ValidationError>> {
1450        self.validate_set_depth_bounds(bounds.clone())?;
1451
1452        Ok(self.set_depth_bounds_unchecked(bounds))
1453    }
1454
1455    fn validate_set_depth_bounds(
1456        &self,
1457        bounds: RangeInclusive<f32>,
1458    ) -> Result<(), Box<ValidationError>> {
1459        if !self
1460            .queue_family_properties()
1461            .queue_flags
1462            .intersects(QueueFlags::GRAPHICS)
1463        {
1464            return Err(Box::new(ValidationError {
1465                problem: "the queue family of the command buffer does not support \
1466                    graphics operations"
1467                    .into(),
1468                vuids: &["VUID-vkCmdSetDepthBounds-commandBuffer-cmdpool"],
1469                ..Default::default()
1470            }));
1471        }
1472
1473        if !self
1474            .device()
1475            .enabled_extensions()
1476            .ext_depth_range_unrestricted
1477        {
1478            if !(0.0..=1.0).contains(bounds.start()) {
1479                return Err(Box::new(ValidationError {
1480                    context: "bounds.start()".into(),
1481                    problem: "is not between `0.0` and `1.0` inclusive".into(),
1482                    requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
1483                        "ext_depth_range_unrestricted",
1484                    )])]),
1485                    vuids: &["VUID-vkCmdSetDepthBounds-minDepthBounds-00600"],
1486                }));
1487            }
1488
1489            if !(0.0..=1.0).contains(bounds.end()) {
1490                return Err(Box::new(ValidationError {
1491                    context: "bounds.end()".into(),
1492                    problem: "is not between `0.0` and `1.0` inclusive".into(),
1493                    requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
1494                        "ext_depth_range_unrestricted",
1495                    )])]),
1496                    vuids: &["VUID-vkCmdSetDepthBounds-maxDepthBounds-00601"],
1497                }));
1498            }
1499        }
1500
1501        Ok(())
1502    }
1503
1504    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1505    pub unsafe fn set_depth_bounds_unchecked(&mut self, bounds: RangeInclusive<f32>) -> &mut Self {
1506        let fns = self.device().fns();
1507        (fns.v1_0.cmd_set_depth_bounds)(self.handle(), *bounds.start(), *bounds.end());
1508
1509        self
1510    }
1511
1512    pub unsafe fn set_depth_bounds_test_enable(
1513        &mut self,
1514        enable: bool,
1515    ) -> Result<&mut Self, Box<ValidationError>> {
1516        self.validate_set_depth_bounds_test_enable(enable)?;
1517
1518        Ok(self.set_depth_bounds_test_enable_unchecked(enable))
1519    }
1520
1521    fn validate_set_depth_bounds_test_enable(
1522        &self,
1523        _enable: bool,
1524    ) -> Result<(), Box<ValidationError>> {
1525        if !(self.device().api_version() >= Version::V1_3
1526            || self.device().enabled_features().extended_dynamic_state)
1527        {
1528            return Err(Box::new(ValidationError {
1529                requires_one_of: RequiresOneOf(&[
1530                    RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]),
1531                    RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]),
1532                ]),
1533                vuids: &["VUID-vkCmdSetDepthBoundsTestEnable-None-03349"],
1534                ..Default::default()
1535            }));
1536        }
1537
1538        if !self
1539            .queue_family_properties()
1540            .queue_flags
1541            .intersects(QueueFlags::GRAPHICS)
1542        {
1543            return Err(Box::new(ValidationError {
1544                problem: "the queue family of the command buffer does not support \
1545                    graphics operations"
1546                    .into(),
1547                vuids: &["VUID-vkCmdSetDepthBoundsTestEnable-commandBuffer-cmdpool"],
1548                ..Default::default()
1549            }));
1550        }
1551
1552        Ok(())
1553    }
1554
1555    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1556    pub unsafe fn set_depth_bounds_test_enable_unchecked(&mut self, enable: bool) -> &mut Self {
1557        let fns = self.device().fns();
1558
1559        if self.device().api_version() >= Version::V1_3 {
1560            (fns.v1_3.cmd_set_depth_bounds_test_enable)(self.handle(), enable.into());
1561        } else {
1562            (fns.ext_extended_dynamic_state
1563                .cmd_set_depth_bounds_test_enable_ext)(self.handle(), enable.into());
1564        }
1565
1566        self
1567    }
1568
1569    pub unsafe fn set_depth_compare_op(
1570        &mut self,
1571        compare_op: CompareOp,
1572    ) -> Result<&mut Self, Box<ValidationError>> {
1573        self.validate_set_depth_compare_op(compare_op)?;
1574
1575        Ok(self.set_depth_compare_op_unchecked(compare_op))
1576    }
1577
1578    fn validate_set_depth_compare_op(
1579        &self,
1580        compare_op: CompareOp,
1581    ) -> Result<(), Box<ValidationError>> {
1582        if !(self.device().api_version() >= Version::V1_3
1583            || self.device().enabled_features().extended_dynamic_state)
1584        {
1585            return Err(Box::new(ValidationError {
1586                requires_one_of: RequiresOneOf(&[
1587                    RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]),
1588                    RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]),
1589                ]),
1590                vuids: &["VUID-vkCmdSetDepthCompareOp-None-03353"],
1591                ..Default::default()
1592            }));
1593        }
1594
1595        if !self
1596            .queue_family_properties()
1597            .queue_flags
1598            .intersects(QueueFlags::GRAPHICS)
1599        {
1600            return Err(Box::new(ValidationError {
1601                problem: "the queue family of the command buffer does not support \
1602                    graphics operations"
1603                    .into(),
1604                vuids: &["VUID-vkCmdSetDepthCompareOp-commandBuffer-cmdpool"],
1605                ..Default::default()
1606            }));
1607        }
1608
1609        compare_op.validate_device(self.device()).map_err(|err| {
1610            err.add_context("compare_op")
1611                .set_vuids(&["VUID-vkCmdSetDepthCompareOp-depthCompareOp-parameter"])
1612        })?;
1613
1614        Ok(())
1615    }
1616
1617    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1618    pub unsafe fn set_depth_compare_op_unchecked(&mut self, compare_op: CompareOp) -> &mut Self {
1619        let fns = self.device().fns();
1620
1621        if self.device().api_version() >= Version::V1_3 {
1622            (fns.v1_3.cmd_set_depth_compare_op)(self.handle(), compare_op.into());
1623        } else {
1624            (fns.ext_extended_dynamic_state.cmd_set_depth_compare_op_ext)(
1625                self.handle(),
1626                compare_op.into(),
1627            );
1628        }
1629
1630        self
1631    }
1632
1633    pub unsafe fn set_depth_test_enable(
1634        &mut self,
1635        enable: bool,
1636    ) -> Result<&mut Self, Box<ValidationError>> {
1637        self.validate_set_depth_test_enable(enable)?;
1638
1639        Ok(self.set_depth_test_enable_unchecked(enable))
1640    }
1641
1642    fn validate_set_depth_test_enable(&self, _enable: bool) -> Result<(), Box<ValidationError>> {
1643        if !(self.device().api_version() >= Version::V1_3
1644            || self.device().enabled_features().extended_dynamic_state)
1645        {
1646            return Err(Box::new(ValidationError {
1647                requires_one_of: RequiresOneOf(&[
1648                    RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]),
1649                    RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]),
1650                ]),
1651                vuids: &["VUID-vkCmdSetDepthTestEnable-None-03352"],
1652                ..Default::default()
1653            }));
1654        }
1655
1656        if !self
1657            .queue_family_properties()
1658            .queue_flags
1659            .intersects(QueueFlags::GRAPHICS)
1660        {
1661            return Err(Box::new(ValidationError {
1662                problem: "the queue family of the command buffer does not support \
1663                    graphics operations"
1664                    .into(),
1665                vuids: &["VUID-vkCmdSetDepthTestEnable-commandBuffer-cmdpool"],
1666                ..Default::default()
1667            }));
1668        }
1669
1670        Ok(())
1671    }
1672
1673    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1674    pub unsafe fn set_depth_test_enable_unchecked(&mut self, enable: bool) -> &mut Self {
1675        let fns = self.device().fns();
1676
1677        if self.device().api_version() >= Version::V1_3 {
1678            (fns.v1_3.cmd_set_depth_test_enable)(self.handle(), enable.into());
1679        } else {
1680            (fns.ext_extended_dynamic_state.cmd_set_depth_test_enable_ext)(
1681                self.handle(),
1682                enable.into(),
1683            );
1684        }
1685
1686        self
1687    }
1688
1689    pub unsafe fn set_depth_write_enable(
1690        &mut self,
1691        enable: bool,
1692    ) -> Result<&mut Self, Box<ValidationError>> {
1693        self.validate_set_depth_write_enable(enable)?;
1694
1695        Ok(self.set_depth_write_enable_unchecked(enable))
1696    }
1697
1698    fn validate_set_depth_write_enable(&self, _enable: bool) -> Result<(), Box<ValidationError>> {
1699        if !(self.device().api_version() >= Version::V1_3
1700            || self.device().enabled_features().extended_dynamic_state)
1701        {
1702            return Err(Box::new(ValidationError {
1703                requires_one_of: RequiresOneOf(&[
1704                    RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]),
1705                    RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]),
1706                ]),
1707                vuids: &["VUID-vkCmdSetDepthWriteEnable-None-03354"],
1708                ..Default::default()
1709            }));
1710        }
1711
1712        if !self
1713            .queue_family_properties()
1714            .queue_flags
1715            .intersects(QueueFlags::GRAPHICS)
1716        {
1717            return Err(Box::new(ValidationError {
1718                problem: "the queue family of the command buffer does not support \
1719                    graphics operations"
1720                    .into(),
1721                vuids: &["VUID-vkCmdSetDepthWriteEnable-commandBuffer-cmdpool"],
1722                ..Default::default()
1723            }));
1724        }
1725
1726        Ok(())
1727    }
1728
1729    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1730    pub unsafe fn set_depth_write_enable_unchecked(&mut self, enable: bool) -> &mut Self {
1731        let fns = self.device().fns();
1732
1733        if self.device().api_version() >= Version::V1_3 {
1734            (fns.v1_3.cmd_set_depth_write_enable)(self.handle(), enable.into());
1735        } else {
1736            (fns.ext_extended_dynamic_state
1737                .cmd_set_depth_write_enable_ext)(self.handle(), enable.into());
1738        }
1739
1740        self
1741    }
1742
1743    pub unsafe fn set_discard_rectangle(
1744        &mut self,
1745        first_rectangle: u32,
1746        rectangles: &[Scissor],
1747    ) -> Result<&mut Self, Box<ValidationError>> {
1748        self.validate_set_discard_rectangle(first_rectangle, rectangles)?;
1749
1750        Ok(self.set_discard_rectangle_unchecked(first_rectangle, rectangles))
1751    }
1752
1753    fn validate_set_discard_rectangle(
1754        &self,
1755        first_rectangle: u32,
1756        rectangles: &[Scissor],
1757    ) -> Result<(), Box<ValidationError>> {
1758        if self.device().enabled_extensions().ext_discard_rectangles {
1759            return Err(Box::new(ValidationError {
1760                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
1761                    "ext_discard_rectangles",
1762                )])]),
1763                ..Default::default()
1764            }));
1765        }
1766
1767        if !self
1768            .queue_family_properties()
1769            .queue_flags
1770            .intersects(QueueFlags::GRAPHICS)
1771        {
1772            return Err(Box::new(ValidationError {
1773                problem: "the queue family of the command buffer does not support \
1774                    graphics operations"
1775                    .into(),
1776                vuids: &["VUID-vkCmdSetDiscardRectangle-commandBuffer-cmdpool"],
1777                ..Default::default()
1778            }));
1779        }
1780
1781        let properties = self.device().physical_device().properties();
1782
1783        if first_rectangle + rectangles.len() as u32 > properties.max_discard_rectangles.unwrap() {
1784            return Err(Box::new(ValidationError {
1785                problem: "`first_rectangle + rectangles.len()` exceeds the \
1786                    `max_discard_rectangles` limit"
1787                    .into(),
1788                vuids: &["VUID-vkCmdSetDiscardRectangleEXT-firstDiscardRectangle-00585"],
1789                ..Default::default()
1790            }));
1791        }
1792
1793        Ok(())
1794    }
1795
1796    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1797    pub unsafe fn set_discard_rectangle_unchecked(
1798        &mut self,
1799        first_rectangle: u32,
1800        rectangles: &[Scissor],
1801    ) -> &mut Self {
1802        let rectangles = rectangles
1803            .iter()
1804            .map(|v| v.into())
1805            .collect::<SmallVec<[_; 2]>>();
1806        if rectangles.is_empty() {
1807            return self;
1808        }
1809
1810        let fns = self.device().fns();
1811        (fns.ext_discard_rectangles.cmd_set_discard_rectangle_ext)(
1812            self.handle(),
1813            first_rectangle,
1814            rectangles.len() as u32,
1815            rectangles.as_ptr(),
1816        );
1817
1818        self
1819    }
1820
1821    pub unsafe fn set_front_face(
1822        &mut self,
1823        face: FrontFace,
1824    ) -> Result<&mut Self, Box<ValidationError>> {
1825        self.validate_set_front_face(face)?;
1826
1827        Ok(self.set_front_face_unchecked(face))
1828    }
1829
1830    fn validate_set_front_face(&self, face: FrontFace) -> Result<(), Box<ValidationError>> {
1831        if !(self.device().api_version() >= Version::V1_3
1832            || self.device().enabled_features().extended_dynamic_state)
1833        {
1834            return Err(Box::new(ValidationError {
1835                requires_one_of: RequiresOneOf(&[
1836                    RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]),
1837                    RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]),
1838                ]),
1839                vuids: &["VUID-vkCmdSetFrontFace-None-03383"],
1840                ..Default::default()
1841            }));
1842        }
1843
1844        if !self
1845            .queue_family_properties()
1846            .queue_flags
1847            .intersects(QueueFlags::GRAPHICS)
1848        {
1849            return Err(Box::new(ValidationError {
1850                problem: "the queue family of the command buffer does not support \
1851                    graphics operations"
1852                    .into(),
1853                vuids: &["VUID-vkCmdSetFrontFace-commandBuffer-cmdpool"],
1854                ..Default::default()
1855            }));
1856        }
1857
1858        face.validate_device(self.device()).map_err(|err| {
1859            err.add_context("face")
1860                .set_vuids(&["VUID-vkCmdSetFrontFace-frontFace-parameter"])
1861        })?;
1862
1863        Ok(())
1864    }
1865
1866    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1867    pub unsafe fn set_front_face_unchecked(&mut self, face: FrontFace) -> &mut Self {
1868        let fns = self.device().fns();
1869
1870        if self.device().api_version() >= Version::V1_3 {
1871            (fns.v1_3.cmd_set_front_face)(self.handle(), face.into());
1872        } else {
1873            (fns.ext_extended_dynamic_state.cmd_set_front_face_ext)(self.handle(), face.into());
1874        }
1875
1876        self
1877    }
1878
1879    pub unsafe fn set_line_stipple(
1880        &mut self,
1881        factor: u32,
1882        pattern: u16,
1883    ) -> Result<&mut Self, Box<ValidationError>> {
1884        self.validate_set_line_stipple(factor, pattern)?;
1885
1886        Ok(self.set_line_stipple_unchecked(factor, pattern))
1887    }
1888
1889    fn validate_set_line_stipple(
1890        &self,
1891        factor: u32,
1892        _pattern: u16,
1893    ) -> Result<(), Box<ValidationError>> {
1894        if !self.device().enabled_extensions().ext_line_rasterization {
1895            return Err(Box::new(ValidationError {
1896                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
1897                    "ext_line_rasterization",
1898                )])]),
1899                ..Default::default()
1900            }));
1901        }
1902
1903        if !self
1904            .queue_family_properties()
1905            .queue_flags
1906            .intersects(QueueFlags::GRAPHICS)
1907        {
1908            return Err(Box::new(ValidationError {
1909                problem: "the queue family of the command buffer does not support \
1910                    graphics operations"
1911                    .into(),
1912                vuids: &["VUID-vkCmdSetLineStippleEXT-commandBuffer-cmdpool"],
1913                ..Default::default()
1914            }));
1915        }
1916
1917        if !(1..=256).contains(&factor) {
1918            return Err(Box::new(ValidationError {
1919                context: "factor".into(),
1920                problem: "is not between 1 and 256 inclusive".into(),
1921                vuids: &["VUID-vkCmdSetLineStippleEXT-lineStippleFactor-02776"],
1922                ..Default::default()
1923            }));
1924        }
1925
1926        Ok(())
1927    }
1928
1929    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1930    pub unsafe fn set_line_stipple_unchecked(&mut self, factor: u32, pattern: u16) -> &mut Self {
1931        let fns = self.device().fns();
1932        (fns.ext_line_rasterization.cmd_set_line_stipple_ext)(self.handle(), factor, pattern);
1933
1934        self
1935    }
1936
1937    pub unsafe fn set_line_width(
1938        &mut self,
1939        line_width: f32,
1940    ) -> Result<&mut Self, Box<ValidationError>> {
1941        self.validate_set_line_width(line_width)?;
1942
1943        Ok(self.set_line_width_unchecked(line_width))
1944    }
1945
1946    fn validate_set_line_width(&self, line_width: f32) -> Result<(), Box<ValidationError>> {
1947        if !self
1948            .queue_family_properties()
1949            .queue_flags
1950            .intersects(QueueFlags::GRAPHICS)
1951        {
1952            return Err(Box::new(ValidationError {
1953                problem: "the queue family of the command buffer does not support \
1954                    graphics operations"
1955                    .into(),
1956                vuids: &["VUID-vkCmdSetLineWidth-commandBuffer-cmdpool"],
1957                ..Default::default()
1958            }));
1959        }
1960
1961        if line_width != 1.0 && !self.device().enabled_features().wide_lines {
1962            return Err(Box::new(ValidationError {
1963                context: "line_width".into(),
1964                problem: "is not 1.0".into(),
1965                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
1966                    "wide_lines",
1967                )])]),
1968                vuids: &["VUID-vkCmdSetLineWidth-lineWidth-00788"],
1969            }));
1970        }
1971
1972        Ok(())
1973    }
1974
1975    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1976    pub unsafe fn set_line_width_unchecked(&mut self, line_width: f32) -> &mut Self {
1977        let fns = self.device().fns();
1978        (fns.v1_0.cmd_set_line_width)(self.handle(), line_width);
1979
1980        self
1981    }
1982
1983    pub unsafe fn set_logic_op(
1984        &mut self,
1985        logic_op: LogicOp,
1986    ) -> Result<&mut Self, Box<ValidationError>> {
1987        self.validate_set_logic_op(logic_op)?;
1988
1989        Ok(self.set_logic_op_unchecked(logic_op))
1990    }
1991
1992    fn validate_set_logic_op(&self, logic_op: LogicOp) -> Result<(), Box<ValidationError>> {
1993        if !self
1994            .device()
1995            .enabled_features()
1996            .extended_dynamic_state2_logic_op
1997        {
1998            return Err(Box::new(ValidationError {
1999                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
2000                    "extended_dynamic_state2_logic_op",
2001                )])]),
2002                vuids: &["VUID-vkCmdSetLogicOpEXT-None-04867"],
2003                ..Default::default()
2004            }));
2005        }
2006
2007        if !self
2008            .queue_family_properties()
2009            .queue_flags
2010            .intersects(QueueFlags::GRAPHICS)
2011        {
2012            return Err(Box::new(ValidationError {
2013                problem: "the queue family of the command buffer does not support \
2014                    graphics operations"
2015                    .into(),
2016                vuids: &["VUID-vkCmdSetLogicOpEXT-commandBuffer-cmdpool"],
2017                ..Default::default()
2018            }));
2019        }
2020
2021        logic_op.validate_device(self.device()).map_err(|err| {
2022            err.add_context("logic_op")
2023                .set_vuids(&["VUID-vkCmdSetLogicOpEXT-logicOp-parameter"])
2024        })?;
2025
2026        Ok(())
2027    }
2028
2029    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
2030    pub unsafe fn set_logic_op_unchecked(&mut self, logic_op: LogicOp) -> &mut Self {
2031        let fns = self.device().fns();
2032        (fns.ext_extended_dynamic_state2.cmd_set_logic_op_ext)(self.handle(), logic_op.into());
2033
2034        self
2035    }
2036
2037    pub unsafe fn set_patch_control_points(
2038        &mut self,
2039        num: u32,
2040    ) -> Result<&mut Self, Box<ValidationError>> {
2041        self.validate_set_patch_control_points(num)?;
2042
2043        Ok(self.set_patch_control_points_unchecked(num))
2044    }
2045
2046    fn validate_set_patch_control_points(&self, num: u32) -> Result<(), Box<ValidationError>> {
2047        if !self
2048            .device()
2049            .enabled_features()
2050            .extended_dynamic_state2_patch_control_points
2051        {
2052            return Err(Box::new(ValidationError {
2053                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
2054                    "extended_dynamic_state2_patch_control_points",
2055                )])]),
2056                vuids: &["VUID-vkCmdSetPatchControlPointsEXT-None-04873"],
2057                ..Default::default()
2058            }));
2059        }
2060
2061        if !self
2062            .queue_family_properties()
2063            .queue_flags
2064            .intersects(QueueFlags::GRAPHICS)
2065        {
2066            return Err(Box::new(ValidationError {
2067                problem: "the queue family of the command buffer does not support \
2068                    graphics operations"
2069                    .into(),
2070                vuids: &["VUID-vkCmdSetPatchControlPointsEXT-commandBuffer-cmdpool"],
2071                ..Default::default()
2072            }));
2073        }
2074
2075        if num == 0 {
2076            return Err(Box::new(ValidationError {
2077                context: "num".into(),
2078                problem: "is zero".into(),
2079                vuids: &["VUID-vkCmdSetPatchControlPointsEXT-patchControlPoints-04874"],
2080                ..Default::default()
2081            }));
2082        }
2083
2084        let properties = self.device().physical_device().properties();
2085
2086        if num > properties.max_tessellation_patch_size {
2087            return Err(Box::new(ValidationError {
2088                context: "num".into(),
2089                problem: "exceeds the `max_tessellation_patch_size` limit".into(),
2090                vuids: &["VUID-vkCmdSetPatchControlPointsEXT-patchControlPoints-04874"],
2091                ..Default::default()
2092            }));
2093        }
2094
2095        Ok(())
2096    }
2097
2098    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
2099    pub unsafe fn set_patch_control_points_unchecked(&mut self, num: u32) -> &mut Self {
2100        let fns = self.device().fns();
2101        (fns.ext_extended_dynamic_state2
2102            .cmd_set_patch_control_points_ext)(self.handle(), num);
2103
2104        self
2105    }
2106
2107    pub unsafe fn set_primitive_restart_enable(
2108        &mut self,
2109        enable: bool,
2110    ) -> Result<&mut Self, Box<ValidationError>> {
2111        self.validate_set_primitive_restart_enable(enable)?;
2112
2113        Ok(self.set_primitive_restart_enable_unchecked(enable))
2114    }
2115
2116    fn validate_set_primitive_restart_enable(
2117        &self,
2118        _enable: bool,
2119    ) -> Result<(), Box<ValidationError>> {
2120        if !(self.device().api_version() >= Version::V1_3
2121            || self.device().enabled_features().extended_dynamic_state2)
2122        {
2123            return Err(Box::new(ValidationError {
2124                requires_one_of: RequiresOneOf(&[
2125                    RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]),
2126                    RequiresAllOf(&[Requires::Feature("extended_dynamic_state2")]),
2127                ]),
2128                vuids: &["VUID-vkCmdSetPrimitiveRestartEnable-None-04866"],
2129                ..Default::default()
2130            }));
2131        }
2132
2133        if !self
2134            .queue_family_properties()
2135            .queue_flags
2136            .intersects(QueueFlags::GRAPHICS)
2137        {
2138            return Err(Box::new(ValidationError {
2139                problem: "the queue family of the command buffer does not support \
2140                    graphics operations"
2141                    .into(),
2142                vuids: &["VUID-vkCmdSetPrimitiveRestartEnable-commandBuffer-cmdpool"],
2143                ..Default::default()
2144            }));
2145        }
2146
2147        Ok(())
2148    }
2149
2150    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
2151    pub unsafe fn set_primitive_restart_enable_unchecked(&mut self, enable: bool) -> &mut Self {
2152        let fns = self.device().fns();
2153
2154        if self.device().api_version() >= Version::V1_3 {
2155            (fns.v1_3.cmd_set_primitive_restart_enable)(self.handle(), enable.into());
2156        } else {
2157            (fns.ext_extended_dynamic_state2
2158                .cmd_set_primitive_restart_enable_ext)(self.handle(), enable.into());
2159        }
2160
2161        self
2162    }
2163
2164    pub unsafe fn set_primitive_topology(
2165        &mut self,
2166        topology: PrimitiveTopology,
2167    ) -> Result<&mut Self, Box<ValidationError>> {
2168        self.validate_set_primitive_topology(topology)?;
2169
2170        Ok(self.set_primitive_topology_unchecked(topology))
2171    }
2172
2173    fn validate_set_primitive_topology(
2174        &self,
2175        topology: PrimitiveTopology,
2176    ) -> Result<(), Box<ValidationError>> {
2177        if !(self.device().api_version() >= Version::V1_3
2178            || self.device().enabled_features().extended_dynamic_state)
2179        {
2180            return Err(Box::new(ValidationError {
2181                requires_one_of: RequiresOneOf(&[
2182                    RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]),
2183                    RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]),
2184                ]),
2185                vuids: &["VUID-vkCmdSetPrimitiveTopology-None-03347"],
2186                ..Default::default()
2187            }));
2188        }
2189
2190        if !self
2191            .queue_family_properties()
2192            .queue_flags
2193            .intersects(QueueFlags::GRAPHICS)
2194        {
2195            return Err(Box::new(ValidationError {
2196                problem: "the queue family of the command buffer does not support \
2197                    graphics operations"
2198                    .into(),
2199                vuids: &["VUID-vkCmdSetPrimitiveTopology-commandBuffer-cmdpool"],
2200                ..Default::default()
2201            }));
2202        }
2203
2204        topology.validate_device(self.device()).map_err(|err| {
2205            err.add_context("topology")
2206                .set_vuids(&["VUID-vkCmdSetPrimitiveTopology-primitiveTopology-parameter"])
2207        })?;
2208
2209        // VUID?
2210        // Since these requirements exist for fixed state when creating the pipeline,
2211        // I assume they exist for dynamic state as well.
2212        match topology {
2213            PrimitiveTopology::TriangleFan => {
2214                if self.device().enabled_extensions().khr_portability_subset
2215                    && !self.device().enabled_features().triangle_fans
2216                {
2217                    return Err(Box::new(ValidationError {
2218                        problem: "this device is a portability subset device, and `topology` \
2219                            is `PrimitiveTopology::TriangleFan`"
2220                            .into(),
2221                        requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
2222                            "triangle_fans",
2223                        )])]),
2224                        ..Default::default()
2225                    }));
2226                }
2227            }
2228            PrimitiveTopology::LineListWithAdjacency
2229            | PrimitiveTopology::LineStripWithAdjacency
2230            | PrimitiveTopology::TriangleListWithAdjacency
2231            | PrimitiveTopology::TriangleStripWithAdjacency => {
2232                if !self.device().enabled_features().geometry_shader {
2233                    return Err(Box::new(ValidationError {
2234                        problem: "`topology` is `PrimitiveTopology::*WithAdjacency`".into(),
2235                        requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
2236                            "geometry_shader",
2237                        )])]),
2238                        ..Default::default()
2239                    }));
2240                }
2241            }
2242            PrimitiveTopology::PatchList => {
2243                if !self.device().enabled_features().tessellation_shader {
2244                    return Err(Box::new(ValidationError {
2245                        problem: "`topology` is `PrimitiveTopology::PatchList`".into(),
2246                        requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
2247                            "tessellation_shader",
2248                        )])]),
2249                        ..Default::default()
2250                    }));
2251                }
2252            }
2253            _ => (),
2254        }
2255
2256        Ok(())
2257    }
2258
2259    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
2260    pub unsafe fn set_primitive_topology_unchecked(
2261        &mut self,
2262        topology: PrimitiveTopology,
2263    ) -> &mut Self {
2264        let fns = self.device().fns();
2265
2266        if self.device().api_version() >= Version::V1_3 {
2267            (fns.v1_3.cmd_set_primitive_topology)(self.handle(), topology.into());
2268        } else {
2269            (fns.ext_extended_dynamic_state
2270                .cmd_set_primitive_topology_ext)(self.handle(), topology.into());
2271        }
2272
2273        self
2274    }
2275
2276    pub unsafe fn set_rasterizer_discard_enable(
2277        &mut self,
2278        enable: bool,
2279    ) -> Result<&mut Self, Box<ValidationError>> {
2280        self.validate_set_rasterizer_discard_enable(enable)?;
2281
2282        Ok(self.set_rasterizer_discard_enable_unchecked(enable))
2283    }
2284
2285    fn validate_set_rasterizer_discard_enable(
2286        &self,
2287        _enable: bool,
2288    ) -> Result<(), Box<ValidationError>> {
2289        if !(self.device().api_version() >= Version::V1_3
2290            || self.device().enabled_features().extended_dynamic_state2)
2291        {
2292            return Err(Box::new(ValidationError {
2293                requires_one_of: RequiresOneOf(&[
2294                    RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]),
2295                    RequiresAllOf(&[Requires::Feature("extended_dynamic_state2")]),
2296                ]),
2297                vuids: &["VUID-vkCmdSetRasterizerDiscardEnable-None-04871"],
2298                ..Default::default()
2299            }));
2300        }
2301
2302        if !self
2303            .queue_family_properties()
2304            .queue_flags
2305            .intersects(QueueFlags::GRAPHICS)
2306        {
2307            return Err(Box::new(ValidationError {
2308                problem: "the queue family of the command buffer does not support \
2309                    graphics operations"
2310                    .into(),
2311                vuids: &["VUID-vkCmdSetRasterizerDiscardEnable-commandBuffer-cmdpool"],
2312                ..Default::default()
2313            }));
2314        }
2315
2316        Ok(())
2317    }
2318
2319    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
2320    pub unsafe fn set_rasterizer_discard_enable_unchecked(&mut self, enable: bool) -> &mut Self {
2321        let fns = self.device().fns();
2322
2323        if self.device().api_version() >= Version::V1_3 {
2324            (fns.v1_3.cmd_set_rasterizer_discard_enable)(self.handle(), enable.into());
2325        } else {
2326            (fns.ext_extended_dynamic_state2
2327                .cmd_set_rasterizer_discard_enable_ext)(self.handle(), enable.into());
2328        }
2329
2330        self
2331    }
2332
2333    pub unsafe fn set_scissor(
2334        &mut self,
2335        first_scissor: u32,
2336        scissors: &[Scissor],
2337    ) -> Result<&mut Self, Box<ValidationError>> {
2338        self.validate_set_scissor(first_scissor, scissors)?;
2339
2340        Ok(self.set_scissor_unchecked(first_scissor, scissors))
2341    }
2342
2343    fn validate_set_scissor(
2344        &self,
2345        first_scissor: u32,
2346        scissors: &[Scissor],
2347    ) -> Result<(), Box<ValidationError>> {
2348        if !self
2349            .queue_family_properties()
2350            .queue_flags
2351            .intersects(QueueFlags::GRAPHICS)
2352        {
2353            return Err(Box::new(ValidationError {
2354                problem: "the queue family of the command buffer does not support \
2355                    graphics operations"
2356                    .into(),
2357                vuids: &["VUID-vkCmdSetScissor-commandBuffer-cmdpool"],
2358                ..Default::default()
2359            }));
2360        }
2361
2362        let properties = self.device().physical_device().properties();
2363
2364        if first_scissor + scissors.len() as u32 > properties.max_viewports {
2365            return Err(Box::new(ValidationError {
2366                problem: "`first_scissor + scissors.len()` exceeds the `max_viewports` limit"
2367                    .into(),
2368                vuids: &["VUID-vkCmdSetScissor-firstScissor-00592"],
2369                ..Default::default()
2370            }));
2371        }
2372
2373        if !self.device().enabled_features().multi_viewport {
2374            if first_scissor != 0 {
2375                return Err(Box::new(ValidationError {
2376                    problem: "`first_scissor` is not 0".into(),
2377                    requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
2378                        "multi_viewport",
2379                    )])]),
2380                    vuids: &["VUID-vkCmdSetScissor-firstScissor-00593"],
2381                    ..Default::default()
2382                }));
2383            }
2384
2385            if scissors.len() > 1 {
2386                return Err(Box::new(ValidationError {
2387                    problem: "`scissors.len()` is greater than 1".into(),
2388                    requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
2389                        "multi_viewport",
2390                    )])]),
2391                    vuids: &["VUID-vkCmdSetScissor-scissorCount-00594"],
2392                    ..Default::default()
2393                }));
2394            }
2395        }
2396
2397        Ok(())
2398    }
2399
2400    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
2401    pub unsafe fn set_scissor_unchecked(
2402        &mut self,
2403        first_scissor: u32,
2404        scissors: &[Scissor],
2405    ) -> &mut Self {
2406        let scissors = scissors
2407            .iter()
2408            .map(ash::vk::Rect2D::from)
2409            .collect::<SmallVec<[_; 2]>>();
2410        if scissors.is_empty() {
2411            return self;
2412        }
2413
2414        let fns = self.device().fns();
2415        (fns.v1_0.cmd_set_scissor)(
2416            self.handle(),
2417            first_scissor,
2418            scissors.len() as u32,
2419            scissors.as_ptr(),
2420        );
2421
2422        self
2423    }
2424
2425    pub unsafe fn set_scissor_with_count(
2426        &mut self,
2427        scissors: &[Scissor],
2428    ) -> Result<&mut Self, Box<ValidationError>> {
2429        self.validate_set_scissor_with_count(scissors)?;
2430
2431        Ok(self.set_scissor_with_count_unchecked(scissors))
2432    }
2433
2434    fn validate_set_scissor_with_count(
2435        &self,
2436        scissors: &[Scissor],
2437    ) -> Result<(), Box<ValidationError>> {
2438        if !(self.device().api_version() >= Version::V1_3
2439            || self.device().enabled_features().extended_dynamic_state)
2440        {
2441            return Err(Box::new(ValidationError {
2442                requires_one_of: RequiresOneOf(&[
2443                    RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]),
2444                    RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]),
2445                ]),
2446                vuids: &["VUID-vkCmdSetScissorWithCount-None-03396"],
2447                ..Default::default()
2448            }));
2449        }
2450
2451        if !self
2452            .queue_family_properties()
2453            .queue_flags
2454            .intersects(QueueFlags::GRAPHICS)
2455        {
2456            return Err(Box::new(ValidationError {
2457                problem: "the queue family of the command buffer does not support \
2458                    graphics operations"
2459                    .into(),
2460                vuids: &["VUID-vkCmdSetScissorWithCount-commandBuffer-cmdpool"],
2461                ..Default::default()
2462            }));
2463        }
2464
2465        let properties = self.device().physical_device().properties();
2466
2467        if scissors.len() as u32 > properties.max_viewports {
2468            return Err(Box::new(ValidationError {
2469                problem: "`scissors.len()` exceeds the `max_viewports` limit".into(),
2470                vuids: &["VUID-vkCmdSetScissorWithCount-scissorCount-03397"],
2471                ..Default::default()
2472            }));
2473        }
2474
2475        if !self.device().enabled_features().multi_viewport && scissors.len() > 1 {
2476            return Err(Box::new(ValidationError {
2477                problem: "`scissors.len()` is greater than 1".into(),
2478                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
2479                    "multi_viewport",
2480                )])]),
2481                vuids: &["VUID-vkCmdSetScissorWithCount-scissorCount-03398"],
2482                ..Default::default()
2483            }));
2484        }
2485
2486        Ok(())
2487    }
2488
2489    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
2490    pub unsafe fn set_scissor_with_count_unchecked(&mut self, scissors: &[Scissor]) -> &mut Self {
2491        let scissors = scissors
2492            .iter()
2493            .map(ash::vk::Rect2D::from)
2494            .collect::<SmallVec<[_; 2]>>();
2495        if scissors.is_empty() {
2496            return self;
2497        }
2498
2499        let fns = self.device().fns();
2500
2501        if self.device().api_version() >= Version::V1_3 {
2502            (fns.v1_3.cmd_set_scissor_with_count)(
2503                self.handle(),
2504                scissors.len() as u32,
2505                scissors.as_ptr(),
2506            );
2507        } else {
2508            (fns.ext_extended_dynamic_state
2509                .cmd_set_scissor_with_count_ext)(
2510                self.handle(),
2511                scissors.len() as u32,
2512                scissors.as_ptr(),
2513            );
2514        }
2515
2516        self
2517    }
2518
2519    pub unsafe fn set_stencil_compare_mask(
2520        &mut self,
2521        faces: StencilFaces,
2522        compare_mask: u32,
2523    ) -> Result<&mut Self, Box<ValidationError>> {
2524        self.validate_set_stencil_compare_mask(faces, compare_mask)?;
2525
2526        Ok(self.set_stencil_compare_mask_unchecked(faces, compare_mask))
2527    }
2528
2529    fn validate_set_stencil_compare_mask(
2530        &self,
2531        faces: StencilFaces,
2532        _compare_mask: u32,
2533    ) -> Result<(), Box<ValidationError>> {
2534        if !self
2535            .queue_family_properties()
2536            .queue_flags
2537            .intersects(QueueFlags::GRAPHICS)
2538        {
2539            return Err(Box::new(ValidationError {
2540                problem: "the queue family of the command buffer does not support \
2541                    graphics operations"
2542                    .into(),
2543                vuids: &["VUID-vkCmdSetStencilCompareMask-commandBuffer-cmdpool"],
2544                ..Default::default()
2545            }));
2546        }
2547
2548        faces.validate_device(self.device()).map_err(|err| {
2549            err.add_context("faces")
2550                .set_vuids(&["VUID-vkCmdSetStencilCompareMask-faceMask-parameter"])
2551        })?;
2552
2553        Ok(())
2554    }
2555
2556    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
2557    pub unsafe fn set_stencil_compare_mask_unchecked(
2558        &mut self,
2559        faces: StencilFaces,
2560        compare_mask: u32,
2561    ) -> &mut Self {
2562        let fns = self.device().fns();
2563        (fns.v1_0.cmd_set_stencil_compare_mask)(self.handle(), faces.into(), compare_mask);
2564
2565        self
2566    }
2567
2568    pub unsafe fn set_stencil_op(
2569        &mut self,
2570        faces: StencilFaces,
2571        fail_op: StencilOp,
2572        pass_op: StencilOp,
2573        depth_fail_op: StencilOp,
2574        compare_op: CompareOp,
2575    ) -> Result<&mut Self, Box<ValidationError>> {
2576        self.validate_set_stencil_op(faces, fail_op, pass_op, depth_fail_op, compare_op)?;
2577
2578        Ok(self.set_stencil_op_unchecked(faces, fail_op, pass_op, depth_fail_op, compare_op))
2579    }
2580
2581    fn validate_set_stencil_op(
2582        &self,
2583        faces: StencilFaces,
2584        fail_op: StencilOp,
2585        pass_op: StencilOp,
2586        depth_fail_op: StencilOp,
2587        compare_op: CompareOp,
2588    ) -> Result<(), Box<ValidationError>> {
2589        if !(self.device().api_version() >= Version::V1_3
2590            || self.device().enabled_features().extended_dynamic_state)
2591        {
2592            return Err(Box::new(ValidationError {
2593                requires_one_of: RequiresOneOf(&[
2594                    RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]),
2595                    RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]),
2596                ]),
2597                vuids: &["VUID-vkCmdSetStencilOp-None-03351"],
2598                ..Default::default()
2599            }));
2600        }
2601
2602        if !self
2603            .queue_family_properties()
2604            .queue_flags
2605            .intersects(QueueFlags::GRAPHICS)
2606        {
2607            return Err(Box::new(ValidationError {
2608                problem: "the queue family of the command buffer does not support \
2609                    graphics operations"
2610                    .into(),
2611                vuids: &["VUID-vkCmdSetStencilOp-commandBuffer-cmdpool"],
2612                ..Default::default()
2613            }));
2614        }
2615
2616        faces.validate_device(self.device()).map_err(|err| {
2617            err.add_context("faces")
2618                .set_vuids(&["VUID-vkCmdSetStencilOp-faceMask-parameter"])
2619        })?;
2620
2621        fail_op.validate_device(self.device()).map_err(|err| {
2622            err.add_context("fail_op")
2623                .set_vuids(&["VUID-vkCmdSetStencilOp-failOp-parameter"])
2624        })?;
2625
2626        pass_op.validate_device(self.device()).map_err(|err| {
2627            err.add_context("pass_op")
2628                .set_vuids(&["VUID-vkCmdSetStencilOp-passOp-parameter"])
2629        })?;
2630
2631        depth_fail_op
2632            .validate_device(self.device())
2633            .map_err(|err| {
2634                err.add_context("depth_fail_op")
2635                    .set_vuids(&["VUID-vkCmdSetStencilOp-depthFailOp-parameter"])
2636            })?;
2637
2638        compare_op.validate_device(self.device()).map_err(|err| {
2639            err.add_context("compare_op")
2640                .set_vuids(&["VUID-vkCmdSetStencilOp-compareOp-parameter"])
2641        })?;
2642
2643        Ok(())
2644    }
2645
2646    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
2647    pub unsafe fn set_stencil_op_unchecked(
2648        &mut self,
2649        faces: StencilFaces,
2650        fail_op: StencilOp,
2651        pass_op: StencilOp,
2652        depth_fail_op: StencilOp,
2653        compare_op: CompareOp,
2654    ) -> &mut Self {
2655        let fns = self.device().fns();
2656
2657        if self.device().api_version() >= Version::V1_3 {
2658            (fns.v1_3.cmd_set_stencil_op)(
2659                self.handle(),
2660                faces.into(),
2661                fail_op.into(),
2662                pass_op.into(),
2663                depth_fail_op.into(),
2664                compare_op.into(),
2665            );
2666        } else {
2667            (fns.ext_extended_dynamic_state.cmd_set_stencil_op_ext)(
2668                self.handle(),
2669                faces.into(),
2670                fail_op.into(),
2671                pass_op.into(),
2672                depth_fail_op.into(),
2673                compare_op.into(),
2674            );
2675        }
2676
2677        self
2678    }
2679
2680    pub unsafe fn set_stencil_reference(
2681        &mut self,
2682        faces: StencilFaces,
2683        reference: u32,
2684    ) -> Result<&mut Self, Box<ValidationError>> {
2685        self.validate_set_stencil_reference(faces, reference)?;
2686
2687        Ok(self.set_stencil_reference_unchecked(faces, reference))
2688    }
2689
2690    fn validate_set_stencil_reference(
2691        &self,
2692        faces: StencilFaces,
2693        _reference: u32,
2694    ) -> Result<(), Box<ValidationError>> {
2695        if !self
2696            .queue_family_properties()
2697            .queue_flags
2698            .intersects(QueueFlags::GRAPHICS)
2699        {
2700            return Err(Box::new(ValidationError {
2701                problem: "the queue family of the command buffer does not support \
2702                    graphics operations"
2703                    .into(),
2704                vuids: &["VUID-vkCmdSetStencilReference-commandBuffer-cmdpool"],
2705                ..Default::default()
2706            }));
2707        }
2708
2709        faces.validate_device(self.device()).map_err(|err| {
2710            err.add_context("faces")
2711                .set_vuids(&["VUID-vkCmdSetStencilReference-faceMask-parameter"])
2712        })?;
2713
2714        Ok(())
2715    }
2716
2717    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
2718    pub unsafe fn set_stencil_reference_unchecked(
2719        &mut self,
2720        faces: StencilFaces,
2721        reference: u32,
2722    ) -> &mut Self {
2723        let fns = self.device().fns();
2724        (fns.v1_0.cmd_set_stencil_reference)(self.handle(), faces.into(), reference);
2725
2726        self
2727    }
2728
2729    pub unsafe fn set_stencil_test_enable(
2730        &mut self,
2731        enable: bool,
2732    ) -> Result<&mut Self, Box<ValidationError>> {
2733        self.validate_set_stencil_test_enable(enable)?;
2734
2735        Ok(self.set_stencil_test_enable_unchecked(enable))
2736    }
2737
2738    fn validate_set_stencil_test_enable(&self, _enable: bool) -> Result<(), Box<ValidationError>> {
2739        if !(self.device().api_version() >= Version::V1_3
2740            || self.device().enabled_features().extended_dynamic_state)
2741        {
2742            return Err(Box::new(ValidationError {
2743                requires_one_of: RequiresOneOf(&[
2744                    RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]),
2745                    RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]),
2746                ]),
2747                vuids: &["VUID-vkCmdSetStencilTestEnable-None-03350"],
2748                ..Default::default()
2749            }));
2750        }
2751
2752        if !self
2753            .queue_family_properties()
2754            .queue_flags
2755            .intersects(QueueFlags::GRAPHICS)
2756        {
2757            return Err(Box::new(ValidationError {
2758                problem: "the queue family of the command buffer does not support \
2759                    graphics operations"
2760                    .into(),
2761                vuids: &["VUID-vkCmdSetStencilTestEnable-commandBuffer-cmdpool"],
2762                ..Default::default()
2763            }));
2764        }
2765
2766        Ok(())
2767    }
2768
2769    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
2770    pub unsafe fn set_stencil_test_enable_unchecked(&mut self, enable: bool) -> &mut Self {
2771        let fns = self.device().fns();
2772
2773        if self.device().api_version() >= Version::V1_3 {
2774            (fns.v1_3.cmd_set_stencil_test_enable)(self.handle(), enable.into());
2775        } else {
2776            (fns.ext_extended_dynamic_state
2777                .cmd_set_stencil_test_enable_ext)(self.handle(), enable.into());
2778        }
2779
2780        self
2781    }
2782
2783    pub unsafe fn set_stencil_write_mask(
2784        &mut self,
2785        faces: StencilFaces,
2786        write_mask: u32,
2787    ) -> Result<&mut Self, Box<ValidationError>> {
2788        self.validate_set_stencil_write_mask(faces, write_mask)?;
2789
2790        Ok(self.set_stencil_write_mask_unchecked(faces, write_mask))
2791    }
2792
2793    fn validate_set_stencil_write_mask(
2794        &self,
2795        faces: StencilFaces,
2796        _write_mask: u32,
2797    ) -> Result<(), Box<ValidationError>> {
2798        if !self
2799            .queue_family_properties()
2800            .queue_flags
2801            .intersects(QueueFlags::GRAPHICS)
2802        {
2803            return Err(Box::new(ValidationError {
2804                problem: "the queue family of the command buffer does not support \
2805                    graphics operations"
2806                    .into(),
2807                vuids: &["VUID-vkCmdSetStencilWriteMask-commandBuffer-cmdpool"],
2808                ..Default::default()
2809            }));
2810        }
2811
2812        faces.validate_device(self.device()).map_err(|err| {
2813            err.add_context("faces")
2814                .set_vuids(&["VUID-vkCmdSetStencilWriteMask-faceMask-parameter"])
2815        })?;
2816
2817        Ok(())
2818    }
2819
2820    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
2821    pub unsafe fn set_stencil_write_mask_unchecked(
2822        &mut self,
2823        faces: StencilFaces,
2824        write_mask: u32,
2825    ) -> &mut Self {
2826        let fns = self.device().fns();
2827        (fns.v1_0.cmd_set_stencil_write_mask)(self.handle(), faces.into(), write_mask);
2828
2829        self
2830    }
2831
2832    pub unsafe fn set_viewport(
2833        &mut self,
2834        first_viewport: u32,
2835        viewports: &[Viewport],
2836    ) -> Result<&mut Self, Box<ValidationError>> {
2837        self.validate_set_viewport(first_viewport, viewports)?;
2838
2839        Ok(self.set_viewport_unchecked(first_viewport, viewports))
2840    }
2841
2842    fn validate_set_viewport(
2843        &self,
2844        first_viewport: u32,
2845        viewports: &[Viewport],
2846    ) -> Result<(), Box<ValidationError>> {
2847        if !self
2848            .queue_family_properties()
2849            .queue_flags
2850            .intersects(QueueFlags::GRAPHICS)
2851        {
2852            return Err(Box::new(ValidationError {
2853                problem: "the queue family of the command buffer does not support \
2854                    graphics operations"
2855                    .into(),
2856                vuids: &["VUID-vkCmdSetViewport-commandBuffer-cmdpool"],
2857                ..Default::default()
2858            }));
2859        }
2860
2861        let properties = self.device().physical_device().properties();
2862
2863        if first_viewport + viewports.len() as u32 > properties.max_viewports {
2864            return Err(Box::new(ValidationError {
2865                problem: "`first_viewport + viewports.len()` exceeds the `max_viewports` limit"
2866                    .into(),
2867                vuids: &["VUID-vkCmdSetViewport-firstViewport-01223"],
2868                ..Default::default()
2869            }));
2870        }
2871
2872        if !self.device().enabled_features().multi_viewport {
2873            if first_viewport != 0 {
2874                return Err(Box::new(ValidationError {
2875                    problem: "`first_viewport` is not 0".into(),
2876                    requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
2877                        "multi_viewport",
2878                    )])]),
2879                    vuids: &["VUID-vkCmdSetViewport-firstViewport-01224"],
2880                    ..Default::default()
2881                }));
2882            }
2883
2884            if viewports.len() > 1 {
2885                return Err(Box::new(ValidationError {
2886                    problem: "`viewports.len()` is greater than 1".into(),
2887                    requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
2888                        "multi_viewport",
2889                    )])]),
2890                    vuids: &["VUID-vkCmdSetViewport-viewportCount-01225"],
2891                    ..Default::default()
2892                }));
2893            }
2894        }
2895
2896        Ok(())
2897    }
2898
2899    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
2900    pub unsafe fn set_viewport_unchecked(
2901        &mut self,
2902        first_viewport: u32,
2903        viewports: &[Viewport],
2904    ) -> &mut Self {
2905        let viewports = viewports
2906            .iter()
2907            .map(|v| v.into())
2908            .collect::<SmallVec<[_; 2]>>();
2909        if viewports.is_empty() {
2910            return self;
2911        }
2912
2913        let fns = self.device().fns();
2914        (fns.v1_0.cmd_set_viewport)(
2915            self.handle(),
2916            first_viewport,
2917            viewports.len() as u32,
2918            viewports.as_ptr(),
2919        );
2920
2921        self
2922    }
2923
2924    pub unsafe fn set_viewport_with_count(
2925        &mut self,
2926        viewports: &[Viewport],
2927    ) -> Result<&mut Self, Box<ValidationError>> {
2928        self.validate_set_viewport_with_count(viewports)?;
2929
2930        Ok(self.set_viewport_with_count_unchecked(viewports))
2931    }
2932
2933    fn validate_set_viewport_with_count(
2934        &self,
2935        viewports: &[Viewport],
2936    ) -> Result<(), Box<ValidationError>> {
2937        if !(self.device().api_version() >= Version::V1_3
2938            || self.device().enabled_features().extended_dynamic_state)
2939        {
2940            return Err(Box::new(ValidationError {
2941                requires_one_of: RequiresOneOf(&[
2942                    RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]),
2943                    RequiresAllOf(&[Requires::Feature("extended_dynamic_state")]),
2944                ]),
2945                vuids: &["VUID-vkCmdSetViewportWithCount-None-03393"],
2946                ..Default::default()
2947            }));
2948        }
2949
2950        if !self
2951            .queue_family_properties()
2952            .queue_flags
2953            .intersects(QueueFlags::GRAPHICS)
2954        {
2955            return Err(Box::new(ValidationError {
2956                problem: "the queue family of the command buffer does not support \
2957                    graphics operations"
2958                    .into(),
2959                vuids: &["VUID-vkCmdSetViewportWithCount-commandBuffer-cmdpool"],
2960                ..Default::default()
2961            }));
2962        }
2963
2964        let properties = self.device().physical_device().properties();
2965
2966        if viewports.len() as u32 > properties.max_viewports {
2967            return Err(Box::new(ValidationError {
2968                problem: "`viewports.len()` exceeds the `max_viewports` limit".into(),
2969                vuids: &["VUID-vkCmdSetViewportWithCount-viewportCount-03394"],
2970                ..Default::default()
2971            }));
2972        }
2973
2974        if viewports.len() > 1 && !self.device().enabled_features().multi_viewport {
2975            return Err(Box::new(ValidationError {
2976                problem: "`viewports.len()` is greater than 1".into(),
2977                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
2978                    "multi_viewport",
2979                )])]),
2980                vuids: &["VUID-vkCmdSetViewportWithCount-viewportCount-03395"],
2981                ..Default::default()
2982            }));
2983        }
2984
2985        Ok(())
2986    }
2987
2988    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
2989    pub unsafe fn set_viewport_with_count_unchecked(
2990        &mut self,
2991        viewports: &[Viewport],
2992    ) -> &mut Self {
2993        let viewports = viewports
2994            .iter()
2995            .map(|v| v.into())
2996            .collect::<SmallVec<[_; 2]>>();
2997        if viewports.is_empty() {
2998            return self;
2999        }
3000
3001        let fns = self.device().fns();
3002
3003        if self.device().api_version() >= Version::V1_3 {
3004            (fns.v1_3.cmd_set_viewport_with_count)(
3005                self.handle(),
3006                viewports.len() as u32,
3007                viewports.as_ptr(),
3008            );
3009        } else {
3010            (fns.ext_extended_dynamic_state
3011                .cmd_set_viewport_with_count_ext)(
3012                self.handle(),
3013                viewports.len() as u32,
3014                viewports.as_ptr(),
3015            );
3016        }
3017
3018        self
3019    }
3020}