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