1use {
2 super::{
3 AccessType, Binding, Command, Graph, Node, Resource, Subresource, SubresourceRange,
4 ViewInfo,
5 },
6 crate::{
7 ExecutionPipeline, TimestampQuery,
8 driver::{
9 compute::ComputePipeline, descriptor_set::DescriptorSet, graphics::GraphicsPipeline,
10 ray_tracing::RayTracingPipeline,
11 },
12 },
13 std::marker::PhantomData,
14};
15
16pub trait Pipeline<'a> {
20 type Command;
22
23 fn bind_cmd(self, _: Command<'a>) -> Self::Command;
27}
28
29macro_rules! pipeline {
30 ($variant:ident, $pipeline:ident, $is_fn:ident, $unwrap_fn:ident) => {
31 paste::paste! {
32 impl<'a> Pipeline<'a> for $pipeline {
33 type Command = PipelineCommand<'a, $pipeline>;
34
35 fn bind_cmd(self, mut cmd: Command<'a>) -> Self::Command {
36 {
37 let cmd = cmd.cmd_mut();
38 if cmd.expect_last_exec().pipeline.is_some() {
39 cmd.execs.push(Default::default());
40 }
41
42 cmd.expect_last_exec_mut().pipeline = Some(ExecutionPipeline::$variant(self));
43 }
44
45 Self::Command {
46 __: PhantomData,
47 cmd,
48 }
49 }
50 }
51
52 impl<'a> Pipeline<'a> for &'a $pipeline {
53 type Command = PipelineCommand<'a, $pipeline>;
54
55 fn bind_cmd(self, mut cmd: Command<'a>) -> Self::Command {
56 {
57 let cmd = cmd.cmd_mut();
58 if cmd.expect_last_exec().pipeline.is_some() {
59 cmd.execs.push(Default::default());
60 }
61
62 cmd.expect_last_exec_mut().pipeline
63 = Some(ExecutionPipeline::$variant(self.clone()));
64 }
65
66 Self::Command {
67 __: PhantomData,
68 cmd,
69 }
70 }
71
72 }
73
74 impl ExecutionPipeline {
75 #[allow(unused)]
76 pub(crate) fn $is_fn(&self) -> bool {
77 matches!(self, Self::$variant(_))
78 }
79
80 #[allow(unused)]
81 pub(crate) fn $unwrap_fn(&self) -> &$pipeline {
82 if let Self::$variant(binding) = self {
83 &binding
84 } else {
85 panic!();
86 }
87 }
88 }
89 }
90 };
91}
92
93pipeline!(Compute, ComputePipeline, is_compute, unwrap_compute);
95pipeline!(Graphics, GraphicsPipeline, is_graphics, unwrap_graphics);
96pipeline!(
97 RayTracing,
98 RayTracingPipeline,
99 is_ray_tracing,
100 unwrap_ray_tracing
101);
102
103pub struct PipelineCommand<'c, T> {
105 pub(super) __: PhantomData<T>,
106 pub(super) cmd: Command<'c>,
107}
108
109#[allow(private_bounds)]
111impl<'c, T> PipelineCommand<'c, T> {
112 pub fn bind_descriptor_set(mut self, descriptor_set: &DescriptorSet) -> Self {
123 self.set_descriptor_set(descriptor_set);
124 self
125 }
126
127 pub fn set_descriptor_set(&mut self, descriptor_set: &DescriptorSet) -> &mut Self {
129 let set = descriptor_set.info().set;
130 let exec = self.cmd.cmd_mut().expect_last_exec_mut();
131 let pipeline = exec.pipeline.as_ref().expect("missing command pipeline");
132 let layout = pipeline
133 .descriptor_info()
134 .layouts
135 .get(&set)
136 .unwrap_or_else(|| panic!("pipeline descriptor set {set} does not exist"));
137
138 assert!(
139 descriptor_set.is_compatible(set, layout),
140 "descriptor set {set} is incompatible with the bound pipeline"
141 );
142
143 exec.descriptor_sets.insert(set, descriptor_set.clone());
144
145 self
146 }
147
148 pub fn bind_pipeline<P>(self, pipeline: P) -> P::Command
150 where
151 P: Pipeline<'c>,
152 {
153 pipeline.bind_cmd(self.cmd)
154 }
155
156 pub fn bind_resource<R>(&mut self, resource: R) -> R::Node
158 where
159 R: Resource,
160 {
161 self.cmd.bind_resource(resource)
162 }
163
164 pub fn write_timestamp(&mut self) -> TimestampQuery {
166 self.cmd.write_timestamp()
167 }
168
169 pub fn end_cmd(self) -> &'c mut Graph {
171 self.cmd.end_cmd()
172 }
173
174 pub fn resource<N>(&self, resource_node: N) -> &N::Resource
176 where
177 N: Node,
178 {
179 self.cmd.resource(resource_node)
180 }
181
182 pub fn resource_access<N>(mut self, resource_node: N, access: AccessType) -> Self
187 where
188 N: Node + Subresource,
189 SubresourceRange: From<N::Range>,
190 {
191 self.cmd.set_resource_access(resource_node, access);
192 self
193 }
194
195 pub fn set_resource_access<N>(&mut self, resource_node: N, access: AccessType) -> &mut Self
197 where
198 N: Node + Subresource,
199 SubresourceRange: From<N::Range>,
200 {
201 self.cmd.set_resource_access(resource_node, access);
202 self
203 }
204
205 pub fn set_shader_resource_access<N>(
207 &mut self,
208 binding: impl Into<Binding>,
209 resource_node: N,
210 access: AccessType,
211 ) -> &mut Self
212 where
213 N: Node + Subresource,
214 N::Info: Copy,
215 SubresourceRange: From<N::Info>,
216 ViewInfo: From<N::Info>,
217 {
218 let subresource = resource_node.info(&self.cmd.graph.resources);
219
220 self.set_shader_subresource_access(binding, resource_node, subresource, access)
221 }
222
223 pub fn set_shader_subresource_access<N>(
225 &mut self,
226 binding: impl Into<Binding>,
227 resource_node: N,
228 subresource: impl Into<N::Info>,
229 access: AccessType,
230 ) -> &mut Self
231 where
232 N: Node + Subresource,
233 N::Info: Copy,
234 SubresourceRange: From<N::Info>,
235 ViewInfo: From<N::Info>,
236 {
237 let binding = binding.into();
238 let subresource = subresource.into();
239 let node_idx = resource_node.index();
240 let view_info = subresource.into();
241
242 self.cmd.push_subresource_access(
243 resource_node,
244 SubresourceRange::from(subresource),
245 access,
246 );
247
248 #[cfg(feature = "checked")]
249 {
250 if let Some(prev) = self.cmd.cmd().expect_last_exec().bindings.get(&binding) {
251 assert!(
252 *prev == (node_idx, view_info),
253 "shader binding {binding:?} already bound to a different resource or view"
254 );
255 }
256 }
257
258 self.cmd
259 .cmd_mut()
260 .expect_last_exec_mut()
261 .bindings
262 .insert(binding, (node_idx, view_info));
263
264 self
265 }
266
267 pub fn set_subresource_access<N>(
269 &mut self,
270 resource_node: N,
271 subresource: impl Into<N::Range>,
272 access: AccessType,
273 ) -> &mut Self
274 where
275 N: Node + Subresource,
276 SubresourceRange: From<N::Range>,
277 {
278 self.cmd
279 .set_subresource_access(resource_node, subresource, access);
280 self
281 }
282
283 pub fn shader_resource_access<N>(
292 mut self,
293 binding: impl Into<Binding>,
294 resource_node: N,
295 access: AccessType,
296 ) -> Self
297 where
298 N: Node + Subresource,
299 N::Info: Copy,
300 SubresourceRange: From<N::Info>,
301 ViewInfo: From<N::Info>,
302 {
303 self.set_shader_resource_access(binding, resource_node, access);
304 self
305 }
306
307 pub fn shader_subresource_access<N>(
317 mut self,
318 binding: impl Into<Binding>,
319 resource_node: N,
320 subresource: impl Into<N::Info>,
321 access: AccessType,
322 ) -> Self
323 where
324 N: Node + Subresource,
325 N::Info: Copy,
326 SubresourceRange: From<N::Info>,
327 ViewInfo: From<N::Info>,
328 {
329 self.set_shader_subresource_access(binding, resource_node, subresource, access);
330 self
331 }
332
333 pub fn subresource_access<N>(
339 mut self,
340 resource_node: N,
341 subresource: impl Into<N::Range>,
342 access: AccessType,
343 ) -> Self
344 where
345 N: Node + Subresource,
346 SubresourceRange: From<N::Range>,
347 {
348 self.cmd
349 .set_subresource_access(resource_node, subresource, access);
350 self
351 }
352}