1     type DrawPushConstant = struct
2         object_index : u32
3     
4     type Renderer
5         let render (objects : Slice<Object>
6                     scene_descriptor_set : DescriptorSet
7                     framebuffer : Framebuffer
8                     color_load_op : EnterOp
9                     color_store_op : ExitOp
10                    depth_load_op : EnterOp
11                    depth_store_op : ExitOp
12                    clear_colors : Slice<Vector4>) =
13            let render_pass = draw/begin framebuffer color_load_op color_store_op
14                                         depth_load_op depth_store_op clear_colors
15    
16            if lighting.descriptor_set <> null then
17                draw/bind_descriptor_set lighting.descriptor_set Renderer.lighting_set
18    
19            draw/bind_descriptor_set scene_descriptor_set Renderer.scene_set
20    
21            let is_depth = framebuffer.format.attachments
22                           |> all { is_depth_format _.format }
23    
24            let mut previous_material_descriptor_set = null
25            let mut previous_pipeline = null
26    
27            for i = 0 until objects.size do
28                let object = objects[i]
29                let mesh = object.mesh
30                let vertex_format = mesh.format
31                if mesh.index_count == 0
32                   || object.material.vertex_shader == ""
33                   || object.material.fragment_shader == ""
34                then
35                    continue
36    
37                do
38                    let scissor = vulkan.framebuffer_scissor.intersect object.scissor
39                    vulkan.command_buffer.scissor scissor
40    
41                let (vertex_shader, fragment_shader) = if is_depth then
42                    if vertex_format == VertexFormat.regular then
43                        vulkan.depth_shader
44                    else
45                        assert vertex_format == VertexFormat.skinned
46                        vulkan.depth_skinned_shader
47                else
48                    (vulkan.get_shader object.material.vertex_shader as VertexShader
49                     vulkan.get_shader object.material.fragment_shader as FragmentShader)
50    
51                draw/bind_vertex_buffer mesh.vertex_buffer
52                draw/bind_index_buffer mesh.index_buffer 0 mesh.index_count
53    
54                let pipeline_cache =
55                    let settings = PipelineSettings =vertex_shader =fragment_shader
56                                                    =cull_mode
57                    vulkan.pipeline_cache settings
58    
59                let pipeline = pipeline_cache.get vertex_format render_pass
60                let material_descriptor_set = if
61                    is_depth
62                    || pipeline_cache.pipeline_layout.descriptor_set_layouts.size
63                       <= Renderer.material_set
64                then
65                    null
66                else
67                    if object.material.pipeline_layout <> pipeline_cache.pipeline_layout
68                       && object.material.descriptor_set <> null
69                    then
70                        object.material.descriptor_set.discard
71                        object.material.descriptor_set = null
72    
73                    if object.material.descriptor_set == null then
74                        if vulkan.material_images.contains object.material then
75                            vulkan.material_images.remove_all object.material
76    
77                        object.material.descriptor_set = DescriptorSet.create
78                            object.material.resources.as_slice
79                            pipeline_cache.pipeline_layout[Renderer.material_set]
80    
81                        object.material.pipeline_layout = pipeline_cache.pipeline_layout
82    
83                        for _, items in object.material.resources do
84                            let add (name : String) =
85                                vulkan.material_images.add object.material name
86    
87                            let add_resource (resource : Resource) = case resource of
88                                Resource/ImageName name -> add name
89                                Resource/ImageNameSampler name _ -> add name
90                                else -> ()
91    
92                            case items of
93                                OneMany/One resource -> add_resource resource
94                                OneMany/Many resources ->
95                                    for resource in resources do
96                                        add_resource resource
97    
98                    object.material.descriptor_set
99    
100               if pipeline <> previous_pipeline then
101                   draw/bind_pipeline pipeline
102                   previous_pipeline = pipeline
103   
104               if material_descriptor_set <> previous_material_descriptor_set then
105                   if material_descriptor_set <> null then
106                       draw/bind_descriptor_set material_descriptor_set
107                                                Renderer.material_set
108   
109                   previous_material_descriptor_set = material_descriptor_set
110   
111               let push_constant = DrawPushConstant object_index = i
112               draw/set_push_constant push_constant@ptr
113               draw/draw
114   
115           vulkan.command_buffer.scissor vulkan.framebuffer_scissor
116           draw/end
117   
118       def render =
119           begin_label "Render Setup"
120   
121           for i = 0 until cameras.size do
122               let c = cameras[i]
123               let view = c.view
124               let projection = c.projection size.value.width size.value.height
125               scene_ubo.cameras[i].view = view.transpose
126                                    view_inverse = view.inverse.transpose
127                                    projection = projection.transpose
128                                    projection_inverse = projection.inverse.transpose
129   
130           scene_ubo.time = vulkan.time as f32
131           scene_buffer.update_single scene_ubo@ptr BarrierFlags/Raster
132   
133           if skin_buffer == null
134              || skin_buffer_size < skin_matrices.size * sizeof Matrix4
135           then
136               if skin_buffer <> null then
137                   vulkan.unused_buffers.add skin_buffer
138   
139               let s = skin_matrices.size * sizeof Matrix4
140                       |> max Renderer.skin_buffer_min_size
141                       |> ceil_to_power_of_2
142   
143               skin_buffer = StorageBuffer.create s
144               skin_buffer_size = s
145   
146           if skin_matrices.size > 0 then
147               skin_buffer.update skin_matrices.as_slice BarrierFlags/Raster
148   
149           for i = 0 until passes.size do
150               update_pass i
151   
152           end_label
153   
154           let clear_colors = List<Vector4>.new
155           for node in nodes do
156               case node of
157                   is Node/Render ->
158                       begin_label "Render Node"
159   
160                       render passes[node.pass].objects.as_slice
161                              passes[node.pass].descriptor_set node.framebuffer
162                              node.ops.color_enter_op node.ops.color_exit_op
163                              node.ops.depth_enter_op node.ops.depth_exit_op
164                              clear_colors.as_slice
165   
166                       end_label
167   
168                       if clear_colors.size > 0 then
169                           clear_colors.clear
170   
171                   is Node/ResolveDepth ->
172                       begin_label "Resolve Depth Node"
173   
174                       compute/resolve_depth node.from node.to size.value
175                                             node.samples.as<i32> BarrierFlags@all
176                       end_label
177   
178                   is Node/ResolveMultisample ->
179                       begin_label "Resolve Multisample Node"
180                       resolve_multisample node.from node.to BarrierFlags@all
181                       end_label
182   
183                   Node/Barrier -> barrier vulkan.command_buffer.object
184                                           BarrierFlags@all BarrierFlags@all
185                   Node/ClearColor color ->
186                       let main_light_intensity = if lighting.lights.is_empty
187                                                  then 1
188                                                  else lighting.lights[0].intensity
189   
190                       clear_colors.add (color * main_light_intensity)
191   
192                   is Node/Tonemap ->
193                       draw/draw_tonemap node.framebuffer node.descriptor_set
194                                         node.size.value node.max_size
195   
196   def render (renderers : List<Renderer>) (delta_time : f32) =
197       let vulkan : Vulkan @auto
198   
199       vulkan.time = (vulkan.time + delta_time as f64) % Renderer.max_time
200       let blit_images = List.new
201   
202       for renderer in renderers do
203           if renderer.size.value.width <> 0 && renderer.size.value.height <> 0 then
204               renderer.render
205               if renderer.maybe_blit_image ? Some blit_image then
206                   blit_images.add blit_image
207   
208       vulkan.acquire_next_image
209       draw/draw_blit blit_images
210   
211       assert vulkan.gpu_state.is_none
212   
213       vulkan.command_buffer.end
214       submit vulkan.sync vulkan.swapchain.image_index
215       vulkan.present
216              next_frame
217   
218   end@ renderer
219