1 // Copyright (c) 2016 The vulkano developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
6 // at your option. All files in the project carrying such
7 // notice may not be copied, modified, or distributed except
8 // according to those terms.
9 
10 /// Builds a `RenderPass` object whose template parameter is of indeterminate type.
11 #[macro_export]
12 macro_rules! single_pass_renderpass {
13     (
14         $device:expr,
15         attachments: { $($a:tt)* },
16         pass: {
17             color: [$($color_atch:ident),* $(,)?],
18             depth_stencil: {$($depth_atch:ident)?}
19             $(,resolve: [$($resolve_atch:ident),* $(,)?])*
20             $(,)*
21         } $(,)?
22     ) => (
23         $crate::ordered_passes_renderpass!(
24             $device,
25             attachments: { $($a)* },
26             passes: [
27                 {
28                     color: [$($color_atch),*],
29                     depth_stencil: {$($depth_atch)*},
30                     input: [],
31                     resolve: [$($($resolve_atch),*)*]
32                 }
33             ]
34         )
35     )
36 }
37 
38 /// Builds a `RenderPass` object whose template parameter is of indeterminate type.
39 #[macro_export]
40 macro_rules! ordered_passes_renderpass {
41     (
42         $device:expr,
43         attachments: {
44             $(
45                 $atch_name:ident: {
46                     load: $load:ident,
47                     store: $store:ident,
48                     format: $format:expr,
49                     samples: $samples:expr
50                     $(,initial_layout: $init_layout:expr)?
51                     $(,final_layout: $final_layout:expr)?
52                     $(,)?
53                 }
54             ),* $(,)?
55         },
56         passes: [
57             $(
58                 {
59                     color: [$($color_atch:ident),* $(,)?],
60                     depth_stencil: {$($depth_atch:ident)* $(,)?},
61                     input: [$($input_atch:ident),* $(,)?]
62                     $(,resolve: [$($resolve_atch:ident),* $(,)?])?
63                     $(,)*
64                 }
65             ),* $(,)?
66         ] $(,)?
67     ) => ({
68         use $crate::render_pass::RenderPass;
69 
70         let create_info = {
71             #[allow(unused)]
72             let mut attachment_num = 0;
73             $(
74                 let $atch_name = attachment_num;
75                 attachment_num += 1;
76             )*
77 
78             #[allow(unused)]
79             let mut layouts: Vec<(
80                 Option<$crate::image::ImageLayout>,
81                 Option<$crate::image::ImageLayout>
82             )> = vec![(None, None); attachment_num as usize];
83 
84             let subpasses = vec![
85                 $({
86                     let desc = $crate::render_pass::SubpassDescription {
87                         color_attachments: vec![
88                             $({
89                                 let layout = &mut layouts[$color_atch as usize];
90                                 layout.0 = layout.0.or(Some($crate::image::ImageLayout::ColorAttachmentOptimal));
91                                 layout.1 = Some($crate::image::ImageLayout::ColorAttachmentOptimal);
92 
93                                 Some($crate::render_pass::AttachmentReference {
94                                     attachment: $color_atch,
95                                     layout: $crate::image::ImageLayout::ColorAttachmentOptimal,
96                                     ..Default::default()
97                                 })
98                             }),*
99                         ],
100                         depth_stencil_attachment: {
101                             let depth: Option<$crate::render_pass::AttachmentReference> = None;
102                             $(
103                                 let layout = &mut layouts[$depth_atch as usize];
104                                 layout.1 = Some($crate::image::ImageLayout::DepthStencilAttachmentOptimal);
105                                 layout.0 = layout.0.or(layout.1);
106 
107                                 let depth = Some($crate::render_pass::AttachmentReference {
108                                     attachment: $depth_atch,
109                                     layout: $crate::image::ImageLayout::DepthStencilAttachmentOptimal,
110                                     ..Default::default()
111                                 });
112                             )*
113                             depth
114                         },
115                         input_attachments: vec![
116                             $({
117                                 let layout = &mut layouts[$input_atch as usize];
118                                 layout.1 = Some($crate::image::ImageLayout::ShaderReadOnlyOptimal);
119                                 layout.0 = layout.0.or(layout.1);
120 
121                                 Some($crate::render_pass::AttachmentReference {
122                                     attachment: $input_atch,
123                                     layout: $crate::image::ImageLayout::ShaderReadOnlyOptimal,
124                                     ..Default::default()
125                                 })
126                             }),*
127                         ],
128                         resolve_attachments: vec![
129                             $($({
130                                 let layout = &mut layouts[$resolve_atch as usize];
131                                 layout.1 = Some($crate::image::ImageLayout::TransferDstOptimal);
132                                 layout.0 = layout.0.or(layout.1);
133 
134                                 Some($crate::render_pass::AttachmentReference {
135                                     attachment: $resolve_atch,
136                                     layout: $crate::image::ImageLayout::TransferDstOptimal,
137                                     ..Default::default()
138                                 })
139                             }),*)*
140                         ],
141                         preserve_attachments: (0 .. attachment_num).filter(|&a| {
142                             $(if a == $color_atch { return false; })*
143                             $(if a == $depth_atch { return false; })*
144                             $(if a == $input_atch { return false; })*
145                             $($(if a == $resolve_atch { return false; })*)*
146                             true
147                         }).collect(),
148                         ..Default::default()
149                     };
150 
151                     assert!(desc.resolve_attachments.is_empty() ||
152                             desc.resolve_attachments.len() == desc.color_attachments.len());
153                     desc
154                 }),*
155             ];
156 
157             let dependencies: Vec<_> = (0..subpasses.len().saturating_sub(1) as u32)
158                 .map(|id| {
159                     // TODO: correct values
160                     let src_stages = $crate::sync::PipelineStages::ALL_GRAPHICS;
161                     let dst_stages = $crate::sync::PipelineStages::ALL_GRAPHICS;
162                     let src_access = $crate::sync::AccessFlags::MEMORY_READ
163                         | $crate::sync::AccessFlags::MEMORY_WRITE;
164                     let dst_access = $crate::sync::AccessFlags::MEMORY_READ
165                         | $crate::sync::AccessFlags::MEMORY_WRITE;
166 
167                     $crate::render_pass::SubpassDependency {
168                         src_subpass: id.into(),
169                         dst_subpass: (id + 1).into(),
170                         src_stages,
171                         dst_stages,
172                         src_access,
173                         dst_access,
174                         // TODO: correct values
175                         dependency_flags: $crate::sync::DependencyFlags::BY_REGION,
176                         ..Default::default()
177                     }
178                 })
179                 .collect();
180 
181             let attachments = vec![
182                 $({
183                     let layout = &mut layouts[$atch_name as usize];
184                     $(layout.0 = Some($init_layout);)*
185                     $(layout.1 = Some($final_layout);)*
186 
187                     $crate::render_pass::AttachmentDescription {
188                         format: Some($format),
189                         samples: $crate::image::SampleCount::try_from($samples).unwrap(),
190                         load_op: $crate::render_pass::LoadOp::$load,
191                         store_op: $crate::render_pass::StoreOp::$store,
192                         stencil_load_op: $crate::render_pass::LoadOp::$load,
193                         stencil_store_op: $crate::render_pass::StoreOp::$store,
194                         initial_layout: layout.0.expect(
195                             format!(
196                                 "Attachment {} is missing initial_layout, this is normally \
197                                 automatically determined but you can manually specify it for an individual \
198                                 attachment in the single_pass_renderpass! macro",
199                                 attachment_num
200                             )
201                             .as_ref(),
202                         ),
203                         final_layout: layout.1.expect(
204                             format!(
205                                 "Attachment {} is missing final_layout, this is normally \
206                                 automatically determined but you can manually specify it for an individual \
207                                 attachment in the single_pass_renderpass! macro",
208                                 attachment_num
209                             )
210                             .as_ref(),
211                         ),
212                         ..Default::default()
213                     }
214                 }),*
215             ];
216 
217             $crate::render_pass::RenderPassCreateInfo {
218                 attachments,
219                 subpasses,
220                 dependencies,
221                 ..Default::default()
222             }
223         };
224 
225         RenderPass::new($device, create_info)
226     });
227 }
228 
229 #[cfg(test)]
230 mod tests {
231     use crate::format::Format;
232 
233     #[test]
single_pass_resolve()234     fn single_pass_resolve() {
235         let (device, _) = gfx_dev_and_queue!();
236         let _ = single_pass_renderpass!(
237             device,
238             attachments: {
239                 a: {
240                     load: Clear,
241                     store: DontCare,
242                     format: Format::R8G8B8A8_UNORM,
243                     samples: 4,
244                 },
245                 b: {
246                     load: DontCare,
247                     store: Store,
248                     format: Format::R8G8B8A8_UNORM,
249                     samples: 1,
250                 },
251             },
252             pass: {
253                 color: [a],
254                 depth_stencil: {},
255                 resolve: [b],
256             },
257         )
258         .unwrap();
259     }
260 }
261