Skip to main content

vk_graph/cmd/
mod.rs

1//! Strongly-typed [`Graph`] commands.
2
3mod cmd_ref;
4mod compute;
5mod graphic;
6mod pipeline;
7mod ray_trace;
8
9pub use self::{
10    cmd_ref::{
11        BuildAccelerationStructureIndirectInfo, BuildAccelerationStructureInfo, CommandRef,
12        UpdateAccelerationStructureIndirectInfo, UpdateAccelerationStructureInfo,
13    },
14    compute::ComputeCommandRef,
15    graphic::{ClearColorValue, GraphicCommandRef, LoadOp, StoreOp},
16    pipeline::{Pipeline, PipelineCommand},
17    ray_trace::RayTraceCommandRef,
18};
19
20use {
21    super::{
22        AccelerationStructureLeaseNode, AccelerationStructureNode, AnyAccelerationStructureNode,
23        AnyBufferNode, AnyImageNode, AnyResource, BufferLeaseNode, BufferNode, CommandData,
24        Execution, ExecutionFunction, Graph, ImageLeaseNode, ImageNode, Node, Resource,
25        SwapchainImageNode,
26    },
27    crate::driver::{buffer::BufferSubresourceRange, image::ImageViewInfo},
28    ash::vk,
29    std::ops::Range,
30    vk_sync::AccessType,
31};
32
33/// Alias for the index of a framebuffer attachment.
34pub(crate) type AttachmentIndex = u32;
35
36/// Alias for the binding index of a shader descriptor.
37pub(crate) type BindingIndex = u32;
38
39/// Alias for the binding offset of a shader descriptor array element.
40pub(crate) type BindingOffset = u32;
41
42/// Alias for the descriptor set index of a shader descriptor.
43pub(crate) type DescriptorSetIndex = u32;
44
45/// A general-purpose Vulkan command which may contain acceleration structure operations, transfers,
46/// or shader pipelines.
47///
48/// There are four main uses of a [`Command`]:
49///
50/// 1. Bind resources ([`Self::bind_resource`])
51/// 1. Declare resource accesses ([`Self::resource_access`])
52/// 1. Record general-purpose command buffers or acceleration structure operations
53///    ([`Self::record_cmd`])
54/// 1. Bind shader pipelines ([`Self::bind_pipeline`])
55///
56/// When bound, a shader pipeline consumes the `Command` and returns a [`PipelineCommand`] which
57/// provides command recording functions specific to each pipeline type.
58pub struct Command<'a> {
59    pub(super) cmd_idx: usize,
60    pub(super) exec_idx: usize,
61    pub(super) graph: &'a mut Graph,
62}
63
64impl<'a> Command<'a> {
65    pub(super) fn new(graph: &'a mut Graph) -> Self {
66        let cmd_idx = graph.cmds.len();
67        graph.cmds.push(CommandData {
68            execs: vec![Default::default()], // We start off with a default execution!
69            name: None,
70        });
71
72        Self {
73            cmd_idx,
74            exec_idx: 0,
75            graph,
76        }
77    }
78
79    fn cmd(&self) -> &CommandData {
80        &self.graph.cmds[self.cmd_idx]
81    }
82
83    fn cmd_mut(&mut self) -> &mut CommandData {
84        &mut self.graph.cmds[self.cmd_idx]
85    }
86
87    /// Binds a Vulkan buffer, image, or acceleration structure resource to the graph associated
88    /// with this command.
89    ///
90    /// Bound nodes may be used in commands for pipeline and shader operations.
91    pub fn bind_resource<R>(&mut self, resource: R) -> R::Node
92    where
93        R: Resource,
94    {
95        self.graph.bind_resource(resource)
96    }
97
98    /// Binds a shader pipeline to the current command, allowing for strongly typed access to the
99    /// related functions.
100    ///
101    /// `P`|`P::Command`
102    /// -|-
103    /// [`ComputePipeline`](crate::driver::compute::ComputePipeline)|[`PipelineCommand<'_,
104    /// ComputePipeline>`]
105    /// [`GraphicPipeline`](crate::driver::graphic::GraphicPipeline)|[`PipelineCommand<'_,
106    /// GraphicPipeline>`]
107    /// [`RayTracePipeline`](crate::driver::ray_trace::RayTracePipeline)|[`PipelineCommand<'_,
108    /// RayTracePipeline>`]
109    pub fn bind_pipeline<P>(self, pipeline: P) -> P::Command
110    where
111        P: Pipeline<'a>,
112    {
113        pipeline.bind_cmd(self)
114    }
115
116    /// Sets a debugging name, but only in debug builds
117    pub fn debug_name(mut self, name: impl Into<String>) -> Self {
118        self.set_debug_name(name);
119        self
120    }
121
122    /// Finalize the recording of this command and return to the `Graph` where you may record
123    /// additional commands.
124    pub fn end_cmd(self) -> &'a mut Graph {
125        // If nothing was done in this pass we can just ignore it
126        if self.exec_idx == 0 {
127            self.graph.cmds.pop();
128        }
129
130        self.graph
131    }
132
133    fn push_exec(&mut self, func: impl FnOnce(CommandRef) + Send + 'static) {
134        let cmd = self.cmd_mut();
135        let exec = {
136            let last_exec = cmd.expect_last_exec_mut();
137            last_exec.func = Some(ExecutionFunction(Box::new(func)));
138
139            Execution {
140                pipeline: last_exec.pipeline.clone(),
141                ..Default::default()
142            }
143        };
144
145        cmd.execs.push(exec);
146        self.exec_idx += 1;
147    }
148
149    fn push_subresource_access(
150        &mut self,
151        resource_node: impl Node,
152        subresource: SubresourceRange,
153        access: AccessType,
154    ) {
155        let node_idx = resource_node.index();
156
157        debug_assert!(self.graph.resources.get(node_idx).is_some());
158
159        let access = SubresourceAccess {
160            access,
161            subresource,
162        };
163        self.cmd_mut()
164            .expect_last_exec_mut()
165            .accesses
166            .entry(node_idx)
167            .and_modify(|accesses| accesses.push(access))
168            .or_insert(vec![access]);
169    }
170
171    /// Begin recording a general-purpose command buffer.
172    ///
173    /// This is the entry point for building and updating an
174    /// [`AccelerationStructure`](crate::driver::accel_struct::AccelerationStructure) instance.
175    ///
176    /// The provided closure allows you to run any Vulkan code, or interoperate with other Vulkan
177    /// code and interfaces.
178    pub fn record_cmd(mut self, func: impl FnOnce(CommandRef<'_>) + Send + 'static) -> Self {
179        self.record_cmd_mut(func);
180        self
181    }
182
183    /// Begin recording a general-purpose command buffer.
184    ///
185    /// This is the entry point for building and updating an
186    /// [`AccelerationStructure`](crate::driver::accel_struct::AccelerationStructure) instance.
187    ///
188    /// The provided closure allows you to run any Vulkan code, or interoperate with other Vulkan
189    /// code and interfaces.
190    pub fn record_cmd_mut(&mut self, func: impl FnOnce(CommandRef<'_>) + Send + 'static) {
191        self.push_exec(move |cmd| {
192            func(cmd);
193        });
194    }
195
196    /// Returns a borrow of the original Vulkan resource (buffer, image or acceleration structure)
197    /// which the given bound resource node represents.
198    pub fn resource<N>(&self, resource_node: N) -> &N::Resource
199    where
200        N: Node,
201    {
202        self.graph.resource(resource_node)
203    }
204
205    /// Informs the command that the next recorded command buffer will read or write `resource_node`
206    /// using `access`.
207    ///
208    /// An access function must be called for `resource_node` before it is used within a
209    /// `record_`-function.
210    pub fn resource_access<N>(mut self, resource_node: N, access: AccessType) -> Self
211    where
212        N: Node + Subresource,
213        SubresourceRange: From<N::Range>,
214    {
215        self.set_resource_access(resource_node, access);
216        self
217    }
218
219    /// Sets a debugging name, but only in debug builds.
220    pub fn set_debug_name(&mut self, _name: impl Into<String>) -> &mut Self {
221        #[cfg(debug_assertions)]
222        {
223            self.cmd_mut().name = Some(_name.into());
224        }
225
226        self
227    }
228
229    /// Informs the command that the next recorded command buffer will read or write `resource_node`
230    /// using `access`.
231    ///
232    /// An access function must be called for `resource_node` before it is used within a
233    /// `record_`-function.
234    pub fn set_resource_access<N>(&mut self, resource_node: N, access: AccessType)
235    where
236        N: Node + Subresource,
237        SubresourceRange: From<N::Range>,
238    {
239        let whole_resource = resource_node.range(&self.graph.resources);
240        let subresource = SubresourceRange::from(whole_resource);
241
242        self.push_subresource_access(resource_node, subresource, access);
243    }
244
245    /// Informs the command that the next recorded command buffer will read or write the
246    /// `subresource` of `resource_node` using `access`.
247    ///
248    /// An access function must be called for `resource_node` before it is used within a
249    /// `record_`-function.
250    pub fn set_subresource_access<N>(
251        &mut self,
252        resource_node: N,
253        subresource: impl Into<N::Range>,
254        access: AccessType,
255    ) where
256        N: Node + Subresource,
257        SubresourceRange: From<N::Range>,
258    {
259        let subresource = subresource.into();
260        let subresource = SubresourceRange::from(subresource);
261
262        self.push_subresource_access(resource_node, subresource, access);
263    }
264
265    /// Informs the command that the next recorded command buffer will read or write the
266    /// `subresource` of `resource` using `access`.
267    ///
268    /// An access function must be called for `resource` before it is used within a
269    /// `record_`-function.
270    pub fn subresource_access<N>(
271        mut self,
272        resource_node: N,
273        subresource: impl Into<N::Range>,
274        access: AccessType,
275    ) -> Self
276    where
277        N: Node + Subresource,
278        SubresourceRange: From<N::Range>,
279    {
280        self.set_subresource_access(resource_node, subresource, access);
281        self
282    }
283}
284
285/// Describes the SPIR-V binding index, and optionally a specific descriptor set
286/// and array index.
287///
288/// Generally you might pass a function a descriptor using a simple integer:
289///
290/// ```rust
291/// # fn my_func(_: usize, _: ()) {}
292/// # let image = ();
293/// let descriptor = 42;
294/// my_func(descriptor, image);
295/// ```
296///
297/// But also:
298///
299/// - `(0, 42)` for descriptor set `0` and binding index `42`
300/// - `(42, [8])` for the same binding, but the 8th element
301/// - `(0, 42, [8])` same as the previous example
302#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
303pub struct Binding {
304    /// The value of the descriptor binding decoration applied to the variable.
305    pub binding: u32,
306
307    /// An array-element offset applied to this descriptor.
308    pub offset: u32,
309
310    /// An optional descriptor set index value.
311    pub set: u32,
312}
313
314impl Binding {
315    pub(super) fn into_tuple(self) -> (DescriptorSetIndex, BindingIndex, BindingOffset) {
316        (self.set, self.binding, self.offset)
317    }
318
319    pub(super) fn set(self) -> DescriptorSetIndex {
320        let (res, _, _) = self.into_tuple();
321        res
322    }
323}
324
325impl From<BindingIndex> for Binding {
326    fn from(binding: BindingIndex) -> Self {
327        Self {
328            binding,
329            offset: 0,
330            set: 0,
331        }
332    }
333}
334
335impl From<(DescriptorSetIndex, BindingIndex)> for Binding {
336    fn from((set, binding): (DescriptorSetIndex, BindingIndex)) -> Self {
337        Self {
338            binding,
339            offset: 0,
340            set,
341        }
342    }
343}
344
345impl From<(BindingIndex, [BindingOffset; 1])> for Binding {
346    fn from((binding, [offset]): (BindingIndex, [BindingOffset; 1])) -> Self {
347        Self {
348            binding,
349            offset,
350            set: 0,
351        }
352    }
353}
354
355impl From<(DescriptorSetIndex, BindingIndex, [BindingOffset; 1])> for Binding {
356    fn from(
357        (set, binding, [offset]): (DescriptorSetIndex, BindingIndex, [BindingOffset; 1]),
358    ) -> Self {
359        Self {
360            binding,
361            offset,
362            set,
363        }
364    }
365}
366
367/// Allows for a resource to be reinterpreted as differently formatted data.
368pub trait Subresource {
369    /// The information about the subresource when bound directly to shader descriptors.
370    type Info;
371
372    /// The information about the subresource when used indirectly by any part of a graph.
373    type Range;
374
375    #[doc(hidden)]
376    fn info(&self, _: &[AnyResource]) -> Self::Info
377    where
378        Self: Node;
379
380    #[doc(hidden)]
381    fn range(&self, _: &[AnyResource]) -> Self::Range
382    where
383        Self: Node;
384}
385
386macro_rules! view_accel_struct {
387    ($name:ident) => {
388        impl Subresource for $name {
389            type Info = Self::Range;
390            type Range = ();
391
392            fn info(&self, _: &[AnyResource]) -> Self::Info
393            where
394                Self: Node,
395            {
396            }
397
398            fn range(&self, _: &[AnyResource]) -> Self::Range
399            where
400                Self: Node,
401            {
402            }
403        }
404    };
405}
406
407view_accel_struct!(AnyAccelerationStructureNode);
408view_accel_struct!(AccelerationStructureLeaseNode);
409view_accel_struct!(AccelerationStructureNode);
410
411macro_rules! view_buffer {
412    ($name:ident) => {
413        impl Subresource for $name {
414            type Info = Self::Range;
415            type Range = BufferSubresourceRange;
416
417            fn info(&self, resources: &[AnyResource]) -> Self::Info
418            where
419                Self: Node,
420            {
421                self.range(resources)
422            }
423
424            fn range(&self, resources: &[AnyResource]) -> Self::Range
425            where
426                Self: Node,
427            {
428                let idx = self.index();
429
430                resources[idx].expect_buffer().info.into()
431            }
432        }
433    };
434}
435
436view_buffer!(AnyBufferNode);
437view_buffer!(BufferLeaseNode);
438view_buffer!(BufferNode);
439
440macro_rules! view_image {
441    ($name:ident) => {
442        impl Subresource for $name {
443            type Info = ImageViewInfo;
444            type Range = vk::ImageSubresourceRange;
445
446            fn info(&self, resources: &[AnyResource]) -> Self::Info
447            where
448                Self: Node,
449            {
450                let idx = self.index();
451
452                resources[idx].expect_image().info.into()
453            }
454
455            fn range(&self, resources: &[AnyResource]) -> Self::Range
456            where
457                Self: Node,
458            {
459                self.info(resources).into()
460            }
461        }
462    };
463}
464
465view_image!(AnyImageNode);
466view_image!(ImageLeaseNode);
467view_image!(ImageNode);
468view_image!(SwapchainImageNode);
469
470#[derive(Clone, Copy, Debug)]
471#[doc(hidden)]
472pub enum SubresourceRange {
473    /// Acceleration structures are bound whole.
474    AccelerationStructure,
475
476    /// Images may be partially bound.
477    Image(vk::ImageSubresourceRange),
478
479    /// Buffers may be partially bound.
480    Buffer(BufferSubresourceRange),
481}
482
483impl SubresourceRange {
484    pub(super) fn as_image(&self) -> Option<&vk::ImageSubresourceRange> {
485        if let Self::Image(subresource) = self {
486            Some(subresource)
487        } else {
488            None
489        }
490    }
491
492    pub(super) fn expect_image(&self) -> &vk::ImageSubresourceRange {
493        self.as_image().expect("missing image subresource")
494    }
495}
496
497impl From<BufferSubresourceRange> for SubresourceRange {
498    fn from(subresource: BufferSubresourceRange) -> Self {
499        Self::Buffer(subresource)
500    }
501}
502
503impl From<()> for SubresourceRange {
504    fn from(_: ()) -> Self {
505        Self::AccelerationStructure
506    }
507}
508
509impl From<ImageViewInfo> for SubresourceRange {
510    fn from(subresource: ImageViewInfo) -> Self {
511        Self::Image(subresource.into())
512    }
513}
514
515impl From<vk::ImageSubresourceRange> for SubresourceRange {
516    fn from(subresource: vk::ImageSubresourceRange) -> Self {
517        Self::Image(subresource)
518    }
519}
520
521#[derive(Clone, Copy, Debug)]
522pub(super) struct SubresourceAccess {
523    pub access: AccessType,
524    pub subresource: SubresourceRange,
525}
526
527/// Describes the interpretation of a resource.
528#[derive(Debug)]
529#[doc(hidden)]
530pub enum ViewInfo {
531    /// Acceleration structures are always whole resources.
532    AccelerationStructure,
533
534    /// Images may be interpreted as differently formatted images.
535    Image(ImageViewInfo),
536
537    /// Buffers may be interpreted as subregions of the same buffer.
538    Buffer(BufferSubresourceRange),
539}
540
541impl ViewInfo {
542    pub(crate) fn as_buffer(&self) -> Option<&BufferSubresourceRange> {
543        match self {
544            Self::Buffer(info) => Some(info),
545            _ => None,
546        }
547    }
548
549    pub(crate) fn as_image(&self) -> Option<&ImageViewInfo> {
550        match self {
551            Self::Image(info) => Some(info),
552            _ => None,
553        }
554    }
555
556    pub(crate) fn expect_buffer(&self) -> &BufferSubresourceRange {
557        self.as_buffer().expect("missing buffer view info")
558    }
559
560    pub(crate) fn expect_image(&self) -> &ImageViewInfo {
561        self.as_image().expect("missing image view info")
562    }
563}
564
565impl From<()> for ViewInfo {
566    fn from(_: ()) -> Self {
567        Self::AccelerationStructure
568    }
569}
570
571impl From<BufferSubresourceRange> for ViewInfo {
572    fn from(info: BufferSubresourceRange) -> Self {
573        Self::Buffer(info)
574    }
575}
576
577impl From<ImageViewInfo> for ViewInfo {
578    fn from(info: ImageViewInfo) -> Self {
579        Self::Image(info)
580    }
581}
582
583impl From<Range<vk::DeviceSize>> for ViewInfo {
584    fn from(range: Range<vk::DeviceSize>) -> Self {
585        Self::Buffer(BufferSubresourceRange {
586            start: range.start,
587            end: range.end,
588        })
589    }
590}
591
592#[allow(deprecated)]
593#[allow(unused)]
594mod deprecated {
595    use {
596        crate::{
597            Graph, Node, Resource,
598            cmd::{Command, CommandRef, Subresource, SubresourceRange},
599            deprecated::Info,
600        },
601        ash::vk,
602        vk_sync::AccessType,
603    };
604
605    impl<'a> Command<'a> {
606        #[deprecated = "use resource_access function"]
607        #[doc(hidden)]
608        pub fn access_node<N>(mut self, node: N, access: AccessType) -> Self
609        where
610            N: Node + Subresource,
611            SubresourceRange: From<N::Range>,
612        {
613            self.resource_access(node, access)
614        }
615
616        #[deprecated = "use set_resource_access function"]
617        #[doc(hidden)]
618        pub fn access_node_mut<N>(&mut self, node: N, access: AccessType) -> &mut Self
619        where
620            N: Node + Subresource,
621            SubresourceRange: From<N::Range>,
622        {
623            self.set_resource_access(node, access);
624            self
625        }
626
627        #[deprecated = "use subresource_access function"]
628        #[doc(hidden)]
629        pub fn access_node_subrange<N>(
630            mut self,
631            node: N,
632            access: AccessType,
633            subresource: impl Into<N::Range>,
634        ) -> Self
635        where
636            N: Node + Subresource,
637            SubresourceRange: From<N::Range>,
638        {
639            self.access_node_subrange_mut(node, access, subresource);
640            self
641        }
642
643        #[deprecated = "use set_subresource_access function"]
644        #[doc(hidden)]
645        pub fn access_node_subrange_mut<N>(
646            &mut self,
647            node: N,
648            access: AccessType,
649            subresource: impl Into<N::Range>,
650        ) -> &mut Self
651        where
652            N: Node + Subresource,
653            SubresourceRange: From<N::Range>,
654        {
655            self.set_subresource_access(node, subresource, access);
656            self
657        }
658
659        #[deprecated = "use resource_access function"]
660        #[doc(hidden)]
661        pub fn access_resource<N>(mut self, node: N, access: AccessType) -> Self
662        where
663            N: Node + Subresource,
664            SubresourceRange: From<N::Range>,
665        {
666            self.resource_access(node, access)
667        }
668
669        #[deprecated = "use subresource_access function"]
670        #[doc(hidden)]
671        pub fn access_subresource<N>(
672            mut self,
673            node: N,
674            subresource: impl Into<N::Range>,
675            access: AccessType,
676        ) -> Self
677        where
678            N: Node + Subresource,
679            SubresourceRange: From<N::Range>,
680        {
681            self.subresource_access(node, subresource, access)
682        }
683
684        #[deprecated = "use bind_resource function"]
685        #[doc(hidden)]
686        pub fn bind_node<R>(&mut self, resource: R) -> R::Node
687        where
688            R: Resource,
689        {
690            self.bind_resource(resource)
691        }
692
693        #[deprecated = "use device_address function of resource function result"]
694        #[doc(hidden)]
695        pub fn node_device_address(&self, node: impl Node) -> vk::DeviceAddress {
696            let idx = node.index();
697
698            self.graph.resources[idx].expect_buffer().device_address()
699        }
700
701        #[deprecated = "dereference info field of resource function result"]
702        #[doc(hidden)]
703        pub fn node_info<N>(&self, node: N) -> N::Type
704        where
705            N: Node + Info,
706        {
707            node.info(&self.graph.resources)
708        }
709
710        #[deprecated = "use record_cmd function"]
711        #[doc(hidden)]
712        pub fn record_acceleration(
713            mut self,
714            func: impl FnOnce(CommandRef<'_>, ()) + Send + 'static,
715        ) -> Self {
716            self.push_exec(|cmd| {
717                func(cmd, ());
718            });
719
720            self
721        }
722
723        #[deprecated = "use end_cmd function"]
724        #[doc(hidden)]
725        pub fn submit_pass(self) -> &'a mut Graph {
726            self.end_cmd()
727        }
728    }
729}