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::{
9            compute::ComputePipeline, graphics::GraphicsPipeline, ray_tracing::RayTracingPipeline,
10        },
11    },
12    std::marker::PhantomData,
13};
14
15/// A trait for pipelines which may be bound to a `Command`.
16///
17/// See [`Command::bind_pipeline`](crate::cmd::Command::bind_pipeline) for details.
18pub trait Pipeline<'a> {
19    /// The resource reference type.
20    type Command;
21
22    /// Binds the resource to a command.
23    ///
24    /// Returns a reference type.
25    fn bind_cmd(self, _: Command<'a>) -> Self::Command;
26}
27
28macro_rules! pipeline {
29    ($variant:ident, $pipeline:ident, $is_fn:ident, $unwrap_fn:ident) => {
30        paste::paste! {
31            impl<'a> Pipeline<'a> for $pipeline {
32                type Command = PipelineCommand<'a, $pipeline>;
33
34                fn bind_cmd(self, mut cmd: Command<'a>) -> Self::Command {
35                    {
36                        let cmd = cmd.cmd_mut();
37                        if cmd.expect_last_exec().pipeline.is_some() {
38                            cmd.execs.push(Default::default());
39                        }
40
41                        cmd.expect_last_exec_mut().pipeline = Some(ExecutionPipeline::$variant(self));
42                    }
43
44                    Self::Command {
45                        __: PhantomData,
46                        cmd,
47                    }
48                }
49            }
50
51            impl<'a> Pipeline<'a> for &'a $pipeline {
52                type Command = PipelineCommand<'a, $pipeline>;
53
54                fn bind_cmd(self, mut cmd: Command<'a>) -> Self::Command {
55                    {
56                        let cmd = cmd.cmd_mut();
57                        if cmd.expect_last_exec().pipeline.is_some() {
58                            cmd.execs.push(Default::default());
59                        }
60
61                        cmd.expect_last_exec_mut().pipeline
62                            = Some(ExecutionPipeline::$variant(self.clone()));
63                    }
64
65                    Self::Command {
66                        __: PhantomData,
67                        cmd,
68                    }
69                }
70
71            }
72
73            impl ExecutionPipeline {
74                #[allow(unused)]
75                pub(crate) fn $is_fn(&self) -> bool {
76                    matches!(self, Self::$variant(_))
77                }
78
79                #[allow(unused)]
80                pub(crate) fn $unwrap_fn(&self) -> &$pipeline {
81                    if let Self::$variant(binding) = self {
82                        &binding
83                    } else {
84                        panic!();
85                    }
86                }
87            }
88        }
89    };
90}
91
92// Pipelines you can bind to a command ref
93pipeline!(Compute, ComputePipeline, is_compute, unwrap_compute);
94pipeline!(Graphics, GraphicsPipeline, is_graphics, unwrap_graphics);
95pipeline!(
96    RayTracing,
97    RayTracingPipeline,
98    is_ray_tracing,
99    unwrap_ray_tracing
100);
101
102/// A [`Command`] which has been bound to a particular compute, graphics, or ray tracing pipeline.
103pub struct PipelineCommand<'c, T> {
104    pub(super) __: PhantomData<T>,
105    pub(super) cmd: Command<'c>,
106}
107
108// NOTE: There are specific implementations of T in the compute, graphics, and ray tracing modules
109#[allow(private_bounds)]
110impl<'c, T> PipelineCommand<'c, T> {
111    /// Equivalent to [`Command::bind_pipeline`] for a command that already has a bound pipeline.
112    pub fn bind_pipeline<P>(self, pipeline: P) -> P::Command
113    where
114        P: Pipeline<'c>,
115    {
116        pipeline.bind_cmd(self.cmd)
117    }
118
119    /// Equivalent to [`Command::bind_resource`] for a command that already has a bound pipeline.
120    pub fn bind_resource<R>(&mut self, resource: R) -> R::Node
121    where
122        R: Resource,
123    {
124        self.cmd.bind_resource(resource)
125    }
126
127    /// Equivalent to [`Command::end_cmd`] for a command that already has a bound pipeline.
128    pub fn end_cmd(self) -> &'c mut Graph {
129        self.cmd.end_cmd()
130    }
131
132    /// Equivalent to [`Command::resource`] for a command that already has a bound pipeline.
133    pub fn resource<N>(&self, resource_node: N) -> &N::Resource
134    where
135        N: Node,
136    {
137        self.cmd.resource(resource_node)
138    }
139
140    /// Informs the command that recorded work will read or write `resource_node` using `access`.
141    ///
142    /// An access function must be called for `resource_node` before it is used within a recording
143    /// function.
144    pub fn resource_access<N>(mut self, resource_node: N, access: AccessType) -> Self
145    where
146        N: Node + Subresource,
147        SubresourceRange: From<N::Range>,
148    {
149        self.cmd.set_resource_access(resource_node, access);
150        self
151    }
152
153    /// Mutable-borrow form of [`Self::resource_access`].
154    pub fn set_resource_access<N>(&mut self, resource_node: N, access: AccessType) -> &mut Self
155    where
156        N: Node + Subresource,
157        SubresourceRange: From<N::Range>,
158    {
159        self.cmd.set_resource_access(resource_node, access);
160        self
161    }
162
163    /// Mutable-borrow form of [`Self::shader_resource_access`].
164    pub fn set_shader_resource_access<N>(
165        &mut self,
166        binding: impl Into<Binding>,
167        resource_node: N,
168        access: AccessType,
169    ) -> &mut Self
170    where
171        N: Node + Subresource,
172        N::Info: Copy,
173        SubresourceRange: From<N::Info>,
174        ViewInfo: From<N::Info>,
175    {
176        let subresource = resource_node.info(&self.cmd.graph.resources);
177
178        self.set_shader_subresource_access(binding, resource_node, subresource, access)
179    }
180
181    /// Mutable-borrow form of [`Self::shader_subresource_access`].
182    pub fn set_shader_subresource_access<N>(
183        &mut self,
184        binding: impl Into<Binding>,
185        resource_node: N,
186        subresource: impl Into<N::Info>,
187        access: AccessType,
188    ) -> &mut Self
189    where
190        N: Node + Subresource,
191        N::Info: Copy,
192        SubresourceRange: From<N::Info>,
193        ViewInfo: From<N::Info>,
194    {
195        let binding = binding.into();
196        let subresource = subresource.into();
197        let node_idx = resource_node.index();
198        let view_info = subresource.into();
199
200        self.cmd.push_subresource_access(
201            resource_node,
202            SubresourceRange::from(subresource),
203            access,
204        );
205
206        #[cfg(feature = "checked")]
207        {
208            if let Some(prev) = self.cmd.cmd().expect_last_exec().bindings.get(&binding) {
209                assert!(
210                    *prev == (node_idx, view_info),
211                    "shader binding {binding:?} already bound to a different resource or view"
212                );
213            }
214        }
215
216        self.cmd
217            .cmd_mut()
218            .expect_last_exec_mut()
219            .bindings
220            .insert(binding, (node_idx, view_info));
221
222        self
223    }
224
225    /// Mutable-borrow form of [`Self::subresource_access`].
226    pub fn set_subresource_access<N>(
227        &mut self,
228        resource_node: N,
229        subresource: impl Into<N::Range>,
230        access: AccessType,
231    ) -> &mut Self
232    where
233        N: Node + Subresource,
234        SubresourceRange: From<N::Range>,
235    {
236        self.cmd
237            .set_subresource_access(resource_node, subresource, access);
238        self
239    }
240
241    /// Informs the command that recorded work will read or write the `resource_node` at the
242    /// specified shader `binding` using `access`.
243    ///
244    /// If the same `binding` slot is used more than once, the last call wins and the previous
245    /// binding is silently overwritten.
246    ///
247    /// An access function must be called for `resource_node` before it is used within a recording
248    /// function.
249    pub fn shader_resource_access<N>(
250        mut self,
251        binding: impl Into<Binding>,
252        resource_node: N,
253        access: AccessType,
254    ) -> Self
255    where
256        N: Node + Subresource,
257        N::Info: Copy,
258        SubresourceRange: From<N::Info>,
259        ViewInfo: From<N::Info>,
260    {
261        self.set_shader_resource_access(binding, resource_node, access);
262        self
263    }
264
265    /// Informs the command that recorded work will read or write the `resource_node` at the
266    /// specified shader `binding` using `access`. The resource will be interpreted using
267    /// `view_info`.
268    ///
269    /// If the same `binding` slot is used more than once, the last call wins and the previous
270    /// binding is silently overwritten.
271    ///
272    /// An access function must be called for `resource_node` before it is used within a recording
273    /// function.
274    pub fn shader_subresource_access<N>(
275        mut self,
276        binding: impl Into<Binding>,
277        resource_node: N,
278        subresource: impl Into<N::Info>,
279        access: AccessType,
280    ) -> Self
281    where
282        N: Node + Subresource,
283        N::Info: Copy,
284        SubresourceRange: From<N::Info>,
285        ViewInfo: From<N::Info>,
286    {
287        self.set_shader_subresource_access(binding, resource_node, subresource, access);
288        self
289    }
290
291    /// Informs the command that recorded work will read or write the `subresource` of
292    /// `resource_node` using `access`.
293    ///
294    /// An access function must be called for `resource_node` before it is used within a recording
295    /// function.
296    pub fn subresource_access<N>(
297        mut self,
298        resource_node: N,
299        subresource: impl Into<N::Range>,
300        access: AccessType,
301    ) -> Self
302    where
303        N: Node + Subresource,
304        SubresourceRange: From<N::Range>,
305    {
306        self.cmd
307            .set_subresource_access(resource_node, subresource, access);
308        self
309    }
310}