vulkano_taskgraph/command_buffer/commands/
dynamic_state.rs

1use crate::command_buffer::{RecordingCommandBuffer, Result};
2use ash::vk;
3use smallvec::SmallVec;
4use std::ops::RangeInclusive;
5use vulkano::{
6    device::DeviceOwned,
7    pipeline::graphics::{
8        color_blend::LogicOp,
9        depth_stencil::{CompareOp, StencilFaces, StencilOp},
10        fragment_shading_rate::FragmentShadingRateCombinerOp,
11        input_assembly::PrimitiveTopology,
12        rasterization::{ConservativeRasterizationMode, CullMode, FrontFace},
13        vertex_input::{
14            VertexInputAttributeDescription, VertexInputBindingDescription, VertexInputState,
15        },
16        viewport::{Scissor, Viewport},
17    },
18    Version, VulkanObject,
19};
20
21/// # Commands to set dynamic state for pipelines
22///
23/// These commands require a queue with a pipeline type that uses the given state.
24impl RecordingCommandBuffer<'_> {
25    /// Sets the dynamic blend constants for future draw calls.
26    pub unsafe fn set_blend_constants(&mut self, constants: &[f32; 4]) -> Result<&mut Self> {
27        Ok(unsafe { self.set_blend_constants_unchecked(constants) })
28    }
29
30    pub unsafe fn set_blend_constants_unchecked(&mut self, constants: &[f32; 4]) -> &mut Self {
31        let fns = self.device().fns();
32        unsafe { (fns.v1_0.cmd_set_blend_constants)(self.handle(), constants) };
33
34        self
35    }
36
37    /// Sets whether dynamic color writes should be enabled for each attachment in the framebuffer.
38    pub unsafe fn set_color_write_enable(&mut self, enables: &[bool]) -> Result<&mut Self> {
39        Ok(unsafe { self.set_color_write_enable_unchecked(enables) })
40    }
41
42    pub unsafe fn set_color_write_enable_unchecked(&mut self, enables: &[bool]) -> &mut Self {
43        if enables.is_empty() {
44            return self;
45        }
46
47        let enables_vk = enables
48            .iter()
49            .copied()
50            .map(|v| v as vk::Bool32)
51            .collect::<SmallVec<[_; 4]>>();
52
53        let fns = self.device().fns();
54        unsafe {
55            (fns.ext_color_write_enable.cmd_set_color_write_enable_ext)(
56                self.handle(),
57                enables_vk.len() as u32,
58                enables_vk.as_ptr(),
59            )
60        };
61
62        self
63    }
64
65    /// Sets the dynamic cull mode for future draw calls.
66    pub unsafe fn set_cull_mode(&mut self, cull_mode: CullMode) -> Result<&mut Self> {
67        Ok(unsafe { self.set_cull_mode_unchecked(cull_mode) })
68    }
69
70    pub unsafe fn set_cull_mode_unchecked(&mut self, cull_mode: CullMode) -> &mut Self {
71        let fns = self.device().fns();
72        let cmd_set_cull_mode = if self.device().api_version() >= Version::V1_3 {
73            fns.v1_3.cmd_set_cull_mode
74        } else {
75            fns.ext_extended_dynamic_state.cmd_set_cull_mode_ext
76        };
77
78        unsafe { cmd_set_cull_mode(self.handle(), cull_mode.into()) };
79
80        self
81    }
82
83    /// Sets the dynamic depth bias values for future draw calls.
84    pub unsafe fn set_depth_bias(
85        &mut self,
86        constant_factor: f32,
87        clamp: f32,
88        slope_factor: f32,
89    ) -> Result<&mut Self> {
90        Ok(unsafe { self.set_depth_bias_unchecked(constant_factor, clamp, slope_factor) })
91    }
92
93    pub unsafe fn set_depth_bias_unchecked(
94        &mut self,
95        constant_factor: f32,
96        clamp: f32,
97        slope_factor: f32,
98    ) -> &mut Self {
99        let fns = self.device().fns();
100        unsafe {
101            (fns.v1_0.cmd_set_depth_bias)(self.handle(), constant_factor, clamp, slope_factor)
102        };
103
104        self
105    }
106
107    /// Sets whether dynamic depth bias is enabled for future draw calls.
108    pub unsafe fn set_depth_bias_enable(&mut self, enable: bool) -> Result<&mut Self> {
109        Ok(unsafe { self.set_depth_bias_enable_unchecked(enable) })
110    }
111
112    pub unsafe fn set_depth_bias_enable_unchecked(&mut self, enable: bool) -> &mut Self {
113        let fns = self.device().fns();
114        let cmd_set_depth_bias_enable = if self.device().api_version() >= Version::V1_3 {
115            fns.v1_3.cmd_set_depth_bias_enable
116        } else {
117            fns.ext_extended_dynamic_state2
118                .cmd_set_depth_bias_enable_ext
119        };
120
121        unsafe { cmd_set_depth_bias_enable(self.handle(), enable.into()) };
122
123        self
124    }
125
126    /// Sets the dynamic depth bounds for future draw calls.
127    pub unsafe fn set_depth_bounds(&mut self, bounds: RangeInclusive<f32>) -> Result<&mut Self> {
128        Ok(unsafe { self.set_depth_bounds_unchecked(bounds.clone()) })
129    }
130
131    pub unsafe fn set_depth_bounds_unchecked(&mut self, bounds: RangeInclusive<f32>) -> &mut Self {
132        let fns = self.device().fns();
133        unsafe { (fns.v1_0.cmd_set_depth_bounds)(self.handle(), *bounds.start(), *bounds.end()) };
134
135        self
136    }
137
138    /// Sets whether dynamic depth bounds testing is enabled for future draw calls.
139    pub unsafe fn set_depth_bounds_test_enable(&mut self, enable: bool) -> Result<&mut Self> {
140        Ok(unsafe { self.set_depth_bounds_test_enable_unchecked(enable) })
141    }
142
143    pub unsafe fn set_depth_bounds_test_enable_unchecked(&mut self, enable: bool) -> &mut Self {
144        let fns = self.device().fns();
145        let cmd_set_depth_bounds_test_enable = if self.device().api_version() >= Version::V1_3 {
146            fns.v1_3.cmd_set_depth_bounds_test_enable
147        } else {
148            fns.ext_extended_dynamic_state
149                .cmd_set_depth_bounds_test_enable_ext
150        };
151
152        unsafe { cmd_set_depth_bounds_test_enable(self.handle(), enable.into()) };
153
154        self
155    }
156
157    /// Sets the dynamic depth compare op for future draw calls.
158    pub unsafe fn set_depth_compare_op(&mut self, compare_op: CompareOp) -> Result<&mut Self> {
159        Ok(unsafe { self.set_depth_compare_op_unchecked(compare_op) })
160    }
161
162    pub unsafe fn set_depth_compare_op_unchecked(&mut self, compare_op: CompareOp) -> &mut Self {
163        let fns = self.device().fns();
164        let cmd_set_depth_compare_op = if self.device().api_version() >= Version::V1_3 {
165            fns.v1_3.cmd_set_depth_compare_op
166        } else {
167            fns.ext_extended_dynamic_state.cmd_set_depth_compare_op_ext
168        };
169
170        unsafe { cmd_set_depth_compare_op(self.handle(), compare_op.into()) };
171
172        self
173    }
174
175    /// Sets whether dynamic depth testing is enabled for future draw calls.
176    pub unsafe fn set_depth_test_enable(&mut self, enable: bool) -> Result<&mut Self> {
177        Ok(unsafe { self.set_depth_test_enable_unchecked(enable) })
178    }
179
180    pub unsafe fn set_depth_test_enable_unchecked(&mut self, enable: bool) -> &mut Self {
181        let fns = self.device().fns();
182        let cmd_set_depth_test_enable = if self.device().api_version() >= Version::V1_3 {
183            fns.v1_3.cmd_set_depth_test_enable
184        } else {
185            fns.ext_extended_dynamic_state.cmd_set_depth_test_enable_ext
186        };
187
188        unsafe { cmd_set_depth_test_enable(self.handle(), enable.into()) };
189
190        self
191    }
192
193    /// Sets whether dynamic depth write is enabled for future draw calls.
194    pub unsafe fn set_depth_write_enable(&mut self, enable: bool) -> Result<&mut Self> {
195        Ok(unsafe { self.set_depth_write_enable_unchecked(enable) })
196    }
197
198    pub unsafe fn set_depth_write_enable_unchecked(&mut self, enable: bool) -> &mut Self {
199        let fns = self.device().fns();
200        let cmd_set_depth_write_enable = if self.device().api_version() >= Version::V1_3 {
201            fns.v1_3.cmd_set_depth_write_enable
202        } else {
203            fns.ext_extended_dynamic_state
204                .cmd_set_depth_write_enable_ext
205        };
206
207        unsafe { cmd_set_depth_write_enable(self.handle(), enable.into()) };
208
209        self
210    }
211
212    /// Sets the dynamic discard rectangles for future draw calls.
213    pub unsafe fn set_discard_rectangle(
214        &mut self,
215        first_rectangle: u32,
216        rectangles: &[Scissor],
217    ) -> Result<&mut Self> {
218        Ok(unsafe { self.set_discard_rectangle_unchecked(first_rectangle, rectangles) })
219    }
220
221    pub unsafe fn set_discard_rectangle_unchecked(
222        &mut self,
223        first_rectangle: u32,
224        rectangles: &[Scissor],
225    ) -> &mut Self {
226        if rectangles.is_empty() {
227            return self;
228        }
229
230        let rectangles_vk = rectangles
231            .iter()
232            .map(Scissor::to_vk)
233            .collect::<SmallVec<[_; 2]>>();
234
235        let fns = self.device().fns();
236        unsafe {
237            (fns.ext_discard_rectangles.cmd_set_discard_rectangle_ext)(
238                self.handle(),
239                first_rectangle,
240                rectangles_vk.len() as u32,
241                rectangles_vk.as_ptr(),
242            )
243        };
244
245        self
246    }
247
248    /// Sets the dynamic front face for future draw calls.
249    pub unsafe fn set_front_face(&mut self, face: FrontFace) -> Result<&mut Self> {
250        Ok(unsafe { self.set_front_face_unchecked(face) })
251    }
252
253    pub unsafe fn set_front_face_unchecked(&mut self, face: FrontFace) -> &mut Self {
254        let fns = self.device().fns();
255        let cmd_set_front_face = if self.device().api_version() >= Version::V1_3 {
256            fns.v1_3.cmd_set_front_face
257        } else {
258            fns.ext_extended_dynamic_state.cmd_set_front_face_ext
259        };
260
261        unsafe { cmd_set_front_face(self.handle(), face.into()) };
262
263        self
264    }
265
266    /// Sets the dynamic line stipple values for future draw calls.
267    pub unsafe fn set_line_stipple(&mut self, factor: u32, pattern: u16) -> Result<&mut Self> {
268        Ok(unsafe { self.set_line_stipple_unchecked(factor, pattern) })
269    }
270
271    pub unsafe fn set_line_stipple_unchecked(&mut self, factor: u32, pattern: u16) -> &mut Self {
272        let fns = self.device().fns();
273        unsafe {
274            (fns.ext_line_rasterization.cmd_set_line_stipple_ext)(self.handle(), factor, pattern)
275        };
276
277        self
278    }
279
280    /// Sets the dynamic line width for future draw calls.
281    pub unsafe fn set_line_width(&mut self, line_width: f32) -> Result<&mut Self> {
282        Ok(unsafe { self.set_line_width_unchecked(line_width) })
283    }
284
285    pub unsafe fn set_line_width_unchecked(&mut self, line_width: f32) -> &mut Self {
286        let fns = self.device().fns();
287        unsafe { (fns.v1_0.cmd_set_line_width)(self.handle(), line_width) };
288
289        self
290    }
291
292    /// Sets the dynamic logic op for future draw calls.
293    pub unsafe fn set_logic_op(&mut self, logic_op: LogicOp) -> Result<&mut Self> {
294        Ok(unsafe { self.set_logic_op_unchecked(logic_op) })
295    }
296
297    pub unsafe fn set_logic_op_unchecked(&mut self, logic_op: LogicOp) -> &mut Self {
298        let fns = self.device().fns();
299        unsafe {
300            (fns.ext_extended_dynamic_state2.cmd_set_logic_op_ext)(self.handle(), logic_op.into())
301        };
302
303        self
304    }
305
306    /// Sets the dynamic number of patch control points for future draw calls.
307    pub unsafe fn set_patch_control_points(&mut self, num: u32) -> Result<&mut Self> {
308        Ok(unsafe { self.set_patch_control_points_unchecked(num) })
309    }
310
311    pub unsafe fn set_patch_control_points_unchecked(&mut self, num: u32) -> &mut Self {
312        let fns = self.device().fns();
313        unsafe {
314            (fns.ext_extended_dynamic_state2
315                .cmd_set_patch_control_points_ext)(self.handle(), num)
316        };
317
318        self
319    }
320
321    /// Sets whether dynamic primitive restart is enabled for future draw calls.
322    pub unsafe fn set_primitive_restart_enable(&mut self, enable: bool) -> Result<&mut Self> {
323        Ok(unsafe { self.set_primitive_restart_enable_unchecked(enable) })
324    }
325
326    pub unsafe fn set_primitive_restart_enable_unchecked(&mut self, enable: bool) -> &mut Self {
327        let fns = self.device().fns();
328        let cmd_set_primitive_restart_enable = if self.device().api_version() >= Version::V1_3 {
329            fns.v1_3.cmd_set_primitive_restart_enable
330        } else {
331            fns.ext_extended_dynamic_state2
332                .cmd_set_primitive_restart_enable_ext
333        };
334
335        unsafe { cmd_set_primitive_restart_enable(self.handle(), enable.into()) };
336
337        self
338    }
339
340    /// Sets the dynamic primitive topology for future draw calls.
341    pub unsafe fn set_primitive_topology(
342        &mut self,
343        topology: PrimitiveTopology,
344    ) -> Result<&mut Self> {
345        Ok(unsafe { self.set_primitive_topology_unchecked(topology) })
346    }
347
348    pub unsafe fn set_primitive_topology_unchecked(
349        &mut self,
350        topology: PrimitiveTopology,
351    ) -> &mut Self {
352        let fns = self.device().fns();
353        let cmd_set_primitive_topology = if self.device().api_version() >= Version::V1_3 {
354            fns.v1_3.cmd_set_primitive_topology
355        } else {
356            fns.ext_extended_dynamic_state
357                .cmd_set_primitive_topology_ext
358        };
359
360        unsafe { cmd_set_primitive_topology(self.handle(), topology.into()) };
361
362        self
363    }
364
365    /// Sets whether dynamic rasterizer discard is enabled for future draw calls.
366    pub unsafe fn set_rasterizer_discard_enable(&mut self, enable: bool) -> Result<&mut Self> {
367        Ok(unsafe { self.set_rasterizer_discard_enable_unchecked(enable) })
368    }
369
370    pub unsafe fn set_rasterizer_discard_enable_unchecked(&mut self, enable: bool) -> &mut Self {
371        let fns = self.device().fns();
372        let cmd_set_rasterizer_discard_enable = if self.device().api_version() >= Version::V1_3 {
373            fns.v1_3.cmd_set_rasterizer_discard_enable
374        } else {
375            fns.ext_extended_dynamic_state2
376                .cmd_set_rasterizer_discard_enable_ext
377        };
378
379        unsafe { cmd_set_rasterizer_discard_enable(self.handle(), enable.into()) };
380
381        self
382    }
383
384    /// Sets the dynamic scissors for future draw calls.
385    pub unsafe fn set_scissor(
386        &mut self,
387        first_scissor: u32,
388        scissors: &[Scissor],
389    ) -> Result<&mut Self> {
390        Ok(unsafe { self.set_scissor_unchecked(first_scissor, scissors) })
391    }
392
393    pub unsafe fn set_scissor_unchecked(
394        &mut self,
395        first_scissor: u32,
396        scissors: &[Scissor],
397    ) -> &mut Self {
398        if scissors.is_empty() {
399            return self;
400        }
401
402        let scissors_vk = scissors
403            .iter()
404            .map(Scissor::to_vk)
405            .collect::<SmallVec<[_; 2]>>();
406
407        let fns = self.device().fns();
408        unsafe {
409            (fns.v1_0.cmd_set_scissor)(
410                self.handle(),
411                first_scissor,
412                scissors_vk.len() as u32,
413                scissors_vk.as_ptr(),
414            )
415        };
416
417        self
418    }
419
420    /// Sets the dynamic scissors with count for future draw calls.
421    pub unsafe fn set_scissor_with_count(&mut self, scissors: &[Scissor]) -> Result<&mut Self> {
422        Ok(unsafe { self.set_scissor_with_count_unchecked(scissors) })
423    }
424
425    pub unsafe fn set_scissor_with_count_unchecked(&mut self, scissors: &[Scissor]) -> &mut Self {
426        if scissors.is_empty() {
427            return self;
428        }
429
430        let scissors_vk = scissors
431            .iter()
432            .map(Scissor::to_vk)
433            .collect::<SmallVec<[_; 2]>>();
434
435        let fns = self.device().fns();
436        let cmd_set_scissor_with_count = if self.device().api_version() >= Version::V1_3 {
437            fns.v1_3.cmd_set_scissor_with_count
438        } else {
439            fns.ext_extended_dynamic_state
440                .cmd_set_scissor_with_count_ext
441        };
442
443        unsafe {
444            cmd_set_scissor_with_count(
445                self.handle(),
446                scissors_vk.len() as u32,
447                scissors_vk.as_ptr(),
448            )
449        };
450
451        self
452    }
453
454    /// Sets the dynamic stencil compare mask on one or both faces for future draw calls.
455    pub unsafe fn set_stencil_compare_mask(
456        &mut self,
457        faces: StencilFaces,
458        compare_mask: u32,
459    ) -> Result<&mut Self> {
460        Ok(unsafe { self.set_stencil_compare_mask_unchecked(faces, compare_mask) })
461    }
462
463    pub unsafe fn set_stencil_compare_mask_unchecked(
464        &mut self,
465        faces: StencilFaces,
466        compare_mask: u32,
467    ) -> &mut Self {
468        let fns = self.device().fns();
469        unsafe {
470            (fns.v1_0.cmd_set_stencil_compare_mask)(self.handle(), faces.into(), compare_mask)
471        };
472
473        self
474    }
475
476    /// Sets the dynamic stencil ops on one or both faces for future draw calls.
477    pub unsafe fn set_stencil_op(
478        &mut self,
479        faces: StencilFaces,
480        fail_op: StencilOp,
481        pass_op: StencilOp,
482        depth_fail_op: StencilOp,
483        compare_op: CompareOp,
484    ) -> Result<&mut Self> {
485        Ok(unsafe {
486            self.set_stencil_op_unchecked(faces, fail_op, pass_op, depth_fail_op, compare_op)
487        })
488    }
489
490    pub unsafe fn set_stencil_op_unchecked(
491        &mut self,
492        faces: StencilFaces,
493        fail_op: StencilOp,
494        pass_op: StencilOp,
495        depth_fail_op: StencilOp,
496        compare_op: CompareOp,
497    ) -> &mut Self {
498        let fns = self.device().fns();
499        let cmd_set_stencil_op = if self.device().api_version() >= Version::V1_3 {
500            fns.v1_3.cmd_set_stencil_op
501        } else {
502            fns.ext_extended_dynamic_state.cmd_set_stencil_op_ext
503        };
504
505        unsafe {
506            cmd_set_stencil_op(
507                self.handle(),
508                faces.into(),
509                fail_op.into(),
510                pass_op.into(),
511                depth_fail_op.into(),
512                compare_op.into(),
513            )
514        };
515
516        self
517    }
518
519    /// Sets the dynamic stencil reference on one or both faces for future draw calls.
520    pub unsafe fn set_stencil_reference(
521        &mut self,
522        faces: StencilFaces,
523        reference: u32,
524    ) -> Result<&mut Self> {
525        Ok(unsafe { self.set_stencil_reference_unchecked(faces, reference) })
526    }
527
528    pub unsafe fn set_stencil_reference_unchecked(
529        &mut self,
530        faces: StencilFaces,
531        reference: u32,
532    ) -> &mut Self {
533        let fns = self.device().fns();
534        unsafe { (fns.v1_0.cmd_set_stencil_reference)(self.handle(), faces.into(), reference) };
535
536        self
537    }
538
539    /// Sets whether dynamic stencil testing is enabled for future draw calls.
540    pub unsafe fn set_stencil_test_enable(&mut self, enable: bool) -> Result<&mut Self> {
541        Ok(unsafe { self.set_stencil_test_enable_unchecked(enable) })
542    }
543
544    pub unsafe fn set_stencil_test_enable_unchecked(&mut self, enable: bool) -> &mut Self {
545        let fns = self.device().fns();
546        let cmd_set_stencil_test_enable = if self.device().api_version() >= Version::V1_3 {
547            fns.v1_3.cmd_set_stencil_test_enable
548        } else {
549            fns.ext_extended_dynamic_state
550                .cmd_set_stencil_test_enable_ext
551        };
552
553        unsafe { cmd_set_stencil_test_enable(self.handle(), enable.into()) };
554
555        self
556    }
557
558    /// Sets the dynamic stencil write mask on one or both faces for future draw calls.
559    pub unsafe fn set_stencil_write_mask(
560        &mut self,
561        faces: StencilFaces,
562        write_mask: u32,
563    ) -> Result<&mut Self> {
564        Ok(unsafe { self.set_stencil_write_mask_unchecked(faces, write_mask) })
565    }
566
567    pub unsafe fn set_stencil_write_mask_unchecked(
568        &mut self,
569        faces: StencilFaces,
570        write_mask: u32,
571    ) -> &mut Self {
572        let fns = self.device().fns();
573        unsafe { (fns.v1_0.cmd_set_stencil_write_mask)(self.handle(), faces.into(), write_mask) };
574
575        self
576    }
577
578    /// Sets the dynamic vertex input for future draw calls.
579    pub unsafe fn set_vertex_input(
580        &mut self,
581        vertex_input_state: &VertexInputState,
582    ) -> Result<&mut Self> {
583        Ok(unsafe { self.set_vertex_input_unchecked(vertex_input_state) })
584    }
585
586    pub unsafe fn set_vertex_input_unchecked(
587        &mut self,
588        vertex_input_state: &VertexInputState,
589    ) -> &mut Self {
590        let mut vertex_binding_descriptions_vk: SmallVec<[_; 8]> = SmallVec::new();
591        let mut vertex_attribute_descriptions_vk: SmallVec<[_; 8]> = SmallVec::new();
592
593        let VertexInputState {
594            bindings,
595            attributes,
596            _ne: _,
597        } = vertex_input_state;
598
599        vertex_binding_descriptions_vk.extend(bindings.iter().map(|(&binding, binding_desc)| {
600            let &VertexInputBindingDescription {
601                stride,
602                input_rate,
603                _ne: _,
604            } = binding_desc;
605
606            let (input_rate, divisor) = input_rate.to_vk();
607
608            vk::VertexInputBindingDescription2EXT {
609                binding,
610                stride,
611                input_rate,
612                divisor,
613                ..Default::default()
614            }
615        }));
616
617        vertex_attribute_descriptions_vk.extend(attributes.iter().map(
618            |(&location, attribute_desc)| {
619                let &VertexInputAttributeDescription {
620                    binding,
621                    format,
622                    offset,
623                    _ne: _,
624                } = attribute_desc;
625
626                vk::VertexInputAttributeDescription2EXT {
627                    location,
628                    binding,
629                    format: format.into(),
630                    offset,
631                    ..Default::default()
632                }
633            },
634        ));
635
636        let fns = self.device().fns();
637        unsafe {
638            (fns.ext_vertex_input_dynamic_state.cmd_set_vertex_input_ext)(
639                self.handle(),
640                vertex_binding_descriptions_vk.len() as u32,
641                vertex_binding_descriptions_vk.as_ptr(),
642                vertex_attribute_descriptions_vk.len() as u32,
643                vertex_attribute_descriptions_vk.as_ptr(),
644            )
645        };
646
647        self
648    }
649
650    /// Sets the dynamic viewports for future draw calls.
651    pub unsafe fn set_viewport(
652        &mut self,
653        first_viewport: u32,
654        viewports: &[Viewport],
655    ) -> Result<&mut Self> {
656        Ok(unsafe { self.set_viewport_unchecked(first_viewport, viewports) })
657    }
658
659    pub unsafe fn set_viewport_unchecked(
660        &mut self,
661        first_viewport: u32,
662        viewports: &[Viewport],
663    ) -> &mut Self {
664        if viewports.is_empty() {
665            return self;
666        }
667
668        let viewports_vk = viewports
669            .iter()
670            .map(Viewport::to_vk)
671            .collect::<SmallVec<[_; 2]>>();
672
673        let fns = self.device().fns();
674        unsafe {
675            (fns.v1_0.cmd_set_viewport)(
676                self.handle(),
677                first_viewport,
678                viewports_vk.len() as u32,
679                viewports_vk.as_ptr(),
680            )
681        };
682
683        self
684    }
685
686    /// Sets the dynamic viewports with count for future draw calls.
687    pub unsafe fn set_viewport_with_count(&mut self, viewports: &[Viewport]) -> Result<&mut Self> {
688        Ok(unsafe { self.set_viewport_with_count_unchecked(viewports) })
689    }
690
691    pub unsafe fn set_viewport_with_count_unchecked(
692        &mut self,
693        viewports: &[Viewport],
694    ) -> &mut Self {
695        if viewports.is_empty() {
696            return self;
697        }
698
699        let viewports_vk = viewports
700            .iter()
701            .map(Viewport::to_vk)
702            .collect::<SmallVec<[_; 2]>>();
703
704        let fns = self.device().fns();
705        let cmd_set_viewport_with_count = if self.device().api_version() >= Version::V1_3 {
706            fns.v1_3.cmd_set_viewport_with_count
707        } else {
708            fns.ext_extended_dynamic_state
709                .cmd_set_viewport_with_count_ext
710        };
711
712        unsafe {
713            cmd_set_viewport_with_count(
714                self.handle(),
715                viewports_vk.len() as u32,
716                viewports_vk.as_ptr(),
717            )
718        };
719
720        self
721    }
722
723    /// Sets the dynamic conservative rasterization mode for future draw calls.
724    pub unsafe fn set_conservative_rasterization_mode(
725        &mut self,
726        conservative_rasterization_mode: ConservativeRasterizationMode,
727    ) -> Result<&mut Self> {
728        Ok(unsafe {
729            self.set_conservative_rasterization_mode_unchecked(conservative_rasterization_mode)
730        })
731    }
732
733    pub unsafe fn set_conservative_rasterization_mode_unchecked(
734        &mut self,
735        conservative_rasterization_mode: ConservativeRasterizationMode,
736    ) -> &mut Self {
737        let fns = self.device().fns();
738        unsafe {
739            (fns.ext_extended_dynamic_state3
740                .cmd_set_conservative_rasterization_mode_ext)(
741                self.handle(),
742                conservative_rasterization_mode.into(),
743            )
744        };
745
746        self
747    }
748
749    /// Sets the dynamic extra primitive overestimation size for future draw calls.
750    pub unsafe fn set_extra_primitive_overestimation_size(
751        &mut self,
752        extra_primitive_overestimation_size: f32,
753    ) -> Result<&mut Self> {
754        Ok(unsafe {
755            self.set_extra_primitive_overestimation_size_unchecked(
756                extra_primitive_overestimation_size,
757            )
758        })
759    }
760
761    pub unsafe fn set_extra_primitive_overestimation_size_unchecked(
762        &mut self,
763        extra_primitive_overestimation_size: f32,
764    ) -> &mut Self {
765        let fns = self.device().fns();
766        unsafe {
767            (fns.ext_extended_dynamic_state3
768                .cmd_set_extra_primitive_overestimation_size_ext)(
769                self.handle(),
770                extra_primitive_overestimation_size,
771            )
772        };
773
774        self
775    }
776
777    /// Sets the dynamic fragment shading rate for future draw calls.
778    pub unsafe fn set_fragment_shading_rate(
779        &mut self,
780        fragment_size: [u32; 2],
781        combiner_ops: [FragmentShadingRateCombinerOp; 2],
782    ) -> Result<&mut Self> {
783        Ok(unsafe { self.set_fragment_shading_rate_unchecked(fragment_size, combiner_ops) })
784    }
785
786    pub unsafe fn set_fragment_shading_rate_unchecked(
787        &mut self,
788        fragment_size: [u32; 2],
789        combiner_ops: [FragmentShadingRateCombinerOp; 2],
790    ) -> &mut Self {
791        let fns = self.device().fns();
792        let fragment_size = vk::Extent2D {
793            width: fragment_size[0],
794            height: fragment_size[1],
795        };
796        let combiner_ops = [combiner_ops[0].into(), combiner_ops[1].into()];
797        unsafe {
798            (fns.khr_fragment_shading_rate
799                .cmd_set_fragment_shading_rate_khr)(
800                self.handle(), &fragment_size, &combiner_ops
801            )
802        }
803
804        self
805    }
806}