Skip to main content

vk_graph/cmd/
pipeline.rs

1use {
2    super::{
3        AccessType, Binding, Command, Graph, Node, Resource, Subresource, SubresourceRange,
4        ViewInfo,
5    },
6    crate::{
7        ExecutionPipeline,
8        driver::{compute::ComputePipeline, graphic::GraphicPipeline, ray_trace::RayTracePipeline},
9    },
10    std::marker::PhantomData,
11};
12
13/// A trait for pipelines which may be bound to a `Command`.
14///
15/// See [`Command::bind_pipeline`](crate::cmd::Command::bind_pipeline) for details.
16pub trait Pipeline<'a> {
17    /// The resource reference type.
18    type Command;
19
20    /// Binds the resource to a command.
21    ///
22    /// Returns a reference type.
23    fn bind_cmd(self, _: Command<'a>) -> Self::Command;
24}
25
26macro_rules! pipeline {
27    ($name:ident) => {
28        paste::paste! {
29            impl<'a> Pipeline<'a> for [<$name Pipeline>] {
30                type Command = PipelineCommand<'a, [<$name Pipeline>]>;
31
32                fn bind_cmd(self, mut cmd: Command<'a>) -> Self::Command {
33                    {
34                        let cmd = cmd.cmd_mut();
35                        if cmd.expect_last_exec().pipeline.is_some() {
36                            cmd.execs.push(Default::default());
37                        }
38
39                        cmd.expect_last_exec_mut().pipeline
40                            = Some(ExecutionPipeline::$name(self));
41                    }
42
43                    Self::Command {
44                        __: PhantomData,
45                        cmd,
46                    }
47                }
48            }
49
50            impl<'a> Pipeline<'a> for &'a [<$name Pipeline>] {
51                type Command = PipelineCommand<'a, [<$name Pipeline>]>;
52
53                fn bind_cmd(self, mut cmd: Command<'a>) -> Self::Command {
54                    {
55                        let cmd = cmd.cmd_mut();
56                        if cmd.expect_last_exec().pipeline.is_some() {
57                            cmd.execs.push(Default::default());
58                        }
59
60                        cmd.expect_last_exec_mut().pipeline
61                            = Some(ExecutionPipeline::$name(self.clone()));
62                    }
63
64                    Self::Command {
65                        __: PhantomData,
66                        cmd,
67                    }
68                }
69
70            }
71
72            impl ExecutionPipeline {
73                #[allow(unused)]
74                pub(crate) fn [<is_ $name:snake>](&self) -> bool {
75                    matches!(self, Self::$name(_))
76                }
77
78                #[allow(unused)]
79                pub(crate) fn [<unwrap_ $name:snake>](&self) -> &[<$name Pipeline>] {
80                    if let Self::$name(binding) = self {
81                        &binding
82                    } else {
83                        panic!();
84                    }
85                }
86            }
87        }
88    };
89}
90
91// Pipelines you can bind to a command ref
92pipeline!(Compute);
93pipeline!(Graphic);
94pipeline!(RayTrace);
95
96/// A [`Command`] which has been bound to a particular compute, graphic, or ray-trace pipeline.
97pub struct PipelineCommand<'c, T> {
98    pub(super) __: PhantomData<T>,
99    pub(super) cmd: Command<'c>,
100}
101
102// NOTE: There are specific implementations of T in the compute, graphic, and ray trace modules
103impl<'c, T> PipelineCommand<'c, T> {
104    /// Binds a shader pipeline to the current command, allowing for strongly typed access to the
105    /// related functions.
106    ///
107    /// `P`|`P::Command`
108    /// -|-
109    /// [`ComputePipeline`](crate::driver::compute::ComputePipeline)|[`PipelineCommand<'_,
110    /// ComputePipeline>`]
111    /// [`GraphicPipeline`](crate::driver::graphic::GraphicPipeline)|[`PipelineCommand<'_,
112    /// GraphicPipeline>`]
113    /// [`RayTracePipeline`](crate::driver::ray_trace::RayTracePipeline)|[`PipelineCommand<'_,
114    /// RayTracePipeline>`]
115    pub fn bind_pipeline<P>(self, pipeline: P) -> P::Command
116    where
117        P: Pipeline<'c>,
118    {
119        pipeline.bind_cmd(self.cmd)
120    }
121
122    /// Binds a Vulkan buffer, image, or acceleration structure resource to the graph associated
123    /// with this command.
124    ///
125    /// Bound nodes may be used in passes for pipeline and shader operations.
126    pub fn bind_resource<R>(&mut self, resource: R) -> R::Node
127    where
128        R: Resource,
129    {
130        self.cmd.bind_resource(resource)
131    }
132
133    /// Finalizes a command and returns the graph so that additional commands may be added.
134    pub fn end_cmd(self) -> &'c mut Graph {
135        self.cmd.end_cmd()
136    }
137
138    /// Returns a borrow of the original Vulkan resource (buffer, image or acceleration structure)
139    /// which the given bound resource node represents.
140    pub fn resource<N>(&self, resource_node: N) -> &N::Resource
141    where
142        N: Node,
143    {
144        self.cmd.resource(resource_node)
145    }
146
147    /// Informs the command that the next recorded command buffer will read or write `resource_node`
148    /// using `access`.
149    ///
150    /// An access function must be called for `resource_node` before it is used within a
151    /// `record_`-function.
152    pub fn resource_access<N>(mut self, resource_node: N, access: AccessType) -> Self
153    where
154        N: Node + Subresource,
155        SubresourceRange: From<N::Range>,
156    {
157        self.cmd.set_resource_access(resource_node, access);
158        self
159    }
160
161    /// Informs the command that the next recorded command buffer will read or write `resource_node`
162    /// using `access`.
163    ///
164    /// An access function must be called for `resource_node` before it is used within a
165    /// `record_`-function.
166    pub fn set_resource_access<N>(&mut self, resource_node: N, access: AccessType) -> &mut Self
167    where
168        N: Node + Subresource,
169        SubresourceRange: From<N::Range>,
170    {
171        self.cmd.set_resource_access(resource_node, access);
172        self
173    }
174
175    /// Informs the command that the next recorded command buffer will read or write the
176    /// `resource_node` at the specified shader `binding` using `access`.
177    ///
178    /// An access function must be called for `resource_node` before it is used within a
179    /// `record_`-function.
180    pub fn set_shader_resource_access<N>(
181        &mut self,
182        binding: impl Into<Binding>,
183        resource_node: N,
184        access: AccessType,
185    ) -> &mut Self
186    where
187        N: Node + Subresource,
188        N::Info: Copy,
189        SubresourceRange: From<N::Info>,
190        ViewInfo: From<N::Info>,
191    {
192        let subresource = resource_node.info(&self.cmd.graph.resources);
193
194        self.set_shader_subresource_access(binding, resource_node, subresource, access)
195    }
196
197    /// Informs the command that the next recorded command buffer will read or write the
198    /// `resource_node` at the specified shader `binding` using `access`. The resource will be
199    /// interpreted using `view_info`.
200    ///
201    /// An access function must be called for `resource_node` before it is used within a
202    /// `record_`-function.
203    pub fn set_shader_subresource_access<N>(
204        &mut self,
205        binding: impl Into<Binding>,
206        resource_node: N,
207        subresource: impl Into<N::Info>,
208        access: AccessType,
209    ) -> &mut Self
210    where
211        N: Node + Subresource,
212        N::Info: Copy,
213        SubresourceRange: From<N::Info>,
214        ViewInfo: From<N::Info>,
215    {
216        let binding = binding.into();
217        let subresource = subresource.into();
218        let node_idx = resource_node.index();
219
220        self.cmd.push_subresource_access(
221            resource_node,
222            SubresourceRange::from(subresource),
223            access,
224        );
225
226        assert!(
227            self.cmd
228                .cmd_mut()
229                .expect_last_exec_mut()
230                .bindings
231                .insert(binding, (node_idx, subresource.into()))
232                .is_none(),
233            "binding {binding:?} has already been bound"
234        );
235
236        self
237    }
238
239    /// Informs the command that the next recorded command buffer will read or write the
240    /// `subresource` of `resource_node` using `access`.
241    ///
242    /// An access function must be called for `resource_node` before it is used within a
243    /// `record_`-function.
244    pub fn set_subresource_access<N>(
245        &mut self,
246        resource_node: N,
247        subresource: impl Into<N::Range>,
248        access: AccessType,
249    ) -> &mut Self
250    where
251        N: Node + Subresource,
252        SubresourceRange: From<N::Range>,
253    {
254        self.cmd
255            .set_subresource_access(resource_node, subresource, access);
256        self
257    }
258
259    /// Informs the command that the next recorded command buffer will read or write the
260    /// `resource_node` at the specified shader `binding` using `access`.
261    ///
262    /// An access function must be called for `resource_node` before it is used within a
263    /// `record_`-function.
264    pub fn shader_resource_access<N>(
265        mut self,
266        binding: impl Into<Binding>,
267        resource_node: N,
268        access: AccessType,
269    ) -> Self
270    where
271        N: Node + Subresource,
272        N::Info: Copy,
273        SubresourceRange: From<N::Info>,
274        ViewInfo: From<N::Info>,
275    {
276        self.set_shader_resource_access(binding, resource_node, access);
277        self
278    }
279
280    /// Informs the command that the next recorded command buffer will read or write the
281    /// `resource_node` at the specified shader `binding` using `access`. The resource will be
282    /// interpreted using `view_info`.
283    ///
284    /// An access function must be called for `resource_node` before it is used within a
285    /// `record_`-function.
286    pub fn shader_subresource_access<N>(
287        mut self,
288        binding: impl Into<Binding>,
289        resource_node: N,
290        subresource: impl Into<N::Info>,
291        access: AccessType,
292    ) -> Self
293    where
294        N: Node + Subresource,
295        N::Info: Copy,
296        SubresourceRange: From<N::Info>,
297        ViewInfo: From<N::Info>,
298    {
299        self.set_shader_subresource_access(binding, resource_node, subresource, access);
300        self
301    }
302
303    /// Informs the command that the next recorded command buffer will read or write the
304    /// `subresource` of `resource_node` using `access`.
305    ///
306    /// An access function must be called for `resource_node` before it is used within a
307    /// `record_`-function.
308    pub fn subresource_access<N>(
309        mut self,
310        resource_node: N,
311        subresource: impl Into<N::Range>,
312        access: AccessType,
313    ) -> Self
314    where
315        N: Node + Subresource,
316        SubresourceRange: From<N::Range>,
317    {
318        self.cmd
319            .set_subresource_access(resource_node, subresource, access);
320        self
321    }
322}
323
324#[allow(deprecated)]
325#[allow(unused)]
326mod deprecated {
327    use {
328        crate::{
329            Graph, Node, Resource,
330            cmd::{Binding, PipelineCommand, Subresource, SubresourceRange, ViewInfo},
331            deprecated::Info,
332            graph::pass_ref::ViewType,
333        },
334        ash::vk,
335        vk_sync::AccessType,
336    };
337
338    impl<'a, T> PipelineCommand<'a, T> {
339        #[deprecated = "use shader_resource_access function"]
340        #[doc(hidden)]
341        pub fn access_descriptor<N>(
342            self,
343            descriptor: impl Into<Binding>,
344            node: N,
345            access: AccessType,
346        ) -> Self
347        where
348            N: Node + Info + Subresource,
349            ViewType: From<<N as Subresource>::Info>,
350            <N as Subresource>::Info: Copy + From<<N as Info>::Type>,
351            <N as Subresource>::Range: From<<N as Subresource>::Info>,
352            SubresourceRange: From<N::Range>,
353        {
354            let view_info = Subresource::info(&node, &self.cmd.graph.resources);
355
356            self.access_descriptor_as(descriptor, node, access, view_info)
357        }
358
359        #[deprecated = "use shader_subresource_access function"]
360        #[doc(hidden)]
361        pub fn access_descriptor_as<N>(
362            self,
363            descriptor: impl Into<Binding>,
364            node: N,
365            access: AccessType,
366            view_info: impl Into<N::Info>,
367        ) -> Self
368        where
369            N: Node + Subresource,
370            <N as Subresource>::Info: Copy + Into<ViewType>,
371            <N as Subresource>::Range: From<<N as Subresource>::Info>,
372            SubresourceRange: From<N::Range>,
373        {
374            let view_info = view_info.into();
375            let subresource = <N as Subresource>::Range::from(view_info);
376
377            self.access_descriptor_subrange(descriptor, node, access, view_info, subresource)
378        }
379
380        #[deprecated = "use shader_subresource_access function"]
381        #[doc(hidden)]
382        pub fn access_descriptor_subrange<N>(
383            mut self,
384            descriptor: impl Into<Binding>,
385            node: N,
386            access: AccessType,
387            view_info: impl Into<N::Info>,
388            subresource: impl Into<N::Range>,
389        ) -> Self
390        where
391            N: Node + Subresource,
392            <N as Subresource>::Info: Into<ViewType>,
393            SubresourceRange: From<N::Range>,
394        {
395            let descriptor = descriptor.into();
396            let view_info = view_info.into();
397            let node_idx = node.index();
398
399            self.cmd.push_subresource_access(
400                node,
401                SubresourceRange::from(subresource.into()),
402                access,
403            );
404
405            assert!(
406                self.cmd
407                    .cmd_mut()
408                    .expect_last_exec_mut()
409                    .bindings
410                    .insert(descriptor, (node_idx, view_info.into()))
411                    .is_none(),
412                "descriptor {descriptor:?} has already been bound"
413            );
414
415            self
416        }
417
418        #[deprecated = "use resource_access function"]
419        #[doc(hidden)]
420        pub fn access_node<N>(mut self, node: N, access: AccessType) -> Self
421        where
422            N: Node + Subresource,
423            SubresourceRange: From<N::Range>,
424        {
425            self.resource_access(node, access)
426        }
427
428        #[deprecated = "use subresource_access function"]
429        #[doc(hidden)]
430        pub fn access_node_subrange<N>(
431            mut self,
432            node: N,
433            access: AccessType,
434            subresource: impl Into<N::Range>,
435        ) -> Self
436        where
437            N: Node + Subresource,
438            SubresourceRange: From<N::Range>,
439        {
440            self.access_node_subrange_mut(node, access, subresource);
441            self
442        }
443
444        #[deprecated = "use set_subresource_access function"]
445        #[doc(hidden)]
446        pub fn access_node_subrange_mut<N>(
447            &mut self,
448            node: N,
449            access: AccessType,
450            subresource: impl Into<N::Range>,
451        ) -> &mut Self
452        where
453            N: Node + Subresource,
454            SubresourceRange: From<N::Range>,
455        {
456            self.set_subresource_access(node, subresource, access)
457        }
458
459        #[deprecated = "use bind_resource function"]
460        #[doc(hidden)]
461        pub fn bind_node<R>(&mut self, resource: R) -> R::Node
462        where
463            R: Resource,
464        {
465            self.bind_resource(resource)
466        }
467
468        #[deprecated = "use device_address function of resource function result"]
469        #[doc(hidden)]
470        pub fn node_device_address(&self, node: impl Node) -> vk::DeviceAddress {
471            let idx = node.index();
472
473            self.cmd.graph.resources[idx]
474                .expect_buffer()
475                .device_address()
476        }
477
478        #[deprecated = "dereference info field of resource function result"]
479        #[doc(hidden)]
480        pub fn node_info<N>(&self, node: N) -> N::Type
481        where
482            N: Node + Info,
483        {
484            node.info(&self.cmd.graph.resources)
485        }
486
487        #[deprecated = "use end_cmd function"]
488        #[doc(hidden)]
489        pub fn submit_pass(self) -> &'a mut Graph {
490            self.end_cmd()
491        }
492    }
493}