1     object Vulkan
2         let vk_attachment_unused : u32 = !0
3     
4     object VkRenderPass =
5         def create (device : VkDevice
6                     attachments : List<AttachmentFormat>
7                     passes : List<SubpassFormat>
8                     settings : Settings) : (SampleCountFlags, VkRenderPass) =
9             let default_access_mask = AccessFlags/InputAttachmentRead
10                                      | AccessFlags/ColorAttachmentRead
11                                      | AccessFlags/ColorAttachmentWrite
12                                      | AccessFlags/DepthStencilAttachmentRead
13                                      | AccessFlags/DepthStencilAttachmentWrite
14    
15            let reading_stages = PipelineStageFlags/ComputeShader
16                                 | PipelineStageFlags/VertexShader
17                                 | PipelineStageFlags/FragmentShader
18                                 | PipelineStageFlags/Transfer
19    
20            let mut dependency_from_external = SubpassDependency
21                src_subpass = Vulkan.subpass_external
22                dst_subpass = 0
23                src_stage_mask = PipelineStageFlags/TopOfPipe
24                dst_stage_mask = PipelineStageFlags/AllGraphics
25                src_access_mask = AccessFlags@zero
26                dst_access_mask = default_access_mask
27                dependency_flags = DependencyFlags@zero
28    
29            let mut dependency_to_external = SubpassDependency
30                src_subpass = 0
31                dst_subpass = Vulkan.subpass_external
32                src_stage_mask = PipelineStageFlags/AllGraphics
33                dst_stage_mask = PipelineStageFlags/BottomOfPipe
34                src_access_mask = default_access_mask
35                dst_access_mask = AccessFlags@zero
36                dependency_flags = DependencyFlags@zero
37    
38            let attachment_descriptions = List<AttachmentDescription>.new
39    
40            for attachment in attachments do
41                let usage = attachment.usage
42                let is_sampled = usage.contains ImageUsageFlags/Sampled
43                let is_storage = usage.contains ImageUsageFlags/Storage
44                let is_color = usage.contains ImageUsageFlags/ColorAttachment
45                let is_depth = usage.contains ImageUsageFlags/DepthStencilAttachment
46    
47                let (enter_op, exit_op) =
48                    if is_depth
49                    then (settings.depth_enter_op, settings.depth_exit_op)
50                    else (settings.color_enter_op, settings.color_exit_op)
51    
52                if enter_op == EnterOp/Clear
53                   || enter_op == EnterOp/Load && is_depth
54                   || not is_depth && not is_color
55                then
56                    dependency_from_external.src_stage_mask |= reading_stages
57    
58                if exit_op == ExitOp/Read then
59                    dependency_to_external.dst_stage_mask |= PipelineStageFlags/Transfer
60                    dependency_to_external.dst_access_mask |= AccessFlags/TransferRead
61    
62                    if is_sampled then
63                        dependency_to_external.dst_stage_mask |=
64                            PipelineStageFlags/VertexShader
65                            | PipelineStageFlags/FragmentShader
66                            | PipelineStageFlags/ComputeShader
67    
68                        dependency_to_external.dst_access_mask |= AccessFlags/ShaderRead
69    
70                    else if is_storage then
71                        dependency_to_external.dst_stage_mask |=
72                            PipelineStageFlags/VertexShader
73                            | PipelineStageFlags/FragmentShader
74                            | PipelineStageFlags/ComputeShader
75    
76                        dependency_to_external.dst_access_mask |=
77                            AccessFlags/ShaderRead | AccessFlags/ShaderWrite
78                    else
79                        dependency_to_external.dst_stage_mask |=
80                            PipelineStageFlags/ColorAttachmentOutput
81    
82                        dependency_to_external.dst_access_mask |=
83                            AccessFlags/ColorAttachmentRead
84                            | AccessFlags/ColorAttachmentWrite
85    
86                    if is_depth then
87                        dependency_to_external.dst_stage_mask |=
88                            PipelineStageFlags/EarlyFragmentTests
89                            | PipelineStageFlags/LateFragmentTests
90    
91                        dependency_to_external.dst_access_mask |=
92                            AccessFlags/DepthStencilAttachmentRead
93                            | AccessFlags/DepthStencilAttachmentWrite
94    
95                let description = if not is_depth && not is_color then
96                    AttachmentDescription
97                        flags = AttachmentDescriptionFlags@zero
98                        format = attachment.format
99                        samples = attachment.samples
100                       load_op = AttachmentLoadOp/DontCare
101                       stencil_load_op = AttachmentLoadOp/DontCare
102                       initial_layout = ImageLayout/Undefined
103                       store_op = AttachmentStoreOp/DontCare
104                       stencil_store_op = AttachmentStoreOp/DontCare
105                       final_layout = ImageLayout/Undefined
106                       f@ AttachmentDescription.default
107               else
108                   let optimal_layout = when
109                       is_color && not is_depth -> ImageLayout/ColorAttachmentOptimal
110                       not is_color && is_depth ->
111                           ImageLayout/DepthStencilAttachmentOptimal
112   
113                       else -> fail
114   
115                   let default_layout = when
116                       is_sampled -> ImageLayout/ShaderReadOnlyOptimal
117                       is_storage -> ImageLayout/General
118                       else -> optimal_layout
119   
120                   let initial_layout = case enter_op of
121                       EnterOp/Clear -> ImageLayout/Undefined
122                       EnterOp/Continue -> optimal_layout
123                       EnterOp/Load -> default_layout
124   
125                   let final_layout = case exit_op of
126                       ExitOp/Continue -> optimal_layout
127                       ExitOp/Read | ExitOp/Discard -> default_layout
128   
129                   let load_op = case enter_op of
130                       EnterOp/Clear -> AttachmentLoadOp/Clear
131                       EnterOp/Load -> AttachmentLoadOp/Load
132                       EnterOp/Continue -> AttachmentLoadOp/Load
133   
134                   let stencil_load_op = when
135                       enter_op == EnterOp/Clear -> AttachmentLoadOp/Clear
136                       is_color -> AttachmentLoadOp/DontCare
137                       is_depth -> AttachmentLoadOp/Load
138                       else -> fail
139   
140                   let (store_op, stencil_store_op) = if is_color then
141                       case exit_op of
142                           ExitOp/Read ->
143                               (AttachmentStoreOp/Store, AttachmentStoreOp/DontCare)
144   
145                           ExitOp/Discard ->
146                               (AttachmentStoreOp/DontCare, AttachmentStoreOp/DontCare)
147   
148                           ExitOp/Continue ->
149                               (AttachmentStoreOp/Store, AttachmentStoreOp/DontCare)
150   
151                   else if is_depth then
152                       case exit_op of
153                           ExitOp/Read ->
154                               (AttachmentStoreOp/Store, AttachmentStoreOp/Store)
155   
156                           ExitOp/Discard ->
157                               (AttachmentStoreOp/DontCare, AttachmentStoreOp/DontCare)
158   
159                           ExitOp/Continue ->
160                               (AttachmentStoreOp/Store, AttachmentStoreOp/Store)
161                   else
162                       fail
163   
164                   AttachmentDescription
165                       flags = AttachmentDescriptionFlags@zero
166                       format = attachment.format
167                       samples = attachment.samples
168                       =load_op
169                       =stencil_load_op
170                       =initial_layout
171                       =store_op
172                       =stencil_store_op
173                       =final_layout
174                       f@ AttachmentDescription.default
175   
176               attachment_descriptions.add description
177   
178           let subpasses = List<SubpassDescription>.new
179           let pass_color_references = List<List<AttachmentReference>>.new
180           let pass_input_references = List<List<AttachmentReference>>.new
181           let pass_resolve_references = List<List<AttachmentReference>>.new
182           let pass_preserve_references = List<List<u32>>.new
183           let pass_depth_references = List<AttachmentReference>.new
184   
185           let subpass_dependencies =
186               if settings.no_dependencies
187               then List<SubpassDependency>.new
188               else [dependency_from_external, dependency_to_external]
189   
190           let get_samples (pass : SubpassFormat) =
191               let attachment = if pass.color_attachments.is_empty
192                                then pass.depth_attachment
193                                else pass.color_attachments[0]
194   
195               attachments[attachment].samples
196   
197           for i = 0 until passes.size do
198               let pass = passes[i]
199               let color_references = List<AttachmentReference>.new
200               let samples = get_samples pass
201   
202               for j = 0 until pass.color_attachments.size do
203                   let attachment = pass.color_attachments[j]
204                   let reference = if attachment == Vulkan.attachment_unused then
205                       AttachmentReference
206                           attachment = Vulkan.vk_attachment_unused
207                           layout = ImageLayout/Undefined
208                   else
209                       assert attachments[attachment].usage.contains
210                                  ImageUsageFlags/ColorAttachment
211                              && attachments[attachment].samples == samples
212   
213                       AttachmentReference
214                           attachment = attachment as u32
215                           layout = ImageLayout/ColorAttachmentOptimal
216   
217                   color_references.add reference
218   
219               let input_references = List<AttachmentReference>.new
220   
221               for j = 0 until pass.input_attachments.size do
222                   let attachment = pass.input_attachments[j]
223                   let reference = if attachment == Vulkan.attachment_unused then
224                       AttachmentReference
225                           attachment = Vulkan.vk_attachment_unused
226                           layout = ImageLayout/Undefined
227                   else
228                       assert attachments[attachment].usage.contains
229                                  ImageUsageFlags/ColorAttachment
230   
231                       AttachmentReference
232                           attachment = attachment as u32
233                           layout = ImageLayout/ShaderReadOnlyOptimal
234   
235                   input_references.add reference
236   
237               let resolve_references = List<AttachmentReference>.new
238   
239               if pass.resolve_attachments.size > 0 then
240                   assert pass.resolve_attachments.size == pass.color_attachments.size
241                          && samples <> SampleCountFlags/1
242   
243               for j = 0 until pass.resolve_attachments.size do
244                   let attachment = pass.resolve_attachments[j]
245                   let reference = if attachment == Vulkan.attachment_unused then
246                       AttachmentReference
247                           attachment = Vulkan.vk_attachment_unused
248                           layout = ImageLayout/Undefined
249                   else
250                       assert pass.color_attachments[j] <> Vulkan.attachment_unused
251                       assert attachments[attachment].usage.contains
252                                  ImageUsageFlags/ColorAttachment
253   
254                       assert attachments[attachment].samples == SampleCountFlags/1
255   
256                       AttachmentReference
257                           attachment = attachment as u32
258                           layout = ImageLayout/ShaderReadOnlyOptimal
259   
260                   resolve_references.add reference
261   
262               let preserve_references = List<u32>.new
263   
264               for j = 0 until pass.preserve_attachments.size do
265                   let attachment = pass.preserve_attachments[j]
266                   assert attachment <> Vulkan.attachment_unused
267                   preserve_references.add attachment.as<u32>
268   
269               let depth_stencil_reference =
270                   if pass.depth_attachment <> Vulkan.attachment_unused then
271                       let attachment = pass.depth_attachment
272                       assert attachments[attachment].usage.contains
273                                  ImageUsageFlags/DepthStencilAttachment
274                              && attachments[attachment].samples == samples
275   
276                       AttachmentReference
277                           attachment = attachment as u32
278                           layout = ImageLayout/DepthStencilAttachmentOptimal
279                   else
280                       AttachmentReference
281                           attachment = Vulkan.vk_attachment_unused
282                           layout = ImageLayout/Undefined
283   
284               pass_depth_references.add depth_stencil_reference
285               let depth_stencil_ref_in_vec = pass_depth_references.last
286   
287               let subpass = SubpassDescription
288                   flags = SubpassDescriptionFlags@zero
289                   pipeline_bind_point = PipelineBindPoint/Graphics
290                   input_attachment_count = input_references.size
291                   input_attachments =
292                       if input_references.size > 0
293                       then input_references.as_ptr
294                       else null
295   
296                   color_attachment_count = color_references.size
297                   color_attachments =
298                       if color_references.size > 0
299                       then color_references.as_ptr
300                       else null
301   
302                   depth_stencil_attachment =
303                       if depth_stencil_ref_in_vec.attachment <> Vulkan.vk_attachment_unused
304                       then depth_stencil_ref_in_vec@ptr
305                       else null
306   
307                   resolve_attachments =
308                       if resolve_references.size > 0
309                       then resolve_references.as_ptr
310                       else null
311   
312                   preserve_attachment_count = preserve_references.size as u32
313                   preserve_attachments =
314                       if preserve_references.size > 0
315                       then preserve_references.as_ptr
316                       else null
317   
318               subpasses.add subpass
319               pass_color_references.add color_references
320               pass_input_references.add input_references
321               pass_resolve_references.add resolve_references
322               pass_preserve_references.add preserve_references
323   
324               if i > 0 then
325                   let dependency = SubpassDependency
326                       src_subpass = i - 1
327                       dst_subpass = i
328                       src_stage_mask = PipelineStageFlags/ColorAttachmentOutput
329                                        | PipelineStageFlags/EarlyFragmentTests
330                                        | PipelineStageFlags/LateFragmentTests
331                       dst_stage_mask = PipelineStageFlags/ColorAttachmentOutput
332                                        | PipelineStageFlags/EarlyFragmentTests
333                                        | PipelineStageFlags/LateFragmentTests
334                                        | PipelineStageFlags/FragmentShader
335                       src_access_mask = AccessFlags/ColorAttachmentWrite
336                                         | AccessFlags/DepthStencilAttachmentWrite
337                       dst_access_mask = AccessFlags/ColorAttachmentRead
338                                         | AccessFlags/ColorAttachmentWrite
339                                         | AccessFlags/DepthStencilAttachmentRead
340                                         | AccessFlags/InputAttachmentRead
341                       dependency_flags = DependencyFlags/ByRegion
342   
343                   subpass_dependencies.add dependency
344   
345           let render_pass_create_info = RenderPassCreateInfo
346               type = StructureType/RenderPassCreateInfo
347               next = null
348               flags = RenderPassCreateFlags@zero
349               attachment_count = attachment_descriptions.size
350               attachments = attachment_descriptions.as_ptr
351               subpass_count = subpasses.size
352               subpasses = subpasses.as_ptr
353               dependency_count = subpass_dependencies.size
354               dependencies = if subpass_dependencies.size > 0
355                              then subpass_dependencies.as_ptr
356                              else null
357   
358           let mut render_pass = null
359           vk/create_render_pass device render_pass_create_info@ptr null
360                                 render_pass@mut_ptr
361           |> assert_success
362   
363           (get_samples passes[0], render_pass)
364   
365   object RenderPass =
366       def create (format : RenderPassFormat
367                   settings : Settings
368                   cache : RenderPassCache) =
369           let instance : Instance @auto
370   
371           if cache.contains settings then
372               return cache.get settings
373   
374           let (samples, object) = VkRenderPass.create instance.device format.attachments
375                                                       format.subpasses settings
376   
377           let render_pass = RenderPass =format =object =samples
378           cache.add settings render_pass
379   
380           render_pass
381