Skip to main content

vk_graph/cmd/
graphics.rs

1use {
2    super::{AttachmentIndex, cmd_ref::CommandRef, pipeline::PipelineCommand},
3    crate::{
4        Attachment, ColorAttachment, ColorResolve, DepthStencilAttachment, DepthStencilResolve,
5        LoadOp, Node, StoreOp, SubresourceAccess,
6        cmd::SubresourceRange,
7        driver::{
8            graphics::{DepthStencilInfo, GraphicsPipeline},
9            image::{
10                ImageInfo, ImageViewInfo, image_subresource_range_contains,
11                image_subresource_range_intersects,
12            },
13            render_pass::ResolveMode,
14        },
15        node::{AnyBufferNode, AnyImageNode},
16    },
17    ash::vk,
18    std::{cell::RefCell, ops::Deref, slice},
19    vk_sync::AccessType,
20};
21
22impl PipelineCommand<'_, GraphicsPipeline> {
23    /// Sets the `color_attachment` attachment index of the following render pass to the given
24    /// `image`.
25    ///
26    /// Note: To use multi-sampled (MSAA) rendering, use an image created with a sample count
27    /// greater than one.
28    ///
29    /// Note: The default view (the whole image) is used for `image`.
30    ///
31    /// See [_Render Pass_](https://docs.vulkan.org/spec/latest/chapters/renderpass.html).
32    pub fn color_attachment_image(
33        mut self,
34        color_attachment: AttachmentIndex,
35        image: impl Into<AnyImageNode>,
36        load: LoadOp<ClearColorValue>,
37        store: StoreOp,
38    ) -> Self {
39        self.set_color_attachment_image(color_attachment, image, load, store);
40        self
41    }
42
43    /// Sets the `color_attachment` attachment index of the following render pass to the given
44    /// `image`, as interpreted by `image_view_info`.
45    ///
46    /// See [_Render Pass_](https://docs.vulkan.org/spec/latest/chapters/renderpass.html).
47    pub fn color_attachment_image_view(
48        mut self,
49        color_attachment: AttachmentIndex,
50        image: impl Into<AnyImageNode>,
51        image_view_info: impl Into<ImageViewInfo>,
52        load: LoadOp<ClearColorValue>,
53        store: StoreOp,
54    ) -> Self {
55        self.set_color_attachment_image_view(color_attachment, image, image_view_info, load, store);
56        self
57    }
58
59    /// Resolves a multi-sampled (MSAA) color image attachment into a single-sampled attachment
60    /// using the given `image`.
61    ///
62    /// Note: The default view (the whole image) is used for `image`.
63    ///
64    /// See [_Render Pass_](https://docs.vulkan.org/spec/latest/chapters/renderpass.html).
65    pub fn color_attachment_resolve_image(
66        mut self,
67        msaa_attachment: AttachmentIndex,
68        color_attachment: AttachmentIndex,
69        image: impl Into<AnyImageNode>,
70    ) -> Self {
71        self.set_color_attachment_resolve_image(msaa_attachment, color_attachment, image);
72        self
73    }
74
75    /// Resolves a multi-sampled (MSAA) color image attachment into a single-sampled attachment
76    /// using the given `image`, as interpreted by `image_view_info`.
77    ///
78    /// See [_Render Pass_](https://docs.vulkan.org/spec/latest/chapters/renderpass.html).
79    pub fn color_attachment_resolve_image_view(
80        mut self,
81        msaa_attachment: AttachmentIndex,
82        color_attachment: AttachmentIndex,
83        image: impl Into<AnyImageNode>,
84        image_view_info: impl Into<ImageViewInfo>,
85    ) -> Self {
86        self.set_color_attachment_resolve_image_view(
87            msaa_attachment,
88            color_attachment,
89            image,
90            image_view_info,
91        );
92        self
93    }
94
95    /// Sets the combined depth and stencil state used by any subsequent command buffer recordings
96    /// of the current graph command.
97    pub fn depth_stencil(mut self, depth_stencil: impl Into<DepthStencilInfo>) -> Self {
98        self.set_depth_stencil(depth_stencil);
99        self
100    }
101
102    /// Sets the combined depth and stencil attachment of the following render pass to the given
103    /// `image`.
104    ///
105    /// Note: To use multi-sampled (MSAA) rendering, use an image created with a sample count
106    /// greater than one.
107    ///
108    /// Note: The default view (the whole image) is used for `image`.
109    ///
110    /// See [_Render Pass_](https://docs.vulkan.org/spec/latest/chapters/renderpass.html).
111    pub fn depth_stencil_attachment_image(
112        mut self,
113        image: impl Into<AnyImageNode>,
114        load: LoadOp<vk::ClearDepthStencilValue>,
115        store: StoreOp,
116    ) -> Self {
117        self.set_depth_stencil_attachment_image(image, load, store);
118        self
119    }
120
121    /// Sets the combined depth and stencil attachment of the following render pass to the given
122    /// `image`, as interpreted by `image_view_info`.
123    ///
124    /// Note: To use multi-sampled (MSAA) rendering, use an image created with a sample count
125    /// greater than one.
126    ///
127    /// Note: The default view (the whole image) is used for `image`.
128    ///
129    /// See [_Render Pass_](https://docs.vulkan.org/spec/latest/chapters/renderpass.html).
130    pub fn depth_stencil_attachment_image_view(
131        mut self,
132        image: impl Into<AnyImageNode>,
133        image_view_info: impl Into<ImageViewInfo>,
134        load: LoadOp<vk::ClearDepthStencilValue>,
135        store: StoreOp,
136    ) -> Self {
137        self.set_depth_stencil_attachment_image_view(image, image_view_info, load, store);
138        self
139    }
140
141    /// Resolves a multi-sampled (MSAA) combined depth and stencil image attachment into a
142    /// single-sampled attachment using the given `image`.
143    ///
144    /// Note: The default view (the whole image) is used for `image`.
145    ///
146    /// See [_Render Pass_](https://docs.vulkan.org/spec/latest/chapters/renderpass.html).
147    pub fn depth_stencil_attachment_resolve_image(
148        mut self,
149        depth_stencil_attachment: AttachmentIndex,
150        image: impl Into<AnyImageNode>,
151        depth_mode: Option<ResolveMode>,
152        stencil_mode: Option<ResolveMode>,
153    ) -> Self {
154        self.set_depth_stencil_attachment_resolve_image(
155            depth_stencil_attachment,
156            image,
157            depth_mode,
158            stencil_mode,
159        );
160        self
161    }
162
163    /// Resolves a multi-sampled (MSAA) combined depth and stencil image attachment into a
164    /// single-sampled attachment using the given `image`, as interpreted by `image_view_info`.
165    ///
166    /// Note: The default view (the whole image) is used for `image`.
167    ///
168    /// See [_Render Pass_](https://docs.vulkan.org/spec/latest/chapters/renderpass.html).
169    pub fn depth_stencil_attachment_resolve_image_view(
170        mut self,
171        depth_stencil_attachment: AttachmentIndex,
172        image: impl Into<AnyImageNode>,
173        image_view_info: impl Into<ImageViewInfo>,
174        depth_mode: Option<ResolveMode>,
175        stencil_mode: Option<ResolveMode>,
176    ) -> Self {
177        self.set_depth_stencil_attachment_resolve_image_view(
178            depth_stencil_attachment,
179            image,
180            image_view_info,
181            depth_mode,
182            stencil_mode,
183        );
184        self
185    }
186
187    /// Sets multiview view and correlation masks used by any subsequent command buffer recordings
188    /// of the current graph command.
189    ///
190    /// See [`VkRenderPassMultiviewCreateInfo`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkRenderPassMultiviewCreateInfo.html).
191    pub fn multiview(mut self, view_mask: u32, correlated_view_mask: u32) -> Self {
192        self.set_multiview(view_mask, correlated_view_mask);
193        self
194    }
195
196    /// Begin recording graphics pipeline work for this graph command.
197    pub fn record_cmd(
198        mut self,
199        func: impl FnOnce(GraphicsCommandRef<'_>) + Send + 'static,
200    ) -> Self {
201        self.record_cmd_mut(func);
202        self
203    }
204
205    /// Mutable-borrow form of [`Self::record_cmd`].
206    pub fn record_cmd_mut(&mut self, func: impl FnOnce(GraphicsCommandRef<'_>) + Send + 'static) {
207        let pipeline = self
208            .cmd
209            .cmd()
210            .expect_last_pipeline()
211            .expect_graphics()
212            .clone();
213
214        self.cmd.push_exec(move |cmd| {
215            func(GraphicsCommandRef { cmd, pipeline });
216        });
217    }
218
219    pub(crate) fn record_stream_mut(
220        &mut self,
221        func: impl for<'r> Fn(GraphicsCommandRef<'r>) + Send + Sync + 'static,
222    ) {
223        let pipeline = self
224            .cmd
225            .cmd()
226            .expect_last_pipeline()
227            .expect_graphics()
228            .clone();
229
230        self.cmd.push_reusable_exec(move |cmd| {
231            func(GraphicsCommandRef {
232                cmd,
233                pipeline: pipeline.clone(),
234            });
235        });
236    }
237
238    /// Sets the render area used when beginning the render pass for subsequent command buffer
239    /// recordings of the current graph command.
240    ///
241    /// See [`VkRenderPassBeginInfo`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkRenderPassBeginInfo.html).
242    ///
243    /// _NOTE:_ Setting this value will cause the viewport and scissor to be unset, which is not the
244    /// default behavior. When this value is set you should call `set_viewport` and `set_scissor` on
245    /// the command buffer.
246    ///
247    /// If not set, this value defaults to the first loaded, resolved, or stored attachment
248    /// dimensions and sets the viewport and scissor to the same values, with a `0..1` depth if not
249    /// specified by `depth_stencil`.
250    pub fn render_area(mut self, area: vk::Rect2D) -> Self {
251        self.set_render_area(area);
252        self
253    }
254
255    /// Mutable-borrow form of [`Self::color_attachment_image`].
256    pub fn set_color_attachment_image(
257        &mut self,
258        color_attachment: AttachmentIndex,
259        image: impl Into<AnyImageNode>,
260        load: LoadOp<ClearColorValue>,
261        store: StoreOp,
262    ) -> &mut Self {
263        let image = image.into();
264        let image_view: ImageViewInfo = self.cmd.graph.resources[image.index()]
265            .expect_image_info()
266            .into();
267
268        self.set_color_attachment_image_view(color_attachment, image, image_view, load, store);
269
270        self
271    }
272
273    /// Mutable-borrow form of [`Self::color_attachment_image_view`].
274    pub fn set_color_attachment_image_view(
275        &mut self,
276        color_attachment: AttachmentIndex,
277        image: impl Into<AnyImageNode>,
278        image_view_info: impl Into<ImageViewInfo>,
279        load: LoadOp<ClearColorValue>,
280        store: StoreOp,
281    ) -> &mut Self {
282        let image = image.into();
283        let image_view_info = image_view_info.into();
284
285        match load {
286            LoadOp::Clear(color) => {
287                self.clear_color_value(color_attachment, image, color, image_view_info);
288            }
289            LoadOp::DontCare => {
290                self.attach_color(image, color_attachment, image_view_info);
291            }
292            LoadOp::Load => {
293                self.load_color(image, color_attachment, image_view_info);
294            }
295        }
296
297        if let StoreOp::Store = store {
298            self.store_color(image, color_attachment, image_view_info);
299        }
300
301        self
302    }
303
304    /// Mutable-borrow form of [`Self::color_attachment_resolve_image`].
305    pub fn set_color_attachment_resolve_image(
306        &mut self,
307        msaa_attachment: AttachmentIndex,
308        color_attachment: AttachmentIndex,
309        image: impl Into<AnyImageNode>,
310    ) -> &mut Self {
311        let image = image.into();
312        let image_view: ImageViewInfo = self.cmd.graph.resources[image.index()]
313            .expect_image_info()
314            .into();
315
316        self.set_color_attachment_resolve_image_view(
317            msaa_attachment,
318            color_attachment,
319            image,
320            image_view,
321        );
322
323        self
324    }
325
326    /// Mutable-borrow form of [`Self::color_attachment_resolve_image_view`].
327    pub fn set_color_attachment_resolve_image_view(
328        &mut self,
329        msaa_attachment: AttachmentIndex,
330        color_attachment: AttachmentIndex,
331        image: impl Into<AnyImageNode>,
332        image_view_info: impl Into<ImageViewInfo>,
333    ) -> &mut Self {
334        let image = image.into();
335        let image_view_info = image_view_info.into();
336
337        self.resolve_color(image, msaa_attachment, color_attachment, image_view_info);
338
339        self
340    }
341
342    /// Mutable-borrow form of [`Self::depth_stencil`].
343    pub fn set_depth_stencil(&mut self, depth_stencil: impl Into<DepthStencilInfo>) -> &mut Self {
344        let depth_stencil = depth_stencil.into();
345        let cmd = self.cmd.cmd_mut();
346        let exec = cmd.expect_last_exec_mut();
347
348        assert!(exec.depth_stencil.is_none());
349
350        exec.depth_stencil = Some(depth_stencil);
351
352        self
353    }
354
355    /// Mutable-borrow form of [`Self::depth_stencil_attachment_image`].
356    pub fn set_depth_stencil_attachment_image(
357        &mut self,
358        image: impl Into<AnyImageNode>,
359        load: LoadOp<vk::ClearDepthStencilValue>,
360        store: StoreOp,
361    ) -> &mut Self {
362        let image = image.into();
363        let image_view_info: ImageViewInfo = self.cmd.graph.resources[image.index()]
364            .expect_image_info()
365            .into();
366
367        self.set_depth_stencil_attachment_image_view(image, image_view_info, load, store);
368
369        self
370    }
371
372    /// Mutable-borrow form of [`Self::depth_stencil_attachment_image_view`].
373    pub fn set_depth_stencil_attachment_image_view(
374        &mut self,
375        image: impl Into<AnyImageNode>,
376        image_view_info: impl Into<ImageViewInfo>,
377        load: LoadOp<vk::ClearDepthStencilValue>,
378        store: StoreOp,
379    ) -> &mut Self {
380        let image = image.into();
381        let image_view_info = image_view_info.into();
382
383        match load {
384            LoadOp::Clear(color) => {
385                self.clear_depth_stencil_value(image, color.depth, color.stencil, image_view_info);
386            }
387            LoadOp::DontCare => {
388                self.attach_depth_stencil(image, image_view_info);
389            }
390            LoadOp::Load => {
391                self.load_depth_stencil(image, image_view_info);
392            }
393        }
394
395        if let StoreOp::Store = store {
396            self.store_depth_stencil(image, image_view_info);
397        }
398
399        self
400    }
401
402    /// Mutable-borrow form of [`Self::depth_stencil_attachment_resolve_image`].
403    pub fn set_depth_stencil_attachment_resolve_image(
404        &mut self,
405        depth_stencil_attachment: AttachmentIndex,
406        image: impl Into<AnyImageNode>,
407        depth_mode: Option<ResolveMode>,
408        stencil_mode: Option<ResolveMode>,
409    ) -> &mut Self {
410        let image = image.into();
411        let image_view: ImageViewInfo = self.cmd.graph.resources[image.index()]
412            .expect_image_info()
413            .into();
414
415        self.set_depth_stencil_attachment_resolve_image_view(
416            depth_stencil_attachment,
417            image,
418            image_view,
419            depth_mode,
420            stencil_mode,
421        );
422
423        self
424    }
425
426    /// Mutable-borrow form of [`Self::depth_stencil_attachment_resolve_image_view`].
427    pub fn set_depth_stencil_attachment_resolve_image_view(
428        &mut self,
429        depth_stencil_attachment: AttachmentIndex,
430        image: impl Into<AnyImageNode>,
431        image_view_info: impl Into<ImageViewInfo>,
432        depth_mode: Option<ResolveMode>,
433        stencil_mode: Option<ResolveMode>,
434    ) -> &mut Self {
435        let image = image.into();
436        let image_view_info = image_view_info.into();
437
438        self.resolve_depth_stencil(
439            image,
440            depth_stencil_attachment,
441            image_view_info,
442            depth_mode,
443            stencil_mode,
444        );
445
446        self
447    }
448
449    /// Mutable-borrow form of [`Self::multiview`].
450    pub fn set_multiview(&mut self, view_mask: u32, correlated_view_mask: u32) -> &mut Self {
451        let cmd = self.cmd.cmd_mut();
452        let exec = cmd.expect_last_exec_mut();
453
454        exec.correlated_view_mask = correlated_view_mask;
455        exec.view_mask = view_mask;
456
457        self
458    }
459
460    /// Mutable-borrow form of [`Self::render_area`].
461    pub fn set_render_area(&mut self, area: vk::Rect2D) -> &mut Self {
462        self.cmd.cmd_mut().expect_last_exec_mut().render_area = Some(area);
463        self
464    }
465}
466
467impl PipelineCommand<'_, GraphicsPipeline> {
468    fn is_input_attachment(&self, attachment_idx: AttachmentIndex) -> bool {
469        self.cmd
470            .cmd()
471            .expect_last_pipeline()
472            .expect_graphics()
473            .inner
474            .input_attachments
475            .contains(&attachment_idx)
476    }
477
478    fn set_color_attachment(
479        &mut self,
480        attachment_idx: AttachmentIndex,
481        attachment: Attachment,
482        load: LoadOp<[f32; 4]>,
483    ) {
484        let is_input = self.is_input_attachment(attachment_idx);
485        let exec = self.cmd.cmd_mut().expect_last_exec_mut();
486
487        if let Some(state) = exec.attachments.color_attachment_mut(attachment_idx) {
488            #[cfg(feature = "checked")]
489            assert!(
490                Attachment::are_compatible(Some(attachment), Some(state.attachment)),
491                "incompatible with existing attachment"
492            );
493
494            state.attachment = attachment;
495            state.load = load;
496            state.is_input = is_input;
497            state.is_attachment = true;
498        } else {
499            exec.attachments.set_color_attachment(
500                attachment_idx,
501                ColorAttachment {
502                    attachment,
503                    load,
504                    store: StoreOp::DontCare,
505                    resolve: None,
506                    is_input,
507                    is_attachment: true,
508                },
509            );
510        }
511    }
512
513    fn set_depth_stencil_attachment(
514        &mut self,
515        attachment: Attachment,
516        load: LoadOp<vk::ClearDepthStencilValue>,
517    ) {
518        let exec = self.cmd.cmd_mut().expect_last_exec_mut();
519
520        if let Some(state) = exec.attachments.depth_stencil_attachment_mut() {
521            #[cfg(feature = "checked")]
522            assert!(
523                Attachment::are_compatible(Some(attachment), Some(state.attachment)),
524                "incompatible with existing attachment"
525            );
526
527            state.attachment = attachment;
528            state.load = load;
529            state.is_attachment = true;
530        } else {
531            exec.attachments
532                .set_depth_stencil_attachment(DepthStencilAttachment {
533                    attachment,
534                    load,
535                    store: StoreOp::DontCare,
536                    resolve: None,
537                    is_attachment: true,
538                });
539        }
540    }
541
542    fn set_color_store(&mut self, attachment_idx: AttachmentIndex, attachment: Attachment) {
543        let is_input = self.is_input_attachment(attachment_idx);
544        let exec = self.cmd.cmd_mut().expect_last_exec_mut();
545
546        if let Some(state) = exec.attachments.color_attachment_mut(attachment_idx) {
547            #[cfg(feature = "checked")]
548            assert!(
549                Attachment::are_compatible(Some(attachment), Some(state.attachment)),
550                "incompatible with existing attachment"
551            );
552
553            state.attachment = attachment;
554            state.store = StoreOp::Store;
555            state.is_attachment = true;
556            state.is_input = is_input;
557        } else {
558            exec.attachments.set_color_attachment(
559                attachment_idx,
560                ColorAttachment {
561                    attachment,
562                    load: LoadOp::DontCare,
563                    store: StoreOp::Store,
564                    resolve: None,
565                    is_input,
566                    is_attachment: true,
567                },
568            );
569        }
570    }
571
572    fn set_depth_stencil_store(&mut self, attachment: Attachment) {
573        let exec = self.cmd.cmd_mut().expect_last_exec_mut();
574
575        if let Some(state) = exec.attachments.depth_stencil_attachment_mut() {
576            #[cfg(feature = "checked")]
577            assert!(
578                Attachment::are_compatible(Some(attachment), Some(state.attachment)),
579                "incompatible with existing attachment"
580            );
581
582            state.attachment = attachment;
583            state.store = StoreOp::Store;
584            state.is_attachment = true;
585        } else {
586            exec.attachments
587                .set_depth_stencil_attachment(DepthStencilAttachment {
588                    attachment,
589                    load: LoadOp::DontCare,
590                    store: StoreOp::Store,
591                    resolve: None,
592                    is_attachment: true,
593                });
594        }
595    }
596
597    fn set_color_resolve(
598        &mut self,
599        src_attachment_idx: AttachmentIndex,
600        dst_attachment_idx: AttachmentIndex,
601        attachment: Attachment,
602    ) {
603        let is_input = self.is_input_attachment(dst_attachment_idx);
604        let exec = self.cmd.cmd_mut().expect_last_exec_mut();
605
606        if let Some(state) = exec.attachments.color_attachment_mut(dst_attachment_idx) {
607            state.resolve = Some(ColorResolve {
608                attachment,
609                src_attachment_idx,
610            });
611            state.is_input = is_input;
612        } else {
613            exec.attachments.set_color_attachment(
614                dst_attachment_idx,
615                ColorAttachment {
616                    attachment,
617                    load: LoadOp::DontCare,
618                    store: StoreOp::DontCare,
619                    resolve: Some(ColorResolve {
620                        attachment,
621                        src_attachment_idx,
622                    }),
623                    is_input,
624                    is_attachment: false,
625                },
626            );
627        }
628    }
629
630    fn set_depth_stencil_resolve(
631        &mut self,
632        dst_attachment_idx: AttachmentIndex,
633        attachment: Attachment,
634        depth_mode: Option<ResolveMode>,
635        stencil_mode: Option<ResolveMode>,
636    ) {
637        let exec = self.cmd.cmd_mut().expect_last_exec_mut();
638
639        if let Some(state) = exec.attachments.depth_stencil_attachment_mut() {
640            state.resolve = Some(DepthStencilResolve {
641                attachment,
642                dst_attachment_idx,
643                depth_mode,
644                stencil_mode,
645            });
646        } else {
647            exec.attachments
648                .set_depth_stencil_attachment(DepthStencilAttachment {
649                    attachment,
650                    load: LoadOp::DontCare,
651                    store: StoreOp::DontCare,
652                    resolve: Some(DepthStencilResolve {
653                        attachment,
654                        dst_attachment_idx,
655                        depth_mode,
656                        stencil_mode,
657                    }),
658                    is_attachment: false,
659                });
660        }
661    }
662
663    fn attach_color(
664        &mut self,
665        image: impl Into<AnyImageNode>,
666        attachment_idx: AttachmentIndex,
667        image_view_info: impl Into<ImageViewInfo>,
668    ) -> &mut Self {
669        let image = image.into();
670        let image_view_info = image_view_info.into();
671        let node_idx = image.index();
672        let ImageInfo { sample_count, .. } =
673            self.cmd.graph.resources[image.index()].expect_image_info();
674
675        self.set_color_attachment(
676            attachment_idx,
677            Attachment::new(image_view_info, sample_count, node_idx),
678            LoadOp::DontCare,
679        );
680
681        self.cmd.push_subresource_access(
682            image,
683            SubresourceRange::Image(image_view_info.into()),
684            AccessType::ColorAttachmentWrite,
685        );
686
687        self
688    }
689
690    fn attach_depth_stencil(
691        &mut self,
692        image: impl Into<AnyImageNode>,
693        image_view_info: impl Into<ImageViewInfo>,
694    ) -> &mut Self {
695        let image = image.into();
696        let image_view_info = image_view_info.into();
697        let node_idx = image.index();
698        let ImageInfo { sample_count, .. } =
699            self.cmd.graph.resources[image.index()].expect_image_info();
700
701        self.set_depth_stencil_attachment(
702            Attachment::new(image_view_info, sample_count, node_idx),
703            LoadOp::DontCare,
704        );
705
706        self.cmd.push_subresource_access(
707            image,
708            SubresourceRange::Image(image_view_info.into()),
709            if image_view_info
710                .aspect_mask
711                .contains(vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL)
712            {
713                AccessType::DepthStencilAttachmentWrite
714            } else if image_view_info
715                .aspect_mask
716                .contains(vk::ImageAspectFlags::DEPTH)
717            {
718                AccessType::DepthAttachmentWriteStencilReadOnly
719            } else {
720                AccessType::StencilAttachmentWriteDepthReadOnly
721            },
722        );
723
724        self
725    }
726
727    fn clear_color_value(
728        &mut self,
729        attachment_idx: AttachmentIndex,
730        image: impl Into<AnyImageNode>,
731        color: impl Into<ClearColorValue>,
732        image_view_info: impl Into<ImageViewInfo>,
733    ) -> &mut Self {
734        let image = image.into();
735        let image_view_info = image_view_info.into();
736        let node_idx = image.index();
737        let ImageInfo { sample_count, .. } =
738            self.cmd.graph.resources[image.index()].expect_image_info();
739
740        let color = color.into();
741        let color: vk::ClearColorValue = color.into();
742        let color = unsafe { color.float32 };
743
744        self.set_color_attachment(
745            attachment_idx,
746            Attachment::new(image_view_info, sample_count, node_idx),
747            LoadOp::Clear(color),
748        );
749
750        let mut image_access = AccessType::ColorAttachmentWrite;
751        let image_range = image_view_info.into();
752
753        if let Some(accesses) = self
754            .cmd
755            .cmd_mut()
756            .expect_last_exec_mut()
757            .accesses
758            .get_mut(&node_idx)
759        {
760            for SubresourceAccess {
761                access,
762                subresource,
763            } in accesses
764            {
765                let access_image_range = *subresource.expect_image();
766                if !image_subresource_range_intersects(access_image_range, image_range) {
767                    continue;
768                }
769
770                image_access = match *access {
771                    AccessType::ColorAttachmentRead | AccessType::ColorAttachmentReadWrite => {
772                        AccessType::ColorAttachmentReadWrite
773                    }
774                    AccessType::ColorAttachmentWrite => AccessType::ColorAttachmentWrite,
775                    _ => continue,
776                };
777
778                *access = image_access;
779
780                if image_subresource_range_contains(access_image_range, image_range) {
781                    return self;
782                }
783            }
784        }
785
786        self.cmd
787            .push_subresource_access(image, SubresourceRange::Image(image_range), image_access);
788
789        self
790    }
791
792    fn clear_depth_stencil_value(
793        &mut self,
794        image: impl Into<AnyImageNode>,
795        depth: f32,
796        stencil: u32,
797        image_view_info: impl Into<ImageViewInfo>,
798    ) -> &mut Self {
799        let image = image.into();
800        let image_view_info = image_view_info.into();
801        let node_idx = image.index();
802        let ImageInfo { sample_count, .. } =
803            self.cmd.graph.resources[image.index()].expect_image_info();
804
805        self.set_depth_stencil_attachment(
806            Attachment::new(image_view_info, sample_count, node_idx),
807            LoadOp::Clear(vk::ClearDepthStencilValue { depth, stencil }),
808        );
809
810        let mut image_access = if image_view_info
811            .aspect_mask
812            .contains(vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL)
813        {
814            AccessType::DepthStencilAttachmentWrite
815        } else if image_view_info
816            .aspect_mask
817            .contains(vk::ImageAspectFlags::DEPTH)
818        {
819            AccessType::DepthAttachmentWriteStencilReadOnly
820        } else {
821            debug_assert!(
822                image_view_info
823                    .aspect_mask
824                    .contains(vk::ImageAspectFlags::STENCIL)
825            );
826
827            AccessType::StencilAttachmentWriteDepthReadOnly
828        };
829        let image_range = image_view_info.into();
830
831        if let Some(accesses) = self
832            .cmd
833            .cmd_mut()
834            .expect_last_exec_mut()
835            .accesses
836            .get_mut(&node_idx)
837        {
838            for SubresourceAccess {
839                access,
840                subresource,
841            } in accesses
842            {
843                let access_image_range = *subresource.expect_image();
844                if !image_subresource_range_intersects(access_image_range, image_range) {
845                    continue;
846                }
847
848                image_access = match *access {
849                    AccessType::DepthAttachmentWriteStencilReadOnly => {
850                        if image_view_info
851                            .aspect_mask
852                            .contains(vk::ImageAspectFlags::STENCIL)
853                        {
854                            AccessType::DepthStencilAttachmentReadWrite
855                        } else {
856                            AccessType::DepthAttachmentWriteStencilReadOnly
857                        }
858                    }
859                    AccessType::DepthStencilAttachmentRead => {
860                        if !image_view_info
861                            .aspect_mask
862                            .contains(vk::ImageAspectFlags::DEPTH)
863                        {
864                            AccessType::StencilAttachmentWriteDepthReadOnly
865                        } else {
866                            AccessType::DepthStencilAttachmentReadWrite
867                        }
868                    }
869                    AccessType::DepthStencilAttachmentWrite => {
870                        AccessType::DepthStencilAttachmentWrite
871                    }
872                    AccessType::StencilAttachmentWriteDepthReadOnly => {
873                        if image_view_info
874                            .aspect_mask
875                            .contains(vk::ImageAspectFlags::DEPTH)
876                        {
877                            AccessType::DepthStencilAttachmentReadWrite
878                        } else {
879                            AccessType::StencilAttachmentWriteDepthReadOnly
880                        }
881                    }
882                    _ => continue,
883                };
884
885                *access = image_access;
886
887                if image_subresource_range_contains(access_image_range, image_range) {
888                    return self;
889                }
890            }
891        }
892
893        self.cmd
894            .push_subresource_access(image, SubresourceRange::Image(image_range), image_access);
895
896        self
897    }
898
899    fn load_color(
900        &mut self,
901        image: impl Into<AnyImageNode>,
902        attachment_idx: AttachmentIndex,
903        image_view_info: impl Into<ImageViewInfo>,
904    ) -> &mut Self {
905        let image = image.into();
906        let image_view_info = image_view_info.into();
907        let node_idx = image.index();
908        let ImageInfo { sample_count, .. } =
909            self.cmd.graph.resources[image.index()].expect_image_info();
910
911        self.set_color_attachment(
912            attachment_idx,
913            Attachment::new(image_view_info, sample_count, node_idx),
914            LoadOp::Load,
915        );
916
917        let mut image_access = AccessType::ColorAttachmentRead;
918        let image_range = image_view_info.into();
919
920        if let Some(accesses) = self
921            .cmd
922            .cmd_mut()
923            .expect_last_exec_mut()
924            .accesses
925            .get_mut(&node_idx)
926        {
927            for SubresourceAccess {
928                access,
929                subresource,
930            } in accesses
931            {
932                let access_image_range = *subresource.expect_image();
933                if !image_subresource_range_intersects(access_image_range, image_range) {
934                    continue;
935                }
936
937                image_access = match *access {
938                    AccessType::ColorAttachmentRead => AccessType::ColorAttachmentRead,
939                    AccessType::ColorAttachmentReadWrite | AccessType::ColorAttachmentWrite => {
940                        AccessType::ColorAttachmentReadWrite
941                    }
942                    _ => continue,
943                };
944
945                *access = image_access;
946
947                if image_subresource_range_contains(access_image_range, image_range) {
948                    return self;
949                }
950            }
951        }
952
953        self.cmd
954            .push_subresource_access(image, SubresourceRange::Image(image_range), image_access);
955
956        self
957    }
958
959    fn load_depth_stencil(
960        &mut self,
961        image: impl Into<AnyImageNode>,
962        image_view_info: impl Into<ImageViewInfo>,
963    ) -> &mut Self {
964        let image = image.into();
965        let image_view_info = image_view_info.into();
966        let node_idx = image.index();
967        let ImageInfo { sample_count, .. } =
968            self.cmd.graph.resources[image.index()].expect_image_info();
969
970        self.set_depth_stencil_attachment(
971            Attachment::new(image_view_info, sample_count, node_idx),
972            LoadOp::Load,
973        );
974
975        let mut image_access = AccessType::DepthStencilAttachmentRead;
976        let image_range = image_view_info.into();
977
978        if let Some(accesses) = self
979            .cmd
980            .cmd_mut()
981            .expect_last_exec_mut()
982            .accesses
983            .get_mut(&node_idx)
984        {
985            for SubresourceAccess {
986                access,
987                subresource,
988            } in accesses
989            {
990                let access_image_range = *subresource.expect_image();
991                if !image_subresource_range_intersects(access_image_range, image_range) {
992                    continue;
993                }
994
995                image_access = match *access {
996                    AccessType::DepthAttachmentWriteStencilReadOnly => {
997                        AccessType::DepthAttachmentWriteStencilReadOnly
998                    }
999                    AccessType::DepthStencilAttachmentRead => {
1000                        AccessType::DepthStencilAttachmentRead
1001                    }
1002                    AccessType::DepthStencilAttachmentWrite => {
1003                        AccessType::DepthStencilAttachmentReadWrite
1004                    }
1005                    AccessType::StencilAttachmentWriteDepthReadOnly => {
1006                        AccessType::DepthStencilAttachmentReadWrite
1007                    }
1008                    _ => continue,
1009                };
1010
1011                *access = image_access;
1012
1013                if image_subresource_range_contains(access_image_range, image_range) {
1014                    return self;
1015                }
1016            }
1017        }
1018
1019        self.cmd
1020            .push_subresource_access(image, SubresourceRange::Image(image_range), image_access);
1021
1022        self
1023    }
1024
1025    fn store_color(
1026        &mut self,
1027        image: impl Into<AnyImageNode>,
1028        attachment_idx: AttachmentIndex,
1029        image_view_info: impl Into<ImageViewInfo>,
1030    ) -> &mut Self {
1031        let image = image.into();
1032        let image_view_info = image_view_info.into();
1033        let node_idx = image.index();
1034        let ImageInfo { sample_count, .. } =
1035            self.cmd.graph.resources[image.index()].expect_image_info();
1036
1037        self.set_color_store(
1038            attachment_idx,
1039            Attachment::new(image_view_info, sample_count, node_idx),
1040        );
1041
1042        let mut image_access = AccessType::ColorAttachmentWrite;
1043        let image_range = image_view_info.into();
1044
1045        if let Some(accesses) = self
1046            .cmd
1047            .cmd_mut()
1048            .expect_last_exec_mut()
1049            .accesses
1050            .get_mut(&node_idx)
1051        {
1052            for SubresourceAccess {
1053                access,
1054                subresource,
1055            } in accesses
1056            {
1057                let access_image_range = *subresource.expect_image();
1058                if !image_subresource_range_intersects(access_image_range, image_range) {
1059                    continue;
1060                }
1061
1062                image_access = match *access {
1063                    AccessType::ColorAttachmentRead | AccessType::ColorAttachmentReadWrite => {
1064                        AccessType::ColorAttachmentReadWrite
1065                    }
1066                    AccessType::ColorAttachmentWrite => AccessType::ColorAttachmentWrite,
1067                    _ => continue,
1068                };
1069
1070                *access = image_access;
1071
1072                if image_subresource_range_contains(access_image_range, image_range) {
1073                    return self;
1074                }
1075            }
1076        }
1077
1078        self.cmd
1079            .push_subresource_access(image, SubresourceRange::Image(image_range), image_access);
1080
1081        self
1082    }
1083
1084    fn store_depth_stencil(
1085        &mut self,
1086        image: impl Into<AnyImageNode>,
1087        image_view_info: impl Into<ImageViewInfo>,
1088    ) -> &mut Self {
1089        let image = image.into();
1090        let image_view_info = image_view_info.into();
1091        let node_idx = image.index();
1092        let ImageInfo { sample_count, .. } =
1093            self.cmd.graph.resources[image.index()].expect_image_info();
1094
1095        self.set_depth_stencil_store(Attachment::new(image_view_info, sample_count, node_idx));
1096
1097        let mut image_access = if image_view_info
1098            .aspect_mask
1099            .contains(vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL)
1100        {
1101            AccessType::DepthStencilAttachmentWrite
1102        } else if image_view_info
1103            .aspect_mask
1104            .contains(vk::ImageAspectFlags::DEPTH)
1105        {
1106            AccessType::DepthAttachmentWriteStencilReadOnly
1107        } else {
1108            debug_assert!(
1109                image_view_info
1110                    .aspect_mask
1111                    .contains(vk::ImageAspectFlags::STENCIL)
1112            );
1113
1114            AccessType::StencilAttachmentWriteDepthReadOnly
1115        };
1116        let image_range = image_view_info.into();
1117
1118        if let Some(accesses) = self
1119            .cmd
1120            .cmd_mut()
1121            .expect_last_exec_mut()
1122            .accesses
1123            .get_mut(&node_idx)
1124        {
1125            for SubresourceAccess {
1126                access,
1127                subresource,
1128            } in accesses
1129            {
1130                let access_image_range = *subresource.expect_image();
1131                if !image_subresource_range_intersects(access_image_range, image_range) {
1132                    continue;
1133                }
1134
1135                image_access = match *access {
1136                    AccessType::DepthAttachmentWriteStencilReadOnly => {
1137                        if image_view_info
1138                            .aspect_mask
1139                            .contains(vk::ImageAspectFlags::STENCIL)
1140                        {
1141                            AccessType::DepthStencilAttachmentReadWrite
1142                        } else {
1143                            AccessType::DepthAttachmentWriteStencilReadOnly
1144                        }
1145                    }
1146                    AccessType::DepthStencilAttachmentRead => {
1147                        if !image_view_info
1148                            .aspect_mask
1149                            .contains(vk::ImageAspectFlags::DEPTH)
1150                        {
1151                            AccessType::StencilAttachmentWriteDepthReadOnly
1152                        } else {
1153                            AccessType::DepthStencilAttachmentReadWrite
1154                        }
1155                    }
1156                    AccessType::DepthStencilAttachmentWrite => {
1157                        AccessType::DepthStencilAttachmentWrite
1158                    }
1159                    AccessType::StencilAttachmentWriteDepthReadOnly => {
1160                        if image_view_info
1161                            .aspect_mask
1162                            .contains(vk::ImageAspectFlags::DEPTH)
1163                        {
1164                            AccessType::DepthStencilAttachmentReadWrite
1165                        } else {
1166                            AccessType::StencilAttachmentWriteDepthReadOnly
1167                        }
1168                    }
1169                    _ => continue,
1170                };
1171
1172                *access = image_access;
1173
1174                if image_subresource_range_contains(access_image_range, image_range) {
1175                    return self;
1176                }
1177            }
1178        }
1179
1180        self.cmd
1181            .push_subresource_access(image, SubresourceRange::Image(image_range), image_access);
1182
1183        self
1184    }
1185
1186    fn resolve_color(
1187        &mut self,
1188        image: impl Into<AnyImageNode>,
1189        src_attachment_idx: AttachmentIndex,
1190        dst_attachment_idx: AttachmentIndex,
1191        image_view_info: impl Into<ImageViewInfo>,
1192    ) -> &mut Self {
1193        let image = image.into();
1194        let image_view_info = image_view_info.into();
1195        let node_idx = image.index();
1196        let ImageInfo { sample_count, .. } =
1197            self.cmd.graph.resources[image.index()].expect_image_info();
1198
1199        self.set_color_resolve(
1200            src_attachment_idx,
1201            dst_attachment_idx,
1202            Attachment::new(image_view_info, sample_count, node_idx),
1203        );
1204
1205        let mut image_access = AccessType::ColorAttachmentWrite;
1206        let image_range = image_view_info.into();
1207
1208        if let Some(accesses) = self
1209            .cmd
1210            .cmd_mut()
1211            .expect_last_exec_mut()
1212            .accesses
1213            .get_mut(&node_idx)
1214        {
1215            for SubresourceAccess {
1216                access,
1217                subresource,
1218            } in accesses
1219            {
1220                let access_image_range = *subresource.expect_image();
1221                if !image_subresource_range_intersects(access_image_range, image_range) {
1222                    continue;
1223                }
1224
1225                image_access = match *access {
1226                    AccessType::ColorAttachmentRead | AccessType::ColorAttachmentReadWrite => {
1227                        AccessType::ColorAttachmentReadWrite
1228                    }
1229                    AccessType::ColorAttachmentWrite => AccessType::ColorAttachmentWrite,
1230                    _ => continue,
1231                };
1232
1233                *access = image_access;
1234
1235                if image_subresource_range_contains(access_image_range, image_range) {
1236                    return self;
1237                }
1238            }
1239        }
1240
1241        self.cmd
1242            .push_subresource_access(image, SubresourceRange::Image(image_range), image_access);
1243
1244        self
1245    }
1246
1247    fn resolve_depth_stencil(
1248        &mut self,
1249        image: impl Into<AnyImageNode>,
1250        dst_attachment_idx: AttachmentIndex,
1251        image_view_info: impl Into<ImageViewInfo>,
1252        depth_mode: Option<ResolveMode>,
1253        stencil_mode: Option<ResolveMode>,
1254    ) -> &mut Self {
1255        let image = image.into();
1256        let image_view_info = image_view_info.into();
1257        let node_idx = image.index();
1258        let ImageInfo { sample_count, .. } =
1259            self.cmd.graph.resources[image.index()].expect_image_info();
1260
1261        self.set_depth_stencil_resolve(
1262            dst_attachment_idx,
1263            Attachment::new(image_view_info, sample_count, node_idx),
1264            depth_mode,
1265            stencil_mode,
1266        );
1267
1268        let mut image_access = if image_view_info
1269            .aspect_mask
1270            .contains(vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL)
1271        {
1272            AccessType::DepthStencilAttachmentWrite
1273        } else if image_view_info
1274            .aspect_mask
1275            .contains(vk::ImageAspectFlags::DEPTH)
1276        {
1277            AccessType::DepthAttachmentWriteStencilReadOnly
1278        } else {
1279            debug_assert!(
1280                image_view_info
1281                    .aspect_mask
1282                    .contains(vk::ImageAspectFlags::STENCIL)
1283            );
1284
1285            AccessType::StencilAttachmentWriteDepthReadOnly
1286        };
1287        let image_range = image_view_info.into();
1288
1289        if let Some(accesses) = self
1290            .cmd
1291            .cmd_mut()
1292            .expect_last_exec_mut()
1293            .accesses
1294            .get_mut(&node_idx)
1295        {
1296            for SubresourceAccess {
1297                access,
1298                subresource,
1299            } in accesses
1300            {
1301                let access_image_range = *subresource.expect_image();
1302                if !image_subresource_range_intersects(access_image_range, image_range) {
1303                    continue;
1304                }
1305
1306                image_access = match *access {
1307                    AccessType::DepthAttachmentWriteStencilReadOnly => {
1308                        if image_view_info
1309                            .aspect_mask
1310                            .contains(vk::ImageAspectFlags::STENCIL)
1311                        {
1312                            AccessType::DepthStencilAttachmentReadWrite
1313                        } else {
1314                            AccessType::DepthAttachmentWriteStencilReadOnly
1315                        }
1316                    }
1317                    AccessType::DepthStencilAttachmentRead => {
1318                        if !image_view_info
1319                            .aspect_mask
1320                            .contains(vk::ImageAspectFlags::DEPTH)
1321                        {
1322                            AccessType::StencilAttachmentWriteDepthReadOnly
1323                        } else {
1324                            AccessType::DepthStencilAttachmentReadWrite
1325                        }
1326                    }
1327                    AccessType::DepthStencilAttachmentWrite => {
1328                        AccessType::DepthStencilAttachmentWrite
1329                    }
1330                    AccessType::StencilAttachmentWriteDepthReadOnly => {
1331                        if image_view_info
1332                            .aspect_mask
1333                            .contains(vk::ImageAspectFlags::DEPTH)
1334                        {
1335                            AccessType::DepthStencilAttachmentReadWrite
1336                        } else {
1337                            AccessType::StencilAttachmentWriteDepthReadOnly
1338                        }
1339                    }
1340                    _ => continue,
1341                };
1342
1343                *access = image_access;
1344
1345                if image_subresource_range_contains(access_image_range, image_range) {
1346                    return self;
1347                }
1348            }
1349        }
1350
1351        self.cmd
1352            .push_subresource_access(image, SubresourceRange::Image(image_range), image_access);
1353
1354        self
1355    }
1356}
1357
1358/// Structure specifying a clear color value.
1359#[derive(Clone, Copy, Debug)]
1360pub enum ClearColorValue {
1361    /// Value as [f32].
1362    ///
1363    /// Use this member for color clear values when the format of the image or attachment is one of
1364    /// the numeric formats with a numeric type that is floating-point. Floating-point values are
1365    /// automatically converted to the format of the image, with the clear value being treated as
1366    /// linear if the image is sRGB.
1367    Float32([f32; 4]),
1368
1369    /// Value as [i32].
1370    ///
1371    /// Use this member for color clear values when the format of the image or attachment has a
1372    /// numeric type that is signed integer. Signed integer values are converted to the format of
1373    /// the image by casting to the smaller type (with negative 32-bit values mapping to negative
1374    /// values in the smaller type). If the integer clear value is not representable in the target
1375    /// type (e.g. would overflow in conversion to that type), the clear value is undefined.
1376    Int32([i32; 4]),
1377
1378    /// Value as [u32].
1379    ///
1380    /// Use this member for color clear values when the format of the image or attachment has a
1381    /// numeric type that is unsigned integer. Unsigned integer values are converted to the format
1382    /// of the image by casting to the integer type with fewer bits.
1383    Uint32([u32; 4]),
1384}
1385
1386impl ClearColorValue {
1387    /// RGB zeros and alpha ones.
1388    pub const BLACK_ALPHA_ONE: Self = Self::Float32([0.0, 0.0, 0.0, 1.0]);
1389
1390    /// All zeros.
1391    pub const BLACK_ALPHA_ZERO: Self = Self::Float32([0.0, 0.0, 0.0, 0.0]);
1392
1393    /// RGB ones and alpha ones.
1394    pub const WHITE_ALPHA_ONE: Self = Self::Float32([1.0, 1.0, 1.0, 1.0]);
1395
1396    /// RGB ones and alpha zeros.
1397    pub const WHITE_ALPHA_ZERO: Self = Self::Float32([1.0, 1.0, 1.0, 0.0]);
1398
1399    /// Convenience constructor for clear color values.
1400    pub const fn rgba(r: f32, g: f32, b: f32, a: f32) -> Self {
1401        Self::Float32([r, g, b, a])
1402    }
1403
1404    /// Convert RGB+A values into a ClearColorValue.
1405    pub const fn from_f32(r: f32, g: f32, b: f32, a: f32) -> Self {
1406        Self::rgba(r, g, b, a)
1407    }
1408
1409    /// Convert RGB+A values into a ClearColorValue.
1410    pub const fn from_u8(r: u8, g: u8, b: u8, a: u8) -> Self {
1411        Self::from_f32(
1412            r as f32 / u8::MAX as f32,
1413            g as f32 / u8::MAX as f32,
1414            b as f32 / u8::MAX as f32,
1415            a as f32 / u8::MAX as f32,
1416        )
1417    }
1418}
1419
1420impl Default for ClearColorValue {
1421    fn default() -> Self {
1422        Self::from_f32(0.0, 0.0, 0.0, 0.0)
1423    }
1424}
1425
1426impl From<[f32; 4]> for ClearColorValue {
1427    fn from(float32: [f32; 4]) -> Self {
1428        Self::Float32(float32)
1429    }
1430}
1431
1432impl From<[i32; 4]> for ClearColorValue {
1433    fn from(int32: [i32; 4]) -> Self {
1434        Self::Int32(int32)
1435    }
1436}
1437
1438impl From<[u8; 4]> for ClearColorValue {
1439    fn from(uint8: [u8; 4]) -> Self {
1440        Self::from_u8(uint8[0], uint8[1], uint8[2], uint8[3])
1441    }
1442}
1443
1444impl From<[u32; 4]> for ClearColorValue {
1445    fn from(uint32: [u32; 4]) -> Self {
1446        Self::Uint32(uint32)
1447    }
1448}
1449
1450impl From<ClearColorValue> for vk::ClearColorValue {
1451    fn from(value: ClearColorValue) -> Self {
1452        match value {
1453            ClearColorValue::Float32(float32) => Self { float32 },
1454            ClearColorValue::Int32(int32) => Self { int32 },
1455            ClearColorValue::Uint32(uint32) => Self { uint32 },
1456        }
1457    }
1458}
1459
1460/// Recording interface for drawing commands.
1461///
1462/// This structure provides a strongly-typed set of methods which allow raster graphics shader code
1463/// to be executed. An instance is provided to the closure argument of
1464/// [`PipelineCommand::record_cmd`] which may be accessed by binding a [`GraphicsPipeline`] to a
1465/// command.
1466///
1467/// # Examples
1468///
1469/// Basic usage:
1470///
1471/// ```no_run
1472/// # use ash::vk;
1473/// # use vk_graph::cmd::{LoadOp, StoreOp};
1474/// # use vk_graph::driver::DriverError;
1475/// # use vk_graph::driver::device::{Device, DeviceInfo};
1476/// # use vk_graph::driver::graphics::{GraphicsPipeline, GraphicsPipelineInfo};
1477/// # use vk_graph::driver::image::{Image, ImageInfo};
1478/// # use vk_graph::Graph;
1479/// # use vk_graph::driver::shader::Shader;
1480/// # fn main() -> Result<(), DriverError> {
1481/// # let device = Device::create(DeviceInfo::default())?;
1482/// # let my_frag_code = [0u8; 1];
1483/// # let my_vert_code = [0u8; 1];
1484/// # let vert = Shader::new_vertex(my_vert_code.as_slice());
1485/// # let frag = Shader::new_fragment(my_frag_code.as_slice());
1486/// # let info = GraphicsPipelineInfo::default();
1487/// # let my_graphic_pipeline = GraphicsPipeline::create(&device, info, [vert, frag])?;
1488/// # let mut my_graph = Graph::default();
1489/// # let info = ImageInfo::image_2d(
1490/// #     32,
1491/// #     32,
1492/// #     vk::Format::R8G8B8A8_UNORM,
1493/// #     vk::ImageUsageFlags::SAMPLED,
1494/// # );
1495/// # let swapchain_image = my_graph.bind_resource(Image::create(&device, info)?);
1496/// my_graph
1497///     .begin_cmd()
1498///     .debug_name("my draw command")
1499///     .bind_pipeline(&my_graphic_pipeline)
1500///     .color_attachment_image(0, swapchain_image, LoadOp::DontCare, StoreOp::Store)
1501///     .record_cmd(move |cmd| {
1502///         // During this closure we have access to the drawing functions!
1503///         cmd.draw(3, 1, 0, 0);
1504///     });
1505/// # Ok(()) }
1506/// ```
1507pub struct GraphicsCommandRef<'a> {
1508    cmd: CommandRef<'a>,
1509    pipeline: GraphicsPipeline,
1510}
1511
1512impl GraphicsCommandRef<'_> {
1513    /// Bind an index buffer to the current command.
1514    ///
1515    /// `offset` is the starting offset in bytes within `buffer` used in index buffer address
1516    /// calculations.
1517    ///
1518    /// # Examples
1519    ///
1520    /// Basic usage:
1521    ///
1522    /// ```no_run
1523    /// # use ash::vk;
1524    /// # use vk_graph::cmd::{LoadOp, StoreOp};
1525    /// # use vk_sync::AccessType;
1526    /// # use vk_graph::driver::DriverError;
1527    /// # use vk_graph::driver::device::{Device, DeviceInfo};
1528    /// # use vk_graph::driver::buffer::{Buffer, BufferInfo};
1529    /// # use vk_graph::driver::graphics::{GraphicsPipeline, GraphicsPipelineInfo};
1530    /// # use vk_graph::driver::image::{Image, ImageInfo};
1531    /// # use vk_graph::driver::shader::Shader;
1532    /// # use vk_graph::Graph;
1533    /// # fn main() -> Result<(), DriverError> {
1534    /// # let device = Device::create(DeviceInfo::default())?;
1535    /// # let my_frag_code = [0u8; 1];
1536    /// # let my_vert_code = [0u8; 1];
1537    /// # let vert = Shader::new_vertex(my_vert_code.as_slice());
1538    /// # let frag = Shader::new_fragment(my_frag_code.as_slice());
1539    /// # let info = GraphicsPipelineInfo::default();
1540    /// # let my_graphic_pipeline = GraphicsPipeline::create(&device, info, [vert, frag])?;
1541    /// # let mut my_graph = Graph::default();
1542    /// # let info = ImageInfo::image_2d(
1543    /// #     32,
1544    /// #     32,
1545    /// #     vk::Format::R8G8B8A8_UNORM,
1546    /// #     vk::ImageUsageFlags::SAMPLED,
1547    /// # );
1548    /// # let swapchain_image = my_graph.bind_resource(Image::create(&device, info)?);
1549    /// # let buf_info = BufferInfo::device_mem(8, vk::BufferUsageFlags::INDEX_BUFFER);
1550    /// # let my_idx_buf = Buffer::create(&device, buf_info)?;
1551    /// # let buf_info = BufferInfo::device_mem(8, vk::BufferUsageFlags::VERTEX_BUFFER);
1552    /// # let my_vtx_buf = Buffer::create(&device, buf_info)?;
1553    /// # let my_idx_buf = my_graph.bind_resource(my_idx_buf);
1554    /// # let my_vtx_buf = my_graph.bind_resource(my_vtx_buf);
1555    /// my_graph
1556    ///     .begin_cmd()
1557    ///     .debug_name("my indexed geometry draw command")
1558    ///     .bind_pipeline(&my_graphic_pipeline)
1559    ///     .color_attachment_image(0, swapchain_image, LoadOp::DontCare, StoreOp::Store)
1560    ///     .resource_access(my_idx_buf, AccessType::IndexBuffer)
1561    ///     .resource_access(my_vtx_buf, AccessType::VertexBuffer)
1562    ///     .record_cmd(move |cmd| {
1563    ///         cmd
1564    ///             .bind_index_buffer(my_idx_buf, 0, vk::IndexType::UINT16)
1565    ///             .bind_vertex_buffer(0, my_vtx_buf, 0)
1566    ///             .draw_indexed(42, 1, 0, 0, 0);
1567    ///     });
1568    /// # Ok(()) }
1569    /// ```
1570    #[profiling::function]
1571    pub fn bind_index_buffer(
1572        &self,
1573        buffer: impl Into<AnyBufferNode>,
1574        offset: vk::DeviceSize,
1575        index_ty: vk::IndexType,
1576    ) -> &Self {
1577        let buffer = buffer.into();
1578        let buffer = self.resource(buffer);
1579
1580        unsafe {
1581            self.cmd
1582                .device
1583                .cmd_bind_index_buffer(self.cmd.handle, buffer.handle, offset, index_ty);
1584        }
1585
1586        self
1587    }
1588
1589    /// Binds a vertex buffer for the current graphics command.
1590    ///
1591    /// The vertex input binding is updated to start at `offset` from the start of `buffer`.
1592    ///
1593    /// # Examples
1594    ///
1595    /// Basic usage:
1596    ///
1597    /// ```no_run
1598    /// # use ash::vk;
1599    /// # use vk_graph::cmd::{LoadOp, StoreOp};
1600    /// # use vk_sync::AccessType;
1601    /// # use vk_graph::driver::DriverError;
1602    /// # use vk_graph::driver::device::{Device, DeviceInfo};
1603    /// # use vk_graph::driver::buffer::{Buffer, BufferInfo};
1604    /// # use vk_graph::driver::graphics::{GraphicsPipeline, GraphicsPipelineInfo};
1605    /// # use vk_graph::driver::image::{Image, ImageInfo};
1606    /// # use vk_graph::driver::shader::Shader;
1607    /// # use vk_graph::Graph;
1608    /// # fn main() -> Result<(), DriverError> {
1609    /// # let device = Device::create(DeviceInfo::default())?;
1610    /// # let buf_info = BufferInfo::device_mem(8, vk::BufferUsageFlags::VERTEX_BUFFER);
1611    /// # let my_vtx_buf = Buffer::create(&device, buf_info)?;
1612    /// # let my_frag_code = [0u8; 1];
1613    /// # let my_vert_code = [0u8; 1];
1614    /// # let vert = Shader::new_vertex(my_vert_code.as_slice());
1615    /// # let frag = Shader::new_fragment(my_frag_code.as_slice());
1616    /// # let info = GraphicsPipelineInfo::default();
1617    /// # let my_graphic_pipeline = GraphicsPipeline::create(&device, info, [vert, frag])?;
1618    /// # let mut my_graph = Graph::default();
1619    /// # let info = ImageInfo::image_2d(
1620    /// #     32,
1621    /// #     32,
1622    /// #     vk::Format::R8G8B8A8_UNORM,
1623    /// #     vk::ImageUsageFlags::SAMPLED,
1624    /// # );
1625    /// # let swapchain_image = my_graph.bind_resource(Image::create(&device, info)?);
1626    /// # let my_vtx_buf = my_graph.bind_resource(my_vtx_buf);
1627    /// my_graph
1628    ///     .begin_cmd()
1629    ///     .debug_name("my unindexed geometry draw command")
1630    ///     .bind_pipeline(&my_graphic_pipeline)
1631    ///     .color_attachment_image(0, swapchain_image, LoadOp::DontCare, StoreOp::Store)
1632    ///     .resource_access(my_vtx_buf, AccessType::VertexBuffer)
1633    ///     .record_cmd(move |cmd| {
1634    ///         cmd
1635    ///             .bind_vertex_buffer(0, my_vtx_buf, 0)
1636    ///             .draw(42, 1, 0, 0);
1637    ///     });
1638    /// # Ok(()) }
1639    /// ```
1640    #[profiling::function]
1641    pub fn bind_vertex_buffer(
1642        &self,
1643        binding: u32,
1644        buffer: impl Into<AnyBufferNode>,
1645        offset: vk::DeviceSize,
1646    ) -> &Self {
1647        let buffer = buffer.into();
1648        let buffer = self.resource(buffer);
1649
1650        unsafe {
1651            self.cmd.device.cmd_bind_vertex_buffers(
1652                self.cmd.handle,
1653                binding,
1654                slice::from_ref(&buffer.handle),
1655                slice::from_ref(&offset),
1656            );
1657        }
1658
1659        self
1660    }
1661
1662    /// Binds multiple vertex buffers for the current graphics command, starting at the given
1663    /// `first_binding`.
1664    ///
1665    /// Each vertex input binding in `buffers` specifies an offset from the start of the
1666    /// corresponding buffer.
1667    ///
1668    /// The vertex input attributes that use each of these bindings will use these updated addresses
1669    /// in their address calculations for subsequent drawing commands.
1670    #[profiling::function]
1671    pub fn bind_vertex_buffers<N>(
1672        &self,
1673        first_binding: u32,
1674        buffer_offsets: impl IntoIterator<Item = (N, vk::DeviceSize)>,
1675    ) -> &Self
1676    where
1677        N: Into<AnyBufferNode>,
1678    {
1679        #[derive(Default)]
1680        struct Tls {
1681            buffers: Vec<vk::Buffer>,
1682            offsets: Vec<vk::DeviceSize>,
1683        }
1684
1685        thread_local! {
1686            static TLS: RefCell<Tls> = Default::default();
1687        }
1688
1689        TLS.with_borrow_mut(|tls| {
1690            tls.buffers.clear();
1691            tls.offsets.clear();
1692
1693            for (buffer, offset) in buffer_offsets {
1694                let buffer = buffer.into();
1695                let buffer = self.resource(buffer);
1696
1697                tls.buffers.push(buffer.handle);
1698                tls.offsets.push(offset);
1699            }
1700
1701            unsafe {
1702                self.cmd.device.cmd_bind_vertex_buffers(
1703                    self.cmd.handle,
1704                    first_binding,
1705                    tls.buffers.as_slice(),
1706                    tls.offsets.as_slice(),
1707                );
1708            }
1709        });
1710
1711        self
1712    }
1713
1714    /// Draw unindexed primitives.
1715    ///
1716    /// When the command is executed, primitives are assembled using the current primitive topology
1717    /// and `vertex_count` consecutive vertex indices with the first `vertex_index` value equal to
1718    /// `first_vertex`. The primitives are drawn `instance_count` times with `instance_index`
1719    /// starting with `first_instance` and increasing sequentially for each instance.
1720    #[profiling::function]
1721    pub fn draw(
1722        &self,
1723        vertex_count: u32,
1724        instance_count: u32,
1725        first_vertex: u32,
1726        first_instance: u32,
1727    ) -> &Self {
1728        unsafe {
1729            self.cmd.device.cmd_draw(
1730                self.cmd.handle,
1731                vertex_count,
1732                instance_count,
1733                first_vertex,
1734                first_instance,
1735            );
1736        }
1737
1738        self
1739    }
1740
1741    /// Draw indexed primitives.
1742    ///
1743    /// When the command is executed, primitives are assembled using the current primitive topology
1744    /// and `index_count` vertices whose indices are retrieved from the index buffer. The index
1745    /// buffer is treated as an array of tightly packed unsigned integers of size defined by the
1746    /// `index_ty` parameter with which the buffer was bound.
1747    #[profiling::function]
1748    pub fn draw_indexed(
1749        &self,
1750        index_count: u32,
1751        instance_count: u32,
1752        first_index: u32,
1753        vertex_offset: i32,
1754        first_instance: u32,
1755    ) -> &Self {
1756        unsafe {
1757            self.cmd.device.cmd_draw_indexed(
1758                self.cmd.handle,
1759                index_count,
1760                instance_count,
1761                first_index,
1762                vertex_offset,
1763                first_instance,
1764            );
1765        }
1766
1767        self
1768    }
1769
1770    /// Draw primitives with indirect parameters and indexed vertices.
1771    ///
1772    /// `draw_indexed_indirect` behaves similarly to `draw_indexed` except that the parameters are
1773    /// read by the device from `buffer` during execution. `draw_count` draws are executed by the
1774    /// command, with parameters taken from `buffer` starting at `offset` and increasing by `stride`
1775    /// bytes for each successive draw. The parameters of each draw are encoded in an array of
1776    /// [`vk::DrawIndexedIndirectCommand`] structures.
1777    ///
1778    /// If `draw_count` is less than or equal to one, `stride` is ignored.
1779    ///
1780    /// # Examples
1781    ///
1782    /// Basic usage:
1783    ///
1784    /// ```no_run
1785    /// # use std::mem::size_of;
1786    /// # use ash::vk;
1787    /// # use vk_graph::cmd::{LoadOp, StoreOp};
1788    /// # use vk_sync::AccessType;
1789    /// # use vk_graph::driver::DriverError;
1790    /// # use vk_graph::driver::device::{Device, DeviceInfo};
1791    /// # use vk_graph::driver::buffer::{Buffer, BufferInfo};
1792    /// # use vk_graph::driver::graphics::{GraphicsPipeline, GraphicsPipelineInfo};
1793    /// # use vk_graph::driver::image::{Image, ImageInfo};
1794    /// # use vk_graph::driver::shader::Shader;
1795    /// # use vk_graph::Graph;
1796    /// # fn main() -> Result<(), DriverError> {
1797    /// # let device = Device::create(DeviceInfo::default())?;
1798    /// # let my_frag_code = [0u8; 1];
1799    /// # let my_vert_code = [0u8; 1];
1800    /// # let vert = Shader::new_vertex(my_vert_code.as_slice());
1801    /// # let frag = Shader::new_fragment(my_frag_code.as_slice());
1802    /// # let info = GraphicsPipelineInfo::default();
1803    /// # let my_graphic_pipeline = GraphicsPipeline::create(&device, info, [vert, frag])?;
1804    /// # let mut my_graph = Graph::default();
1805    /// # let buf_info = BufferInfo::device_mem(8, vk::BufferUsageFlags::INDEX_BUFFER);
1806    /// # let my_idx_buf = Buffer::create(&device, buf_info)?;
1807    /// # let buf_info = BufferInfo::device_mem(8, vk::BufferUsageFlags::VERTEX_BUFFER);
1808    /// # let my_vtx_buf = Buffer::create(&device, buf_info)?;
1809    /// # let my_idx_buf = my_graph.bind_resource(my_idx_buf);
1810    /// # let my_vtx_buf = my_graph.bind_resource(my_vtx_buf);
1811    /// # let info = ImageInfo::image_2d(
1812    /// #     32,
1813    /// #     32,
1814    /// #     vk::Format::R8G8B8A8_UNORM,
1815    /// #     vk::ImageUsageFlags::SAMPLED,
1816    /// # );
1817    /// # let swapchain_image = my_graph.bind_resource(Image::create(&device, info)?);
1818    /// const CMD_SIZE: usize = size_of::<vk::DrawIndexedIndirectCommand>();
1819    ///
1820    /// let cmd = vk::DrawIndexedIndirectCommand {
1821    ///     index_count: 3,
1822    ///     instance_count: 1,
1823    ///     first_index: 0,
1824    ///     vertex_offset: 0,
1825    ///     first_instance: 0,
1826    /// };
1827    /// let cmd_data = unsafe {
1828    ///     std::slice::from_raw_parts(&cmd as *const _ as *const _, CMD_SIZE)
1829    /// };
1830    ///
1831    /// let buf_flags = vk::BufferUsageFlags::STORAGE_BUFFER;
1832    /// let buf = Buffer::create_from_slice(&device, buf_flags, cmd_data)?;
1833    /// let buf_node = my_graph.bind_resource(buf);
1834    ///
1835    /// my_graph
1836    ///     .begin_cmd()
1837    ///     .debug_name("draw a single triangle")
1838    ///     .bind_pipeline(&my_graphic_pipeline)
1839    ///     .color_attachment_image(0, swapchain_image, LoadOp::DontCare, StoreOp::Store)
1840    ///     .resource_access(my_idx_buf, AccessType::IndexBuffer)
1841    ///     .resource_access(my_vtx_buf, AccessType::VertexBuffer)
1842    ///     .resource_access(buf_node, AccessType::IndirectBuffer)
1843    ///     .record_cmd(move |cmd| {
1844    ///         cmd
1845    ///             .bind_index_buffer(my_idx_buf, 0, vk::IndexType::UINT16)
1846    ///             .bind_vertex_buffer(0, my_vtx_buf, 0)
1847    ///             .draw_indexed_indirect(buf_node, 0, 1, 0);
1848    ///     });
1849    /// # Ok(()) }
1850    /// ```
1851    #[profiling::function]
1852    pub fn draw_indexed_indirect(
1853        &self,
1854        buffer: impl Into<AnyBufferNode>,
1855        offset: vk::DeviceSize,
1856        draw_count: u32,
1857        stride: u32,
1858    ) -> &Self {
1859        let buffer = buffer.into();
1860        let buffer = self.resource(buffer);
1861
1862        unsafe {
1863            self.cmd.device.cmd_draw_indexed_indirect(
1864                self.cmd.handle,
1865                buffer.handle,
1866                offset,
1867                draw_count,
1868                stride,
1869            );
1870        }
1871
1872        self
1873    }
1874
1875    /// Draw primitives with indirect parameters, indexed vertices, and draw count.
1876    ///
1877    /// `draw_indexed_indirect_count` behaves similarly to `draw_indexed_indirect` except that the
1878    /// draw count is read by the device from `buffer` during execution. The command will read an
1879    /// unsigned 32-bit integer from `count_buf` located at `count_buf_offset` and use this as the
1880    /// draw count.
1881    ///
1882    /// `max_draw_count` specifies the maximum number of draws that will be executed. The actual
1883    /// number of executed draw calls is the minimum of the count specified in `count_buf` and
1884    /// `max_draw_count`.
1885    ///
1886    /// `stride` is the byte stride between successive sets of draw parameters.
1887    #[profiling::function]
1888    pub fn draw_indexed_indirect_count(
1889        &self,
1890        buffer: impl Into<AnyBufferNode>,
1891        offset: vk::DeviceSize,
1892        count_buf: impl Into<AnyBufferNode>,
1893        count_buf_offset: vk::DeviceSize,
1894        max_draw_count: u32,
1895        stride: u32,
1896    ) -> &Self {
1897        let buffer = buffer.into();
1898        let buffer = self.resource(buffer);
1899
1900        let count_buf = count_buf.into();
1901        let count_buf = self.resource(count_buf);
1902
1903        unsafe {
1904            self.cmd.device.cmd_draw_indexed_indirect_count(
1905                self.cmd.handle,
1906                buffer.handle,
1907                offset,
1908                count_buf.handle,
1909                count_buf_offset,
1910                max_draw_count,
1911                stride,
1912            );
1913        }
1914
1915        self
1916    }
1917
1918    /// Draw primitives with indirect parameters and unindexed vertices.
1919    ///
1920    /// Behaves otherwise similar to [`Self::draw_indexed_indirect`].
1921    #[profiling::function]
1922    pub fn draw_indirect(
1923        &self,
1924        buffer: impl Into<AnyBufferNode>,
1925        offset: vk::DeviceSize,
1926        draw_count: u32,
1927        stride: u32,
1928    ) -> &Self {
1929        let buffer = buffer.into();
1930        let buffer = self.resource(buffer);
1931
1932        unsafe {
1933            self.cmd.device.cmd_draw_indirect(
1934                self.cmd.handle,
1935                buffer.handle,
1936                offset,
1937                draw_count,
1938                stride,
1939            );
1940        }
1941
1942        self
1943    }
1944
1945    /// Draw primitives with indirect parameters, unindexed vertices, and draw count.
1946    ///
1947    /// Behaves otherwise similar to [`Self::draw_indexed_indirect_count`].
1948    #[profiling::function]
1949    pub fn draw_indirect_count(
1950        &self,
1951        buffer: impl Into<AnyBufferNode>,
1952        offset: vk::DeviceSize,
1953        count_buf: impl Into<AnyBufferNode>,
1954        count_buf_offset: vk::DeviceSize,
1955        max_draw_count: u32,
1956        stride: u32,
1957    ) -> &Self {
1958        let buffer = buffer.into();
1959        let buffer = self.resource(buffer);
1960
1961        let count_buf = count_buf.into();
1962        let count_buf = self.resource(count_buf);
1963
1964        unsafe {
1965            self.cmd.device.cmd_draw_indirect_count(
1966                self.cmd.handle,
1967                buffer.handle,
1968                offset,
1969                count_buf.handle,
1970                count_buf_offset,
1971                max_draw_count,
1972                stride,
1973            );
1974        }
1975
1976        self
1977    }
1978
1979    /// Updates push constants.
1980    ///
1981    /// Push constants represent a high-speed path to modify constant data in pipelines that is
1982    /// expected to outperform memory-backed resource updates.
1983    ///
1984    /// Push constant values can be updated incrementally, causing shader stages to read the new
1985    /// data for push constants modified by this command, while still reading the previous data for
1986    /// push constants not modified by this command.
1987    ///
1988    /// # Device limitations
1989    ///
1990    /// See [`VkPhysicalDeviceLimits::maxPushConstantsSize`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkPhysicalDeviceLimits.html)
1991    /// for the limit of the current device. You may also check [gpuinfo.org] for a listing of
1992    /// reported limits on other devices.
1993    ///
1994    /// # Examples
1995    ///
1996    /// Basic usage:
1997    ///
1998    /// ```
1999    /// # vk_shader_macros::glsl!(r#"
2000    /// #version 450
2001    /// #pragma shader_stage(fragment)
2002    ///
2003    /// layout(push_constant) uniform PushConstants {
2004    ///     layout(offset = 0) uint the_answer;
2005    /// } push_constants;
2006    ///
2007    /// void main() {
2008    ///     uint value = push_constants.the_answer;
2009    /// }
2010    /// # "#);
2011    /// ```
2012    ///
2013    /// ```no_run
2014    /// # use ash::vk;
2015    /// # use vk_graph::cmd::{LoadOp, StoreOp};
2016    /// # use vk_graph::driver::DriverError;
2017    /// # use vk_graph::driver::device::{Device, DeviceInfo};
2018    /// # use vk_graph::driver::graphics::{GraphicsPipeline, GraphicsPipelineInfo};
2019    /// # use vk_graph::driver::image::{Image, ImageInfo};
2020    /// # use vk_graph::Graph;
2021    /// # use vk_graph::driver::shader::Shader;
2022    /// # fn main() -> Result<(), DriverError> {
2023    /// # let device = Device::create(DeviceInfo::default())?;
2024    /// # let my_frag_code = [0u8; 1];
2025    /// # let my_vert_code = [0u8; 1];
2026    /// # let vert = Shader::new_vertex(my_vert_code.as_slice());
2027    /// # let frag = Shader::new_fragment(my_frag_code.as_slice());
2028    /// # let info = GraphicsPipelineInfo::default();
2029    /// # let my_graphic_pipeline = GraphicsPipeline::create(&device, info, [vert, frag])?;
2030    /// # let info = ImageInfo::image_2d(
2031    /// #     32,
2032    /// #     32,
2033    /// #     vk::Format::R8G8B8A8_UNORM,
2034    /// #     vk::ImageUsageFlags::SAMPLED,
2035    /// # );
2036    /// # let swapchain_image = Image::create(&device, info)?;
2037    /// # let mut my_graph = Graph::default();
2038    /// # let swapchain_image = my_graph.bind_resource(swapchain_image);
2039    /// my_graph
2040    ///     .begin_cmd()
2041    ///     .debug_name("draw a quad")
2042    ///     .bind_pipeline(&my_graphic_pipeline)
2043    ///     .color_attachment_image(0, swapchain_image, LoadOp::DontCare, StoreOp::Store)
2044    ///     .record_cmd(move |cmd| {
2045    ///         cmd
2046    ///             .push_constants(0, &[42])
2047    ///             .draw(6, 1, 0, 0);
2048    ///     });
2049    /// # Ok(()) }
2050    /// ```
2051    ///
2052    /// See [`vkCmdPushConstants`](https://registry.khronos.org/vulkan/specs/latest/man/html/vkCmdPushConstants.html).
2053    #[profiling::function]
2054    pub fn push_constants(&self, offset: u32, data: &[u8]) -> &Self {
2055        self.cmd_push_constants(
2056            self.pipeline.inner.layout,
2057            &self.pipeline.inner.push_constants,
2058            offset,
2059            data,
2060        );
2061
2062        self
2063    }
2064
2065    /// Sets scissor rectangles dynamically for the current command.
2066    ///
2067    /// The default scissor state is no-clip.
2068    ///
2069    /// See [`vkCmdSetScissor`](https://registry.khronos.org/vulkan/specs/latest/man/html/vkCmdSetScissor.html).
2070    #[profiling::function]
2071    pub fn set_scissor(&self, first_scissor: u32, scissors: &[vk::Rect2D]) -> &Self {
2072        unsafe {
2073            self.cmd
2074                .device
2075                .cmd_set_scissor(self.cmd.handle, first_scissor, scissors);
2076        }
2077
2078        self
2079    }
2080
2081    /// Sets viewports dynamically for the current command.
2082    ///
2083    /// The default viewport state is the entire render target as defined by all combined image
2084    /// attachments.
2085    ///
2086    /// See [`vkCmdSetViewport`](https://registry.khronos.org/vulkan/specs/latest/man/html/vkCmdSetViewport.html).
2087    #[profiling::function]
2088    pub fn set_viewport(&self, first_viewport: u32, viewports: &[vk::Viewport]) -> &Self {
2089        unsafe {
2090            self.cmd
2091                .device
2092                .cmd_set_viewport(self.cmd.handle, first_viewport, viewports);
2093        }
2094
2095        self
2096    }
2097}
2098
2099impl<'a> Deref for GraphicsCommandRef<'a> {
2100    type Target = CommandRef<'a>;
2101
2102    fn deref(&self) -> &Self::Target {
2103        &self.cmd
2104    }
2105}
2106
2107impl LoadOp<ClearColorValue> {
2108    /// A load operation which results in a color attachment filled with RGB zeros and alpha ones.
2109    pub const CLEAR_BLACK_ALPHA_ONE: Self = Self::Clear(ClearColorValue::BLACK_ALPHA_ONE);
2110
2111    /// A load operation which results in a color attachment filled with zeros.
2112    pub const CLEAR_BLACK_ALPHA_ZERO: Self = Self::Clear(ClearColorValue::BLACK_ALPHA_ZERO);
2113
2114    /// A load operation which results in a color attachment filled with RGB ones and alpha ones.
2115    pub const CLEAR_WHITE_ALPHA_ONE: Self = Self::Clear(ClearColorValue::WHITE_ALPHA_ONE);
2116
2117    /// A load operation which results in a color attachment filled with RGB ones and alpha zeros.
2118    pub const CLEAR_WHITE_ALPHA_ZERO: Self = Self::Clear(ClearColorValue::WHITE_ALPHA_ZERO);
2119
2120    /// Convenience constructor for clear color values.
2121    pub fn clear_rgba(r: f32, g: f32, b: f32, a: f32) -> Self {
2122        Self::Clear(ClearColorValue::rgba(r, g, b, a))
2123    }
2124}
2125
2126impl LoadOp<vk::ClearDepthStencilValue> {
2127    /// A load operation which results in a depth attachment filled with ones and stencil filled
2128    /// with zeros.
2129    pub const CLEAR_ONE_STENCIL_ZERO: Self = Self::Clear(vk::ClearDepthStencilValue {
2130        depth: 1.0,
2131        stencil: 0,
2132    });
2133
2134    /// A load operation which results in a depth and stencil attachment filled with zeros.
2135    pub const CLEAR_ZERO_STENCIL_ZERO: Self = Self::Clear(vk::ClearDepthStencilValue {
2136        depth: 0.0,
2137        stencil: 0,
2138    });
2139
2140    /// Convenience constructor for clear depth and stencil values.
2141    pub fn clear_depth_stencil(depth: f32, stencil: u32) -> Self {
2142        Self::Clear(vk::ClearDepthStencilValue { depth, stencil })
2143    }
2144}