comparison semiconginev2/old/renderer.nim @ 1218:56781cc0fc7c compiletime-tests

did: renamge main package
author sam <sam@basx.dev>
date Wed, 17 Jul 2024 21:01:37 +0700
parents semicongine/old/renderer.nim@a3eb305bcac2
children
comparison
equal deleted inserted replaced
1217:f819a874058f 1218:56781cc0fc7c
1 import std/options
2 import std/tables
3 import std/strformat
4 import std/sequtils
5 import std/strutils
6 import std/logging
7
8 import ./core
9 import ./vulkan/commandbuffer
10 import ./vulkan/buffer
11 import ./vulkan/device
12 import ./vulkan/drawable
13 import ./vulkan/physicaldevice
14 import ./vulkan/pipeline
15 import ./vulkan/renderpass
16 import ./vulkan/swapchain
17 import ./vulkan/shader
18 import ./vulkan/descriptor
19 import ./vulkan/image
20
21 import ./scene
22 import ./mesh
23 import ./material
24
25 const VERTEX_ATTRIB_ALIGNMENT = 4 # used for buffer alignment
26
27 type
28 ShaderData = ref object
29 descriptorPool: DescriptorPool
30 descriptorSets: seq[DescriptorSet] # len = n swapchain images
31 uniformBuffers: seq[Buffer]
32 textures: Table[string, seq[VulkanTexture]]
33
34 SceneData = ref object
35 drawables: seq[tuple[drawable: Drawable, mesh: Mesh]]
36 vertexBuffers: Table[MemoryPerformanceHint, Buffer]
37 indexBuffer: Buffer
38 attributeLocation: Table[string, MemoryPerformanceHint]
39 vertexBufferOffsets: Table[(Mesh, string), uint64]
40 materials: Table[MaterialType, seq[MaterialData]]
41 shaderData: Table[VkPipeline, ShaderData]
42 Renderer* = object
43 device: Device
44 renderPass: RenderPass
45 swapchain: Swapchain
46 scenedata: Table[Scene, SceneData]
47 emptyTexture: VulkanTexture
48 queue: Queue
49 commandBufferPool: CommandBufferPool
50 nextFrameReady: bool = false
51
52 proc currentFrameCommandBuffer(renderer: Renderer): VkCommandBuffer =
53 renderer.commandBufferPool.buffers[renderer.swapchain.currentInFlight]
54
55 proc HasScene*(renderer: Renderer, scene: Scene): bool =
56 scene in renderer.scenedata
57
58 proc InitRenderer*(
59 device: Device,
60 shaders: openArray[(MaterialType, ShaderConfiguration)],
61 clearColor = NewVec4f(0, 0, 0, 0),
62 backFaceCulling = true,
63 vSync = false,
64 inFlightFrames = 2,
65 samples = VK_SAMPLE_COUNT_1_BIT,
66 ): Renderer =
67 assert device.vk.Valid
68
69 result.device = device
70 result.renderPass = device.CreateRenderPass(
71 shaders,
72 clearColor = clearColor,
73 backFaceCulling = backFaceCulling,
74 samples = samples
75 )
76 let swapchain = device.CreateSwapchain(
77 result.renderPass.vk,
78 device.physicalDevice.GetSurfaceFormats().FilterSurfaceFormat(),
79 vSync = vSync,
80 inFlightFrames = inFlightFrames,
81 samples = samples,
82 )
83 if not swapchain.isSome:
84 raise newException(Exception, "Unable to create swapchain")
85
86 result.queue = device.FirstGraphicsQueue().get()
87 result.commandBufferPool = device.CreateCommandBufferPool(result.queue.family, swapchain.get().inFlightFrames)
88 result.swapchain = swapchain.get()
89 result.emptyTexture = device.UploadTexture(result.queue, EMPTY_TEXTURE)
90
91 func shadersForScene(renderer: Renderer, scene: Scene): seq[(MaterialType, ShaderPipeline)] =
92 for (materialType, shaderPipeline) in renderer.renderPass.shaderPipelines:
93 if scene.UsesMaterial(materialType):
94 result.add (materialType, shaderPipeline)
95
96 func vertexInputsForScene(renderer: Renderer, scene: Scene): seq[ShaderAttribute] =
97 var found: Table[string, ShaderAttribute]
98 for (materialType, shaderPipeline) in renderer.shadersForScene(scene):
99 for input in shaderPipeline.Inputs:
100 if found.contains(input.name):
101 assert input.name == found[input.name].name, &"{input.name}: {input.name} != {found[input.name].name}"
102 assert input.theType == found[input.name].theType, &"{input.name}: {input.theType} != {found[input.name].theType}"
103 assert input.arrayCount == found[input.name].arrayCount, &"{input.name}: {input.arrayCount} != {found[input.name].arrayCount}"
104 assert input.memoryPerformanceHint == found[input.name].memoryPerformanceHint, &"{input.name}: {input.memoryPerformanceHint} != {found[input.name].memoryPerformanceHint}"
105 else:
106 result.add input
107 found[input.name] = input
108
109 proc SetupDrawableBuffers*(renderer: var Renderer, scene: var Scene) =
110 assert not (scene in renderer.scenedata)
111
112 var scenedata = SceneData()
113
114 # find all material data and group it by material type
115 for mesh in scene.meshes:
116 assert mesh.material != nil, "Mesh {mesh} has no material assigned"
117 if not scenedata.materials.contains(mesh.material.theType):
118 scenedata.materials[mesh.material.theType] = @[]
119 if not scenedata.materials[mesh.material.theType].contains(mesh.material):
120 scenedata.materials[mesh.material.theType].add mesh.material
121
122 # automatically populate material and tranform attributes
123 for mesh in scene.meshes:
124 if not (TRANSFORM_ATTRIB in mesh[].Attributes):
125 mesh[].InitInstanceAttribute(TRANSFORM_ATTRIB, Unit4)
126 if not (MATERIALINDEX_ATTRIBUTE in mesh[].Attributes):
127 mesh[].InitInstanceAttribute(MATERIALINDEX_ATTRIBUTE, uint16(scenedata.materials[mesh.material.theType].find(mesh.material)))
128
129 # create index buffer if necessary
130 var indicesBufferSize = 0'u64
131 for mesh in scene.meshes:
132 if mesh[].indexType != MeshIndexType.None:
133 let indexAlignment = case mesh[].indexType
134 of MeshIndexType.None: 0'u64
135 of Tiny: 1'u64
136 of Small: 2'u64
137 of Big: 4'u64
138 # index value alignment required by Vulkan
139 if indicesBufferSize mod indexAlignment != 0:
140 indicesBufferSize += indexAlignment - (indicesBufferSize mod indexAlignment)
141 indicesBufferSize += mesh[].IndexSize
142 if indicesBufferSize > 0:
143 scenedata.indexBuffer = renderer.device.CreateBuffer(
144 size = indicesBufferSize,
145 usage = [VK_BUFFER_USAGE_INDEX_BUFFER_BIT],
146 requireMappable = false,
147 preferVRAM = true,
148 )
149
150 # calculcate offsets for attributes in vertex buffers
151 # trying to use one buffer per memory type
152 var perLocationSizes: Table[MemoryPerformanceHint, uint64]
153 for hint in MemoryPerformanceHint:
154 perLocationSizes[hint] = 0
155
156 let sceneVertexInputs = renderer.vertexInputsForScene(scene)
157 let sceneShaders = renderer.shadersForScene(scene)
158
159 for (materialType, shaderPipeline) in sceneShaders:
160 scenedata.shaderData[shaderPipeline.vk] = ShaderData()
161
162 for vertexAttribute in sceneVertexInputs:
163 scenedata.attributeLocation[vertexAttribute.name] = vertexAttribute.memoryPerformanceHint
164 # setup one buffer per vertexAttribute-location-type
165 for mesh in scene.meshes:
166 # align size to VERTEX_ATTRIB_ALIGNMENT bytes (the important thing is the correct alignment of the offsets, but
167 # we need to expand the buffer size as well, therefore considering alignment already here as well
168 if perLocationSizes[vertexAttribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT != 0:
169 perLocationSizes[vertexAttribute.memoryPerformanceHint] += VERTEX_ATTRIB_ALIGNMENT - (perLocationSizes[vertexAttribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT)
170 perLocationSizes[vertexAttribute.memoryPerformanceHint] += mesh[].AttributeSize(vertexAttribute.name)
171
172 # create vertex buffers
173 for memoryPerformanceHint, bufferSize in perLocationSizes.pairs:
174 if bufferSize > 0:
175 scenedata.vertexBuffers[memoryPerformanceHint] = renderer.device.CreateBuffer(
176 size = bufferSize,
177 usage = [VK_BUFFER_USAGE_VERTEX_BUFFER_BIT],
178 requireMappable = memoryPerformanceHint == PreferFastWrite,
179 preferVRAM = true,
180 )
181
182 # calculate offset of each attribute for all meshes
183 var perLocationOffsets: Table[MemoryPerformanceHint, uint64]
184 var indexBufferOffset = 0'u64
185 for hint in MemoryPerformanceHint:
186 perLocationOffsets[hint] = 0
187
188 for mesh in scene.meshes:
189 for attribute in sceneVertexInputs:
190 scenedata.vertexBufferOffsets[(mesh, attribute.name)] = perLocationOffsets[attribute.memoryPerformanceHint]
191 if mesh[].Attributes.contains(attribute.name):
192 perLocationOffsets[attribute.memoryPerformanceHint] += mesh[].AttributeSize(attribute.name)
193 if perLocationOffsets[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT != 0:
194 perLocationOffsets[attribute.memoryPerformanceHint] += VERTEX_ATTRIB_ALIGNMENT - (perLocationOffsets[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT)
195
196 # fill offsets per shaderPipeline (as sequence corresponds to shader input binding)
197 var offsets: Table[VkPipeline, seq[(string, MemoryPerformanceHint, uint64)]]
198 for (materialType, shaderPipeline) in sceneShaders:
199 offsets[shaderPipeline.vk] = newSeq[(string, MemoryPerformanceHint, uint64)]()
200 for attribute in shaderPipeline.Inputs:
201 offsets[shaderPipeline.vk].add (attribute.name, attribute.memoryPerformanceHint, scenedata.vertexBufferOffsets[(mesh, attribute.name)])
202
203 # create drawables
204 let indexed = mesh.indexType != MeshIndexType.None
205 var drawable = Drawable(
206 name: mesh.name,
207 elementCount: if indexed: mesh[].IndicesCount else: mesh[].vertexCount,
208 bufferOffsets: offsets,
209 instanceCount: mesh[].InstanceCount,
210 indexed: indexed,
211 )
212 if indexed:
213 let indexAlignment = case mesh.indexType
214 of MeshIndexType.None: 0'u64
215 of Tiny: 1'u64
216 of Small: 2'u64
217 of Big: 4'u64
218 # index value alignment required by Vulkan
219 if indexBufferOffset mod indexAlignment != 0:
220 indexBufferOffset += indexAlignment - (indexBufferOffset mod indexAlignment)
221 drawable.indexBufferOffset = indexBufferOffset
222 drawable.indexType = mesh.indexType
223 var (pdata, size) = mesh[].GetRawIndexData()
224 scenedata.indexBuffer.SetData(renderer.queue, pdata, size, indexBufferOffset)
225 indexBufferOffset += size
226 scenedata.drawables.add (drawable, mesh)
227
228 # setup uniforms and textures (anything descriptor)
229 var uploadedTextures: Table[Texture, VulkanTexture]
230 for (materialType, shaderPipeline) in sceneShaders:
231 # gather textures
232 for textureAttribute in shaderPipeline.Samplers:
233 scenedata.shaderData[shaderPipeline.vk].textures[textureAttribute.name] = newSeq[VulkanTexture]()
234 if scene.shaderGlobals.contains(textureAttribute.name):
235 for textureValue in scene.shaderGlobals[textureAttribute.name][Texture][]:
236 if not uploadedTextures.contains(textureValue):
237 uploadedTextures[textureValue] = renderer.device.UploadTexture(renderer.queue, textureValue)
238 scenedata.shaderData[shaderPipeline.vk].textures[textureAttribute.name].add uploadedTextures[textureValue]
239 else:
240 var foundTexture = false
241 for material in scene.GetMaterials(materialType):
242 if material.HasMatchingAttribute(textureAttribute):
243 foundTexture = true
244 let value = material[textureAttribute.name, Texture][]
245 assert value.len == 1, &"Mesh material attribute '{textureAttribute.name}' has texture-array, but only single textures are allowed"
246 if not uploadedTextures.contains(value[0]):
247 uploadedTextures[value[0]] = renderer.device.UploadTexture(renderer.queue, value[0])
248 scenedata.shaderData[shaderPipeline.vk].textures[textureAttribute.name].add uploadedTextures[value[0]]
249 assert foundTexture, &"No texture found in shaderGlobals or materials for '{textureAttribute.name}'"
250 let nTextures = scenedata.shaderData[shaderPipeline.vk].textures[textureAttribute.name].len.uint32
251 assert (textureAttribute.arrayCount == 0 and nTextures == 1) or textureAttribute.arrayCount >= nTextures, &"Shader assigned to render '{materialType}' expected {textureAttribute.arrayCount} textures for '{textureAttribute.name}' but got {nTextures}"
252 if textureAttribute.arrayCount < nTextures:
253 warn &"Shader assigned to render '{materialType}' expected {textureAttribute.arrayCount} textures for '{textureAttribute.name}' but got {nTextures}"
254
255 # gather uniform sizes
256 var uniformBufferSize = 0'u64
257 for uniform in shaderPipeline.Uniforms:
258 uniformBufferSize += uniform.Size
259 if uniformBufferSize > 0:
260 for frame_i in 0 ..< renderer.swapchain.inFlightFrames:
261 scenedata.shaderData[shaderPipeline.vk].uniformBuffers.add renderer.device.CreateBuffer(
262 size = uniformBufferSize,
263 usage = [VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT],
264 requireMappable = true,
265 preferVRAM = true,
266 )
267
268 # TODO: rework the whole descriptor/pool/layout stuff, a bit unclear
269 var poolsizes = @[(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, renderer.swapchain.inFlightFrames.uint32)]
270 var nTextures = 0'u32
271 for descriptor in shaderPipeline.descriptorSetLayout.descriptors:
272 if descriptor.thetype == ImageSampler:
273 nTextures += descriptor.count
274 if nTextures > 0:
275 poolsizes.add (VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nTextures * renderer.swapchain.inFlightFrames.uint32)
276 scenedata.shaderData[shaderPipeline.vk].descriptorPool = renderer.device.CreateDescriptorSetPool(poolsizes)
277
278 scenedata.shaderData[shaderPipeline.vk].descriptorSets = shaderPipeline.SetupDescriptors(
279 scenedata.shaderData[shaderPipeline.vk].descriptorPool,
280 scenedata.shaderData[shaderPipeline.vk].uniformBuffers,
281 scenedata.shaderData[shaderPipeline.vk].textures,
282 inFlightFrames = renderer.swapchain.inFlightFrames,
283 emptyTexture = renderer.emptyTexture,
284 )
285 for frame_i in 0 ..< renderer.swapchain.inFlightFrames:
286 scenedata.shaderData[shaderPipeline.vk].descriptorSets[frame_i].WriteDescriptorSet()
287
288 renderer.scenedata[scene] = scenedata
289
290 proc UpdateMeshData*(renderer: var Renderer, scene: var Scene, forceAll = false) =
291 assert scene in renderer.scenedata
292
293 var addedBarrier = false;
294 for (drawable, mesh) in renderer.scenedata[scene].drawables.mitems:
295 if mesh[].Attributes.contains(TRANSFORM_ATTRIB):
296 mesh[].UpdateInstanceTransforms(TRANSFORM_ATTRIB)
297 let attrs = (if forceAll: mesh[].Attributes else: mesh[].DirtyAttributes)
298 for attribute in attrs:
299 # ignore attributes that are not used in this scene
300 if attribute in renderer.scenedata[scene].attributeLocation:
301 debug &"Update mesh attribute {attribute}"
302 let memoryPerformanceHint = renderer.scenedata[scene].attributeLocation[attribute]
303 # if we have to do a vkCmdCopyBuffer (not buffer.canMap), then we want to added a barrier to
304 # not infer with the current frame that is being renderer (relevant when we have multiple frames in flight)
305 # (remark: ...I think..., I am pretty new to this sync stuff)
306 if not renderer.scenedata[scene].vertexBuffers[memoryPerformanceHint].CanMap and not addedBarrier:
307 WithSingleUseCommandBuffer(renderer.device, renderer.queue, commandBuffer):
308 let barrier = VkMemoryBarrier(
309 sType: VK_STRUCTURE_TYPE_MEMORY_BARRIER,
310 srcAccessMask: [VK_ACCESS_MEMORY_READ_BIT].toBits,
311 dstAccessMask: [VK_ACCESS_MEMORY_WRITE_BIT].toBits,
312 )
313 commandBuffer.PipelineBarrier(
314 srcStages = [VK_PIPELINE_STAGE_VERTEX_INPUT_BIT],
315 dstStages = [VK_PIPELINE_STAGE_TRANSFER_BIT],
316 memoryBarriers = [barrier]
317 )
318 addedBarrier = true
319 renderer.scenedata[scene].vertexBuffers[memoryPerformanceHint].SetData(
320 renderer.queue,
321 mesh[].GetPointer(attribute),
322 mesh[].AttributeSize(attribute),
323 renderer.scenedata[scene].vertexBufferOffsets[(mesh, attribute)]
324 )
325 mesh[].ClearDirtyAttributes()
326
327 proc UpdateUniformData*(renderer: var Renderer, scene: var Scene, forceAll = false) =
328 assert scene in renderer.scenedata
329
330 let dirty = scene.DirtyShaderGlobals
331
332 if forceAll:
333 debug "Update uniforms because 'forceAll' was given"
334 elif dirty.len > 0:
335 debug &"Update uniforms because of dirty scene globals: {dirty}"
336
337 # loop over all used shaders/pipelines
338 for (materialType, shaderPipeline) in renderer.shadersForScene(scene):
339 if renderer.scenedata[scene].shaderData[shaderPipeline.vk].uniformBuffers.len > 0:
340 var dirtyMaterialAttribs: seq[string]
341 for material in renderer.scenedata[scene].materials[materialType].mitems:
342 dirtyMaterialAttribs.add material.DirtyAttributes
343 material.ClearDirtyAttributes()
344 assert renderer.scenedata[scene].shaderData[shaderPipeline.vk].uniformBuffers[renderer.swapchain.currentInFlight].vk.Valid
345 if forceAll:
346 for buffer in renderer.scenedata[scene].shaderData[shaderPipeline.vk].uniformBuffers:
347 assert buffer.vk.Valid
348
349 var offset = 0'u64
350 # loop over all uniforms of the shader-shaderPipeline
351 for uniform in shaderPipeline.Uniforms:
352 if dirty.contains(uniform.name) or dirtyMaterialAttribs.contains(uniform.name) or forceAll: # only update uniforms if necessary
353 var value = InitDataList(uniform.theType)
354 if scene.shaderGlobals.hasKey(uniform.name):
355 assert scene.shaderGlobals[uniform.name].thetype == uniform.thetype
356 value = scene.shaderGlobals[uniform.name]
357 else:
358 var foundValue = false
359 for material in renderer.scenedata[scene].materials[materialType]:
360 if material.HasMatchingAttribute(uniform):
361 value.AppendValues(material[uniform.name])
362 foundValue = true
363 assert foundValue, &"Uniform '{uniform.name}' not found in scene shaderGlobals or materials"
364 assert (uniform.arrayCount == 0 and value.len == 1) or value.len.uint <= uniform.arrayCount, &"Uniform '{uniform.name}' found has wrong length (shader declares {uniform.arrayCount} but shaderGlobals and materials provide {value.len})"
365 if value.len.uint <= uniform.arrayCount:
366 debug &"Uniform '{uniform.name}' found has short length (shader declares {uniform.arrayCount} but shaderGlobals and materials provide {value.len})"
367 assert value.Size <= uniform.Size, &"During uniform update: gathered value has size {value.Size} but uniform expects size {uniform.Size}"
368 if value.Size < uniform.Size:
369 debug &"During uniform update: gathered value has size {value.Size} but uniform expects size {uniform.Size}"
370 debug &" update uniform '{uniform.name}' with value: {value}"
371 # TODO: technically we would only need to update the uniform buffer of the current
372 # frameInFlight (I think), but we don't track for which frame the shaderglobals are no longer dirty
373 # therefore we have to update the uniform values in all buffers, of all inFlightframes (usually 2)
374 for buffer in renderer.scenedata[scene].shaderData[shaderPipeline.vk].uniformBuffers:
375 buffer.SetData(renderer.queue, value.GetPointer(), value.Size, offset)
376 offset += uniform.Size
377 scene.ClearDirtyShaderGlobals()
378
379 proc StartNewFrame*(renderer: var Renderer): bool =
380 # first, we need to await the next free frame from the swapchain
381 if not renderer.swapchain.AcquireNextFrame():
382 # so, there was a problem while acquiring the frame
383 # lets first take a break (not sure if this helps anything)
384 checkVkResult renderer.device.vk.vkDeviceWaitIdle()
385 # now, first thing is, we recreate the swapchain, because a invalid swapchain
386 # is a common reason for the inability to acquire the next frame
387 let res = renderer.swapchain.Recreate()
388 if res.isSome:
389 # okay, swapchain recreation worked
390 # Now we can swap old and new swapchain
391 # the vkDeviceWaitIdle makes the resizing of windows not super smooth,
392 # but things seem to be more stable this way
393 var oldSwapchain = renderer.swapchain
394 renderer.swapchain = res.get()
395 checkVkResult renderer.device.vk.vkDeviceWaitIdle()
396 oldSwapchain.Destroy()
397 # NOW, we still have to acquire that next frame with the NEW swapchain
398 # if that fails, I don't know what to smart to do...
399 if not renderer.swapchain.AcquireNextFrame():
400 return false
401 else:
402 # dang, swapchain could not be recreated. Some bigger issues is at hand...
403 return false
404 renderer.nextFrameReady = true
405 return true
406
407 proc Render*(renderer: var Renderer, scene: Scene) =
408 assert scene in renderer.scenedata
409 assert renderer.nextFrameReady, "startNewFrame() must be called before calling render()"
410
411 # preparation
412 renderer.currentFrameCommandBuffer.BeginRenderCommands(renderer.renderPass, renderer.swapchain.CurrentFramebuffer(), oneTimeSubmit = true)
413
414 # debug output
415 debug "Scene buffers:"
416 for (location, buffer) in renderer.scenedata[scene].vertexBuffers.pairs:
417 debug " ", location, ": ", buffer
418 debug " Index buffer: ", renderer.scenedata[scene].indexBuffer
419
420 # draw all meshes
421 for (materialType, shaderPipeline) in renderer.renderPass.shaderPipelines:
422 if scene.UsesMaterial(materialType):
423 debug &"Start shaderPipeline for '{materialType}'"
424 renderer.currentFrameCommandBuffer.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, shaderPipeline.vk)
425 renderer.currentFrameCommandBuffer.vkCmdBindDescriptorSets(
426 VK_PIPELINE_BIND_POINT_GRAPHICS,
427 shaderPipeline.layout,
428 0,
429 1,
430 addr(renderer.scenedata[scene].shaderData[shaderPipeline.vk].descriptorSets[renderer.swapchain.currentInFlight].vk),
431 0,
432 nil
433 )
434 for (drawable, mesh) in renderer.scenedata[scene].drawables.filterIt(it[1].visible and it[1].material.theType == materialType):
435 drawable.Draw(renderer.currentFrameCommandBuffer, vertexBuffers = renderer.scenedata[scene].vertexBuffers, indexBuffer = renderer.scenedata[scene].indexBuffer, shaderPipeline.vk)
436
437 # done rendering
438 renderer.currentFrameCommandBuffer.EndRenderCommands()
439
440 # swap framebuffer
441 if not renderer.swapchain.Swap(renderer.queue, renderer.currentFrameCommandBuffer):
442 let res = renderer.swapchain.Recreate()
443 if res.isSome:
444 var oldSwapchain = renderer.swapchain
445 renderer.swapchain = res.get()
446 checkVkResult renderer.device.vk.vkDeviceWaitIdle()
447 oldSwapchain.Destroy()
448 renderer.swapchain.currentInFlight = (renderer.swapchain.currentInFlight + 1) mod renderer.swapchain.inFlightFrames
449 renderer.nextFrameReady = false
450
451 func Valid*(renderer: Renderer): bool =
452 renderer.device.vk.Valid
453
454 proc Destroy*(renderer: var Renderer, scene: Scene) =
455 checkVkResult renderer.device.vk.vkDeviceWaitIdle()
456 var scenedata = renderer.scenedata[scene]
457
458 for buffer in scenedata.vertexBuffers.mvalues:
459 assert buffer.vk.Valid
460 buffer.Destroy()
461
462 if scenedata.indexBuffer.vk.Valid:
463 assert scenedata.indexBuffer.vk.Valid
464 scenedata.indexBuffer.Destroy()
465
466 var destroyedTextures: seq[VkImage]
467
468 for (vkPipeline, shaderData) in scenedata.shaderData.mpairs:
469
470 for buffer in shaderData.uniformBuffers.mitems:
471 assert buffer.vk.Valid
472 buffer.Destroy()
473
474 for textures in shaderData.textures.mvalues:
475 for texture in textures.mitems:
476 if not destroyedTextures.contains(texture.image.vk):
477 destroyedTextures.add texture.image.vk
478 texture.Destroy()
479
480 shaderData.descriptorPool.Destroy()
481
482 renderer.scenedata.del(scene)
483
484 proc Destroy*(renderer: var Renderer) =
485 for scene in renderer.scenedata.keys.toSeq:
486 renderer.Destroy(scene)
487 assert renderer.scenedata.len == 0
488 renderer.emptyTexture.Destroy()
489 renderer.renderPass.Destroy()
490 renderer.commandBufferPool.Destroy()
491 renderer.swapchain.Destroy()