Skip to main content

vk_graph/
lib.rs

1/*!
2
3This crate provides a high-performance [Vulkan](https://www.vulkan.org/) driver featuring automated
4resource management and execution.
5
6For an overview, including installation and typical usage, see the
7[Guide Book](https://attackgoat.github.io/vk-graph).
8
9
10
11
12*/
13
14#![deny(missing_docs)]
15#![deny(rustdoc::broken_intra_doc_links)]
16
17pub mod cmd;
18pub mod driver;
19pub mod node;
20pub mod pool;
21
22mod submission;
23
24use std::sync::Arc;
25
26use crate::{
27    cmd::{ClearColorValue, CommandRef},
28    driver::{
29        accel_struct::AccelerationStructure, buffer::Buffer, image::Image,
30        swapchain::SwapchainImage,
31    },
32    pool::Lease,
33};
34
35pub use self::submission::Submission;
36
37#[allow(deprecated)]
38pub use self::deprecated::{Display, DisplayInfo, DisplayInfoBuilder};
39
40use {
41    self::{
42        cmd::{AttachmentIndex, Binding, Command, SubresourceAccess, ViewInfo},
43        node::{
44            AccelerationStructureLeaseNode, AccelerationStructureNode,
45            AnyAccelerationStructureNode, AnyBufferNode, AnyImageNode, BufferLeaseNode, BufferNode,
46            ImageLeaseNode, ImageNode, SwapchainImageNode,
47        },
48    },
49    crate::driver::{
50        DescriptorBindingMap,
51        compute::ComputePipeline,
52        format_aspect_mask, format_texel_block_extent, format_texel_block_size,
53        graphic::{DepthStencilInfo, GraphicPipeline},
54        image::{ImageInfo, ImageViewInfo, SampleCount},
55        image_subresource_range_from_layers,
56        ray_trace::RayTracePipeline,
57        render_pass::ResolveMode,
58        shader::PipelineDescriptorInfo,
59    },
60    ash::vk,
61    std::{
62        cmp::Ord,
63        collections::{BTreeMap, HashMap},
64        fmt::{Debug, Formatter},
65        ops::Range,
66    },
67    vk_sync::AccessType,
68};
69
70type ExecFn = Box<dyn FnOnce(CommandRef) + Send>;
71type NodeIndex = usize;
72
73#[derive(Debug)]
74#[doc(hidden)]
75pub enum AnyResource {
76    AccelerationStructure(Arc<AccelerationStructure>),
77    AccelerationStructureLease(Arc<Lease<AccelerationStructure>>),
78    Buffer(Arc<Buffer>),
79    BufferLease(Arc<Lease<Buffer>>),
80    Image(Arc<Image>),
81    ImageLease(Arc<Lease<Image>>),
82    SwapchainImage(Box<SwapchainImage>),
83}
84
85impl AnyResource {
86    fn as_accel_struct(&self) -> Option<&AccelerationStructure> {
87        Some(match self {
88            Self::AccelerationStructure(resource) => resource,
89            Self::AccelerationStructureLease(resource) => resource,
90            _ => return None,
91        })
92    }
93
94    fn as_buffer(&self) -> Option<&Buffer> {
95        Some(match self {
96            Self::Buffer(resource) => resource,
97            Self::BufferLease(resource) => resource,
98            _ => return None,
99        })
100    }
101
102    fn as_image(&self) -> Option<&Image> {
103        Some(match self {
104            Self::Image(resource) => resource,
105            Self::ImageLease(resource) => resource,
106            Self::SwapchainImage(resource) => resource,
107            _ => return None,
108        })
109    }
110
111    fn as_swapchain_image(&self) -> Option<&SwapchainImage> {
112        Some(match self {
113            Self::SwapchainImage(resource) => resource,
114            _ => return None,
115        })
116    }
117
118    fn expect_accel_struct(&self) -> &AccelerationStructure {
119        self.as_accel_struct()
120            .expect("missing acceleration structure resource")
121    }
122
123    fn expect_buffer(&self) -> &Buffer {
124        self.as_buffer().expect("missing buffer resource")
125    }
126
127    fn expect_image(&self) -> &Image {
128        self.as_image().expect("missing image resource")
129    }
130}
131
132#[derive(Clone, Copy, Debug)]
133struct Attachment {
134    array_layer_count: u32,
135    aspect_mask: vk::ImageAspectFlags,
136    base_array_layer: u32,
137    base_mip_level: u32,
138    format: vk::Format,
139    mip_level_count: u32,
140    sample_count: SampleCount,
141    target: NodeIndex,
142}
143
144impl Attachment {
145    fn new(image_view_info: ImageViewInfo, sample_count: SampleCount, target: NodeIndex) -> Self {
146        Self {
147            array_layer_count: image_view_info.array_layer_count,
148            aspect_mask: image_view_info.aspect_mask,
149            base_array_layer: image_view_info.base_array_layer,
150            base_mip_level: image_view_info.base_mip_level,
151            format: image_view_info.fmt,
152            mip_level_count: image_view_info.mip_level_count,
153            sample_count,
154            target,
155        }
156    }
157
158    fn are_compatible(lhs: Option<Self>, rhs: Option<Self>) -> bool {
159        // Two attachment references are compatible if they have matching format and sample
160        // count, or are both VK_ATTACHMENT_UNUSED or the pointer that would contain the
161        // reference is NULL.
162        let (Some(lhs), Some(rhs)) = (lhs, rhs) else {
163            return true;
164        };
165
166        Self::are_identical(lhs, rhs)
167    }
168
169    fn are_identical(lhs: Self, rhs: Self) -> bool {
170        lhs.array_layer_count == rhs.array_layer_count
171            && lhs.base_array_layer == rhs.base_array_layer
172            && lhs.base_mip_level == rhs.base_mip_level
173            && lhs.format == rhs.format
174            && lhs.mip_level_count == rhs.mip_level_count
175            && lhs.sample_count == rhs.sample_count
176            && lhs.target == rhs.target
177    }
178
179    fn image_view_info(self, image_info: ImageInfo) -> ImageViewInfo {
180        image_info
181            .into_builder()
182            .array_layer_count(self.array_layer_count)
183            .mip_level_count(self.mip_level_count)
184            .fmt(self.format)
185            .into_image_view()
186            .aspect_mask(self.aspect_mask)
187            .base_array_layer(self.base_array_layer)
188            .base_mip_level(self.base_mip_level)
189            .build()
190    }
191}
192
193#[derive(Default)]
194struct Execution {
195    accesses: HashMap<NodeIndex, Vec<SubresourceAccess>>,
196    bindings: BTreeMap<Binding, (NodeIndex, ViewInfo)>,
197
198    correlated_view_mask: u32,
199    depth_stencil: Option<DepthStencilInfo>,
200    render_area: Option<vk::Rect2D>,
201    view_mask: u32,
202
203    color_attachments: HashMap<AttachmentIndex, Attachment>,
204    color_clears: HashMap<AttachmentIndex, (Attachment, [f32; 4])>,
205    color_loads: HashMap<AttachmentIndex, Attachment>,
206    color_resolves: HashMap<AttachmentIndex, (Attachment, AttachmentIndex)>,
207    color_stores: HashMap<AttachmentIndex, Attachment>,
208    depth_stencil_attachment: Option<Attachment>,
209    depth_stencil_clear: Option<(Attachment, vk::ClearDepthStencilValue)>,
210    depth_stencil_load: Option<Attachment>,
211    depth_stencil_resolve: Option<(
212        Attachment,
213        AttachmentIndex,
214        Option<ResolveMode>,
215        Option<ResolveMode>,
216    )>,
217    depth_stencil_store: Option<Attachment>,
218
219    func: Option<ExecutionFunction>,
220    pipeline: Option<ExecutionPipeline>,
221}
222
223impl Debug for Execution {
224    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
225        // The only field missing is func which cannot easily be implemented because it is a
226        // FnOnce.
227        f.debug_struct("Execution")
228            .field("accesses", &self.accesses)
229            .field("bindings", &self.bindings)
230            .field("depth_stencil", &self.depth_stencil)
231            .field("color_attachments", &self.color_attachments)
232            .field("color_clears", &self.color_clears)
233            .field("color_loads", &self.color_loads)
234            .field("color_resolves", &self.color_resolves)
235            .field("color_stores", &self.color_stores)
236            .field("depth_stencil_attachment", &self.depth_stencil_attachment)
237            .field("depth_stencil_clear", &self.depth_stencil_clear)
238            .field("depth_stencil_load", &self.depth_stencil_load)
239            .field("depth_stencil_resolve", &self.depth_stencil_resolve)
240            .field("depth_stencil_store", &self.depth_stencil_store)
241            .field("pipeline", &self.pipeline)
242            .finish()
243    }
244}
245
246struct ExecutionFunction(ExecFn);
247
248#[derive(Clone, Debug)]
249enum ExecutionPipeline {
250    Compute(ComputePipeline),
251    Graphic(GraphicPipeline),
252    RayTrace(RayTracePipeline),
253}
254
255impl ExecutionPipeline {
256    fn as_graphic(&self) -> Option<&GraphicPipeline> {
257        if let Self::Graphic(pipeline) = self {
258            Some(pipeline)
259        } else {
260            None
261        }
262    }
263
264    fn bind_point(&self) -> vk::PipelineBindPoint {
265        match self {
266            ExecutionPipeline::Compute(_) => vk::PipelineBindPoint::COMPUTE,
267            ExecutionPipeline::Graphic(_) => vk::PipelineBindPoint::GRAPHICS,
268            ExecutionPipeline::RayTrace(_) => vk::PipelineBindPoint::RAY_TRACING_KHR,
269        }
270    }
271
272    fn descriptor_bindings(&self) -> &DescriptorBindingMap {
273        match self {
274            ExecutionPipeline::Compute(pipeline) => &pipeline.inner.descriptor_bindings,
275            ExecutionPipeline::Graphic(pipeline) => &pipeline.inner.descriptor_bindings,
276            ExecutionPipeline::RayTrace(pipeline) => &pipeline.inner.descriptor_bindings,
277        }
278    }
279
280    fn descriptor_info(&self) -> &PipelineDescriptorInfo {
281        match self {
282            ExecutionPipeline::Compute(pipeline) => &pipeline.inner.descriptor_info,
283            ExecutionPipeline::Graphic(pipeline) => &pipeline.inner.descriptor_info,
284            ExecutionPipeline::RayTrace(pipeline) => &pipeline.inner.descriptor_info,
285        }
286    }
287
288    fn expect_compute(&self) -> &ComputePipeline {
289        if let Self::Compute(pipeline) = self {
290            pipeline
291        } else {
292            panic!("missing compute pipeline")
293        }
294    }
295
296    fn expect_graphic(&self) -> &GraphicPipeline {
297        self.as_graphic().expect("missing graphic pipeline")
298    }
299
300    fn expect_ray_trace(&self) -> &RayTracePipeline {
301        if let Self::RayTrace(pipeline) = self {
302            pipeline
303        } else {
304            panic!("missing ray trace pipeline")
305        }
306    }
307
308    fn layout(&self) -> vk::PipelineLayout {
309        match self {
310            ExecutionPipeline::Compute(pipeline) => pipeline.inner.layout,
311            ExecutionPipeline::Graphic(pipeline) => pipeline.inner.layout,
312            ExecutionPipeline::RayTrace(pipeline) => pipeline.inner.layout,
313        }
314    }
315
316    fn stage(&self) -> vk::PipelineStageFlags {
317        match self {
318            ExecutionPipeline::Compute(_) => vk::PipelineStageFlags::COMPUTE_SHADER,
319            ExecutionPipeline::Graphic(_) => vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT,
320            ExecutionPipeline::RayTrace(_) => vk::PipelineStageFlags::RAY_TRACING_SHADER_KHR,
321        }
322    }
323}
324
325#[derive(Debug)]
326struct CommandData {
327    execs: Vec<Execution>,
328    name: Option<String>,
329}
330
331impl CommandData {
332    fn descriptor_pools_sizes(
333        &self,
334    ) -> impl Iterator<Item = impl Iterator<Item = (&vk::DescriptorType, &u32)>> {
335        self.execs
336            .iter()
337            .flat_map(|exec| &exec.pipeline)
338            .map(|pipeline| {
339                pipeline
340                    .descriptor_info()
341                    .pool_sizes
342                    .values()
343                    .flat_map(HashMap::iter)
344            })
345    }
346
347    fn expect_first_exec(&self) -> &Execution {
348        self.execs.first().expect("missing command execution")
349    }
350
351    /// # Panics
352    ///
353    /// Panics if the execution list is empty (a command always has at least one execution).
354    fn expect_last_exec(&self) -> &Execution {
355        self.execs.last().expect("missing command execution")
356    }
357
358    /// # Panics
359    ///
360    /// Panics if the execution list is empty (a command always has at least one execution).
361    fn expect_last_exec_mut(&mut self) -> &mut Execution {
362        self.execs.last_mut().expect("missing command execution")
363    }
364
365    fn expect_last_pipeline(&self) -> &ExecutionPipeline {
366        self.expect_last_exec()
367            .pipeline
368            .as_ref()
369            .expect("missing command pipeline")
370    }
371
372    fn name(&self) -> &str {
373        self.name.as_deref().unwrap_or("command")
374    }
375}
376
377/// A composable graph of Vulkan command buffer operations.
378///
379/// `Graph` instances are are intended for one-time use.
380///
381/// The design of this code originated with a combination of
382/// [`PassBuilder`](https://github.com/EmbarkStudios/kajiya/blob/main/crates/lib/kajiya-rg/src/pass_builder.rs)
383/// and
384/// [`graph.cpp`](https://github.com/Themaister/Granite/blob/master/renderer/graph.cpp).
385#[derive(Debug, Default)]
386pub struct Graph {
387    cmds: Vec<CommandData>,
388    resources: Vec<AnyResource>,
389}
390
391impl Graph {
392    /// Constructs a default `Graph`.
393    pub fn new() -> Self {
394        Self::default()
395    }
396
397    /// Allocates and begins writing a new command.
398    pub fn begin_cmd(&mut self) -> Command<'_> {
399        Command::new(self)
400    }
401
402    /// Binds a Vulkan buffer, image, or acceleration structure resource to this graph.
403    ///
404    /// Bound resource nodes may be used in commands for shader pipeline operations and other
405    /// general functions.
406    pub fn bind_resource<R>(&mut self, resource: R) -> R::Node
407    where
408        R: Resource,
409    {
410        resource.bind_graph(self)
411    }
412
413    /// Copy an image, potentially performing format conversion.
414    pub fn blit_image(
415        &mut self,
416        src: impl Into<AnyImageNode>,
417        dst: impl Into<AnyImageNode>,
418        filter: vk::Filter,
419    ) -> &mut Self {
420        let src = src.into();
421        let src_info = self.resource(src).info;
422
423        let dst = dst.into();
424        let dst_info = self.resource(dst).info;
425
426        self.blit_image_region(
427            src,
428            dst,
429            filter,
430            [vk::ImageBlit {
431                src_subresource: vk::ImageSubresourceLayers {
432                    aspect_mask: format_aspect_mask(src_info.fmt),
433                    mip_level: 0,
434                    base_array_layer: 0,
435                    layer_count: 1,
436                },
437                src_offsets: [
438                    vk::Offset3D { x: 0, y: 0, z: 0 },
439                    vk::Offset3D {
440                        x: src_info.width as _,
441                        y: src_info.height as _,
442                        z: src_info.depth as _,
443                    },
444                ],
445                dst_subresource: vk::ImageSubresourceLayers {
446                    aspect_mask: format_aspect_mask(dst_info.fmt),
447                    mip_level: 0,
448                    base_array_layer: 0,
449                    layer_count: 1,
450                },
451                dst_offsets: [
452                    vk::Offset3D { x: 0, y: 0, z: 0 },
453                    vk::Offset3D {
454                        x: dst_info.width as _,
455                        y: dst_info.height as _,
456                        z: dst_info.depth as _,
457                    },
458                ],
459            }],
460        )
461    }
462
463    /// Copy regions of an image, potentially performing format conversion.
464    #[profiling::function]
465    pub fn blit_image_region(
466        &mut self,
467        src: impl Into<AnyImageNode>,
468        dst: impl Into<AnyImageNode>,
469        filter: vk::Filter,
470        regions: impl AsRef<[vk::ImageBlit]> + 'static + Send,
471    ) -> &mut Self {
472        let src = src.into();
473        let dst = dst.into();
474
475        let mut cmd = self.begin_cmd().debug_name("blit image");
476
477        for region in regions.as_ref() {
478            let src_region = image_subresource_range_from_layers(region.src_subresource);
479            cmd.set_subresource_access(src, src_region, AccessType::TransferRead);
480
481            let dst_region = image_subresource_range_from_layers(region.dst_subresource);
482            cmd.set_subresource_access(dst, dst_region, AccessType::TransferWrite);
483        }
484
485        cmd.record_cmd(move |cmd| {
486            let src_image = cmd.resource(src).handle;
487            let dst_image = cmd.resource(dst).handle;
488
489            unsafe {
490                cmd.device.cmd_blit_image(
491                    cmd.handle,
492                    src_image,
493                    vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
494                    dst_image,
495                    vk::ImageLayout::TRANSFER_DST_OPTIMAL,
496                    regions.as_ref(),
497                    filter,
498                );
499            }
500        })
501        .end_cmd()
502    }
503
504    /// Clear a color image.
505    #[profiling::function]
506    pub fn clear_color_image(
507        &mut self,
508        image: impl Into<AnyImageNode>,
509        color: impl Into<ClearColorValue>,
510    ) -> &mut Self {
511        let color = color.into().into();
512        let image = image.into();
513        let image_view = self.resource(image).info.into();
514
515        self.begin_cmd()
516            .debug_name("clear color")
517            .subresource_access(image, image_view, AccessType::TransferWrite)
518            .record_cmd(move |cmd| {
519                let image = cmd.resource(image);
520
521                unsafe {
522                    cmd.device.cmd_clear_color_image(
523                        cmd.handle,
524                        image.handle,
525                        vk::ImageLayout::TRANSFER_DST_OPTIMAL,
526                        &color,
527                        &[image_view],
528                    );
529                }
530            })
531            .end_cmd()
532    }
533
534    /// Clears a depth/stencil image.
535    #[profiling::function]
536    pub fn clear_depth_stencil_image(
537        &mut self,
538        image: impl Into<AnyImageNode>,
539        depth: f32,
540        stencil: u32,
541    ) -> &mut Self {
542        let image = image.into();
543        let image_view = self.resource(image).info.into();
544
545        self.begin_cmd()
546            .debug_name("clear depth/stencil")
547            .subresource_access(image, image_view, AccessType::TransferWrite)
548            .record_cmd(move |cmd| {
549                let image = cmd.resource(image);
550
551                unsafe {
552                    cmd.device.cmd_clear_depth_stencil_image(
553                        cmd.handle,
554                        image.handle,
555                        vk::ImageLayout::TRANSFER_DST_OPTIMAL,
556                        &vk::ClearDepthStencilValue { depth, stencil },
557                        &[image_view],
558                    );
559                }
560            })
561            .end_cmd()
562    }
563
564    /// Copy data between buffers
565    pub fn copy_buffer(
566        &mut self,
567        src: impl Into<AnyBufferNode>,
568        dst: impl Into<AnyBufferNode>,
569    ) -> &mut Self {
570        let src = src.into();
571        let dst = dst.into();
572        let src_info = self.resource(src).info;
573        let dst_info = self.resource(dst).info;
574
575        self.copy_buffer_region(
576            src,
577            dst,
578            [vk::BufferCopy {
579                src_offset: 0,
580                dst_offset: 0,
581                size: src_info.size.min(dst_info.size),
582            }],
583        )
584    }
585
586    /// Copy data between buffer regions.
587    #[profiling::function]
588    pub fn copy_buffer_region(
589        &mut self,
590        src: impl Into<AnyBufferNode>,
591        dst: impl Into<AnyBufferNode>,
592        regions: impl AsRef<[vk::BufferCopy]> + 'static + Send,
593    ) -> &mut Self {
594        let src = src.into();
595        let dst = dst.into();
596
597        #[cfg(debug_assertions)]
598        let src_size = self.resource(src).info.size;
599
600        #[cfg(debug_assertions)]
601        let dst_size = self.resource(dst).info.size;
602
603        let mut cmd = self.begin_cmd().debug_name("copy buffer");
604
605        for region in regions.as_ref() {
606            #[cfg(debug_assertions)]
607            {
608                assert!(
609                    region.src_offset + region.size <= src_size,
610                    "source range end ({}) exceeds source size ({src_size})",
611                    region.src_offset + region.size
612                );
613                assert!(
614                    region.dst_offset + region.size <= dst_size,
615                    "destination range end ({}) exceeds destination size ({dst_size})",
616                    region.dst_offset + region.size
617                );
618            };
619
620            cmd.set_subresource_access(
621                src,
622                region.src_offset..region.src_offset + region.size,
623                AccessType::TransferRead,
624            );
625            cmd.set_subresource_access(
626                dst,
627                region.dst_offset..region.dst_offset + region.size,
628                AccessType::TransferWrite,
629            );
630        }
631
632        cmd.record_cmd(move |cmd| {
633            let src = cmd.resource(src);
634            let dst = cmd.resource(dst);
635
636            unsafe {
637                cmd.device
638                    .cmd_copy_buffer(cmd.handle, src.handle, dst.handle, regions.as_ref());
639            }
640        })
641        .end_cmd()
642    }
643
644    /// Copy data from a buffer into an image.
645    pub fn copy_buffer_to_image(
646        &mut self,
647        src: impl Into<AnyBufferNode>,
648        dst: impl Into<AnyImageNode>,
649    ) -> &mut Self {
650        let dst = dst.into();
651        let dst_info = self.resource(dst).info;
652
653        self.copy_buffer_to_image_region(
654            src,
655            dst,
656            [vk::BufferImageCopy {
657                buffer_offset: 0,
658                buffer_row_length: dst_info.width,
659                buffer_image_height: dst_info.height,
660                image_subresource: vk::ImageSubresourceLayers {
661                    aspect_mask: format_aspect_mask(dst_info.fmt),
662                    mip_level: 0,
663                    base_array_layer: 0,
664                    layer_count: 1,
665                },
666                image_offset: Default::default(),
667                image_extent: vk::Extent3D {
668                    depth: dst_info.depth,
669                    height: dst_info.height,
670                    width: dst_info.width,
671                },
672            }],
673        )
674    }
675
676    /// Copy data from a buffer into an image.
677    #[profiling::function]
678    pub fn copy_buffer_to_image_region(
679        &mut self,
680        src: impl Into<AnyBufferNode>,
681        dst: impl Into<AnyImageNode>,
682        regions: impl AsRef<[vk::BufferImageCopy]> + 'static + Send,
683    ) -> &mut Self {
684        let src = src.into();
685        let dst = dst.into();
686        let dst_info = self.resource(dst).info;
687
688        let mut cmd = self.begin_cmd().debug_name("copy buffer to image");
689
690        for region in regions.as_ref() {
691            let block_bytes_size = format_texel_block_size(dst_info.fmt);
692            let (block_height, block_width) = format_texel_block_extent(dst_info.fmt);
693            let data_size = block_bytes_size
694                * (region.buffer_row_length / block_width)
695                * (region.buffer_image_height / block_height);
696
697            cmd.set_subresource_access(
698                src,
699                region.buffer_offset..region.buffer_offset + data_size as vk::DeviceSize,
700                AccessType::TransferRead,
701            );
702            cmd.set_subresource_access(
703                dst,
704                image_subresource_range_from_layers(region.image_subresource),
705                AccessType::TransferWrite,
706            );
707        }
708
709        cmd.record_cmd(move |cmd| {
710            let src = cmd.resource(src);
711            let dst = cmd.resource(dst);
712
713            unsafe {
714                cmd.device.cmd_copy_buffer_to_image(
715                    cmd.handle,
716                    src.handle,
717                    dst.handle,
718                    vk::ImageLayout::TRANSFER_DST_OPTIMAL,
719                    regions.as_ref(),
720                );
721            }
722        })
723        .end_cmd()
724    }
725
726    /// Copy all layers of a source image to a destination image.
727    pub fn copy_image(
728        &mut self,
729        src: impl Into<AnyImageNode>,
730        dst: impl Into<AnyImageNode>,
731    ) -> &mut Self {
732        let src = src.into();
733        let src_info = self.resource(src).info;
734
735        let dst = dst.into();
736        let dst_info = self.resource(dst).info;
737
738        self.copy_image_region(
739            src,
740            dst,
741            [vk::ImageCopy {
742                src_subresource: vk::ImageSubresourceLayers {
743                    aspect_mask: format_aspect_mask(src_info.fmt),
744                    mip_level: 0,
745                    base_array_layer: 0,
746                    layer_count: src_info.array_layer_count,
747                },
748                src_offset: vk::Offset3D { x: 0, y: 0, z: 0 },
749                dst_subresource: vk::ImageSubresourceLayers {
750                    aspect_mask: format_aspect_mask(dst_info.fmt),
751                    mip_level: 0,
752                    base_array_layer: 0,
753                    layer_count: src_info.array_layer_count,
754                },
755                dst_offset: vk::Offset3D { x: 0, y: 0, z: 0 },
756                extent: vk::Extent3D {
757                    depth: src_info.depth.clamp(1, dst_info.depth),
758                    height: src_info.height.clamp(1, dst_info.height),
759                    width: src_info.width.min(dst_info.width),
760                },
761            }],
762        )
763    }
764
765    /// Copy data between images.
766    #[profiling::function]
767    pub fn copy_image_region(
768        &mut self,
769        src: impl Into<AnyImageNode>,
770        dst: impl Into<AnyImageNode>,
771        regions: impl AsRef<[vk::ImageCopy]> + 'static + Send,
772    ) -> &mut Self {
773        let src = src.into();
774        let dst = dst.into();
775
776        let mut cmd = self.begin_cmd().debug_name("copy image");
777
778        for region in regions.as_ref() {
779            cmd.set_subresource_access(
780                src,
781                image_subresource_range_from_layers(region.src_subresource),
782                AccessType::TransferRead,
783            );
784            cmd.set_subresource_access(
785                dst,
786                image_subresource_range_from_layers(region.dst_subresource),
787                AccessType::TransferWrite,
788            );
789        }
790
791        cmd.record_cmd(move |cmd| {
792            let src = cmd.resource(src);
793            let dst = cmd.resource(dst);
794
795            unsafe {
796                cmd.device.cmd_copy_image(
797                    cmd.handle,
798                    src.handle,
799                    vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
800                    dst.handle,
801                    vk::ImageLayout::TRANSFER_DST_OPTIMAL,
802                    regions.as_ref(),
803                );
804            }
805        })
806        .end_cmd()
807    }
808
809    /// Copy image data into a buffer.
810    pub fn copy_image_to_buffer(
811        &mut self,
812        src: impl Into<AnyImageNode>,
813        dst: impl Into<AnyBufferNode>,
814    ) -> &mut Self {
815        let src = src.into();
816        let dst = dst.into();
817
818        let src_info = self.resource(src).info;
819
820        self.copy_image_to_buffer_region(
821            src,
822            dst,
823            [vk::BufferImageCopy {
824                buffer_offset: 0,
825                buffer_row_length: src_info.width,
826                buffer_image_height: src_info.height,
827                image_subresource: vk::ImageSubresourceLayers {
828                    aspect_mask: format_aspect_mask(src_info.fmt),
829                    mip_level: 0,
830                    base_array_layer: 0,
831                    layer_count: 1,
832                },
833                image_offset: Default::default(),
834                image_extent: vk::Extent3D {
835                    depth: src_info.depth,
836                    height: src_info.height,
837                    width: src_info.width,
838                },
839            }],
840        )
841    }
842
843    /// Copy image data into a buffer.
844    #[profiling::function]
845    pub fn copy_image_to_buffer_region(
846        &mut self,
847        src: impl Into<AnyImageNode>,
848        dst: impl Into<AnyBufferNode>,
849        regions: impl AsRef<[vk::BufferImageCopy]> + 'static + Send,
850    ) -> &mut Self {
851        let src = src.into();
852        let src_info = self.resource(src).info;
853        let dst = dst.into();
854
855        let mut cmd = self.begin_cmd().debug_name("copy image to buffer");
856
857        for region in regions.as_ref() {
858            let block_bytes_size = format_texel_block_size(src_info.fmt);
859            let (block_height, block_width) = format_texel_block_extent(src_info.fmt);
860            let data_size = block_bytes_size
861                * (region.buffer_row_length / block_width)
862                * (region.buffer_image_height / block_height);
863
864            cmd.set_subresource_access(
865                src,
866                image_subresource_range_from_layers(region.image_subresource),
867                AccessType::TransferRead,
868            );
869            cmd.set_subresource_access(
870                dst,
871                region.buffer_offset..region.buffer_offset + data_size as vk::DeviceSize,
872                AccessType::TransferWrite,
873            );
874        }
875
876        cmd.record_cmd(move |cmd| {
877            let src = cmd.resource(src);
878            let dst = cmd.resource(dst);
879
880            unsafe {
881                cmd.device.cmd_copy_image_to_buffer(
882                    cmd.handle,
883                    src.handle,
884                    vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
885                    dst.handle,
886                    regions.as_ref(),
887                );
888            }
889        })
890        .end_cmd()
891    }
892
893    /// Fill a region of a buffer with a fixed value.
894    pub fn fill_buffer(
895        &mut self,
896        buffer: impl Into<AnyBufferNode>,
897        region: Range<vk::DeviceSize>,
898        data: u32,
899    ) -> &mut Self {
900        let buffer = buffer.into();
901
902        self.begin_cmd()
903            .debug_name("fill buffer")
904            .subresource_access(buffer, region.clone(), AccessType::TransferWrite)
905            .record_cmd(move |cmd| {
906                let buffer = cmd.resource(buffer);
907
908                unsafe {
909                    cmd.device.cmd_fill_buffer(
910                        cmd.handle,
911                        buffer.handle,
912                        region.start,
913                        region.end - region.start,
914                        data,
915                    );
916                }
917            })
918            .end_cmd()
919    }
920
921    /// Returns the index of the first pass which accesses a given node
922    #[profiling::function]
923    fn first_node_access_pass_index(&self, resource_node: impl Node) -> Option<usize> {
924        let node_idx = resource_node.index();
925
926        for (pass_idx, pass) in self.cmds.iter().enumerate() {
927            for exec in pass.execs.iter() {
928                if exec.accesses.contains_key(&node_idx) {
929                    return Some(pass_idx);
930                }
931            }
932        }
933
934        None
935    }
936
937    /// Finalizes the graph and provides an object with functions for submitting the resulting
938    /// commands.
939    #[profiling::function]
940    pub fn into_submission(mut self) -> Submission {
941        // The final execution of each pass has no function
942        for cmd in &mut self.cmds {
943            debug_assert!(cmd.expect_last_exec().func.is_none());
944
945            cmd.execs.pop();
946        }
947
948        Submission::new(self)
949    }
950
951    /// Returns a borrow of the original Vulkan resource (buffer, image or acceleration structure)
952    /// which the given bound resource node represents.
953    pub fn resource<N>(&self, resource_node: N) -> &N::Resource
954    where
955        N: Node,
956    {
957        resource_node.borrow(&self.resources)
958    }
959
960    /// Note: `data` must not exceed 65536 bytes.
961    #[profiling::function]
962    pub fn update_buffer(
963        &mut self,
964        buffer: impl Into<AnyBufferNode>,
965        offset: vk::DeviceSize,
966        data: impl AsRef<[u8]> + 'static + Send,
967    ) -> &mut Self {
968        let buffer = buffer.into();
969        let data_end = offset + data.as_ref().len() as vk::DeviceSize;
970
971        #[cfg(debug_assertions)]
972        {
973            let buffer_info = self.resource(buffer).info;
974
975            assert!(
976                data_end <= buffer_info.size,
977                "data range end ({data_end}) exceeds buffer size ({})",
978                buffer_info.size
979            );
980        }
981
982        self.begin_cmd()
983            .debug_name("update buffer")
984            .subresource_access(buffer, offset..data_end, AccessType::TransferWrite)
985            .record_cmd(move |cmd| {
986                let buffer = cmd.resource(buffer);
987
988                unsafe {
989                    cmd.device
990                        .cmd_update_buffer(cmd.handle, buffer.handle, offset, data.as_ref());
991                }
992            })
993            .end_cmd()
994    }
995}
996
997/// A Vulkan resource which has been bound to a [`Graph`].
998///
999/// See [`Graph::bind_resource`].
1000pub trait Node {
1001    /// The Vulkan buffer, image, or acceleration struction type.
1002    type Resource;
1003
1004    #[doc(hidden)]
1005    fn borrow(self, resources: &[AnyResource]) -> &Self::Resource;
1006
1007    #[doc(hidden)]
1008    fn index(&self) -> NodeIndex;
1009}
1010
1011/// A Vulkan resource which may be bound to a [`Graph`].
1012///
1013/// See [`Graph::bind_resource`] and
1014/// [`Command::bind_resource`](crate::cmd::Command::bind_resource).
1015pub trait Resource {
1016    /// The resource handle type.
1017    type Node;
1018
1019    #[doc(hidden)]
1020    fn bind_graph(self, _: &mut Graph) -> Self::Node;
1021
1022    #[deprecated = "use bind_graph function"]
1023    #[doc(hidden)]
1024    fn bind(self, graph: &mut Graph) -> Self::Node
1025    where
1026        Self: Sized,
1027    {
1028        self.bind_graph(graph)
1029    }
1030}
1031
1032impl Resource for SwapchainImage {
1033    type Node = SwapchainImageNode;
1034
1035    fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1036        // We will return a new node
1037        let node = Self::Node::new(graph.resources.len());
1038
1039        //trace!("Node {}: {:?}", res.idx, &self);
1040
1041        let resource = AnyResource::SwapchainImage(Box::new(self));
1042        graph.resources.push(resource);
1043
1044        node
1045    }
1046}
1047
1048macro_rules! resource {
1049    ($name:ident) => {
1050        paste::paste! {
1051            impl Resource for $name {
1052                type Node = [<$name Node>];
1053
1054                #[profiling::function]
1055                fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1056                    // In this function we are resource a new item (Image or Buffer or etc)
1057                    // We will return a new node
1058                    let node = Self::Node::new(graph.resources.len());
1059
1060                    let resource = AnyResource::$name(Arc::new(self));
1061                    graph.resources.push(resource);
1062
1063                    node
1064                }
1065            }
1066
1067            impl Resource for Arc<$name> {
1068                type Node = [<$name Node>];
1069
1070                #[profiling::function]
1071                fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1072                    // In this function we are resource an existing resource (Arc<Image> or
1073                    // Arc<Buffer> or etc)
1074                    // We will return an existing node, if possible
1075                    // TODO: Could store a sorted list of these shared pointers to avoid the O(N)
1076                    for (idx, existing_resource) in graph.resources.iter_mut().enumerate() {
1077                        if let AnyResource::$name(existing_resource) = existing_resource
1078                            && Arc::ptr_eq(existing_resource, &self) {
1079                                return Self::Node::new(idx);
1080                        }
1081                    }
1082
1083                    // Return a new node
1084                    let node = Self::Node::new(graph.resources.len());
1085                    let resource = AnyResource::$name(self);
1086                    graph.resources.push(resource);
1087
1088                    node
1089                }
1090            }
1091
1092            impl<'a> Resource for &'a Arc<$name> {
1093                type Node = [<$name Node>];
1094
1095                fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1096                    // In this function we are resource a borrowed resource (&Arc<Image> or
1097                    // &Arc<Buffer> or etc)
1098
1099                    Arc::clone(self).bind_graph(graph)
1100                }
1101            }
1102
1103            impl Resource for Lease<$name> {
1104                type Node = [<$name LeaseNode>];
1105
1106                #[profiling::function]
1107                fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1108                    // In this function we are wrapping a newly pooled resource (Lease<Image> or
1109                    // Lease<Buffer> or etc)
1110
1111                    // We will return a new node
1112                    let node = Self::Node::new(graph.resources.len());
1113                    let resource = AnyResource::[<$name Lease>](Arc::new(self));
1114                    graph.resources.push(resource);
1115
1116                    node
1117                }
1118            }
1119
1120            impl Resource  for Arc<Lease<$name>> {
1121                type Node = [<$name LeaseNode>];
1122
1123                #[profiling::function]
1124                fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1125                    // In this function we are wrapping an existing pooled resource
1126                    // (Arc<Lease<Image>> or Arc<Lease<Buffer>> or etc)
1127
1128                    // We will return an existing node, if possible
1129                    // TODO: Could store a sorted list of these shared pointers to avoid the O(N)
1130                    for (idx, existing_resource) in graph.resources.iter().enumerate() {
1131                        if let AnyResource::[<$name Lease>](existing_resource) = existing_resource
1132                            && Arc::ptr_eq(existing_resource, &self) {
1133                                return Self::Node::new(idx);
1134                        }
1135                    }
1136
1137                    // We will return a new node
1138                    let node = Self::Node::new(graph.resources.len());
1139                    let resource = AnyResource::[<$name Lease>](self);
1140                    graph.resources.push(resource);
1141
1142                    node
1143                }
1144            }
1145
1146            impl<'a> Resource for &'a Arc<Lease<$name>> {
1147                type Node = [<$name LeaseNode>];
1148
1149                fn bind_graph(self, graph: &mut Graph) -> Self::Node {
1150                    // In this function we are resource a borrowed resource (&Arc<Lease<Image>> or
1151                    // &Arc<Lease<Buffer>> or etc)
1152
1153                    Arc::clone(self).bind_graph(graph)
1154                }
1155            }
1156        }
1157    };
1158}
1159
1160resource!(AccelerationStructure);
1161resource!(Image);
1162resource!(Buffer);
1163
1164#[deprecated]
1165#[doc(hidden)]
1166pub mod graph {
1167    #[deprecated = "use vk_graph::node module"]
1168    pub mod node {
1169        #[deprecated = "use vk_graph::node::AccelerationStructureLeaseNode"]
1170        pub type AccelerationStructureLeaseNode = crate::node::AccelerationStructureLeaseNode;
1171
1172        #[deprecated = "use vk_graph::node::AccelerationStructureNode"]
1173        pub type AccelerationStructureNode = crate::node::AccelerationStructureNode;
1174
1175        #[deprecated = "use vk_graph::node::AnyAccelerationStructureNode"]
1176        pub type AnyAccelerationStructureNode = crate::node::AnyAccelerationStructureNode;
1177
1178        #[deprecated = "use vk_graph::node::AnyBufferNode"]
1179        pub type AnyBufferNode = crate::node::AnyBufferNode;
1180
1181        #[deprecated = "use vk_graph::node::AnyImageNode"]
1182        pub type AnyImageNode = crate::node::AnyImageNode;
1183
1184        #[deprecated = "use vk_graph::node::BufferLeaseNode"]
1185        pub type BufferLeaseNode = crate::node::BufferLeaseNode;
1186
1187        #[deprecated = "use vk_graph::node::BufferNode"]
1188        pub type BufferNode = crate::node::BufferNode;
1189
1190        #[deprecated = "use vk_graph::node::ImageLeaseNode"]
1191        pub type ImageLeaseNode = crate::node::ImageLeaseNode;
1192
1193        #[deprecated = "use vk_graph::node::ImageNode"]
1194        pub type ImageNode = crate::node::ImageNode;
1195
1196        #[deprecated = "use vk_graph::node::Node"]
1197        pub type Node = dyn crate::Node<Resource = ()>;
1198
1199        #[deprecated = "use vk_graph::node::SwapchainImageNode"]
1200        pub type SwapchainImageNode = crate::node::SwapchainImageNode;
1201    }
1202
1203    #[deprecated]
1204    #[doc(hidden)]
1205    pub mod pass_ref {
1206        #[deprecated = "use vk_graph::cmd::CommandRef"]
1207        pub type Acceleration<'a> = crate::cmd::CommandRef<'a>;
1208
1209        #[deprecated = "use vk_graph::cmd::CommandRef"]
1210        pub type AccelerationStructureBuildInfo = crate::cmd::BuildAccelerationStructureInfo;
1211
1212        #[deprecated = "use vk_graph::cmd::CommandRef"]
1213        pub type AccelerationStructureIndirectBuildInfo =
1214            crate::cmd::BuildAccelerationStructureIndirectInfo;
1215
1216        #[deprecated = "use vk_graph::cmd::CommandRef"]
1217        pub type AccelerationStructureIndirectUpdateInfo =
1218            crate::cmd::UpdateAccelerationStructureIndirectInfo;
1219
1220        #[deprecated = "use vk_graph::cmd::CommandRef"]
1221        pub type AccelerationStructureUpdateInfo = crate::cmd::UpdateAccelerationStructureInfo;
1222
1223        #[deprecated = "use vk_graph::cmd::Binding"]
1224        pub type Descriptor = crate::cmd::Binding;
1225
1226        #[deprecated = "use vk_graph::cmd::GraphicCommandRef"]
1227        pub type Draw<'a> = crate::cmd::GraphicCommandRef<'a>;
1228
1229        #[deprecated = "use vk_graph::cmd::CommandRef"]
1230        pub type PassRef<'a> = crate::cmd::Command<'a>;
1231
1232        #[deprecated = "use vk_graph::cmd::PipelineCommand"]
1233        pub type PipelinePassRef<'a, T> = crate::cmd::PipelineCommand<'a, T>;
1234
1235        #[deprecated = "use vk_graph::cmd::RayTraceCommandRef"]
1236        pub type RayTrace<'a> = crate::cmd::RayTraceCommandRef<'a>;
1237
1238        #[deprecated = "use vk_graph::ViewInfo"]
1239        pub type ViewType = crate::cmd::ViewInfo;
1240
1241        #[deprecated = "remove"]
1242        pub trait View {
1243            type Information;
1244        }
1245    }
1246
1247    #[deprecated = "use vk_graph::Graph"]
1248    pub type RenderGraph = crate::Graph;
1249
1250    #[deprecated = "use vk_graph::Submission"]
1251    pub type Resolver = crate::Submission;
1252}
1253
1254#[allow(deprecated)]
1255#[allow(unused)]
1256#[doc(hidden)]
1257pub(crate) mod deprecated {
1258    use {
1259        crate::{
1260            AnyResource, Graph, Node, Resource,
1261            driver::{
1262                DriverError,
1263                accel_struct::{AccelerationStructure, AccelerationStructureInfo},
1264                buffer::{Buffer, BufferInfo},
1265                cmd_buf::{CommandBuffer, CommandBufferInfo},
1266                descriptor_set::{DescriptorPool, DescriptorPoolInfo},
1267                device::Device,
1268                image::{Image, ImageInfo},
1269                render_pass::{RenderPass, RenderPassInfo},
1270                swapchain::{Swapchain, SwapchainImage, SwapchainInfo},
1271            },
1272            node::{
1273                AccelerationStructureLeaseNode, AccelerationStructureNode,
1274                AnyAccelerationStructureNode, AnyBufferNode, AnyImageNode, BufferLeaseNode,
1275                BufferNode, ImageLeaseNode, ImageNode, SwapchainImageNode,
1276            },
1277            pool::{Lease, Pool},
1278        },
1279        ash::vk,
1280        std::{error, fmt, ops::Range, sync::Arc},
1281    };
1282
1283    /// Specifies a color attachment clear value which can be used to initliaze an image.
1284    #[derive(Clone, Copy, Debug)]
1285    pub struct ClearColorValue(pub [f32; 4]);
1286
1287    impl From<[f32; 3]> for ClearColorValue {
1288        fn from(color: [f32; 3]) -> Self {
1289            [color[0], color[1], color[2], 1.0].into()
1290        }
1291    }
1292
1293    impl From<[f32; 4]> for ClearColorValue {
1294        fn from(color: [f32; 4]) -> Self {
1295            Self(color)
1296        }
1297    }
1298
1299    impl From<[u8; 3]> for ClearColorValue {
1300        fn from(color: [u8; 3]) -> Self {
1301            [color[0], color[1], color[2], u8::MAX].into()
1302        }
1303    }
1304
1305    impl From<[u8; 4]> for ClearColorValue {
1306        fn from(color: [u8; 4]) -> Self {
1307            [
1308                color[0] as f32 / u8::MAX as f32,
1309                color[1] as f32 / u8::MAX as f32,
1310                color[2] as f32 / u8::MAX as f32,
1311                color[3] as f32 / u8::MAX as f32,
1312            ]
1313            .into()
1314        }
1315    }
1316
1317    #[deprecated = "use Swapchain from vk_graph_window crate"]
1318    #[derive(Debug)]
1319    #[doc(hidden)]
1320    pub struct Display {
1321        swapchain_info: SwapchainInfo,
1322    }
1323
1324    impl Display {
1325        pub fn new(
1326            device: &Arc<Device>,
1327            swapchain: Swapchain,
1328            info: impl Into<DisplayInfo>,
1329        ) -> Result<Self, DriverError> {
1330            let _ = device;
1331            let _ = swapchain;
1332            let _ = info.into();
1333
1334            Err(DriverError::Unsupported)
1335        }
1336
1337        pub fn acquire_next_image(&mut self) -> Result<Option<SwapchainImage>, DisplayError> {
1338            Err(DisplayError)
1339        }
1340
1341        pub fn present_image(
1342            &mut self,
1343            pool: &mut impl ResolverPool,
1344            render_graph: crate::graph::RenderGraph,
1345            swapchain_image: SwapchainImageNode,
1346            queue_index: u32,
1347        ) -> Result<(), DisplayError> {
1348            let _ = pool;
1349            let _ = render_graph;
1350            let _ = swapchain_image;
1351            let _ = queue_index;
1352
1353            Err(DisplayError)
1354        }
1355
1356        pub fn set_swapchain_info(&mut self, info: impl Into<SwapchainInfo>) {
1357            self.swapchain_info = info.into();
1358        }
1359
1360        pub fn swapchain_info(&self) -> SwapchainInfo {
1361            self.swapchain_info
1362        }
1363    }
1364
1365    #[deprecated = "use vk_graph_window::SwapchainError"]
1366    #[derive(Clone, Copy, Debug, Default)]
1367    #[doc(hidden)]
1368    pub struct DisplayError;
1369
1370    impl fmt::Display for DisplayError {
1371        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1372            f.write_str("deprecated Display API is unsupported; use vk_graph_window swapchain APIs")
1373        }
1374    }
1375
1376    impl error::Error for DisplayError {}
1377
1378    #[deprecated = "use vk_graph_window::SwapchainInfo"]
1379    #[derive(Clone, Copy, Debug, Default)]
1380    #[doc(hidden)]
1381    pub struct DisplayInfo;
1382
1383    #[deprecated = "use vk_graph_window::SwapchainInfoBuilder"]
1384    #[derive(Clone, Copy, Debug, Default)]
1385    #[doc(hidden)]
1386    pub struct DisplayInfoBuilder;
1387
1388    // General stuff
1389    impl Graph {
1390        #[deprecated = "use begin_cmd function"]
1391        #[doc(hidden)]
1392        pub fn begin_pass(&mut self, name: impl AsRef<str>) -> crate::graph::pass_ref::PassRef<'_> {
1393            self.begin_cmd().debug_name(name.as_ref().to_owned())
1394        }
1395
1396        #[deprecated = "use bind_resource function"]
1397        #[doc(hidden)]
1398        pub fn bind_node<R>(&mut self, resource: R) -> R::Node
1399        where
1400            R: Resource,
1401        {
1402            self.bind_resource(resource)
1403        }
1404
1405        #[deprecated = "use blit_image_region function"]
1406        #[doc(hidden)]
1407        pub fn blit_image_regions(
1408            &mut self,
1409            src_node: impl Into<AnyImageNode>,
1410            dst_node: impl Into<AnyImageNode>,
1411            filter: vk::Filter,
1412            regions: impl AsRef<[vk::ImageBlit]> + 'static + Send,
1413        ) -> &mut Self {
1414            self.blit_image_region(src_node, dst_node, filter, regions)
1415        }
1416
1417        #[deprecated = "use clear_color_image function"]
1418        #[doc(hidden)]
1419        pub fn clear_color_image_value(
1420            &mut self,
1421            image_node: impl Into<AnyImageNode>,
1422            color_value: impl Into<ClearColorValue>,
1423        ) -> &mut Self {
1424            self.clear_color_image(image_node, color_value.into().0)
1425        }
1426
1427        #[deprecated = "use clear_depth_stencil_image function"]
1428        #[doc(hidden)]
1429        pub fn clear_depth_stencil_image_value(
1430            &mut self,
1431            image_node: impl Into<AnyImageNode>,
1432            depth: f32,
1433            stencil: u32,
1434        ) -> &mut Self {
1435            self.clear_depth_stencil_image(image_node, depth, stencil)
1436        }
1437
1438        #[deprecated = "use copy_buffer_region function"]
1439        #[doc(hidden)]
1440        pub fn copy_buffer_regions(
1441            &mut self,
1442            src_node: impl Into<AnyBufferNode>,
1443            dst_node: impl Into<AnyBufferNode>,
1444            regions: impl AsRef<[vk::BufferCopy]> + 'static + Send,
1445        ) -> &mut Self {
1446            self.copy_buffer_region(src_node, dst_node, regions)
1447        }
1448
1449        #[deprecated = "use copy_buffer_to_image_region function"]
1450        #[doc(hidden)]
1451        pub fn copy_buffer_to_image_regions(
1452            &mut self,
1453            src_node: impl Into<AnyBufferNode>,
1454            dst_node: impl Into<AnyImageNode>,
1455            regions: impl AsRef<[vk::BufferImageCopy]> + 'static + Send,
1456        ) -> &mut Self {
1457            self.copy_buffer_to_image_region(src_node, dst_node, regions)
1458        }
1459
1460        #[deprecated = "use copy_image_region function"]
1461        #[doc(hidden)]
1462        pub fn copy_image_regions(
1463            &mut self,
1464            src_node: impl Into<AnyImageNode>,
1465            dst_node: impl Into<AnyImageNode>,
1466            regions: impl AsRef<[vk::ImageCopy]> + 'static + Send,
1467        ) -> &mut Self {
1468            self.copy_image_region(src_node, dst_node, regions)
1469        }
1470
1471        #[deprecated = "use copy_image_to_buffer_region function"]
1472        #[doc(hidden)]
1473        pub fn copy_image_to_buffer_regions(
1474            &mut self,
1475            src_node: impl Into<AnyImageNode>,
1476            dst_node: impl Into<AnyBufferNode>,
1477            regions: impl AsRef<[vk::BufferImageCopy]> + 'static + Send,
1478        ) -> &mut Self {
1479            self.copy_image_to_buffer_region(src_node, dst_node, regions)
1480        }
1481
1482        #[deprecated = "use fill_buffer function"]
1483        #[doc(hidden)]
1484        pub fn fill_buffer_region(
1485            &mut self,
1486            buffer_node: impl Into<AnyBufferNode>,
1487            data: u32,
1488            region: Range<vk::DeviceSize>,
1489        ) -> &mut Self {
1490            self.fill_buffer(buffer_node, region, data)
1491        }
1492
1493        #[deprecated = "use device_address function of resource function result"]
1494        #[doc(hidden)]
1495        pub fn node_device_address(&self, node: impl Node) -> vk::DeviceAddress {
1496            let idx = node.index();
1497
1498            self.resources[idx]
1499                .as_buffer()
1500                .expect("missing buffer resource")
1501                .device_address()
1502        }
1503
1504        #[deprecated = "dereference info field of resource function result"]
1505        #[doc(hidden)]
1506        pub fn node_info<N>(&self, node: N) -> N::Type
1507        where
1508            N: Node + Info,
1509        {
1510            node.info(&self.resources)
1511        }
1512
1513        #[deprecated = "use into_submission function"]
1514        #[doc(hidden)]
1515        pub fn resolve(self) -> crate::graph::Resolver {
1516            self.into_submission()
1517        }
1518
1519        #[deprecated = "use resource and clone functions"]
1520        #[doc(hidden)]
1521        pub fn unbind_node<N>(&mut self, node: N) -> N::Result
1522        where
1523            N: Unbind,
1524        {
1525            node.unbind(&self.resources)
1526        }
1527
1528        #[deprecated = "use update_buffer function"]
1529        #[doc(hidden)]
1530        pub fn update_buffer_offset(
1531            &mut self,
1532            buffer_node: impl Into<AnyBufferNode>,
1533            offset: vk::DeviceSize,
1534            data: impl AsRef<[u8]> + 'static + Send,
1535        ) -> &mut Self {
1536            self.update_buffer(buffer_node, offset, data)
1537        }
1538    }
1539
1540    pub trait Info {
1541        type Type;
1542
1543        fn info(&self, _: &[AnyResource]) -> Self::Type
1544        where
1545            Self: Node;
1546    }
1547
1548    impl Info for SwapchainImageNode {
1549        type Type = ImageInfo;
1550
1551        fn info(&self, resources: &[AnyResource]) -> Self::Type
1552        where
1553            Self: Node,
1554        {
1555            resources[self.index()]
1556                .as_swapchain_image()
1557                .expect("missing swapchain image")
1558                .info
1559        }
1560    }
1561
1562    macro_rules! info {
1563        ($name:ident) => {
1564            paste::paste! {
1565                impl Info for [<$name Node>] {
1566                    type Type = [<$name Info>];
1567
1568                    fn info(&self, resources: &[AnyResource]) -> Self::Type
1569                    where
1570                        Self: Node,
1571                    {
1572                        let AnyResource::$name(resource) = &resources[self.index()] else {
1573                            panic!("invalid node");
1574                        };
1575
1576                        resource.info
1577                    }
1578                }
1579
1580                impl Info for [<Any $name Node>] {
1581                    type Type = [<$name Info>];
1582
1583                    fn info(&self, resources: &[AnyResource]) -> Self::Type
1584                    where
1585                        Self: Node,
1586                    {
1587                        let AnyResource::$name(resource) = &resources[self.index()] else {
1588                            panic!("invalid node");
1589                        };
1590
1591                        resource.info
1592                    }
1593                }
1594
1595                impl Info for [<$name LeaseNode>] {
1596                    type Type = [<$name Info>];
1597
1598                    fn info(&self, resources: &[AnyResource]) -> Self::Type
1599                    where
1600                        Self: Node,
1601                    {
1602                        let AnyResource::[<$name Lease>](resource) = &resources[self.index()] else {
1603                            panic!("invalid node");
1604                        };
1605
1606                        resource.info
1607                    }
1608                }
1609
1610                impl Unbind for [<$name Node>] {
1611                    type Result = Arc<$name>;
1612
1613                    fn unbind(&self, resources: &[AnyResource]) -> Self::Result {
1614                        let AnyResource::$name(resource) = &resources[self.index()] else {
1615                            panic!("invalid node");
1616                        };
1617
1618                        resource.clone()
1619                    }
1620                }
1621
1622                impl Unbind for [<$name LeaseNode>] {
1623                    type Result = Arc<Lease<$name>>;
1624
1625                    fn unbind(&self, resources: &[AnyResource]) -> Self::Result {
1626                        let AnyResource::[<$name Lease>](resource) = &resources[self.index()] else {
1627                            panic!("invalid node");
1628                        };
1629
1630                        resource.clone()
1631                    }
1632                }
1633            }
1634        };
1635    }
1636
1637    info!(AccelerationStructure);
1638    info!(Buffer);
1639    info!(Image);
1640
1641    #[deprecated = "remove"]
1642    pub trait ResolverPool:
1643        Pool<DescriptorPoolInfo, DescriptorPool>
1644        + Pool<RenderPassInfo, RenderPass>
1645        + Pool<CommandBufferInfo, CommandBuffer>
1646        + Send
1647    {
1648    }
1649
1650    pub trait Unbind: Node {
1651        type Result;
1652
1653        fn unbind(&self, _: &[AnyResource]) -> Self::Result;
1654    }
1655}