comparison src/semicongine/renderer.nim @ 326:4ec852355750

fix: many issues, better mesh-handling, still need to cope with different binding numbers when using different pipelines...
author Sam <sam@basx.dev>
date Fri, 25 Aug 2023 00:29:51 +0700
parents 9defff46da48
children a63bd8f29252
comparison
equal deleted inserted replaced
325:0c3f4f6f1aa2 326:4ec852355750
1 import std/options 1 import std/options
2 import std/tables 2 import std/tables
3 import std/strformat 3 import std/strformat
4 import std/sequtils
4 import std/logging 5 import std/logging
5 import std/sequtils 6 import std/enumerate
6 7
7 import ./core 8 import ./core
8 import ./vulkan/buffer 9 import ./vulkan/buffer
9 import ./vulkan/device 10 import ./vulkan/device
10 import ./vulkan/drawable 11 import ./vulkan/drawable
17 import ./vulkan/image 18 import ./vulkan/image
18 19
19 import ./scene 20 import ./scene
20 import ./mesh 21 import ./mesh
21 22
23 const MATERIALINDEXATTRIBUTE = "materialIndex"
24 const TRANSFORMATTRIBUTE = "transform"
25
22 type 26 type
23 SceneData = object 27 SceneData = object
24 drawables*: OrderedTable[Mesh, Drawable] 28 drawables*: seq[tuple[drawable: Drawable, meshIndex: int]]
25 vertexBuffers*: Table[MemoryPerformanceHint, Buffer] 29 vertexBuffers*: Table[MemoryPerformanceHint, Buffer]
26 indexBuffer*: Buffer 30 indexBuffer*: Buffer
27 uniformBuffers*: Table[VkPipeline, seq[Buffer]] # one per frame-in-flight 31 uniformBuffers*: Table[VkPipeline, seq[Buffer]] # one per frame-in-flight
28 textures*: Table[string, seq[VulkanTexture]] # per frame-in-flight 32 textures*: Table[string, seq[VulkanTexture]] # per frame-in-flight
29 attributeLocation*: Table[string, MemoryPerformanceHint] 33 attributeLocation*: Table[string, MemoryPerformanceHint]
30 attributeBindingNumber*: Table[string, int] 34 attributeBindingNumber*: Table[string, int]
31 transformAttribute: string # name of attribute that is used for per-instance mesh transformation
32 materialIndexAttribute: string # name of attribute that is used for material selection
33 materials: seq[Material]
34 entityTransformationCache: Table[Mesh, Mat4] # remembers last transformation, avoid to send GPU-updates if no changes
35 descriptorPools*: Table[VkPipeline, DescriptorPool] 35 descriptorPools*: Table[VkPipeline, DescriptorPool]
36 descriptorSets*: Table[VkPipeline, seq[DescriptorSet]] 36 descriptorSets*: Table[VkPipeline, seq[DescriptorSet]]
37 materials: seq[Material]
37 Renderer* = object 38 Renderer* = object
38 device: Device 39 device: Device
39 surfaceFormat: VkSurfaceFormatKHR 40 surfaceFormat: VkSurfaceFormatKHR
40 renderPass: RenderPass 41 renderPass: RenderPass
41 swapchain: Swapchain 42 swapchain: Swapchain
42 scenedata: Table[Scene, SceneData] 43 scenedata: Table[Scene, SceneData]
43 emptyTexture: VulkanTexture 44 emptyTexture: VulkanTexture
44 45
45 func usesMaterialType(scenedata: SceneData, materialType: string): bool = 46 func usesMaterialType(scene: Scene, materialType: string): bool =
46 for drawable in scenedata.drawables.values: 47 return scene.meshes.anyIt(it.material.materialType == materialType)
47 if drawable.mesh.material.materialType == materialType:
48 return true
49 return false
50 48
51 proc initRenderer*(device: Device, shaders: Table[string, ShaderConfiguration], clearColor=Vec4f([0.8'f32, 0.8'f32, 0.8'f32, 1'f32])): Renderer = 49 proc initRenderer*(device: Device, shaders: Table[string, ShaderConfiguration], clearColor=Vec4f([0.8'f32, 0.8'f32, 0.8'f32, 1'f32])): Renderer =
52 assert device.vk.valid 50 assert device.vk.valid
53 51
54 result.device = device 52 result.device = device
60 raise newException(Exception, "Unable to create swapchain") 58 raise newException(Exception, "Unable to create swapchain")
61 59
62 result.swapchain = swapchain.get() 60 result.swapchain = swapchain.get()
63 result.emptyTexture = device.uploadTexture(EMPTYTEXTURE) 61 result.emptyTexture = device.uploadTexture(EMPTYTEXTURE)
64 62
65 func inputs(renderer: Renderer): seq[ShaderAttribute] = 63 func inputs(renderer: Renderer, scene: Scene): seq[ShaderAttribute] =
64 var found: Table[string, ShaderAttribute]
66 for i in 0 ..< renderer.renderPass.subpasses.len: 65 for i in 0 ..< renderer.renderPass.subpasses.len:
67 for pipeline in renderer.renderPass.subpasses[i].pipelines.values: 66 for materialType, pipeline in renderer.renderPass.subpasses[i].pipelines.pairs:
68 result.add pipeline.inputs 67 if scene.usesMaterialType(materialType):
69 68 for input in pipeline.inputs:
70 func samplers(renderer: Renderer): seq[ShaderAttribute] = 69 if found.contains(input.name):
70 assert input == found[input.name]
71 else:
72 result.add input
73 found[input.name] = input
74
75 func samplers(renderer: Renderer, scene: Scene): seq[ShaderAttribute] =
71 for i in 0 ..< renderer.renderPass.subpasses.len: 76 for i in 0 ..< renderer.renderPass.subpasses.len:
72 for pipeline in renderer.renderPass.subpasses[i].pipelines.values: 77 for materialType, pipeline in renderer.renderPass.subpasses[i].pipelines.pairs:
73 result.add pipeline.samplers 78 if scene.usesMaterialType(materialType):
74 79 result.add pipeline.samplers
75 proc setupDrawableBuffers*(renderer: var Renderer, scene: Scene) = 80
81 proc setupDrawableBuffers*(renderer: var Renderer, scene: var Scene) =
76 assert not (scene in renderer.scenedata) 82 assert not (scene in renderer.scenedata)
77 const VERTEX_ATTRIB_ALIGNMENT = 4 # used for buffer alignment 83 const VERTEX_ATTRIB_ALIGNMENT = 4 # used for buffer alignment
78 84
79 let 85 let
80 inputs = renderer.inputs 86 inputs = renderer.inputs(scene)
81 samplers = renderer.samplers 87 samplers = renderer.samplers(scene)
82 var scenedata = SceneData() 88 var scenedata = SceneData()
83 89
84 # if mesh transformation are handled through the scenegraph-transformation, set it up here 90 for mesh in scene.meshes:
85 if scene.transformAttribute != "":
86 var hasTransformAttribute = false
87 for input in inputs:
88 if input.name == scene.transformAttribute:
89 assert input.perInstance == true, $input
90 assert getDataType[Mat4]() == input.thetype, $input
91 hasTransformAttribute = true
92 assert hasTransformAttribute
93 scenedata.transformAttribute = scene.transformAttribute
94
95 # check if we have support for material indices, if required
96 if scene.materialIndexAttribute != "":
97 var hasMaterialIndexAttribute = false
98 for input in inputs:
99 if input.name == scene.materialIndexAttribute:
100 assert getDataType[uint16]() == input.thetype
101 hasMaterialIndexAttribute = true
102 assert hasMaterialIndexAttribute
103 scenedata.materialIndexAttribute = scene.materialIndexAttribute
104
105 for mesh in allComponentsOfType[Mesh](scene.root):
106 if mesh.material != nil and not scenedata.materials.contains(mesh.material): 91 if mesh.material != nil and not scenedata.materials.contains(mesh.material):
107 scenedata.materials.add mesh.material 92 scenedata.materials.add mesh.material
108 for textureName, texture in mesh.material.textures.pairs: 93 for textureName, texture in mesh.material.textures.pairs:
109 if not scenedata.textures.hasKey(textureName): 94 if not scenedata.textures.hasKey(textureName):
110 scenedata.textures[textureName] = @[] 95 scenedata.textures[textureName] = @[]
111 scenedata.textures[textureName].add renderer.device.uploadTexture(texture) 96 scenedata.textures[textureName].add renderer.device.uploadTexture(texture)
112 97
113 # find all meshes, populate missing attribute values for shader 98 # find all meshes, populate missing attribute values for shader
114 var allMeshes: seq[Mesh] 99 for mesh in scene.meshes.mitems:
115 for mesh in allComponentsOfType[Mesh](scene.root):
116 allMeshes.add mesh
117 for inputAttr in inputs: 100 for inputAttr in inputs:
118 if scenedata.materialIndexAttribute != "" and inputAttr.name == scenedata.materialIndexAttribute: 101 if inputAttr.name == TRANSFORMATTRIBUTE:
119 assert mesh.material != nil, "Missing material specification for mesh. Either set the 'materials' attribute or pass the argument 'materialIndexAttribute=\"\"' when calling 'addScene'" 102 mesh.initInstanceAttribute(inputAttr.name, inputAttr.thetype)
103 elif inputAttr.name == MATERIALINDEXATTRIBUTE:
104 assert mesh.material != nil, "Missing material specification for mesh. Set material attribute on mesh"
120 let matIndex = scenedata.materials.find(mesh.material) 105 let matIndex = scenedata.materials.find(mesh.material)
121 if matIndex < 0: 106 if matIndex < 0:
122 raise newException(Exception, &"Required material '{mesh.material}' not available in scene (available are: {scenedata.materials})") 107 raise newException(Exception, &"Required material '{mesh.material}' not available in scene (available are: {scenedata.materials})")
123 mesh.initAttribute(inputAttr, uint16(matIndex)) 108 mesh.initInstanceAttribute(inputAttr.name, uint16(matIndex))
124 elif not mesh.hasAttribute(inputAttr.name): 109 elif not mesh.attributes.contains(inputAttr.name):
125 warn(&"Mesh is missing data for shader attribute {inputAttr.name}, auto-filling with empty values") 110 warn(&"Mesh is missing data for shader attribute {inputAttr.name}, auto-filling with empty values")
126 mesh.initAttribute(inputAttr) 111 if inputAttr.perInstance:
112 mesh.initInstanceAttribute(inputAttr.name, inputAttr.thetype)
113 else:
114 mesh.initVertexAttribute(inputAttr.name, inputAttr.thetype)
127 assert mesh.attributeType(inputAttr.name) == inputAttr.thetype, &"mesh attribute {inputAttr.name} has type {mesh.attributeType(inputAttr.name)} but shader expects {inputAttr.thetype}" 115 assert mesh.attributeType(inputAttr.name) == inputAttr.thetype, &"mesh attribute {inputAttr.name} has type {mesh.attributeType(inputAttr.name)} but shader expects {inputAttr.thetype}"
128 116
129 # create index buffer if necessary 117 # create index buffer if necessary
130 var indicesBufferSize = 0'u64 118 var indicesBufferSize = 0
131 for mesh in allMeshes: 119 for mesh in scene.meshes:
132 if mesh.indexType != MeshIndexType.None: 120 if mesh.indexType != MeshIndexType.None:
133 let indexAlignment = case mesh.indexType 121 let indexAlignment = case mesh.indexType
134 of MeshIndexType.None: 0'u64 122 of MeshIndexType.None: 0
135 of Tiny: 1'u64 123 of Tiny: 1
136 of Small: 2'u64 124 of Small: 2
137 of Big: 4'u64 125 of Big: 4
138 # index value alignment required by Vulkan 126 # index value alignment required by Vulkan
139 if indicesBufferSize mod indexAlignment != 0: 127 if indicesBufferSize mod indexAlignment != 0:
140 indicesBufferSize += indexAlignment - (indicesBufferSize mod indexAlignment) 128 indicesBufferSize += indexAlignment - (indicesBufferSize mod indexAlignment)
141 indicesBufferSize += mesh.indexSize 129 indicesBufferSize += mesh.indexSize
142 if indicesBufferSize > 0: 130 if indicesBufferSize > 0:
148 ) 136 )
149 137
150 # create vertex buffers and calculcate offsets 138 # create vertex buffers and calculcate offsets
151 # trying to use one buffer per memory type 139 # trying to use one buffer per memory type
152 var 140 var
153 perLocationOffsets: Table[MemoryPerformanceHint, uint64] 141 perLocationOffsets: Table[MemoryPerformanceHint, int]
154 perLocationSizes: Table[MemoryPerformanceHint, uint64] 142 perLocationSizes: Table[MemoryPerformanceHint, int]
155 bindingNumber = 0 143 bindingNumber = 0
156 for hint in MemoryPerformanceHint: 144 for hint in MemoryPerformanceHint:
157 perLocationOffsets[hint] = 0 145 perLocationOffsets[hint] = 0
158 perLocationSizes[hint] = 0 146 perLocationSizes[hint] = 0
159 for attribute in inputs: 147 for attribute in inputs:
160 scenedata.attributeLocation[attribute.name] = attribute.memoryPerformanceHint 148 scenedata.attributeLocation[attribute.name] = attribute.memoryPerformanceHint
161 scenedata.attributeBindingNumber[attribute.name] = bindingNumber 149 scenedata.attributeBindingNumber[attribute.name] = bindingNumber
162 inc bindingNumber 150 inc bindingNumber
163 # setup one buffer per attribute-location-type 151 # setup one buffer per attribute-location-type
164 for mesh in allMeshes: 152 for mesh in scene.meshes:
165 # align size to VERTEX_ATTRIB_ALIGNMENT bytes (the important thing is the correct alignment of the offsets, but 153 # align size to VERTEX_ATTRIB_ALIGNMENT bytes (the important thing is the correct alignment of the offsets, but
166 # we need to expand the buffer size as well, therefore considering alignment already here as well 154 # we need to expand the buffer size as well, therefore considering alignment already here as well
167 if perLocationSizes[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT != 0: 155 if perLocationSizes[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT != 0:
168 perLocationSizes[attribute.memoryPerformanceHint] += VERTEX_ATTRIB_ALIGNMENT - (perLocationSizes[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT) 156 perLocationSizes[attribute.memoryPerformanceHint] += VERTEX_ATTRIB_ALIGNMENT - (perLocationSizes[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT)
169 perLocationSizes[attribute.memoryPerformanceHint] += mesh.attributeSize(attribute.name) 157 perLocationSizes[attribute.memoryPerformanceHint] += mesh.attributeSize(attribute.name)
175 requireMappable=memoryPerformanceHint==PreferFastWrite, 163 requireMappable=memoryPerformanceHint==PreferFastWrite,
176 preferVRAM=true, 164 preferVRAM=true,
177 ) 165 )
178 166
179 # fill vertex buffers 167 # fill vertex buffers
180 var indexBufferOffset = 0'u64 168 var indexBufferOffset = 0
181 for mesh in allMeshes: 169 for (meshIndex, mesh) in enumerate(scene.meshes):
182 var offsets: seq[(string, MemoryPerformanceHint, uint64)] 170 var offsets: seq[(string, MemoryPerformanceHint, int)]
183 for attribute in inputs: 171 for attribute in inputs:
184 offsets.add (attribute.name, attribute.memoryPerformanceHint, perLocationOffsets[attribute.memoryPerformanceHint]) 172 offsets.add (attribute.name, attribute.memoryPerformanceHint, perLocationOffsets[attribute.memoryPerformanceHint])
185 var (pdata, size) = mesh.getRawData(attribute.name) 173 var (pdata, size) = mesh.getRawData(attribute.name)
186 if pdata != nil: # no data 174 if pdata != nil: # no data
187 scenedata.vertexBuffers[attribute.memoryPerformanceHint].setData(pdata, size, perLocationOffsets[attribute.memoryPerformanceHint]) 175 scenedata.vertexBuffers[attribute.memoryPerformanceHint].setData(pdata, size, perLocationOffsets[attribute.memoryPerformanceHint])
189 if perLocationOffsets[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT != 0: 177 if perLocationOffsets[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT != 0:
190 perLocationOffsets[attribute.memoryPerformanceHint] += VERTEX_ATTRIB_ALIGNMENT - (perLocationOffsets[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT) 178 perLocationOffsets[attribute.memoryPerformanceHint] += VERTEX_ATTRIB_ALIGNMENT - (perLocationOffsets[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT)
191 179
192 let indexed = mesh.indexType != MeshIndexType.None 180 let indexed = mesh.indexType != MeshIndexType.None
193 var drawable = Drawable( 181 var drawable = Drawable(
194 mesh: mesh,
195 elementCount: if indexed: mesh.indicesCount else: mesh.vertexCount, 182 elementCount: if indexed: mesh.indicesCount else: mesh.vertexCount,
196 bufferOffsets: offsets, 183 bufferOffsets: offsets,
197 instanceCount: mesh.instanceCount, 184 instanceCount: mesh.instanceCount,
198 indexed: indexed, 185 indexed: indexed,
199 ) 186 )
200 if indexed: 187 if indexed:
201 let indexAlignment = case mesh.indexType 188 let indexAlignment = case mesh.indexType
202 of MeshIndexType.None: 0'u64 189 of MeshIndexType.None: 0
203 of Tiny: 1'u64 190 of Tiny: 1
204 of Small: 2'u64 191 of Small: 2
205 of Big: 4'u64 192 of Big: 4
206 # index value alignment required by Vulkan 193 # index value alignment required by Vulkan
207 if indexBufferOffset mod indexAlignment != 0: 194 if indexBufferOffset mod indexAlignment != 0:
208 indexBufferOffset += indexAlignment - (indexBufferOffset mod indexAlignment) 195 indexBufferOffset += indexAlignment - (indexBufferOffset mod indexAlignment)
209 drawable.indexBufferOffset = indexBufferOffset 196 drawable.indexBufferOffset = indexBufferOffset
210 drawable.indexType = mesh.indexType 197 drawable.indexType = mesh.indexType
211 var (pdata, size) = mesh.getRawIndexData() 198 var (pdata, size) = mesh.getRawIndexData()
212 scenedata.indexBuffer.setData(pdata, size, indexBufferOffset) 199 scenedata.indexBuffer.setData(pdata, size, indexBufferOffset)
213 indexBufferOffset += size 200 indexBufferOffset += size
214 scenedata.drawables[mesh] = drawable 201 scenedata.drawables.add (drawable, meshIndex)
215 202
216 # setup uniforms and samplers 203 # setup uniforms and samplers
217 for subpass_i in 0 ..< renderer.renderPass.subpasses.len: 204 for subpass_i in 0 ..< renderer.renderPass.subpasses.len:
218 for material, pipeline in renderer.renderPass.subpasses[subpass_i].pipelines.pairs: 205 for materialType, pipeline in renderer.renderPass.subpasses[subpass_i].pipelines.pairs:
219 var uniformBufferSize = 0'u64 206 if scene.usesMaterialType(materialType):
220 for uniform in pipeline.uniforms: 207 var uniformBufferSize = 0
221 uniformBufferSize += uniform.size 208 for uniform in pipeline.uniforms:
222 if uniformBufferSize > 0: 209 uniformBufferSize += uniform.size
223 scenedata.uniformBuffers[pipeline.vk] = newSeq[Buffer]() 210 if uniformBufferSize > 0:
211 scenedata.uniformBuffers[pipeline.vk] = newSeq[Buffer]()
212 for frame_i in 0 ..< renderer.swapchain.inFlightFrames:
213 scenedata.uniformBuffers[pipeline.vk].add renderer.device.createBuffer(
214 size=uniformBufferSize,
215 usage=[VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT],
216 requireMappable=true,
217 preferVRAM=true,
218 )
219
220 var poolsizes = @[(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, renderer.swapchain.inFlightFrames)]
221 if samplers.len > 0:
222 var samplercount = 0
223 for sampler in samplers:
224 samplercount += (if sampler.arrayCount == 0: 1 else: sampler.arrayCount)
225 poolsizes.add (VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, renderer.swapchain.inFlightFrames * samplercount * 2)
226
227 scenedata.descriptorPools[pipeline.vk] = renderer.device.createDescriptorSetPool(poolsizes)
228
229 scenedata.descriptorSets[pipeline.vk] = pipeline.setupDescriptors(
230 scenedata.descriptorPools[pipeline.vk],
231 scenedata.uniformBuffers.getOrDefault(pipeline.vk, @[]),
232 scenedata.textures,
233 inFlightFrames=renderer.swapchain.inFlightFrames,
234 emptyTexture=renderer.emptyTexture,
235 )
224 for frame_i in 0 ..< renderer.swapchain.inFlightFrames: 236 for frame_i in 0 ..< renderer.swapchain.inFlightFrames:
225 scenedata.uniformBuffers[pipeline.vk].add renderer.device.createBuffer( 237 scenedata.descriptorSets[pipeline.vk][frame_i].writeDescriptorSet()
226 size=uniformBufferSize,
227 usage=[VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT],
228 requireMappable=true,
229 preferVRAM=true,
230 )
231
232 var poolsizes = @[(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, uint32(renderer.swapchain.inFlightFrames))]
233 if samplers.len > 0:
234 var samplercount = 0'u32
235 for sampler in samplers:
236 samplercount += (if sampler.arrayCount == 0: 1'u32 else: sampler.arrayCount)
237 poolsizes.add (VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, uint32(renderer.swapchain.inFlightFrames) * samplercount * 2)
238
239 scenedata.descriptorPools[pipeline.vk] = renderer.device.createDescriptorSetPool(poolsizes)
240
241 scenedata.descriptorSets[pipeline.vk] = pipeline.setupDescriptors(
242 scenedata.descriptorPools[pipeline.vk],
243 scenedata.uniformBuffers.getOrDefault(pipeline.vk, @[]),
244 scenedata.textures,
245 inFlightFrames=renderer.swapchain.inFlightFrames,
246 emptyTexture=renderer.emptyTexture,
247 )
248 for frame_i in 0 ..< renderer.swapchain.inFlightFrames:
249 scenedata.descriptorSets[pipeline.vk][frame_i].writeDescriptorSet()
250 238
251 renderer.scenedata[scene] = scenedata 239 renderer.scenedata[scene] = scenedata
252 240
253 proc refreshMeshAttributeData(sceneData: var SceneData, mesh: Mesh, attribute: string) = 241 proc refreshMeshAttributeData(renderer: Renderer, scene: Scene, drawable: Drawable, meshIndex: int, attribute: string) =
254 debug &"Refreshing data on mesh {mesh} for {attribute}" 242 debug &"Refreshing data on mesh {scene.meshes[meshIndex]} for {attribute}"
255 # ignore attributes that are not used in this shader 243 # ignore attributes that are not used in this shader
256 if not (attribute in sceneData.attributeLocation): 244 if not (attribute in renderer.scenedata[scene].attributeLocation):
257 return 245 return
258 var (pdata, size) = mesh.getRawData(attribute) 246 var (pdata, size) = scene.meshes[meshIndex].getRawData(attribute)
259 let memoryPerformanceHint = sceneData.attributeLocation[attribute] 247 let memoryPerformanceHint = renderer.scenedata[scene].attributeLocation[attribute]
260 let bindingNumber = sceneData.attributeBindingNumber[attribute] 248 let bindingNumber = renderer.scenedata[scene].attributeBindingNumber[attribute]
261 sceneData.vertexBuffers[memoryPerformanceHint].setData(pdata, size, sceneData.drawables[mesh].bufferOffsets[bindingNumber][2]) 249 renderer.scenedata[scene].vertexBuffers[memoryPerformanceHint].setData(pdata, size, drawable.bufferOffsets[bindingNumber][2])
262 250
263 proc updateMeshData*(renderer: var Renderer, scene: Scene) = 251 proc updateMeshData*(renderer: var Renderer, scene: var Scene) =
264 assert scene in renderer.scenedata 252 assert scene in renderer.scenedata
265 253
266 for mesh in allComponentsOfType[Mesh](scene.root): 254 for (drawable, meshIndex) in renderer.scenedata[scene].drawables.mitems:
267 # if mesh transformation attribute is enabled, update the model matrix 255 if scene.meshes[meshIndex].attributes.contains(TRANSFORMATTRIBUTE):
268 if renderer.scenedata[scene].transformAttribute != "": 256 scene.meshes[meshIndex].updateInstanceTransforms(TRANSFORMATTRIBUTE)
269 let transform = mesh.entity.getModelTransform() 257 for attribute in scene.meshes[meshIndex].dirtyAttributes:
270 if not (mesh in renderer.scenedata[scene].entityTransformationCache) or renderer.scenedata[scene].entityTransformationCache[mesh] != transform or mesh.areInstanceTransformsDirty : 258 renderer.refreshMeshAttributeData(scene, drawable, meshIndex, attribute)
271 var updatedTransform = newSeq[Mat4](int(mesh.instanceCount)) 259 debug &"Update mesh attribute {attribute}"
272 for i in 0 ..< mesh.instanceCount: 260 scene.meshes[meshIndex].clearDirtyAttributes()
273 updatedTransform[i] = transform * mesh.getInstanceTransform(i)
274 debug &"Update mesh transformation"
275 mesh.updateInstanceData(renderer.scenedata[scene].transformAttribute, updatedTransform)
276 renderer.scenedata[scene].entityTransformationCache[mesh] = transform
277
278 # update any changed mesh attributes
279 for attribute in mesh.vertexAttributes:
280 if mesh.hasDataChanged(attribute):
281 renderer.scenedata[scene].refreshMeshAttributeData(mesh, attribute)
282 debug &"Update mesh vertex attribute {attribute}"
283 for attribute in mesh.instanceAttributes:
284 if mesh.hasDataChanged(attribute):
285 renderer.scenedata[scene].refreshMeshAttributeData(mesh, attribute)
286 debug &"Update mesh instance attribute {attribute}"
287 var m = mesh
288 m.clearDataChanged()
289
290 proc updateAnimations*(renderer: var Renderer, scene: var Scene, dt: float32) =
291 for animation in allComponentsOfType[EntityAnimation](scene.root):
292 debug &"Update animation {animation}"
293 animation.update(dt)
294 261
295 proc updateUniformData*(renderer: var Renderer, scene: var Scene) = 262 proc updateUniformData*(renderer: var Renderer, scene: var Scene) =
296 assert scene in renderer.scenedata 263 assert scene in renderer.scenedata
297 264
298 for i in 0 ..< renderer.renderPass.subpasses.len: 265 for i in 0 ..< renderer.renderPass.subpasses.len:
299 for materialType, pipeline in renderer.renderPass.subpasses[i].pipelines.pairs: 266 for materialType, pipeline in renderer.renderPass.subpasses[i].pipelines.pairs:
300 if renderer.scenedata[scene].usesMaterialType(materialType) and renderer.scenedata[scene].uniformBuffers.hasKey(pipeline.vk) and renderer.scenedata[scene].uniformBuffers[pipeline.vk].len != 0: 267 if scene.usesMaterialType(materialType) and renderer.scenedata[scene].uniformBuffers.hasKey(pipeline.vk) and renderer.scenedata[scene].uniformBuffers[pipeline.vk].len != 0:
301 assert renderer.scenedata[scene].uniformBuffers[pipeline.vk][renderer.swapchain.currentInFlight].vk.valid 268 assert renderer.scenedata[scene].uniformBuffers[pipeline.vk][renderer.swapchain.currentInFlight].vk.valid
302 var offset = 0'u64 269 var offset = 0
303 for uniform in pipeline.uniforms: 270 for uniform in pipeline.uniforms:
304 if not scene.shaderGlobals.hasKey(uniform.name): 271 if not scene.shaderGlobals.hasKey(uniform.name):
305 raise newException(Exception, &"Uniform '{uniform.name}' not found in scene shaderGlobals") 272 raise newException(Exception, &"Uniform '{uniform.name}' not found in scene shaderGlobals")
306 if uniform.thetype != scene.shaderGlobals[uniform.name].thetype: 273 if uniform.thetype != scene.shaderGlobals[uniform.name].thetype:
307 raise newException(Exception, &"Uniform '{uniform.name}' has wrong type {uniform.thetype}, required is {scene.shaderGlobals[uniform.name].thetype}") 274 raise newException(Exception, &"Uniform '{uniform.name}' has wrong type {uniform.thetype}, required is {scene.shaderGlobals[uniform.name].thetype}")
308 debug &"Update uniforms {uniform.name}" 275 debug &"Update uniforms {uniform.name}"
309 let (pdata, size) = scene.shaderGlobals[uniform.name].getRawData() 276 let (pdata, size) = scene.shaderGlobals[uniform.name].getRawData()
310 renderer.scenedata[scene].uniformBuffers[pipeline.vk][renderer.swapchain.currentInFlight].setData(pdata, size, offset) 277 renderer.scenedata[scene].uniformBuffers[pipeline.vk][renderer.swapchain.currentInFlight].setData(pdata, size, offset)
311 offset += size 278 offset += size
312 279
313 proc render*(renderer: var Renderer, scene: var Scene) = 280 proc render*(renderer: var Renderer, scene: Scene) =
314 assert scene in renderer.scenedata 281 assert scene in renderer.scenedata
315 282
316 var 283 var
317 commandBufferResult = renderer.swapchain.nextFrame() 284 commandBufferResult = renderer.swapchain.nextFrame()
318 commandBuffer: VkCommandBuffer 285 commandBuffer: VkCommandBuffer
334 debug " ", location, ": ", buffer 301 debug " ", location, ": ", buffer
335 debug " Index buffer: ", renderer.scenedata[scene].indexBuffer 302 debug " Index buffer: ", renderer.scenedata[scene].indexBuffer
336 303
337 for i in 0 ..< renderer.renderPass.subpasses.len: 304 for i in 0 ..< renderer.renderPass.subpasses.len:
338 for materialType, pipeline in renderer.renderPass.subpasses[i].pipelines.pairs: 305 for materialType, pipeline in renderer.renderPass.subpasses[i].pipelines.pairs:
339 if renderer.scenedata[scene].usesMaterialType(materialType): 306 if scene.usesMaterialType(materialType):
340 debug &"Start pipeline for {materialType}" 307 debug &"Start pipeline for {materialType}"
341 commandBuffer.vkCmdBindPipeline(renderer.renderPass.subpasses[i].pipelineBindPoint, pipeline.vk) 308 commandBuffer.vkCmdBindPipeline(renderer.renderPass.subpasses[i].pipelineBindPoint, pipeline.vk)
342 commandBuffer.vkCmdBindDescriptorSets(renderer.renderPass.subpasses[i].pipelineBindPoint, pipeline.layout, 0, 1, addr(renderer.scenedata[scene].descriptorSets[pipeline.vk][renderer.swapchain.currentInFlight].vk), 0, nil) 309 commandBuffer.vkCmdBindDescriptorSets(renderer.renderPass.subpasses[i].pipelineBindPoint, pipeline.layout, 0, 1, addr(renderer.scenedata[scene].descriptorSets[pipeline.vk][renderer.swapchain.currentInFlight].vk), 0, nil)
343 310
344 for drawable in renderer.scenedata[scene].drawables.values: 311 for (drawable, meshIndex) in renderer.scenedata[scene].drawables:
345 if drawable.mesh.material != nil and drawable.mesh.material.materialType == materialType: 312 if scene.meshes[meshIndex].material != nil and scene.meshes[meshIndex].material.materialType == materialType:
346 drawable.draw(commandBuffer, vertexBuffers=renderer.scenedata[scene].vertexBuffers, indexBuffer=renderer.scenedata[scene].indexBuffer) 313 drawable.draw(commandBuffer, vertexBuffers=renderer.scenedata[scene].vertexBuffers, indexBuffer=renderer.scenedata[scene].indexBuffer)
347 314
348 if i < renderer.renderPass.subpasses.len - 1: 315 if i < renderer.renderPass.subpasses.len - 1:
349 commandBuffer.vkCmdNextSubpass(VK_SUBPASS_CONTENTS_INLINE) 316 commandBuffer.vkCmdNextSubpass(VK_SUBPASS_CONTENTS_INLINE)
350 317