Skip to main content

vk_graph/cmd/
graphic.rs

1use {
2    super::{AttachmentIndex, cmd_ref::CommandRef, pipeline::PipelineCommand},
3    crate::{
4        driver::{
5            graphic::{DepthStencilInfo, GraphicPipeline},
6            image::ImageViewInfo,
7            render_pass::ResolveMode,
8        },
9        node::{AnyBufferNode, AnyImageNode},
10    },
11    ash::vk,
12    std::{cell::RefCell, ops::Deref, slice},
13};
14
15impl PipelineCommand<'_, GraphicPipeline> {
16    /// Sets the `color_attachment` attachment index of the following render pass to the given
17    /// `image`.
18    ///
19    /// Note: To use multi-sampled (MSAA) rendering, use an image created with a sample count
20    /// greater than one.
21    ///
22    /// Note: The default view (the whole image) is used for `image`.
23    ///
24    /// See [_Render Pass_](https://docs.vulkan.org/spec/latest/chapters/renderpass.html)
25    pub fn color_attachment_image(
26        mut self,
27        color_attachment: AttachmentIndex,
28        image: impl Into<AnyImageNode>,
29        load: LoadOp<ClearColorValue>,
30        store: StoreOp,
31    ) -> Self {
32        self.set_color_attachment_image(color_attachment, image, load, store);
33        self
34    }
35
36    /// Sets the `color_attachment` attachment index of the following render pass to the given
37    /// `image`, as interpreted by `image_view_info`.
38    ///
39    /// See [_Render Pass_](https://docs.vulkan.org/spec/latest/chapters/renderpass.html)
40    pub fn color_attachment_image_view(
41        mut self,
42        color_attachment: AttachmentIndex,
43        image: impl Into<AnyImageNode>,
44        image_view_info: impl Into<ImageViewInfo>,
45        load: LoadOp<ClearColorValue>,
46        store: StoreOp,
47    ) -> Self {
48        self.set_color_attachment_image_view(color_attachment, image, image_view_info, load, store);
49        self
50    }
51
52    /// Resolves a multi-sampled (MSAA) color image attachment into a single-sampled attachment
53    /// using the given `image`.
54    ///
55    /// Note: The default view (the whole image) is used for `image`.
56    ///
57    /// See [_Render Pass_](https://docs.vulkan.org/spec/latest/chapters/renderpass.html)
58    pub fn color_attachment_resolve_image(
59        mut self,
60        msaa_attachment: AttachmentIndex,
61        color_attachment: AttachmentIndex,
62        image: impl Into<AnyImageNode>,
63    ) -> Self {
64        self.set_color_attachment_resolve_image(msaa_attachment, color_attachment, image);
65        self
66    }
67
68    /// Resolves a multi-sampled (MSAA) color image attachment into a single-sampled attachment
69    /// using the given `image`, as interpreted by `image_view_info`.
70    ///
71    /// See [_Render Pass_](https://docs.vulkan.org/spec/latest/chapters/renderpass.html)
72    pub fn color_attachment_resolve_image_view(
73        mut self,
74        msaa_attachment: AttachmentIndex,
75        color_attachment: AttachmentIndex,
76        image: impl Into<AnyImageNode>,
77        image_view_info: impl Into<ImageViewInfo>,
78    ) -> Self {
79        self.set_color_attachment_resolve_image_view(
80            msaa_attachment,
81            color_attachment,
82            image,
83            image_view_info,
84        );
85        self
86    }
87
88    /// Sets the combined depth and stencil state used by any subsequent command buffer recordings
89    /// of the current graph command.
90    pub fn depth_stencil(mut self, depth_stencil: impl Into<DepthStencilInfo>) -> Self {
91        self.set_depth_stencil(depth_stencil);
92        self
93    }
94
95    /// Sets the combined depth and stencil attachment of the following render pass to the given
96    /// `image`.
97    ///
98    /// Note: To use multi-sampled (MSAA) rendering, use an image created with a sample count
99    /// greater than one.
100    ///
101    /// Note: The default view (the whole image) is used for `image`.
102    ///
103    /// See [_Render Pass_](https://docs.vulkan.org/spec/latest/chapters/renderpass.html)
104    pub fn depth_stencil_attachment_image(
105        mut self,
106        image: impl Into<AnyImageNode>,
107        load: LoadOp<vk::ClearDepthStencilValue>,
108        store: StoreOp,
109    ) -> Self {
110        self.set_depth_stencil_attachment_image(image, load, store);
111        self
112    }
113
114    /// Sets the combined depth and stencil attachment of the following render pass to the given
115    /// `image`, as interpreted by `image_view_info`.
116    ///
117    /// Note: To use multi-sampled (MSAA) rendering, use an image created with a sample count
118    /// greater than one.
119    ///
120    /// Note: The default view (the whole image) is used for `image`.
121    ///
122    /// See [_Render Pass_](https://docs.vulkan.org/spec/latest/chapters/renderpass.html)
123    pub fn depth_stencil_attachment_image_view(
124        mut self,
125        image: impl Into<AnyImageNode>,
126        image_view_info: impl Into<ImageViewInfo>,
127        load: LoadOp<vk::ClearDepthStencilValue>,
128        store: StoreOp,
129    ) -> Self {
130        self.set_depth_stencil_attachment_image_view(image, image_view_info, load, store);
131        self
132    }
133
134    /// Resolves a multi-sampled (MSAA) combined depth and stencil image attachment into a
135    /// single-sampled attachment using the given `image`.
136    ///
137    /// Note: The default view (the whole image) is used for `image`.
138    ///
139    /// See [_Render Pass_](https://docs.vulkan.org/spec/latest/chapters/renderpass.html)
140    pub fn depth_stencil_attachment_resolve_image(
141        mut self,
142        depth_stencil_attachment: AttachmentIndex,
143        image: impl Into<AnyImageNode>,
144        depth_mode: Option<ResolveMode>,
145        stencil_mode: Option<ResolveMode>,
146    ) -> Self {
147        self.set_depth_stencil_attachment_resolve_image(
148            depth_stencil_attachment,
149            image,
150            depth_mode,
151            stencil_mode,
152        );
153        self
154    }
155
156    /// Resolves a multi-sampled (MSAA) combined depth and stencil image attachment into a
157    /// single-sampled attachment using the given `image`, as interpreted by `image_view_info`.
158    ///
159    /// Note: The default view (the whole image) is used for `image`.
160    ///
161    /// See [_Render Pass_](https://docs.vulkan.org/spec/latest/chapters/renderpass.html)
162    pub fn depth_stencil_attachment_resolve_image_view(
163        mut self,
164        depth_stencil_attachment: AttachmentIndex,
165        image: impl Into<AnyImageNode>,
166        image_view_info: impl Into<ImageViewInfo>,
167        depth_mode: Option<ResolveMode>,
168        stencil_mode: Option<ResolveMode>,
169    ) -> Self {
170        self.set_depth_stencil_attachment_resolve_image_view(
171            depth_stencil_attachment,
172            image,
173            image_view_info,
174            depth_mode,
175            stencil_mode,
176        );
177        self
178    }
179
180    /// Sets multiview view and correlation masks used by any subsequent command buffer recordings
181    /// of the current graph command.
182    ///
183    /// See [`VkRenderPassMultiviewCreateInfo`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkRenderPassMultiviewCreateInfo.html).
184    pub fn multiview(mut self, view_mask: u32, correlated_view_mask: u32) -> Self {
185        self.set_multiview(view_mask, correlated_view_mask);
186        self
187    }
188
189    /// Begin recording a graphics pipeline command buffer.
190    pub fn record_cmd(mut self, func: impl FnOnce(GraphicCommandRef<'_>) + Send + 'static) -> Self {
191        self.record_cmd_mut(func);
192        self
193    }
194
195    /// Begin recording a graphics pipeline command buffer.
196    pub fn record_cmd_mut(&mut self, func: impl FnOnce(GraphicCommandRef<'_>) + Send + 'static) {
197        let pipeline = self
198            .cmd
199            .cmd()
200            .expect_last_pipeline()
201            .expect_graphic()
202            .clone();
203
204        self.cmd.push_exec(move |cmd| {
205            func(GraphicCommandRef { cmd, pipeline });
206        });
207    }
208
209    /// See [`VkRenderPassBeginInfo`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkRenderPassBeginInfo.html).
210    /// field when beginning a render pass used by any subsequent command buffer recordings
211    /// of the current graph command.
212    ///
213    /// _NOTE:_ Setting this value will cause the viewport and scissor to be unset, which is not the
214    /// default behavior. When this value is set you should call `set_viewport` and `set_scissor` on
215    /// the command buffer.
216    ///
217    /// If not set, this value defaults to the first loaded, resolved, or stored attachment
218    /// dimensions and sets the viewport and scissor to the same values, with a `0..1` depth if not
219    /// specified by `depth_stencil`.
220    pub fn render_area(mut self, area: vk::Rect2D) -> Self {
221        self.set_render_area(area);
222        self
223    }
224
225    /// See [`Self::color_attachment_image`]
226    pub fn set_color_attachment_image(
227        &mut self,
228        color_attachment: AttachmentIndex,
229        image: impl Into<AnyImageNode>,
230        load: LoadOp<ClearColorValue>,
231        store: StoreOp,
232    ) -> &mut Self {
233        let image = image.into();
234        let image_view = self.resource(image).info;
235
236        self.set_color_attachment_image_view(color_attachment, image, image_view, load, store);
237
238        self
239    }
240
241    /// See [`Self::color_attachment_image_view`]
242    pub fn set_color_attachment_image_view(
243        &mut self,
244        color_attachment: AttachmentIndex,
245        image: impl Into<AnyImageNode>,
246        image_view_info: impl Into<ImageViewInfo>,
247        load: LoadOp<ClearColorValue>,
248        store: StoreOp,
249    ) -> &mut Self {
250        let image = image.into();
251        let image_view_info = image_view_info.into();
252
253        #[allow(deprecated)]
254        {
255            match load {
256                LoadOp::Clear(color) => {
257                    self.set_clear_color_value_as(color_attachment, image, color, image_view_info)
258                }
259                LoadOp::DontCare => {
260                    self.set_attach_color_as(color_attachment, image, image_view_info)
261                }
262                LoadOp::Load => self.set_load_color_as(color_attachment, image, image_view_info),
263            };
264
265            if let StoreOp::Store = store {
266                self.set_store_color_as(color_attachment, image, image_view_info);
267            }
268        }
269
270        self
271    }
272
273    /// See [`Self::color_attachment_resolve_image`]
274    pub fn set_color_attachment_resolve_image(
275        &mut self,
276        msaa_attachment: AttachmentIndex,
277        color_attachment: AttachmentIndex,
278        image: impl Into<AnyImageNode>,
279    ) -> &mut Self {
280        let image = image.into();
281        let image_view = self.resource(image).info;
282
283        self.set_color_attachment_resolve_image_view(
284            msaa_attachment,
285            color_attachment,
286            image,
287            image_view,
288        );
289
290        self
291    }
292
293    /// See [`Self::color_attachment_resolve_image_view`]
294    pub fn set_color_attachment_resolve_image_view(
295        &mut self,
296        msaa_attachment: AttachmentIndex,
297        color_attachment: AttachmentIndex,
298        image: impl Into<AnyImageNode>,
299        image_view_info: impl Into<ImageViewInfo>,
300    ) -> &mut Self {
301        let image = image.into();
302        let image_view_info = image_view_info.into();
303
304        #[allow(deprecated)]
305        self.set_resolve_color_as(msaa_attachment, color_attachment, image, image_view_info);
306
307        self
308    }
309
310    /// See [`Self::depth_stencil`]
311    pub fn set_depth_stencil(&mut self, depth_stencil: impl Into<DepthStencilInfo>) -> &mut Self {
312        let depth_stencil = depth_stencil.into();
313        let cmd = self.cmd.cmd_mut();
314        let exec = cmd.expect_last_exec_mut();
315
316        assert!(exec.depth_stencil.is_none());
317
318        exec.depth_stencil = Some(depth_stencil);
319
320        self
321    }
322
323    /// See [`Self::depth_stencil_attachment_image`]
324    pub fn set_depth_stencil_attachment_image(
325        &mut self,
326        image: impl Into<AnyImageNode>,
327        load: LoadOp<vk::ClearDepthStencilValue>,
328        store: StoreOp,
329    ) -> &mut Self {
330        let image = image.into();
331        let image_view_info = self.resource(image).info;
332
333        self.set_depth_stencil_attachment_image_view(image, image_view_info, load, store);
334
335        self
336    }
337
338    /// See [`Self::depth_stencil_attachment_image_view`]
339    pub fn set_depth_stencil_attachment_image_view(
340        &mut self,
341        image: impl Into<AnyImageNode>,
342        image_view_info: impl Into<ImageViewInfo>,
343        load: LoadOp<vk::ClearDepthStencilValue>,
344        store: StoreOp,
345    ) -> &mut Self {
346        let image = image.into();
347        let image_view_info = image_view_info.into();
348
349        #[allow(deprecated)]
350        {
351            match load {
352                LoadOp::Clear(color) => self.set_clear_depth_stencil_value_as(
353                    image,
354                    color.depth,
355                    color.stencil,
356                    image_view_info,
357                ),
358                LoadOp::DontCare => self.set_attach_depth_stencil_as(image, image_view_info),
359                LoadOp::Load => self.set_load_depth_stencil_as(image, image_view_info),
360            };
361
362            if let StoreOp::Store = store {
363                self.set_store_depth_stencil_as(image, image_view_info);
364            }
365        }
366
367        self
368    }
369
370    /// See [`Self::depth_stencil_attachment_resolve_image`]
371    pub fn set_depth_stencil_attachment_resolve_image(
372        &mut self,
373        depth_stencil_attachment: AttachmentIndex,
374        image: impl Into<AnyImageNode>,
375        depth_mode: Option<ResolveMode>,
376        stencil_mode: Option<ResolveMode>,
377    ) -> &mut Self {
378        let image = image.into();
379        let image_view = self.resource(image).info;
380
381        self.set_depth_stencil_attachment_resolve_image_view(
382            depth_stencil_attachment,
383            image,
384            image_view,
385            depth_mode,
386            stencil_mode,
387        );
388
389        self
390    }
391
392    /// See [`Self::depth_stencil_attachment_resolve_image_view`]
393    pub fn set_depth_stencil_attachment_resolve_image_view(
394        &mut self,
395        depth_stencil_attachment: AttachmentIndex,
396        image: impl Into<AnyImageNode>,
397        image_view_info: impl Into<ImageViewInfo>,
398        depth_mode: Option<ResolveMode>,
399        stencil_mode: Option<ResolveMode>,
400    ) -> &mut Self {
401        let image = image.into();
402        let image_view_info = image_view_info.into();
403
404        #[allow(deprecated)]
405        self.set_resolve_depth_stencil_as(
406            depth_stencil_attachment,
407            image,
408            image_view_info,
409            depth_mode,
410            stencil_mode,
411        );
412
413        self
414    }
415
416    /// See [`Self::multiview`]
417    pub fn set_multiview(&mut self, view_mask: u32, correlated_view_mask: u32) -> &mut Self {
418        let cmd = self.cmd.cmd_mut();
419        let exec = cmd.expect_last_exec_mut();
420
421        exec.correlated_view_mask = correlated_view_mask;
422        exec.view_mask = view_mask;
423
424        self
425    }
426
427    /// See [`Self::render_area`]
428    pub fn set_render_area(&mut self, area: vk::Rect2D) -> &mut Self {
429        self.cmd.cmd_mut().expect_last_exec_mut().render_area = Some(area);
430        self
431    }
432}
433
434/// Structure specifying a clear color value.
435#[derive(Clone, Copy, Debug)]
436pub enum ClearColorValue {
437    /// Value as [f32].
438    ///
439    /// Use this member for color clear values when the format of the image or attachment is one of
440    /// the numeric formats with a numeric type that is floating-point. Floating-point values are
441    /// automatically converted to the format of the image, with the clear value being treated as
442    /// linear if the image is sRGB.
443    Float32([f32; 4]),
444
445    /// Value as [i32].
446    ///
447    /// Use this member for color clear values when the format of the image or attachment has a
448    /// numeric type that is signed integer. Signed integer values are converted to the format of
449    /// the image by casting to the smaller type (with negative 32-bit values mapping to negative
450    /// values in the smaller type). If the integer clear value is not representable in the target
451    /// type (e.g. would overflow in conversion to that type), the clear value is undefined.
452    Int32([i32; 4]),
453
454    /// Value as [u32].
455    ///
456    /// Use this member for color clear values when the format of the image or attachment has a
457    /// numeric type that is unsigned integer. Unsigned integer values are converted to the format
458    /// of the image by casting to the integer type with fewer bits.
459    Uint32([u32; 4]),
460}
461
462impl ClearColorValue {
463    /// RGB zeros and alpha ones.
464    pub const BLACK_ALPHA_ONE: Self = Self::Float32([0.0, 0.0, 0.0, 1.0]);
465
466    /// All zeros.
467    pub const BLACK_ALPHA_ZERO: Self = Self::Float32([0.0, 0.0, 0.0, 0.0]);
468
469    /// RGB zeros and alpha ones.
470    pub const WHITE_ALPHA_ONE: Self = Self::Float32([1.0, 1.0, 1.0, 1.0]);
471
472    /// RGB ones and alpha zeros.
473    pub const WHITE_ALPHA_ZERO: Self = Self::Float32([1.0, 1.0, 1.0, 0.0]);
474
475    /// Convenience constructor for clear color values.
476    pub const fn rgba(r: f32, g: f32, b: f32, a: f32) -> Self {
477        Self::Float32([r, g, b, a])
478    }
479
480    /// Convert RGB+A values into a ClearColorValue.
481    pub const fn from_f32(r: f32, g: f32, b: f32, a: f32) -> Self {
482        Self::rgba(r, g, b, a)
483    }
484
485    /// Convert RGB+A values into a ClearColorValue.
486    pub const fn from_u8(r: u8, g: u8, b: u8, a: u8) -> Self {
487        Self::from_f32(
488            r as f32 / u8::MAX as f32,
489            g as f32 / u8::MAX as f32,
490            b as f32 / u8::MAX as f32,
491            a as f32 / u8::MAX as f32,
492        )
493    }
494}
495
496impl Default for ClearColorValue {
497    fn default() -> Self {
498        Self::from_f32(0.0, 0.0, 0.0, 0.0)
499    }
500}
501
502impl From<[f32; 4]> for ClearColorValue {
503    fn from(float32: [f32; 4]) -> Self {
504        Self::Float32(float32)
505    }
506}
507
508impl From<[i32; 4]> for ClearColorValue {
509    fn from(int32: [i32; 4]) -> Self {
510        Self::Int32(int32)
511    }
512}
513
514impl From<[u8; 4]> for ClearColorValue {
515    fn from(uint8: [u8; 4]) -> Self {
516        Self::from_u8(uint8[0], uint8[1], uint8[2], uint8[3])
517    }
518}
519
520impl From<[u32; 4]> for ClearColorValue {
521    fn from(uint32: [u32; 4]) -> Self {
522        Self::Uint32(uint32)
523    }
524}
525
526impl From<ClearColorValue> for vk::ClearColorValue {
527    fn from(value: ClearColorValue) -> Self {
528        match value {
529            ClearColorValue::Float32(float32) => Self { float32 },
530            ClearColorValue::Int32(int32) => Self { int32 },
531            ClearColorValue::Uint32(uint32) => Self { uint32 },
532        }
533    }
534}
535
536/// Recording interface for drawing commands.
537///
538/// This structure provides a strongly-typed set of methods which allow raster graphics shader code
539/// to be executed. An instance is provided to the closure argument of
540/// [`PipelineCommand::record_cmd`] which may be accessed by binding a [`GraphicPipeline`] to a
541/// command.
542///
543/// # Examples
544///
545/// Basic usage:
546///
547/// ```no_run
548/// # use ash::vk;
549/// # use vk_graph::cmd::{LoadOp, StoreOp};
550/// # use vk_graph::driver::DriverError;
551/// # use vk_graph::driver::device::{Device, DeviceInfo};
552/// # use vk_graph::driver::graphic::{GraphicPipeline, GraphicPipelineInfo};
553/// # use vk_graph::driver::image::{Image, ImageInfo};
554/// # use vk_graph::Graph;
555/// # use vk_graph::driver::shader::Shader;
556/// # fn main() -> Result<(), DriverError> {
557/// # let device = Device::new(DeviceInfo::default())?;
558/// # let my_frag_code = [0u8; 1];
559/// # let my_vert_code = [0u8; 1];
560/// # let vert = Shader::new_vertex(my_vert_code.as_slice());
561/// # let frag = Shader::new_fragment(my_frag_code.as_slice());
562/// # let info = GraphicPipelineInfo::default();
563/// # let my_graphic_pipeline = GraphicPipeline::create(&device, info, [vert, frag])?;
564/// # let mut my_graph = Graph::default();
565/// # let info = ImageInfo::image_2d(
566/// #     32,
567/// #     32,
568/// #     vk::Format::R8G8B8A8_UNORM,
569/// #     vk::ImageUsageFlags::SAMPLED,
570/// # );
571/// # let swapchain_image = my_graph.bind_resource(Image::create(&device, info)?);
572/// my_graph
573///     .begin_cmd()
574///     .debug_name("my draw command")
575///     .bind_pipeline(&my_graphic_pipeline)
576///     .color_attachment_image(0, swapchain_image, LoadOp::DontCare, StoreOp::Store)
577///     .record_cmd(move |cmd| {
578///         // During this closure we have access to the drawing functions!
579///         cmd.draw(3, 1, 0, 0);
580///     });
581/// # Ok(()) }
582/// ```
583pub struct GraphicCommandRef<'a> {
584    cmd: CommandRef<'a>,
585    pipeline: GraphicPipeline,
586}
587
588impl GraphicCommandRef<'_> {
589    /// Bind an index buffer to the current command.
590    ///
591    /// `offset` is the starting offset in bytes within `buffer` used in index buffer address
592    /// calculations.
593    ///
594    /// # Examples
595    ///
596    /// Basic usage:
597    ///
598    /// ```no_run
599    /// # use ash::vk;
600    /// # use vk_graph::cmd::{LoadOp, StoreOp};
601    /// # use vk_graph::driver::{AccessType, DriverError};
602    /// # use vk_graph::driver::device::{Device, DeviceInfo};
603    /// # use vk_graph::driver::buffer::{Buffer, BufferInfo};
604    /// # use vk_graph::driver::graphic::{GraphicPipeline, GraphicPipelineInfo};
605    /// # use vk_graph::driver::image::{Image, ImageInfo};
606    /// # use vk_graph::driver::shader::Shader;
607    /// # use vk_graph::Graph;
608    /// # fn main() -> Result<(), DriverError> {
609    /// # let device = Device::new(DeviceInfo::default())?;
610    /// # let my_frag_code = [0u8; 1];
611    /// # let my_vert_code = [0u8; 1];
612    /// # let vert = Shader::new_vertex(my_vert_code.as_slice());
613    /// # let frag = Shader::new_fragment(my_frag_code.as_slice());
614    /// # let info = GraphicPipelineInfo::default();
615    /// # let my_graphic_pipeline = GraphicPipeline::create(&device, info, [vert, frag])?;
616    /// # let mut my_graph = Graph::default();
617    /// # let info = ImageInfo::image_2d(
618    /// #     32,
619    /// #     32,
620    /// #     vk::Format::R8G8B8A8_UNORM,
621    /// #     vk::ImageUsageFlags::SAMPLED,
622    /// # );
623    /// # let swapchain_image = my_graph.bind_resource(Image::create(&device, info)?);
624    /// # let buf_info = BufferInfo::device_mem(8, vk::BufferUsageFlags::INDEX_BUFFER);
625    /// # let my_idx_buf = Buffer::create(&device, buf_info)?;
626    /// # let buf_info = BufferInfo::device_mem(8, vk::BufferUsageFlags::VERTEX_BUFFER);
627    /// # let my_vtx_buf = Buffer::create(&device, buf_info)?;
628    /// # let my_idx_buf = my_graph.bind_resource(my_idx_buf);
629    /// # let my_vtx_buf = my_graph.bind_resource(my_vtx_buf);
630    /// my_graph
631    ///     .begin_cmd()
632    ///     .debug_name("my indexed geometry draw pass")
633    ///     .bind_pipeline(&my_graphic_pipeline)
634    ///     .color_attachment_image(0, swapchain_image, LoadOp::DontCare, StoreOp::Store)
635    ///     .resource_access(my_idx_buf, AccessType::IndexBuffer)
636    ///     .resource_access(my_vtx_buf, AccessType::VertexBuffer)
637    ///     .record_cmd(move |cmd| {
638    ///         cmd
639    ///             .bind_index_buffer(my_idx_buf, 0, vk::IndexType::UINT16)
640    ///             .bind_vertex_buffer(0, my_vtx_buf, 0)
641    ///             .draw_indexed(42, 1, 0, 0, 0);
642    ///     });
643    /// # Ok(()) }
644    /// ```
645    #[profiling::function]
646    pub fn bind_index_buffer(
647        &self,
648        buffer: impl Into<AnyBufferNode>,
649        offset: vk::DeviceSize,
650        index_ty: vk::IndexType,
651    ) -> &Self {
652        let buffer = buffer.into();
653        let buffer = self.resource(buffer);
654
655        unsafe {
656            self.cmd
657                .device
658                .cmd_bind_index_buffer(self.cmd.handle, buffer.handle, offset, index_ty);
659        }
660
661        self
662    }
663
664    /// Bind a vertex buffer to the current pass.
665    ///
666    /// The vertex input binding is updated to start at `offset` from the start of `buffer`.
667    ///
668    /// # Examples
669    ///
670    /// Basic usage:
671    ///
672    /// ```no_run
673    /// # use ash::vk;
674    /// # use vk_graph::cmd::{LoadOp, StoreOp};
675    /// # use vk_graph::driver::{sync::AccessType, DriverError};
676    /// # use vk_graph::driver::device::{Device, DeviceInfo};
677    /// # use vk_graph::driver::buffer::{Buffer, BufferInfo};
678    /// # use vk_graph::driver::graphic::{GraphicPipeline, GraphicPipelineInfo};
679    /// # use vk_graph::driver::image::{Image, ImageInfo};
680    /// # use vk_graph::driver::shader::Shader;
681    /// # use vk_graph::Graph;
682    /// # fn main() -> Result<(), DriverError> {
683    /// # let device = Device::new(DeviceInfo::default())?;
684    /// # let buf_info = BufferInfo::device_mem(8, vk::BufferUsageFlags::VERTEX_BUFFER);
685    /// # let my_vtx_buf = Buffer::create(&device, buf_info)?;
686    /// # let my_frag_code = [0u8; 1];
687    /// # let my_vert_code = [0u8; 1];
688    /// # let vert = Shader::new_vertex(my_vert_code.as_slice());
689    /// # let frag = Shader::new_fragment(my_frag_code.as_slice());
690    /// # let info = GraphicPipelineInfo::default();
691    /// # let my_graphic_pipeline = GraphicPipeline::create(&device, info, [vert, frag])?;
692    /// # let mut my_graph = Graph::default();
693    /// # let info = ImageInfo::image_2d(
694    /// #     32,
695    /// #     32,
696    /// #     vk::Format::R8G8B8A8_UNORM,
697    /// #     vk::ImageUsageFlags::SAMPLED,
698    /// # );
699    /// # let swapchain_image = my_graph.bind_resource(Image::create(&device, info)?);
700    /// # let my_vtx_buf = my_graph.bind_resource(my_vtx_buf);
701    /// my_graph
702    ///     .begin_cmd()
703    ///     .debug_name("my unindexed geometry draw pass")
704    ///     .bind_pipeline(&my_graphic_pipeline)
705    ///     .color_attachment_image(0, swapchain_image, LoadOp::DontCare, StoreOp::Store)
706    ///     .resource_access(my_vtx_buf, AccessType::VertexBuffer)
707    ///     .record_cmd(move |cmd| {
708    ///         cmd
709    ///             .bind_vertex_buffer(0, my_vtx_buf, 0)
710    ///             .draw(42, 1, 0, 0);
711    ///     });
712    /// # Ok(()) }
713    /// ```
714    #[profiling::function]
715    pub fn bind_vertex_buffer(
716        &self,
717        binding: u32,
718        buffer: impl Into<AnyBufferNode>,
719        offset: vk::DeviceSize,
720    ) -> &Self {
721        let buffer = buffer.into();
722        let buffer = self.resource(buffer);
723
724        unsafe {
725            self.cmd.device.cmd_bind_vertex_buffers(
726                self.cmd.handle,
727                binding,
728                slice::from_ref(&buffer.handle),
729                slice::from_ref(&offset),
730            );
731        }
732
733        self
734    }
735
736    /// Binds multiple vertex buffers to the current pass, starting at the given `first_binding`.
737    ///
738    /// Each vertex input binding in `buffers` specifies an offset from the start of the
739    /// corresponding buffer.
740    ///
741    /// The vertex input attributes that use each of these bindings will use these updated addresses
742    /// in their address calculations for subsequent drawing commands.
743    #[profiling::function]
744    pub fn bind_vertex_buffers<N>(
745        &self,
746        first_binding: u32,
747        buffer_offsets: impl IntoIterator<Item = (N, vk::DeviceSize)>,
748    ) -> &Self
749    where
750        N: Into<AnyBufferNode>,
751    {
752        #[derive(Default)]
753        struct Tls {
754            buffers: Vec<vk::Buffer>,
755            offsets: Vec<vk::DeviceSize>,
756        }
757
758        thread_local! {
759            static TLS: RefCell<Tls> = Default::default();
760        }
761
762        TLS.with_borrow_mut(|tls| {
763            tls.buffers.clear();
764            tls.offsets.clear();
765
766            for (buffer, offset) in buffer_offsets {
767                let buffer = buffer.into();
768                let buffer = self.resource(buffer);
769
770                tls.buffers.push(buffer.handle);
771                tls.offsets.push(offset);
772            }
773
774            unsafe {
775                self.cmd.device.cmd_bind_vertex_buffers(
776                    self.cmd.handle,
777                    first_binding,
778                    tls.buffers.as_slice(),
779                    tls.offsets.as_slice(),
780                );
781            }
782        });
783
784        self
785    }
786
787    /// Draw unindexed primitives.
788    ///
789    /// When the command is executed, primitives are assembled using the current primitive topology
790    /// and `vertex_count` consecutive vertex indices with the first `vertex_index` value equal to
791    /// `first_vertex`. The primitives are drawn `instance_count` times with `instance_index`
792    /// starting with `first_instance` and increasing sequentially for each instance.
793    #[profiling::function]
794    pub fn draw(
795        &self,
796        vertex_count: u32,
797        instance_count: u32,
798        first_vertex: u32,
799        first_instance: u32,
800    ) -> &Self {
801        unsafe {
802            self.cmd.device.cmd_draw(
803                self.cmd.handle,
804                vertex_count,
805                instance_count,
806                first_vertex,
807                first_instance,
808            );
809        }
810
811        self
812    }
813
814    /// Draw indexed primitives.
815    ///
816    /// When the command is executed, primitives are assembled using the current primitive topology
817    /// and `index_count` vertices whose indices are retrieved from the index buffer. The index
818    /// buffer is treated as an array of tightly packed unsigned integers of size defined by the
819    /// `index_ty` parameter with which the buffer was bound.
820    #[profiling::function]
821    pub fn draw_indexed(
822        &self,
823        index_count: u32,
824        instance_count: u32,
825        first_index: u32,
826        vertex_offset: i32,
827        first_instance: u32,
828    ) -> &Self {
829        unsafe {
830            self.cmd.device.cmd_draw_indexed(
831                self.cmd.handle,
832                index_count,
833                instance_count,
834                first_index,
835                vertex_offset,
836                first_instance,
837            );
838        }
839
840        self
841    }
842
843    /// Draw primitives with indirect parameters and indexed vertices.
844    ///
845    /// `draw_indexed_indirect` behaves similarly to `draw_indexed` except that the parameters are
846    /// read by the device from `buffer` during execution. `draw_count` draws are executed by the
847    /// command, with parameters taken from `buffer` starting at `offset` and increasing by `stride`
848    /// bytes for each successive draw. The parameters of each draw are encoded in an array of
849    /// [`vk::DrawIndexedIndirectCommand`] structures.
850    ///
851    /// If `draw_count` is less than or equal to one, `stride` is ignored.
852    ///
853    /// # Examples
854    ///
855    /// Basic usage:
856    ///
857    /// ```no_run
858    /// # use std::mem::size_of;
859    /// # use ash::vk;
860    /// # use vk_graph::cmd::{LoadOp, StoreOp};
861    /// # use vk_graph::driver::{AccessType, DriverError};
862    /// # use vk_graph::driver::device::{Device, DeviceInfo};
863    /// # use vk_graph::driver::buffer::{Buffer, BufferInfo};
864    /// # use vk_graph::driver::graphic::{GraphicPipeline, GraphicPipelineInfo};
865    /// # use vk_graph::driver::image::{Image, ImageInfo};
866    /// # use vk_graph::driver::shader::Shader;
867    /// # use vk_graph::Graph;
868    /// # fn main() -> Result<(), DriverError> {
869    /// # let device = Device::new(DeviceInfo::default())?;
870    /// # let my_frag_code = [0u8; 1];
871    /// # let my_vert_code = [0u8; 1];
872    /// # let vert = Shader::new_vertex(my_vert_code.as_slice());
873    /// # let frag = Shader::new_fragment(my_frag_code.as_slice());
874    /// # let info = GraphicPipelineInfo::default();
875    /// # let my_graphic_pipeline = GraphicPipeline::create(&device, info, [vert, frag])?;
876    /// # let mut my_graph = Graph::default();
877    /// # let buf_info = BufferInfo::device_mem(8, vk::BufferUsageFlags::INDEX_BUFFER);
878    /// # let my_idx_buf = Buffer::create(&device, buf_info)?;
879    /// # let buf_info = BufferInfo::device_mem(8, vk::BufferUsageFlags::VERTEX_BUFFER);
880    /// # let my_vtx_buf = Buffer::create(&device, buf_info)?;
881    /// # let my_idx_buf = my_graph.bind_resource(my_idx_buf);
882    /// # let my_vtx_buf = my_graph.bind_resource(my_vtx_buf);
883    /// # let info = ImageInfo::image_2d(
884    /// #     32,
885    /// #     32,
886    /// #     vk::Format::R8G8B8A8_UNORM,
887    /// #     vk::ImageUsageFlags::SAMPLED,
888    /// # );
889    /// # let swapchain_image = my_graph.bind_resource(Image::create(&device, info)?);
890    /// const CMD_SIZE: usize = size_of::<vk::DrawIndexedIndirectCommand>();
891    ///
892    /// let cmd = vk::DrawIndexedIndirectCommand {
893    ///     index_count: 3,
894    ///     instance_count: 1,
895    ///     first_index: 0,
896    ///     vertex_offset: 0,
897    ///     first_instance: 0,
898    /// };
899    /// let cmd_data = unsafe {
900    ///     std::slice::from_raw_parts(&cmd as *const _ as *const _, CMD_SIZE)
901    /// };
902    ///
903    /// let buf_flags = vk::BufferUsageFlags::STORAGE_BUFFER;
904    /// let buf = Buffer::create_from_slice(&device, buf_flags, cmd_data)?;
905    /// let buf_node = my_graph.bind_resource(buf);
906    ///
907    /// my_graph
908    ///     .begin_cmd()
909    ///     .debug_name("draw a single triangle")
910    ///     .bind_pipeline(&my_graphic_pipeline)
911    ///     .color_attachment_image(0, swapchain_image, LoadOp::DontCare, StoreOp::Store)
912    ///     .resource_access(my_idx_buf, AccessType::IndexBuffer)
913    ///     .resource_access(my_vtx_buf, AccessType::VertexBuffer)
914    ///     .resource_access(buf_node, AccessType::IndirectBuffer)
915    ///     .record_cmd(move |cmd| {
916    ///         cmd
917    ///             .bind_index_buffer(my_idx_buf, 0, vk::IndexType::UINT16)
918    ///             .bind_vertex_buffer(0, my_vtx_buf, 0)
919    ///             .draw_indexed_indirect(buf_node, 0, 1, 0);
920    ///     });
921    /// # Ok(()) }
922    /// ```
923    #[profiling::function]
924    pub fn draw_indexed_indirect(
925        &self,
926        buffer: impl Into<AnyBufferNode>,
927        offset: vk::DeviceSize,
928        draw_count: u32,
929        stride: u32,
930    ) -> &Self {
931        let buffer = buffer.into();
932        let buffer = self.resource(buffer);
933
934        unsafe {
935            self.cmd.device.cmd_draw_indexed_indirect(
936                self.cmd.handle,
937                buffer.handle,
938                offset,
939                draw_count,
940                stride,
941            );
942        }
943
944        self
945    }
946
947    /// Draw primitives with indirect parameters, indexed vertices, and draw count.
948    ///
949    /// `draw_indexed_indirect_count` behaves similarly to `draw_indexed_indirect` except that the
950    /// draw count is read by the device from `buffer` during execution. The command will read an
951    /// unsigned 32-bit integer from `count_buf` located at `count_buf_offset` and use this as the
952    /// draw count.
953    ///
954    /// `max_draw_count` specifies the maximum number of draws that will be executed. The actual
955    /// number of executed draw calls is the minimum of the count specified in `count_buf` and
956    /// `max_draw_count`.
957    ///
958    /// `stride` is the byte stride between successive sets of draw parameters.
959    #[profiling::function]
960    pub fn draw_indexed_indirect_count(
961        &self,
962        buffer: impl Into<AnyBufferNode>,
963        offset: vk::DeviceSize,
964        count_buf: impl Into<AnyBufferNode>,
965        count_buf_offset: vk::DeviceSize,
966        max_draw_count: u32,
967        stride: u32,
968    ) -> &Self {
969        let buffer = buffer.into();
970        let buffer = self.resource(buffer);
971
972        let count_buf = count_buf.into();
973        let count_buf = self.resource(count_buf);
974
975        unsafe {
976            self.cmd.device.cmd_draw_indexed_indirect_count(
977                self.cmd.handle,
978                buffer.handle,
979                offset,
980                count_buf.handle,
981                count_buf_offset,
982                max_draw_count,
983                stride,
984            );
985        }
986
987        self
988    }
989
990    /// Draw primitives with indirect parameters and unindexed vertices.
991    ///
992    /// Behaves otherwise similar to [`Self::draw_indexed_indirect`].
993    #[profiling::function]
994    pub fn draw_indirect(
995        &self,
996        buffer: impl Into<AnyBufferNode>,
997        offset: vk::DeviceSize,
998        draw_count: u32,
999        stride: u32,
1000    ) -> &Self {
1001        let buffer = buffer.into();
1002        let buffer = self.resource(buffer);
1003
1004        unsafe {
1005            self.cmd.device.cmd_draw_indirect(
1006                self.cmd.handle,
1007                buffer.handle,
1008                offset,
1009                draw_count,
1010                stride,
1011            );
1012        }
1013
1014        self
1015    }
1016
1017    /// Draw primitives with indirect parameters, unindexed vertices, and draw count.
1018    ///
1019    /// Behaves otherwise similar to [`Self::draw_indexed_indirect_count`].
1020    #[profiling::function]
1021    pub fn draw_indirect_count(
1022        &self,
1023        buffer: impl Into<AnyBufferNode>,
1024        offset: vk::DeviceSize,
1025        count_buf: impl Into<AnyBufferNode>,
1026        count_buf_offset: vk::DeviceSize,
1027        max_draw_count: u32,
1028        stride: u32,
1029    ) -> &Self {
1030        let buffer = buffer.into();
1031        let buffer = self.resource(buffer);
1032
1033        let count_buf = count_buf.into();
1034        let count_buf = self.resource(count_buf);
1035
1036        unsafe {
1037            self.cmd.device.cmd_draw_indirect_count(
1038                self.cmd.handle,
1039                buffer.handle,
1040                offset,
1041                count_buf.handle,
1042                count_buf_offset,
1043                max_draw_count,
1044                stride,
1045            );
1046        }
1047
1048        self
1049    }
1050
1051    /// Updates push constants.
1052    ///
1053    /// Push constants represent a high speed path to modify constant data in pipelines that is
1054    /// expected to outperform memory-backed resource updates.
1055    ///
1056    /// Push constant values can be updated incrementally, causing shader stages to read the new
1057    /// data for push constants modified by this command, while still reading the previous data for
1058    /// push constants not modified by this command.
1059    ///
1060    /// # Device limitations
1061    ///
1062    /// See
1063    /// [`device.physical_device.props.limits.max_push_constants_size`](vk::PhysicalDeviceLimits)
1064    /// for the limits of the current device. You may also check [gpuinfo.org] for a listing of
1065    /// reported limits on other devices.
1066    ///
1067    /// # Examples
1068    ///
1069    /// Basic usage:
1070    ///
1071    /// ```
1072    /// # vk_shader_macros::glsl!(r#"
1073    /// #version 450
1074    /// #pragma shader_stage(compute)
1075    ///
1076    /// layout(push_constant) uniform PushConstants {
1077    ///     layout(offset = 0) uint the_answer;
1078    /// } push_constants;
1079    ///
1080    /// void main() {
1081    ///     // TODO: Add code!
1082    /// }
1083    /// # "#);
1084    /// ```
1085    ///
1086    /// ```no_run
1087    /// # use ash::vk;
1088    /// # use vk_graph::cmd::{LoadOp, StoreOp};
1089    /// # use vk_graph::driver::DriverError;
1090    /// # use vk_graph::driver::device::{Device, DeviceInfo};
1091    /// # use vk_graph::driver::graphic::{GraphicPipeline, GraphicPipelineInfo};
1092    /// # use vk_graph::driver::image::{Image, ImageInfo};
1093    /// # use vk_graph::Graph;
1094    /// # use vk_graph::driver::shader::Shader;
1095    /// # fn main() -> Result<(), DriverError> {
1096    /// # let device = Device::new(DeviceInfo::default())?;
1097    /// # let my_frag_code = [0u8; 1];
1098    /// # let my_vert_code = [0u8; 1];
1099    /// # let vert = Shader::new_vertex(my_vert_code.as_slice());
1100    /// # let frag = Shader::new_fragment(my_frag_code.as_slice());
1101    /// # let info = GraphicPipelineInfo::default();
1102    /// # let my_graphic_pipeline = GraphicPipeline::create(&device, info, [vert, frag])?;
1103    /// # let info = ImageInfo::image_2d(
1104    /// #     32,
1105    /// #     32,
1106    /// #     vk::Format::R8G8B8A8_UNORM,
1107    /// #     vk::ImageUsageFlags::SAMPLED,
1108    /// # );
1109    /// # let swapchain_image = Image::create(&device, info)?;
1110    /// # let mut my_graph = Graph::default();
1111    /// # let swapchain_image = my_graph.bind_resource(swapchain_image);
1112    /// my_graph
1113    ///     .begin_cmd()
1114    ///     .debug_name("draw a quad")
1115    ///     .bind_pipeline(&my_graphic_pipeline)
1116    ///     .color_attachment_image(0, swapchain_image, LoadOp::DontCare, StoreOp::Store)
1117    ///     .record_cmd(move |cmd| {
1118    ///         cmd
1119    ///             .push_constants(0, &[42])
1120    ///             .draw(6, 1, 0, 0);
1121    ///     });
1122    /// # Ok(()) }
1123    /// ```
1124    ///
1125    /// See [`vkCmdPushConstants`](https://registry.khronos.org/vulkan/specs/latest/man/html/vkCmdPushConstants.html).
1126    #[profiling::function]
1127    pub fn push_constants(&self, offset: u32, data: &[u8]) -> &Self {
1128        self.cmd_push_constants(
1129            self.pipeline.inner.layout,
1130            &self.pipeline.inner.push_constants,
1131            offset,
1132            data,
1133        );
1134
1135        self
1136    }
1137
1138    /// Set scissor rectangle dynamically for the current command.
1139    ///
1140    /// The default scissor state is no-clip.
1141    #[profiling::function]
1142    pub fn set_scissor(&self, first_scissor: u32, scissors: &[vk::Rect2D]) -> &Self {
1143        unsafe {
1144            self.cmd
1145                .device
1146                .cmd_set_scissor(self.cmd.handle, first_scissor, scissors);
1147        }
1148
1149        self
1150    }
1151
1152    /// Set the viewport dynamically for the current command.
1153    ///
1154    /// The default viewport state is the entire render target as defined by all combined image
1155    /// attachments.
1156    #[profiling::function]
1157    pub fn set_viewport(&self, first_viewport: u32, viewports: &[vk::Viewport]) -> &Self {
1158        unsafe {
1159            self.cmd
1160                .device
1161                .cmd_set_viewport(self.cmd.handle, first_viewport, viewports);
1162        }
1163
1164        self
1165    }
1166}
1167
1168impl<'a> Deref for GraphicCommandRef<'a> {
1169    type Target = CommandRef<'a>;
1170
1171    fn deref(&self) -> &Self::Target {
1172        &self.cmd
1173    }
1174}
1175
1176/// Specifies the state of a color or combined depth and stencil attachment image during graphic
1177/// render pass framebuffer load operations.
1178///
1179/// Use this to specify the desired contents of any image before use in a pipeline command buffer.
1180#[derive(Clone, Copy, Debug)]
1181pub enum LoadOp<T> {
1182    /// Clears the attachment.
1183    ///
1184    /// `T` will be [ClearColorValue] for color images or [vk::ClearDepthStencilValue] for
1185    /// combined depth and stencil images.
1186    Clear(T),
1187
1188    /// The attachment will become undefined and reads will produce garbage data.
1189    DontCare,
1190
1191    /// The attachment will be preserved in memory.
1192    Load,
1193}
1194
1195impl LoadOp<ClearColorValue> {
1196    /// A load operation which results in a color attachment filled with rgb zeros and alpha ones.
1197    pub const CLEAR_BLACK_ALPHA_ONE: Self = Self::Clear(ClearColorValue::BLACK_ALPHA_ONE);
1198
1199    /// A load operation which results in a color attachment filled with zeros.
1200    pub const CLEAR_BLACK_ALPHA_ZERO: Self = Self::Clear(ClearColorValue::BLACK_ALPHA_ZERO);
1201
1202    /// A load operation which results in a color attachment filled with rgb zeros and alpha ones.
1203    pub const CLEAR_WHITE_ALPHA_ONE: Self = Self::Clear(ClearColorValue::WHITE_ALPHA_ONE);
1204
1205    /// A load operation which results in a color attachment filled with rgb ones and alpha zeros.
1206    pub const CLEAR_WHITE_ALPHA_ZERO: Self = Self::Clear(ClearColorValue::WHITE_ALPHA_ZERO);
1207
1208    /// Convenience constructor for clear color values.
1209    pub fn clear_rgba(r: f32, g: f32, b: f32, a: f32) -> Self {
1210        Self::Clear(ClearColorValue::rgba(r, g, b, a))
1211    }
1212}
1213
1214impl LoadOp<vk::ClearDepthStencilValue> {
1215    /// A load operation which results in a depth attachment filled with ones and stencil filled
1216    /// with zeros.
1217    pub const CLEAR_ONE_STENCIL_ZERO: Self = Self::Clear(vk::ClearDepthStencilValue {
1218        depth: 1.0,
1219        stencil: 0,
1220    });
1221
1222    /// A load operation which results in a depth and stencil attachment filled with zeros.
1223    pub const CLEAR_ZERO_STENCIL_ZERO: Self = Self::Clear(vk::ClearDepthStencilValue {
1224        depth: 0.0,
1225        stencil: 0,
1226    });
1227
1228    /// Convenience constructor for clear depth and stencil values.
1229    pub fn clear_depth_stencil(depth: f32, stencil: u32) -> Self {
1230        Self::Clear(vk::ClearDepthStencilValue { depth, stencil })
1231    }
1232}
1233
1234/// Specifies the state of a color or combined depth and stencil attachment image after graphic
1235/// render pass framebuffer store operations.
1236///
1237/// Use this to specify the desired contents of any image after use in a pipeline command buffer.
1238#[derive(Clone, Copy, Debug)]
1239pub enum StoreOp {
1240    /// The attachment will become undefined and reads will produce garbage data.
1241    DontCare,
1242
1243    /// The attachment will be preserved in memory.
1244    Store,
1245}
1246
1247#[allow(unused)]
1248mod deprecated {
1249    use {
1250        crate::{
1251            Attachment, Node, SubresourceAccess,
1252            cmd::{
1253                AttachmentIndex, Binding, ClearColorValue, PipelineCommand, Subresource,
1254                SubresourceRange, ViewInfo, graphic::GraphicCommandRef,
1255            },
1256            driver::{
1257                graphic::GraphicPipeline,
1258                image::{
1259                    ImageInfo, ImageViewInfo, image_subresource_range_contains,
1260                    image_subresource_range_intersects,
1261                },
1262                render_pass::ResolveMode,
1263            },
1264            node::AnyImageNode,
1265        },
1266        ash::vk,
1267        vk_sync::AccessType,
1268    };
1269
1270    impl GraphicCommandRef<'_> {
1271        #[deprecated = "use push_constants function"]
1272        #[doc(hidden)]
1273        pub fn push_constants_offset(&self, offset: u32, data: &[u8]) -> &Self {
1274            self.push_constants(offset, data)
1275        }
1276    }
1277
1278    // Attachment functions from previous version
1279    impl PipelineCommand<'_, GraphicPipeline> {
1280        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1281        #[doc(hidden)]
1282        pub fn attach_color(
1283            self,
1284            attachment_idx: AttachmentIndex,
1285            image: impl Into<AnyImageNode>,
1286        ) -> Self {
1287            let image = image.into();
1288            let image_info = self.resource(image).info;
1289            let image_view_info: ImageViewInfo = image_info.into();
1290
1291            #[allow(deprecated)]
1292            self.attach_color_as(attachment_idx, image, image_view_info)
1293        }
1294
1295        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1296        #[doc(hidden)]
1297        pub fn attach_color_as(
1298            mut self,
1299            attachment_idx: AttachmentIndex,
1300            image: impl Into<AnyImageNode>,
1301            image_view_info: impl Into<ImageViewInfo>,
1302        ) -> Self {
1303            #[allow(deprecated)]
1304            self.set_attach_color_as(attachment_idx, image, image_view_info);
1305
1306            self
1307        }
1308
1309        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1310        #[doc(hidden)]
1311        pub fn attach_depth_stencil(self, image: impl Into<AnyImageNode>) -> Self {
1312            let image = image.into();
1313            let image_view_info = self.resource(image).info;
1314
1315            #[allow(deprecated)]
1316            self.attach_depth_stencil_as(image, image_view_info)
1317        }
1318
1319        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1320        #[doc(hidden)]
1321        pub fn attach_depth_stencil_as(
1322            mut self,
1323            image: impl Into<AnyImageNode>,
1324            image_view_info: impl Into<ImageViewInfo>,
1325        ) -> Self {
1326            #[allow(deprecated)]
1327            self.set_attach_depth_stencil_as(image, image_view_info);
1328
1329            self
1330        }
1331
1332        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1333        #[doc(hidden)]
1334        pub fn clear_color(
1335            self,
1336            attachment_idx: AttachmentIndex,
1337            image: impl Into<AnyImageNode>,
1338        ) -> Self {
1339            #[allow(deprecated)]
1340            self.clear_color_value(attachment_idx, image, [0.0, 0.0, 0.0, 0.0])
1341        }
1342
1343        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1344        #[doc(hidden)]
1345        pub fn clear_color_value(
1346            self,
1347            attachment_idx: AttachmentIndex,
1348            image: impl Into<AnyImageNode>,
1349            color: impl Into<ClearColorValue>,
1350        ) -> Self {
1351            let image = image.into();
1352            let image_info = self.resource(image).info;
1353            let image_view_info: ImageViewInfo = image_info.into();
1354
1355            #[allow(deprecated)]
1356            self.clear_color_value_as(attachment_idx, image, color, image_view_info)
1357        }
1358
1359        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1360        #[doc(hidden)]
1361        pub fn clear_color_value_as(
1362            mut self,
1363            attachment_idx: AttachmentIndex,
1364            image: impl Into<AnyImageNode>,
1365            color: impl Into<ClearColorValue>,
1366            image_view_info: impl Into<ImageViewInfo>,
1367        ) -> Self {
1368            #[allow(deprecated)]
1369            self.set_clear_color_value_as(attachment_idx, image, color, image_view_info);
1370
1371            self
1372        }
1373
1374        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1375        #[doc(hidden)]
1376        pub fn clear_depth_stencil(self, image: impl Into<AnyImageNode>) -> Self {
1377            #[allow(deprecated)]
1378            self.clear_depth_stencil_value(image, 1.0, 0)
1379        }
1380
1381        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1382        #[doc(hidden)]
1383        pub fn clear_depth_stencil_value(
1384            self,
1385            image: impl Into<AnyImageNode>,
1386            depth: f32,
1387            stencil: u32,
1388        ) -> Self {
1389            let image = image.into();
1390            let image_info = self.resource(image).info;
1391            let image_view_info: ImageViewInfo = image_info.into();
1392
1393            #[allow(deprecated)]
1394            self.clear_depth_stencil_value_as(image, depth, stencil, image_view_info)
1395        }
1396
1397        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1398        #[doc(hidden)]
1399        pub fn clear_depth_stencil_value_as(
1400            mut self,
1401            image: impl Into<AnyImageNode>,
1402            depth: f32,
1403            stencil: u32,
1404            image_view_info: impl Into<ImageViewInfo>,
1405        ) -> Self {
1406            #[allow(deprecated)]
1407            self.set_clear_depth_stencil_value_as(image, depth, stencil, image_view_info);
1408
1409            self
1410        }
1411
1412        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1413        #[doc(hidden)]
1414        pub fn load_color(
1415            self,
1416            attachment_idx: AttachmentIndex,
1417            image: impl Into<AnyImageNode>,
1418        ) -> Self {
1419            let image = image.into();
1420            let image_info = self.resource(image).info;
1421
1422            // Use the plain node information as the whole view of the node
1423            let image_view_info = image_info;
1424
1425            #[allow(deprecated)]
1426            self.load_color_as(attachment_idx, image, image_view_info)
1427        }
1428
1429        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1430        #[doc(hidden)]
1431        pub fn load_color_as(
1432            mut self,
1433            attachment_idx: AttachmentIndex,
1434            image: impl Into<AnyImageNode>,
1435            image_view_info: impl Into<ImageViewInfo>,
1436        ) -> Self {
1437            #[allow(deprecated)]
1438            self.set_load_color_as(attachment_idx, image, image_view_info);
1439
1440            self
1441        }
1442
1443        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1444        #[doc(hidden)]
1445        pub fn load_depth_stencil(self, image: impl Into<AnyImageNode>) -> Self {
1446            let image = image.into();
1447            let image_view_info = self.resource(image).info;
1448
1449            #[allow(deprecated)]
1450            self.load_depth_stencil_as(image, image_view_info)
1451        }
1452
1453        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1454        #[doc(hidden)]
1455        pub fn load_depth_stencil_as(
1456            mut self,
1457            image: impl Into<AnyImageNode>,
1458            image_view_info: impl Into<ImageViewInfo>,
1459        ) -> Self {
1460            #[allow(deprecated)]
1461            self.set_load_depth_stencil_as(image, image_view_info);
1462
1463            self
1464        }
1465
1466        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1467        #[doc(hidden)]
1468        pub fn store_color(
1469            self,
1470            attachment_idx: AttachmentIndex,
1471            image: impl Into<AnyImageNode>,
1472        ) -> Self {
1473            let image = image.into();
1474            let image_view_info = self.resource(image).info;
1475
1476            #[allow(deprecated)]
1477            self.store_color_as(attachment_idx, image, image_view_info)
1478        }
1479
1480        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1481        #[doc(hidden)]
1482        pub fn store_color_as(
1483            mut self,
1484            attachment_idx: AttachmentIndex,
1485            image: impl Into<AnyImageNode>,
1486            image_view_info: impl Into<ImageViewInfo>,
1487        ) -> Self {
1488            #[allow(deprecated)]
1489            self.set_store_color_as(attachment_idx, image, image_view_info);
1490
1491            self
1492        }
1493
1494        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1495        #[doc(hidden)]
1496        pub fn store_depth_stencil(self, image: impl Into<AnyImageNode>) -> Self {
1497            let image = image.into();
1498            let image_view_info = self.resource(image).info;
1499
1500            #[allow(deprecated)]
1501            self.store_depth_stencil_as(image, image_view_info)
1502        }
1503
1504        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1505        #[doc(hidden)]
1506        pub fn store_depth_stencil_as(
1507            mut self,
1508            image: impl Into<AnyImageNode>,
1509            image_view_info: impl Into<ImageViewInfo>,
1510        ) -> Self {
1511            #[allow(deprecated)]
1512            self.set_store_depth_stencil_as(image, image_view_info);
1513
1514            self
1515        }
1516
1517        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1518        #[doc(hidden)]
1519        pub fn resolve_color(
1520            self,
1521            src_attachment_idx: AttachmentIndex,
1522            dst_attachment_idx: AttachmentIndex,
1523            image: impl Into<AnyImageNode>,
1524        ) -> Self {
1525            let image = image.into();
1526            let image_view_info = self.resource(image).info;
1527
1528            #[allow(deprecated)]
1529            self.resolve_color_as(
1530                src_attachment_idx,
1531                dst_attachment_idx,
1532                image,
1533                image_view_info,
1534            )
1535        }
1536
1537        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1538        #[doc(hidden)]
1539        pub fn resolve_color_as(
1540            mut self,
1541            src_attachment_idx: AttachmentIndex,
1542            dst_attachment_idx: AttachmentIndex,
1543            image: impl Into<AnyImageNode>,
1544            image_view_info: impl Into<ImageViewInfo>,
1545        ) -> Self {
1546            #[allow(deprecated)]
1547            self.set_resolve_color_as(
1548                src_attachment_idx,
1549                dst_attachment_idx,
1550                image,
1551                image_view_info,
1552            );
1553
1554            self
1555        }
1556
1557        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1558        #[doc(hidden)]
1559        pub fn resolve_depth_stencil(
1560            self,
1561            dst_attachment_idx: AttachmentIndex,
1562            image: impl Into<AnyImageNode>,
1563            depth_mode: Option<ResolveMode>,
1564            stencil_mode: Option<ResolveMode>,
1565        ) -> Self {
1566            let image = image.into();
1567            let image_view_info = self.resource(image).info;
1568
1569            #[allow(deprecated)]
1570            self.resolve_depth_stencil_as(
1571                dst_attachment_idx,
1572                image,
1573                image_view_info,
1574                depth_mode,
1575                stencil_mode,
1576            )
1577        }
1578
1579        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1580        #[doc(hidden)]
1581        pub fn resolve_depth_stencil_as(
1582            mut self,
1583            dst_attachment_idx: AttachmentIndex,
1584            image: impl Into<AnyImageNode>,
1585            image_view_info: impl Into<ImageViewInfo>,
1586            depth_mode: Option<ResolveMode>,
1587            stencil_mode: Option<ResolveMode>,
1588        ) -> Self {
1589            #[allow(deprecated)]
1590            self.set_resolve_depth_stencil_as(
1591                dst_attachment_idx,
1592                image,
1593                image_view_info,
1594                depth_mode,
1595                stencil_mode,
1596            );
1597
1598            self
1599        }
1600    }
1601
1602    // Attachment functions as setters
1603    impl PipelineCommand<'_, GraphicPipeline> {
1604        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1605        #[doc(hidden)]
1606        pub fn set_attach_color(
1607            &mut self,
1608            attachment_idx: AttachmentIndex,
1609            image: impl Into<AnyImageNode>,
1610        ) -> &mut Self {
1611            let image = image.into();
1612            let image_info = self.resource(image).info;
1613            let image_view_info: ImageViewInfo = image_info.into();
1614
1615            #[allow(deprecated)]
1616            self.set_attach_color_as(attachment_idx, image, image_view_info)
1617        }
1618
1619        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1620        #[doc(hidden)]
1621        pub fn set_attach_color_as(
1622            &mut self,
1623            attachment_idx: AttachmentIndex,
1624            image: impl Into<AnyImageNode>,
1625            image_view_info: impl Into<ImageViewInfo>,
1626        ) -> &mut Self {
1627            let image = image.into();
1628            let image_view_info = image_view_info.into();
1629            let node_idx = image.index();
1630            let ImageInfo { sample_count, .. } = self.resource(image).info;
1631
1632            debug_assert!(
1633                !self
1634                    .cmd
1635                    .cmd()
1636                    .expect_last_exec()
1637                    .color_clears
1638                    .contains_key(&attachment_idx),
1639                "color attachment {attachment_idx} already attached via clear"
1640            );
1641            debug_assert!(
1642                !self
1643                    .cmd
1644                    .cmd()
1645                    .expect_last_exec()
1646                    .color_loads
1647                    .contains_key(&attachment_idx),
1648                "color attachment {attachment_idx} already attached via load"
1649            );
1650
1651            self.cmd
1652                .cmd_mut()
1653                .expect_last_exec_mut()
1654                .color_attachments
1655                .insert(
1656                    attachment_idx,
1657                    Attachment::new(image_view_info, sample_count, node_idx),
1658                );
1659
1660            debug_assert!(
1661                Attachment::are_compatible(
1662                    self.cmd
1663                        .cmd()
1664                        .expect_last_exec()
1665                        .color_resolves
1666                        .get(&attachment_idx)
1667                        .map(|(attachment, _)| *attachment),
1668                    self.cmd
1669                        .cmd()
1670                        .expect_last_exec()
1671                        .color_attachments
1672                        .get(&attachment_idx)
1673                        .copied()
1674                ),
1675                "color attachment {attachment_idx} incompatible with existing resolve"
1676            );
1677            debug_assert!(
1678                Attachment::are_compatible(
1679                    self.cmd
1680                        .cmd()
1681                        .expect_last_exec()
1682                        .color_stores
1683                        .get(&attachment_idx)
1684                        .copied(),
1685                    self.cmd
1686                        .cmd()
1687                        .expect_last_exec()
1688                        .color_attachments
1689                        .get(&attachment_idx)
1690                        .copied()
1691                ),
1692                "color attachment {attachment_idx} incompatible with existing store"
1693            );
1694
1695            self.cmd.push_subresource_access(
1696                image,
1697                SubresourceRange::Image(image_view_info.into()),
1698                AccessType::ColorAttachmentWrite,
1699            );
1700
1701            self
1702        }
1703
1704        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1705        #[doc(hidden)]
1706        pub fn set_attach_depth_stencil(&mut self, image: impl Into<AnyImageNode>) -> &mut Self {
1707            let image = image.into();
1708            let image_view_info = self.resource(image).info;
1709
1710            #[allow(deprecated)]
1711            self.set_attach_depth_stencil_as(image, image_view_info)
1712        }
1713
1714        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1715        #[doc(hidden)]
1716        pub fn set_attach_depth_stencil_as(
1717            &mut self,
1718            image: impl Into<AnyImageNode>,
1719            image_view_info: impl Into<ImageViewInfo>,
1720        ) -> &mut Self {
1721            let image = image.into();
1722            let image_view_info = image_view_info.into();
1723            let node_idx = image.index();
1724            let ImageInfo { sample_count, .. } = self.resource(image).info;
1725
1726            debug_assert!(
1727                self.cmd
1728                    .cmd()
1729                    .expect_last_exec()
1730                    .depth_stencil_clear
1731                    .is_none(),
1732                "depth/stencil attachment already attached via clear"
1733            );
1734            debug_assert!(
1735                self.cmd
1736                    .cmd()
1737                    .expect_last_exec()
1738                    .depth_stencil_load
1739                    .is_none(),
1740                "depth/stencil attachment already attached via load"
1741            );
1742
1743            self.cmd
1744                .cmd_mut()
1745                .expect_last_exec_mut()
1746                .depth_stencil_attachment =
1747                Some(Attachment::new(image_view_info, sample_count, node_idx));
1748
1749            debug_assert!(
1750                Attachment::are_compatible(
1751                    self.cmd
1752                        .cmd()
1753                        .expect_last_exec()
1754                        .depth_stencil_resolve
1755                        .map(|(attachment, ..)| attachment),
1756                    self.cmd.cmd().expect_last_exec().depth_stencil_attachment
1757                ),
1758                "depth/stencil attachment incompatible with existing resolve"
1759            );
1760            debug_assert!(
1761                Attachment::are_compatible(
1762                    self.cmd.cmd().expect_last_exec().depth_stencil_store,
1763                    self.cmd.cmd().expect_last_exec().depth_stencil_attachment
1764                ),
1765                "depth/stencil attachment incompatible with existing store"
1766            );
1767
1768            self.cmd.push_subresource_access(
1769                image,
1770                SubresourceRange::Image(image_view_info.into()),
1771                if image_view_info
1772                    .aspect_mask
1773                    .contains(vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL)
1774                {
1775                    AccessType::DepthStencilAttachmentWrite
1776                } else if image_view_info
1777                    .aspect_mask
1778                    .contains(vk::ImageAspectFlags::DEPTH)
1779                {
1780                    AccessType::DepthAttachmentWriteStencilReadOnly
1781                } else {
1782                    AccessType::StencilAttachmentWriteDepthReadOnly
1783                },
1784            );
1785
1786            self
1787        }
1788
1789        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1790        #[doc(hidden)]
1791        pub fn set_clear_color(
1792            &mut self,
1793            attachment_idx: AttachmentIndex,
1794            image: impl Into<AnyImageNode>,
1795        ) -> &mut Self {
1796            #[allow(deprecated)]
1797            self.set_clear_color_value(attachment_idx, image, [0.0, 0.0, 0.0, 0.0])
1798        }
1799
1800        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1801        #[doc(hidden)]
1802        pub fn set_clear_color_value(
1803            &mut self,
1804            attachment_idx: AttachmentIndex,
1805            image: impl Into<AnyImageNode>,
1806            color: impl Into<ClearColorValue>,
1807        ) -> &mut Self {
1808            let image = image.into();
1809            let image_info = self.resource(image).info;
1810            let image_view_info: ImageViewInfo = image_info.into();
1811
1812            #[allow(deprecated)]
1813            self.set_clear_color_value_as(attachment_idx, image, color, image_view_info)
1814        }
1815
1816        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1817        #[doc(hidden)]
1818        pub fn set_clear_color_value_as(
1819            &mut self,
1820            attachment_idx: AttachmentIndex,
1821            image: impl Into<AnyImageNode>,
1822            color: impl Into<ClearColorValue>,
1823            image_view_info: impl Into<ImageViewInfo>,
1824        ) -> &mut Self {
1825            let image = image.into();
1826            let image_view_info = image_view_info.into();
1827            let node_idx = image.index();
1828            let ImageInfo { sample_count, .. } = self.resource(image).info;
1829
1830            let color = color.into();
1831            let color: vk::ClearColorValue = color.into();
1832            let color = unsafe { color.float32 };
1833
1834            debug_assert!(
1835                !self
1836                    .cmd
1837                    .cmd()
1838                    .expect_last_exec()
1839                    .color_attachments
1840                    .contains_key(&attachment_idx),
1841                "color attachment {attachment_idx} already attached"
1842            );
1843            debug_assert!(
1844                !self
1845                    .cmd
1846                    .cmd()
1847                    .expect_last_exec()
1848                    .color_loads
1849                    .contains_key(&attachment_idx),
1850                "color attachment {attachment_idx} already attached via load"
1851            );
1852
1853            self.cmd
1854                .cmd_mut()
1855                .expect_last_exec_mut()
1856                .color_clears
1857                .insert(
1858                    attachment_idx,
1859                    (
1860                        Attachment::new(image_view_info, sample_count, node_idx),
1861                        color,
1862                    ),
1863                );
1864
1865            debug_assert!(
1866                Attachment::are_compatible(
1867                    self.cmd
1868                        .cmd()
1869                        .expect_last_exec()
1870                        .color_resolves
1871                        .get(&attachment_idx)
1872                        .map(|(attachment, _)| *attachment),
1873                    self.cmd
1874                        .cmd()
1875                        .expect_last_exec()
1876                        .color_clears
1877                        .get(&attachment_idx)
1878                        .map(|(attachment, _)| *attachment)
1879                ),
1880                "color attachment {attachment_idx} clear incompatible with existing resolve"
1881            );
1882            debug_assert!(
1883                Attachment::are_compatible(
1884                    self.cmd
1885                        .cmd()
1886                        .expect_last_exec()
1887                        .color_stores
1888                        .get(&attachment_idx)
1889                        .copied(),
1890                    self.cmd
1891                        .cmd()
1892                        .expect_last_exec()
1893                        .color_clears
1894                        .get(&attachment_idx)
1895                        .map(|(attachment, _)| *attachment)
1896                ),
1897                "color attachment {attachment_idx} clear incompatible with existing store"
1898            );
1899
1900            let mut image_access = AccessType::ColorAttachmentWrite;
1901            let image_range = image_view_info.into();
1902
1903            // Upgrade existing read access to read-write
1904            if let Some(accesses) = self
1905                .cmd
1906                .cmd_mut()
1907                .expect_last_exec_mut()
1908                .accesses
1909                .get_mut(&node_idx)
1910            {
1911                for SubresourceAccess {
1912                    access,
1913                    subresource,
1914                } in accesses
1915                {
1916                    let access_image_range = *subresource.expect_image();
1917                    if !image_subresource_range_intersects(access_image_range, image_range) {
1918                        continue;
1919                    }
1920
1921                    image_access = match *access {
1922                        AccessType::ColorAttachmentRead | AccessType::ColorAttachmentReadWrite => {
1923                            AccessType::ColorAttachmentReadWrite
1924                        }
1925                        AccessType::ColorAttachmentWrite => AccessType::ColorAttachmentWrite,
1926                        _ => continue,
1927                    };
1928
1929                    *access = image_access;
1930
1931                    // If the clear access is a subset of the existing access range there is no need
1932                    // to push a new access
1933                    if image_subresource_range_contains(access_image_range, image_range) {
1934                        return self;
1935                    }
1936                }
1937            }
1938
1939            self.cmd.push_subresource_access(
1940                image,
1941                SubresourceRange::Image(image_range),
1942                image_access,
1943            );
1944
1945            self
1946        }
1947
1948        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1949        #[doc(hidden)]
1950        pub fn set_clear_depth_stencil(&mut self, image: impl Into<AnyImageNode>) -> &mut Self {
1951            #[allow(deprecated)]
1952            self.set_clear_depth_stencil_value(image, 1.0, 0)
1953        }
1954
1955        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1956        #[doc(hidden)]
1957        pub fn set_clear_depth_stencil_value(
1958            &mut self,
1959            image: impl Into<AnyImageNode>,
1960            depth: f32,
1961            stencil: u32,
1962        ) -> &mut Self {
1963            let image = image.into();
1964            let image_info = self.resource(image).info;
1965            let image_view_info: ImageViewInfo = image_info.into();
1966
1967            #[allow(deprecated)]
1968            self.set_clear_depth_stencil_value_as(image, depth, stencil, image_view_info)
1969        }
1970
1971        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
1972        #[doc(hidden)]
1973        pub fn set_clear_depth_stencil_value_as(
1974            &mut self,
1975            image: impl Into<AnyImageNode>,
1976            depth: f32,
1977            stencil: u32,
1978            image_view_info: impl Into<ImageViewInfo>,
1979        ) -> &mut Self {
1980            let image = image.into();
1981            let image_view_info = image_view_info.into();
1982            let node_idx = image.index();
1983            let ImageInfo { sample_count, .. } = self.resource(image).info;
1984
1985            debug_assert!(
1986                self.cmd
1987                    .cmd()
1988                    .expect_last_exec()
1989                    .depth_stencil_attachment
1990                    .is_none(),
1991                "depth/stencil attachment already attached"
1992            );
1993            debug_assert!(
1994                self.cmd
1995                    .cmd()
1996                    .expect_last_exec()
1997                    .depth_stencil_load
1998                    .is_none(),
1999                "depth/stencil attachment already attached via load"
2000            );
2001
2002            self.cmd
2003                .cmd_mut()
2004                .expect_last_exec_mut()
2005                .depth_stencil_clear = Some((
2006                Attachment::new(image_view_info, sample_count, node_idx),
2007                vk::ClearDepthStencilValue { depth, stencil },
2008            ));
2009
2010            debug_assert!(
2011                Attachment::are_compatible(
2012                    self.cmd
2013                        .cmd()
2014                        .expect_last_exec()
2015                        .depth_stencil_resolve
2016                        .map(|(attachment, ..)| attachment),
2017                    self.cmd
2018                        .cmd()
2019                        .expect_last_exec()
2020                        .depth_stencil_clear
2021                        .map(|(attachment, _)| attachment)
2022                ),
2023                "depth/stencil attachment clear incompatible with existing resolve"
2024            );
2025            debug_assert!(
2026                Attachment::are_compatible(
2027                    self.cmd.cmd().expect_last_exec().depth_stencil_store,
2028                    self.cmd
2029                        .cmd()
2030                        .expect_last_exec()
2031                        .depth_stencil_clear
2032                        .map(|(attachment, _)| attachment)
2033                ),
2034                "depth/stencil attachment clear incompatible with existing store"
2035            );
2036
2037            let mut image_access = if image_view_info
2038                .aspect_mask
2039                .contains(vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL)
2040            {
2041                AccessType::DepthStencilAttachmentWrite
2042            } else if image_view_info
2043                .aspect_mask
2044                .contains(vk::ImageAspectFlags::DEPTH)
2045            {
2046                AccessType::DepthAttachmentWriteStencilReadOnly
2047            } else {
2048                debug_assert!(
2049                    image_view_info
2050                        .aspect_mask
2051                        .contains(vk::ImageAspectFlags::STENCIL)
2052                );
2053
2054                AccessType::StencilAttachmentWriteDepthReadOnly
2055            };
2056            let image_range = image_view_info.into();
2057
2058            // Upgrade existing read access to read-write
2059            if let Some(accesses) = self
2060                .cmd
2061                .cmd_mut()
2062                .expect_last_exec_mut()
2063                .accesses
2064                .get_mut(&node_idx)
2065            {
2066                for SubresourceAccess {
2067                    access,
2068                    subresource,
2069                } in accesses
2070                {
2071                    let access_image_range = *subresource.expect_image();
2072                    if !image_subresource_range_intersects(access_image_range, image_range) {
2073                        continue;
2074                    }
2075
2076                    image_access = match *access {
2077                        AccessType::DepthAttachmentWriteStencilReadOnly => {
2078                            if image_view_info
2079                                .aspect_mask
2080                                .contains(vk::ImageAspectFlags::STENCIL)
2081                            {
2082                                AccessType::DepthStencilAttachmentReadWrite
2083                            } else {
2084                                AccessType::DepthAttachmentWriteStencilReadOnly
2085                            }
2086                        }
2087                        AccessType::DepthStencilAttachmentRead => {
2088                            if !image_view_info
2089                                .aspect_mask
2090                                .contains(vk::ImageAspectFlags::DEPTH)
2091                            {
2092                                AccessType::StencilAttachmentWriteDepthReadOnly
2093                            } else {
2094                                AccessType::DepthAttachmentWriteStencilReadOnly
2095                            }
2096                        }
2097                        AccessType::DepthStencilAttachmentWrite => {
2098                            AccessType::DepthStencilAttachmentWrite
2099                        }
2100                        AccessType::StencilAttachmentWriteDepthReadOnly => {
2101                            if image_view_info
2102                                .aspect_mask
2103                                .contains(vk::ImageAspectFlags::DEPTH)
2104                            {
2105                                AccessType::DepthStencilAttachmentReadWrite
2106                            } else {
2107                                AccessType::StencilAttachmentWriteDepthReadOnly
2108                            }
2109                        }
2110                        _ => continue,
2111                    };
2112
2113                    *access = image_access;
2114
2115                    // If the clear access is a subset of the existing access range there is no need
2116                    // to push a new access
2117                    if image_subresource_range_contains(access_image_range, image_range) {
2118                        return self;
2119                    }
2120                }
2121            }
2122
2123            self.cmd.push_subresource_access(
2124                image,
2125                SubresourceRange::Image(image_range),
2126                image_access,
2127            );
2128
2129            self
2130        }
2131
2132        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
2133        #[doc(hidden)]
2134        pub fn set_load_color(
2135            &mut self,
2136            attachment_idx: AttachmentIndex,
2137            image: impl Into<AnyImageNode>,
2138        ) -> &mut Self {
2139            let image = image.into();
2140            let image_info = self.resource(image).info;
2141
2142            // Use the plain node information as the whole view of the node
2143            let image_view_info = image_info;
2144
2145            #[allow(deprecated)]
2146            self.set_load_color_as(attachment_idx, image, image_view_info)
2147        }
2148
2149        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
2150        #[doc(hidden)]
2151        pub fn set_load_color_as(
2152            &mut self,
2153            attachment_idx: AttachmentIndex,
2154            image: impl Into<AnyImageNode>,
2155            image_view_info: impl Into<ImageViewInfo>,
2156        ) -> &mut Self {
2157            let image = image.into();
2158            let image_view_info = image_view_info.into();
2159            let node_idx = image.index();
2160            let ImageInfo { sample_count, .. } = self.resource(image).info;
2161
2162            debug_assert!(
2163                !self
2164                    .cmd
2165                    .cmd()
2166                    .expect_last_exec()
2167                    .color_attachments
2168                    .contains_key(&attachment_idx),
2169                "color attachment {attachment_idx} already attached"
2170            );
2171            debug_assert!(
2172                !self
2173                    .cmd
2174                    .cmd()
2175                    .expect_last_exec()
2176                    .color_clears
2177                    .contains_key(&attachment_idx),
2178                "color attachment {attachment_idx} already attached via clear"
2179            );
2180
2181            self.cmd
2182                .cmd_mut()
2183                .expect_last_exec_mut()
2184                .color_loads
2185                .insert(
2186                    attachment_idx,
2187                    Attachment::new(image_view_info, sample_count, node_idx),
2188                );
2189
2190            debug_assert!(
2191                Attachment::are_compatible(
2192                    self.cmd
2193                        .cmd()
2194                        .expect_last_exec()
2195                        .color_resolves
2196                        .get(&attachment_idx)
2197                        .map(|(attachment, _)| *attachment),
2198                    self.cmd
2199                        .cmd()
2200                        .expect_last_exec()
2201                        .color_loads
2202                        .get(&attachment_idx)
2203                        .copied()
2204                ),
2205                "color attachment {attachment_idx} load incompatible with existing resolve"
2206            );
2207            debug_assert!(
2208                Attachment::are_compatible(
2209                    self.cmd
2210                        .cmd()
2211                        .expect_last_exec()
2212                        .color_stores
2213                        .get(&attachment_idx)
2214                        .copied(),
2215                    self.cmd
2216                        .cmd()
2217                        .expect_last_exec()
2218                        .color_loads
2219                        .get(&attachment_idx)
2220                        .copied()
2221                ),
2222                "color attachment {attachment_idx} load incompatible with existing store"
2223            );
2224
2225            let mut image_access = AccessType::ColorAttachmentRead;
2226            let image_range = image_view_info.into();
2227
2228            // Upgrade existing write access to read-write
2229            if let Some(accesses) = self
2230                .cmd
2231                .cmd_mut()
2232                .expect_last_exec_mut()
2233                .accesses
2234                .get_mut(&node_idx)
2235            {
2236                for SubresourceAccess {
2237                    access,
2238                    subresource,
2239                } in accesses
2240                {
2241                    let access_image_range = *subresource.expect_image();
2242                    if !image_subresource_range_intersects(access_image_range, image_range) {
2243                        continue;
2244                    }
2245
2246                    image_access = match *access {
2247                        AccessType::ColorAttachmentRead => AccessType::ColorAttachmentRead,
2248                        AccessType::ColorAttachmentReadWrite | AccessType::ColorAttachmentWrite => {
2249                            AccessType::ColorAttachmentReadWrite
2250                        }
2251                        _ => continue,
2252                    };
2253
2254                    *access = image_access;
2255
2256                    // If the load access is a subset of the existing access range there is no need
2257                    // to push a new access
2258                    if image_subresource_range_contains(access_image_range, image_range) {
2259                        return self;
2260                    }
2261                }
2262            }
2263
2264            self.cmd.push_subresource_access(
2265                image,
2266                SubresourceRange::Image(image_range),
2267                image_access,
2268            );
2269
2270            self
2271        }
2272
2273        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
2274        #[doc(hidden)]
2275        pub fn set_load_depth_stencil(&mut self, image: impl Into<AnyImageNode>) -> &mut Self {
2276            let image = image.into();
2277            let image_view_info = self.resource(image).info;
2278
2279            #[allow(deprecated)]
2280            self.set_load_depth_stencil_as(image, image_view_info)
2281        }
2282
2283        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
2284        #[doc(hidden)]
2285        pub fn set_load_depth_stencil_as(
2286            &mut self,
2287            image: impl Into<AnyImageNode>,
2288            image_view_info: impl Into<ImageViewInfo>,
2289        ) -> &mut Self {
2290            let image = image.into();
2291            let image_view_info = image_view_info.into();
2292            let node_idx = image.index();
2293            let ImageInfo { sample_count, .. } = self.resource(image).info;
2294
2295            debug_assert!(
2296                self.cmd
2297                    .cmd()
2298                    .expect_last_exec()
2299                    .depth_stencil_attachment
2300                    .is_none(),
2301                "depth/stencil attachment already attached"
2302            );
2303            debug_assert!(
2304                self.cmd
2305                    .cmd()
2306                    .expect_last_exec()
2307                    .depth_stencil_clear
2308                    .is_none(),
2309                "depth/stencil attachment already attached via clear"
2310            );
2311
2312            self.cmd.cmd_mut().expect_last_exec_mut().depth_stencil_load =
2313                Some(Attachment::new(image_view_info, sample_count, node_idx));
2314
2315            debug_assert!(
2316                Attachment::are_compatible(
2317                    self.cmd
2318                        .cmd()
2319                        .expect_last_exec()
2320                        .depth_stencil_resolve
2321                        .map(|(attachment, ..)| attachment),
2322                    self.cmd.cmd().expect_last_exec().depth_stencil_load
2323                ),
2324                "depth/stencil attachment load incompatible with existing resolve"
2325            );
2326            debug_assert!(
2327                Attachment::are_compatible(
2328                    self.cmd.cmd().expect_last_exec().depth_stencil_store,
2329                    self.cmd.cmd().expect_last_exec().depth_stencil_load
2330                ),
2331                "depth/stencil attachment load incompatible with existing store"
2332            );
2333
2334            let mut image_access = AccessType::DepthStencilAttachmentRead;
2335            let image_range = image_view_info.into();
2336
2337            // Upgrade existing write access to read-write
2338            if let Some(accesses) = self
2339                .cmd
2340                .cmd_mut()
2341                .expect_last_exec_mut()
2342                .accesses
2343                .get_mut(&node_idx)
2344            {
2345                for SubresourceAccess {
2346                    access,
2347                    subresource,
2348                } in accesses
2349                {
2350                    let access_image_range = *subresource.expect_image();
2351                    if !image_subresource_range_intersects(access_image_range, image_range) {
2352                        continue;
2353                    }
2354
2355                    image_access = match *access {
2356                        AccessType::DepthAttachmentWriteStencilReadOnly => {
2357                            AccessType::DepthAttachmentWriteStencilReadOnly
2358                        }
2359                        AccessType::DepthStencilAttachmentRead => {
2360                            AccessType::DepthStencilAttachmentRead
2361                        }
2362                        AccessType::DepthStencilAttachmentWrite => {
2363                            AccessType::DepthStencilAttachmentReadWrite
2364                        }
2365                        AccessType::StencilAttachmentWriteDepthReadOnly => {
2366                            AccessType::StencilAttachmentWriteDepthReadOnly
2367                        }
2368                        _ => continue,
2369                    };
2370
2371                    *access = image_access;
2372
2373                    // If the load access is a subset of the existing access range there is no need
2374                    // to push a new access
2375                    if image_subresource_range_contains(access_image_range, image_range) {
2376                        return self;
2377                    }
2378                }
2379            }
2380
2381            self.cmd.push_subresource_access(
2382                image,
2383                SubresourceRange::Image(image_range),
2384                image_access,
2385            );
2386
2387            self
2388        }
2389
2390        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
2391        #[doc(hidden)]
2392        pub fn set_store_color(
2393            &mut self,
2394            attachment_idx: AttachmentIndex,
2395            image: impl Into<AnyImageNode>,
2396        ) -> &mut Self {
2397            let image = image.into();
2398            let image_view_info = self.resource(image).info;
2399
2400            #[allow(deprecated)]
2401            self.set_store_color_as(attachment_idx, image, image_view_info)
2402        }
2403
2404        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
2405        #[doc(hidden)]
2406        pub fn set_store_color_as(
2407            &mut self,
2408            attachment_idx: AttachmentIndex,
2409            image: impl Into<AnyImageNode>,
2410            image_view_info: impl Into<ImageViewInfo>,
2411        ) -> &mut Self {
2412            let image = image.into();
2413            let image_view_info = image_view_info.into();
2414            let node_idx = image.index();
2415            let ImageInfo { sample_count, .. } = self.resource(image).info;
2416
2417            self.cmd
2418                .cmd_mut()
2419                .expect_last_exec_mut()
2420                .color_stores
2421                .insert(
2422                    attachment_idx,
2423                    Attachment::new(image_view_info, sample_count, node_idx),
2424                );
2425
2426            debug_assert!(
2427                Attachment::are_compatible(
2428                    self.cmd
2429                        .cmd()
2430                        .expect_last_exec()
2431                        .color_attachments
2432                        .get(&attachment_idx)
2433                        .copied(),
2434                    self.cmd
2435                        .cmd()
2436                        .expect_last_exec()
2437                        .color_stores
2438                        .get(&attachment_idx)
2439                        .copied()
2440                ),
2441                "color attachment {attachment_idx} store incompatible with existing attachment"
2442            );
2443            debug_assert!(
2444                Attachment::are_compatible(
2445                    self.cmd
2446                        .cmd()
2447                        .expect_last_exec()
2448                        .color_clears
2449                        .get(&attachment_idx)
2450                        .map(|(attachment, _)| *attachment),
2451                    self.cmd
2452                        .cmd()
2453                        .expect_last_exec()
2454                        .color_stores
2455                        .get(&attachment_idx)
2456                        .copied()
2457                ),
2458                "color attachment {attachment_idx} store incompatible with existing clear"
2459            );
2460            debug_assert!(
2461                Attachment::are_compatible(
2462                    self.cmd
2463                        .cmd()
2464                        .expect_last_exec()
2465                        .color_loads
2466                        .get(&attachment_idx)
2467                        .copied(),
2468                    self.cmd
2469                        .cmd()
2470                        .expect_last_exec()
2471                        .color_stores
2472                        .get(&attachment_idx)
2473                        .copied()
2474                ),
2475                "color attachment {attachment_idx} store incompatible with existing load"
2476            );
2477
2478            let mut image_access = AccessType::ColorAttachmentWrite;
2479            let image_range = image_view_info.into();
2480
2481            // Upgrade existing read access to read-write
2482            if let Some(accesses) = self
2483                .cmd
2484                .cmd_mut()
2485                .expect_last_exec_mut()
2486                .accesses
2487                .get_mut(&node_idx)
2488            {
2489                for SubresourceAccess {
2490                    access,
2491                    subresource,
2492                } in accesses
2493                {
2494                    let access_image_range = *subresource.expect_image();
2495                    if !image_subresource_range_intersects(access_image_range, image_range) {
2496                        continue;
2497                    }
2498
2499                    image_access = match *access {
2500                        AccessType::ColorAttachmentRead | AccessType::ColorAttachmentReadWrite => {
2501                            AccessType::ColorAttachmentReadWrite
2502                        }
2503                        AccessType::ColorAttachmentWrite => AccessType::ColorAttachmentWrite,
2504                        _ => continue,
2505                    };
2506
2507                    *access = image_access;
2508
2509                    // If the store access is a subset of the existing access range there is no need
2510                    // to push a new access
2511                    if image_subresource_range_contains(access_image_range, image_range) {
2512                        return self;
2513                    }
2514                }
2515            }
2516
2517            self.cmd.push_subresource_access(
2518                image,
2519                SubresourceRange::Image(image_range),
2520                image_access,
2521            );
2522
2523            self
2524        }
2525
2526        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
2527        #[doc(hidden)]
2528        pub fn set_store_depth_stencil(&mut self, image: impl Into<AnyImageNode>) -> &mut Self {
2529            let image = image.into();
2530            let image_view_info = self.resource(image).info;
2531
2532            #[allow(deprecated)]
2533            self.set_store_depth_stencil_as(image, image_view_info)
2534        }
2535
2536        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
2537        #[doc(hidden)]
2538        pub fn set_store_depth_stencil_as(
2539            &mut self,
2540            image: impl Into<AnyImageNode>,
2541            image_view_info: impl Into<ImageViewInfo>,
2542        ) -> &mut Self {
2543            let image = image.into();
2544            let image_view_info = image_view_info.into();
2545            let node_idx = image.index();
2546            let ImageInfo { sample_count, .. } = self.resource(image).info;
2547
2548            self.cmd
2549                .cmd_mut()
2550                .expect_last_exec_mut()
2551                .depth_stencil_store =
2552                Some(Attachment::new(image_view_info, sample_count, node_idx));
2553
2554            debug_assert!(
2555                Attachment::are_compatible(
2556                    self.cmd.cmd().expect_last_exec().depth_stencil_attachment,
2557                    self.cmd.cmd().expect_last_exec().depth_stencil_store
2558                ),
2559                "depth/stencil attachment store incompatible with existing attachment"
2560            );
2561            debug_assert!(
2562                Attachment::are_compatible(
2563                    self.cmd
2564                        .cmd()
2565                        .expect_last_exec()
2566                        .depth_stencil_clear
2567                        .map(|(attachment, _)| attachment),
2568                    self.cmd.cmd().expect_last_exec().depth_stencil_store
2569                ),
2570                "depth/stencil attachment store incompatible with existing clear"
2571            );
2572            debug_assert!(
2573                Attachment::are_compatible(
2574                    self.cmd.cmd().expect_last_exec().depth_stencil_load,
2575                    self.cmd.cmd().expect_last_exec().depth_stencil_store
2576                ),
2577                "depth/stencil attachment store incompatible with existing load"
2578            );
2579
2580            let mut image_access = if image_view_info
2581                .aspect_mask
2582                .contains(vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL)
2583            {
2584                AccessType::DepthStencilAttachmentWrite
2585            } else if image_view_info
2586                .aspect_mask
2587                .contains(vk::ImageAspectFlags::DEPTH)
2588            {
2589                AccessType::DepthAttachmentWriteStencilReadOnly
2590            } else {
2591                debug_assert!(
2592                    image_view_info
2593                        .aspect_mask
2594                        .contains(vk::ImageAspectFlags::STENCIL)
2595                );
2596
2597                AccessType::StencilAttachmentWriteDepthReadOnly
2598            };
2599            let image_range = image_view_info.into();
2600
2601            // Upgrade existing read access to read-write
2602            if let Some(accesses) = self
2603                .cmd
2604                .cmd_mut()
2605                .expect_last_exec_mut()
2606                .accesses
2607                .get_mut(&node_idx)
2608            {
2609                for SubresourceAccess {
2610                    access,
2611                    subresource,
2612                } in accesses
2613                {
2614                    let access_image_range = *subresource.expect_image();
2615                    if !image_subresource_range_intersects(access_image_range, image_range) {
2616                        continue;
2617                    }
2618
2619                    image_access = match *access {
2620                        AccessType::DepthAttachmentWriteStencilReadOnly => {
2621                            if image_view_info
2622                                .aspect_mask
2623                                .contains(vk::ImageAspectFlags::STENCIL)
2624                            {
2625                                AccessType::DepthStencilAttachmentReadWrite
2626                            } else {
2627                                AccessType::DepthAttachmentWriteStencilReadOnly
2628                            }
2629                        }
2630                        AccessType::DepthStencilAttachmentRead => {
2631                            if !image_view_info
2632                                .aspect_mask
2633                                .contains(vk::ImageAspectFlags::DEPTH)
2634                            {
2635                                AccessType::StencilAttachmentWriteDepthReadOnly
2636                            } else {
2637                                AccessType::DepthStencilAttachmentReadWrite
2638                            }
2639                        }
2640                        AccessType::DepthStencilAttachmentWrite => {
2641                            AccessType::DepthStencilAttachmentWrite
2642                        }
2643                        AccessType::StencilAttachmentWriteDepthReadOnly => {
2644                            if image_view_info
2645                                .aspect_mask
2646                                .contains(vk::ImageAspectFlags::DEPTH)
2647                            {
2648                                AccessType::DepthStencilAttachmentReadWrite
2649                            } else {
2650                                AccessType::StencilAttachmentWriteDepthReadOnly
2651                            }
2652                        }
2653                        _ => continue,
2654                    };
2655
2656                    *access = image_access;
2657
2658                    // If the store access is a subset of the existing access range there is no need
2659                    // to push a new access
2660                    if image_subresource_range_contains(access_image_range, image_range) {
2661                        return self;
2662                    }
2663                }
2664            }
2665
2666            self.cmd.push_subresource_access(
2667                image,
2668                SubresourceRange::Image(image_range),
2669                image_access,
2670            );
2671
2672            self
2673        }
2674
2675        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
2676        #[doc(hidden)]
2677        pub fn set_resolve_color(
2678            &mut self,
2679            src_attachment_idx: AttachmentIndex,
2680            dst_attachment_idx: AttachmentIndex,
2681            image: impl Into<AnyImageNode>,
2682        ) -> &mut Self {
2683            let image = image.into();
2684            let image_view_info = self.resource(image).info;
2685
2686            #[allow(deprecated)]
2687            self.set_resolve_color_as(
2688                src_attachment_idx,
2689                dst_attachment_idx,
2690                image,
2691                image_view_info,
2692            )
2693        }
2694
2695        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
2696        #[doc(hidden)]
2697        pub fn set_resolve_color_as(
2698            &mut self,
2699            src_attachment_idx: AttachmentIndex,
2700            dst_attachment_idx: AttachmentIndex,
2701            image: impl Into<AnyImageNode>,
2702            image_view_info: impl Into<ImageViewInfo>,
2703        ) -> &mut Self {
2704            let image = image.into();
2705            let image_view_info = image_view_info.into();
2706            let node_idx = image.index();
2707            let ImageInfo { sample_count, .. } = self.resource(image).info;
2708
2709            self.cmd
2710                .cmd_mut()
2711                .expect_last_exec_mut()
2712                .color_resolves
2713                .insert(
2714                    dst_attachment_idx,
2715                    (
2716                        Attachment::new(image_view_info, sample_count, node_idx),
2717                        src_attachment_idx,
2718                    ),
2719                );
2720
2721            debug_assert!(
2722                Attachment::are_compatible(
2723                    self.cmd
2724                        .cmd()
2725                        .expect_last_exec()
2726                        .color_attachments
2727                        .get(&dst_attachment_idx)
2728                        .copied(),
2729                    self.cmd
2730                        .cmd()
2731                        .expect_last_exec()
2732                        .color_resolves
2733                        .get(&dst_attachment_idx)
2734                        .map(|(attachment, _)| *attachment)
2735                ),
2736                "color attachment {dst_attachment_idx} resolve conflict",
2737            );
2738            debug_assert!(
2739                Attachment::are_compatible(
2740                    self.cmd
2741                        .cmd()
2742                        .expect_last_exec()
2743                        .color_clears
2744                        .get(&dst_attachment_idx)
2745                        .map(|(attachment, _)| *attachment),
2746                    self.cmd
2747                        .cmd()
2748                        .expect_last_exec()
2749                        .color_resolves
2750                        .get(&dst_attachment_idx)
2751                        .map(|(attachment, _)| *attachment)
2752                ),
2753                "color attachment {dst_attachment_idx} resolve incompatible with existing clear"
2754            );
2755            debug_assert!(
2756                Attachment::are_compatible(
2757                    self.cmd
2758                        .cmd()
2759                        .expect_last_exec()
2760                        .color_loads
2761                        .get(&dst_attachment_idx)
2762                        .copied(),
2763                    self.cmd
2764                        .cmd()
2765                        .expect_last_exec()
2766                        .color_resolves
2767                        .get(&dst_attachment_idx)
2768                        .map(|(attachment, _)| *attachment)
2769                ),
2770                "color attachment {dst_attachment_idx} resolve incompatible with existing load"
2771            );
2772
2773            let mut image_access = AccessType::ColorAttachmentWrite;
2774            let image_range = image_view_info.into();
2775
2776            // Upgrade existing read access to read-write
2777            if let Some(accesses) = self
2778                .cmd
2779                .cmd_mut()
2780                .expect_last_exec_mut()
2781                .accesses
2782                .get_mut(&node_idx)
2783            {
2784                for SubresourceAccess {
2785                    access,
2786                    subresource,
2787                } in accesses
2788                {
2789                    let access_image_range = *subresource.expect_image();
2790                    if !image_subresource_range_intersects(access_image_range, image_range) {
2791                        continue;
2792                    }
2793
2794                    image_access = match *access {
2795                        AccessType::ColorAttachmentRead | AccessType::ColorAttachmentReadWrite => {
2796                            AccessType::ColorAttachmentReadWrite
2797                        }
2798                        AccessType::ColorAttachmentWrite => AccessType::ColorAttachmentWrite,
2799                        _ => continue,
2800                    };
2801
2802                    *access = image_access;
2803
2804                    // If the resolve access is a subset of the existing access range there is no
2805                    // need to push a new access
2806                    if image_subresource_range_contains(access_image_range, image_range) {
2807                        return self;
2808                    }
2809                }
2810            }
2811
2812            self.cmd.push_subresource_access(
2813                image,
2814                SubresourceRange::Image(image_range),
2815                image_access,
2816            );
2817
2818            self
2819        }
2820
2821        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
2822        #[doc(hidden)]
2823        pub fn set_resolve_depth_stencil(
2824            &mut self,
2825            dst_attachment_idx: AttachmentIndex,
2826            image: impl Into<AnyImageNode>,
2827            depth_mode: Option<ResolveMode>,
2828            stencil_mode: Option<ResolveMode>,
2829        ) -> &mut Self {
2830            let image = image.into();
2831            let image_view_info = self.resource(image).info;
2832
2833            #[allow(deprecated)]
2834            self.set_resolve_depth_stencil_as(
2835                dst_attachment_idx,
2836                image,
2837                image_view_info,
2838                depth_mode,
2839                stencil_mode,
2840            )
2841        }
2842
2843        #[deprecated = "upgrade guide: https://github.com/attackgoat/vk-graph/pull/107"]
2844        #[doc(hidden)]
2845        pub fn set_resolve_depth_stencil_as(
2846            &mut self,
2847            dst_attachment_idx: AttachmentIndex,
2848            image: impl Into<AnyImageNode>,
2849            image_view_info: impl Into<ImageViewInfo>,
2850            depth_mode: Option<ResolveMode>,
2851            stencil_mode: Option<ResolveMode>,
2852        ) -> &mut Self {
2853            let image = image.into();
2854            let image_view_info = image_view_info.into();
2855            let node_idx = image.index();
2856            let ImageInfo { sample_count, .. } = self.resource(image).info;
2857
2858            self.cmd
2859                .cmd_mut()
2860                .expect_last_exec_mut()
2861                .depth_stencil_resolve = Some((
2862                Attachment::new(image_view_info, sample_count, node_idx),
2863                dst_attachment_idx,
2864                depth_mode,
2865                stencil_mode,
2866            ));
2867
2868            let mut image_access = if image_view_info
2869                .aspect_mask
2870                .contains(vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL)
2871            {
2872                AccessType::DepthStencilAttachmentWrite
2873            } else if image_view_info
2874                .aspect_mask
2875                .contains(vk::ImageAspectFlags::DEPTH)
2876            {
2877                AccessType::DepthAttachmentWriteStencilReadOnly
2878            } else {
2879                debug_assert!(
2880                    image_view_info
2881                        .aspect_mask
2882                        .contains(vk::ImageAspectFlags::STENCIL)
2883                );
2884
2885                AccessType::StencilAttachmentWriteDepthReadOnly
2886            };
2887            let image_range = image_view_info.into();
2888
2889            // Upgrade existing read access to read-write
2890            if let Some(accesses) = self
2891                .cmd
2892                .cmd_mut()
2893                .expect_last_exec_mut()
2894                .accesses
2895                .get_mut(&node_idx)
2896            {
2897                for SubresourceAccess {
2898                    access,
2899                    subresource,
2900                } in accesses
2901                {
2902                    let access_image_range = *subresource.expect_image();
2903                    if !image_subresource_range_intersects(access_image_range, image_range) {
2904                        continue;
2905                    }
2906
2907                    image_access = match *access {
2908                        AccessType::DepthAttachmentWriteStencilReadOnly => {
2909                            if image_view_info
2910                                .aspect_mask
2911                                .contains(vk::ImageAspectFlags::STENCIL)
2912                            {
2913                                AccessType::DepthStencilAttachmentReadWrite
2914                            } else {
2915                                AccessType::DepthAttachmentWriteStencilReadOnly
2916                            }
2917                        }
2918                        AccessType::DepthStencilAttachmentRead => {
2919                            if !image_view_info
2920                                .aspect_mask
2921                                .contains(vk::ImageAspectFlags::DEPTH)
2922                            {
2923                                AccessType::StencilAttachmentWriteDepthReadOnly
2924                            } else {
2925                                AccessType::DepthStencilAttachmentReadWrite
2926                            }
2927                        }
2928                        AccessType::DepthStencilAttachmentWrite => {
2929                            AccessType::DepthStencilAttachmentWrite
2930                        }
2931                        AccessType::StencilAttachmentWriteDepthReadOnly => {
2932                            if image_view_info
2933                                .aspect_mask
2934                                .contains(vk::ImageAspectFlags::DEPTH)
2935                            {
2936                                AccessType::DepthStencilAttachmentReadWrite
2937                            } else {
2938                                AccessType::StencilAttachmentWriteDepthReadOnly
2939                            }
2940                        }
2941                        _ => continue,
2942                    };
2943
2944                    *access = image_access;
2945
2946                    // If the resolve access is a subset of the existing access range there is no
2947                    // need to push a new access
2948                    if image_subresource_range_contains(access_image_range, image_range) {
2949                        return self;
2950                    }
2951                }
2952            }
2953
2954            self.cmd.push_subresource_access(
2955                image,
2956                SubresourceRange::Image(image_range),
2957                image_access,
2958            );
2959
2960            self
2961        }
2962    }
2963
2964    // Resource functions
2965    impl PipelineCommand<'_, GraphicPipeline> {
2966        #[deprecated = "use shader_resource_access"]
2967        #[doc(hidden)]
2968        pub fn read_descriptor<N>(self, binding: impl Into<Binding>, node: N) -> Self
2969        where
2970            N: Node + Subresource,
2971            N::Info: Copy,
2972            SubresourceRange: From<N::Info>,
2973            ViewInfo: From<N::Info>,
2974        {
2975            self.shader_resource_access(
2976                binding,
2977                node,
2978                AccessType::AnyShaderReadSampledImageOrUniformTexelBuffer,
2979            )
2980        }
2981
2982        #[deprecated = "use shader_subresource_access"]
2983        #[doc(hidden)]
2984        pub fn read_descriptor_as<N>(
2985            self,
2986            descriptor: impl Into<Binding>,
2987            node: N,
2988            node_view: impl Into<N::Info>,
2989        ) -> Self
2990        where
2991            N: Node + Subresource,
2992            N::Info: Copy,
2993            SubresourceRange: From<N::Info>,
2994            ViewInfo: From<N::Info>,
2995        {
2996            self.shader_subresource_access(
2997                descriptor,
2998                node,
2999                node_view,
3000                AccessType::AnyShaderReadSampledImageOrUniformTexelBuffer,
3001            )
3002        }
3003
3004        #[deprecated = "use record_cmd function"]
3005        #[doc(hidden)]
3006        pub fn record_subpass(
3007            self,
3008            func: impl FnOnce(GraphicCommandRef<'_>, ()) + Send + 'static,
3009        ) -> Self {
3010            self.record_cmd(|cmd| {
3011                func(cmd, ());
3012            })
3013        }
3014
3015        #[deprecated = "use shader_resource_access function with AccessType::AnyShaderWrite"]
3016        #[doc(hidden)]
3017        pub fn write_descriptor<N>(self, descriptor: impl Into<Binding>, node: N) -> Self
3018        where
3019            N: Node + Subresource,
3020            N::Info: Copy,
3021            SubresourceRange: From<N::Info>,
3022            ViewInfo: From<N::Info>,
3023        {
3024            self.shader_resource_access(descriptor, node, AccessType::AnyShaderWrite)
3025        }
3026
3027        #[deprecated = "use shader_subresource_access function with AccessType::AnyShaderWrite"]
3028        #[doc(hidden)]
3029        pub fn write_descriptor_as<N>(
3030            self,
3031            descriptor: impl Into<Binding>,
3032            node: N,
3033            node_view: impl Into<N::Info>,
3034        ) -> Self
3035        where
3036            N: Node + Subresource,
3037            N::Info: Copy,
3038            SubresourceRange: From<N::Info>,
3039            ViewInfo: From<N::Info>,
3040        {
3041            self.shader_subresource_access(descriptor, node, node_view, AccessType::AnyShaderWrite)
3042        }
3043    }
3044}