comparison src/zamikongine/engine.nim @ 489:54a1f8ee208e

big refactoring, part1
author Sam <sam@basx.dev>
date Sat, 14 Jan 2023 14:08:00 +0700
parents b4a972bd37d5
children 680c4b8ca28a
comparison
equal deleted inserted replaced
488:455f1a416fe7 489:54a1f8ee208e
1 import std/times
1 import std/typetraits 2 import std/typetraits
2 import std/strformat 3 import std/strformat
3 import std/enumerate 4 import std/enumerate
4 import std/logging 5 import std/logging
5 6
11 import ./shader 12 import ./shader
12 import ./vertex 13 import ./vertex
13 import ./buffer 14 import ./buffer
14 import ./thing 15 import ./thing
15 import ./mesh 16 import ./mesh
17 import ./descriptor
16 18
17 const MAX_FRAMES_IN_FLIGHT = 2 19 const MAX_FRAMES_IN_FLIGHT = 2
18 const DEBUG_LOG = not defined(release) 20 const DEBUG_LOG = not defined(release)
19 21
20 var logger = newConsoleLogger() 22 var logger = newConsoleLogger()
33 presentationQueue: VkQueue 35 presentationQueue: VkQueue
34 Swapchain = object 36 Swapchain = object
35 swapchain: VkSwapchainKHR 37 swapchain: VkSwapchainKHR
36 images: seq[VkImage] 38 images: seq[VkImage]
37 imageviews: seq[VkImageView] 39 imageviews: seq[VkImageView]
38 RenderPipeline = object 40 RenderPipeline[T] = object
39 shaders*: seq[ShaderProgram] 41 device*: VkDevice
42 shaders*: seq[ShaderProgram[T]]
40 layout*: VkPipelineLayout 43 layout*: VkPipelineLayout
41 pipeline*: VkPipeline 44 pipeline*: VkPipeline
45 uniformLayout*: VkDescriptorSetLayout
46 vertexBuffers*: seq[(seq[Buffer], uint32)]
47 indexedVertexBuffers*: seq[(seq[Buffer], Buffer, uint32, VkIndexType)]
48 uniformBuffers*: array[MAX_FRAMES_IN_FLIGHT, Buffer]
42 QueueFamily = object 49 QueueFamily = object
43 properties*: VkQueueFamilyProperties 50 properties*: VkQueueFamilyProperties
44 hasSurfaceSupport*: bool 51 hasSurfaceSupport*: bool
45 PhysicalDevice = object 52 PhysicalDevice = object
46 device*: VkPhysicalDevice 53 device*: VkPhysicalDevice
49 features*: VkPhysicalDeviceFeatures 56 features*: VkPhysicalDeviceFeatures
50 queueFamilies*: seq[QueueFamily] 57 queueFamilies*: seq[QueueFamily]
51 formats: seq[VkSurfaceFormatKHR] 58 formats: seq[VkSurfaceFormatKHR]
52 presentModes: seq[VkPresentModeKHR] 59 presentModes: seq[VkPresentModeKHR]
53 Vulkan* = object 60 Vulkan* = object
54 debugMessenger: VkDebugUtilsMessengerEXT 61 debugMessenger*: VkDebugUtilsMessengerEXT
55 instance*: VkInstance 62 instance*: VkInstance
56 deviceList*: seq[PhysicalDevice] 63 deviceList*: seq[PhysicalDevice]
57 device*: Device 64 device*: Device
58 surface*: VkSurfaceKHR 65 surface*: VkSurfaceKHR
59 surfaceFormat: VkSurfaceFormatKHR 66 surfaceFormat*: VkSurfaceFormatKHR
60 frameDimension: VkExtent2D 67 frameDimension*: VkExtent2D
61 swapchain: Swapchain 68 swapchain*: Swapchain
62 framebuffers: seq[VkFramebuffer] 69 framebuffers*: seq[VkFramebuffer]
63 renderPass*: VkRenderPass 70 renderPass*: VkRenderPass
64 pipeline*: RenderPipeline
65 commandPool*: VkCommandPool 71 commandPool*: VkCommandPool
66 commandBuffers*: array[MAX_FRAMES_IN_FLIGHT, VkCommandBuffer] 72 commandBuffers*: array[MAX_FRAMES_IN_FLIGHT, VkCommandBuffer]
67 imageAvailableSemaphores*: array[MAX_FRAMES_IN_FLIGHT, VkSemaphore] 73 imageAvailableSemaphores*: array[MAX_FRAMES_IN_FLIGHT, VkSemaphore]
68 renderFinishedSemaphores*: array[MAX_FRAMES_IN_FLIGHT, VkSemaphore] 74 renderFinishedSemaphores*: array[MAX_FRAMES_IN_FLIGHT, VkSemaphore]
69 inFlightFences*: array[MAX_FRAMES_IN_FLIGHT, VkFence] 75 inFlightFences*: array[MAX_FRAMES_IN_FLIGHT, VkFence]
70 vertexBuffers: seq[(seq[Buffer], uint32)]
71 indexedVertexBuffers: seq[(seq[Buffer], Buffer, uint32, VkIndexType)]
72 Engine* = object 76 Engine* = object
73 vulkan: Vulkan 77 vulkan*: Vulkan
74 window: NativeWindow 78 window*: NativeWindow
75 currentscenedata: ref Thing 79 currentscenedata*: ref Thing
76 80
77 proc getAllPhysicalDevices(instance: VkInstance, surface: VkSurfaceKHR): seq[PhysicalDevice] = 81 proc getAllPhysicalDevices(instance: VkInstance, surface: VkSurfaceKHR): seq[PhysicalDevice] =
78 for vulkanPhysicalDevice in getVulkanPhysicalDevices(instance): 82 for vulkanPhysicalDevice in getVulkanPhysicalDevices(instance):
79 var device = PhysicalDevice(device: vulkanPhysicalDevice, extensions: getDeviceExtensions(vulkanPhysicalDevice)) 83 var device = PhysicalDevice(device: vulkanPhysicalDevice, extensions: getDeviceExtensions(vulkanPhysicalDevice))
80 vkGetPhysicalDeviceProperties(vulkanPhysicalDevice, addr(device.properties)) 84 vkGetPhysicalDeviceProperties(vulkanPhysicalDevice, addr(device.properties))
244 dependencyCount: 1, 248 dependencyCount: 1,
245 pDependencies: addr(dependency), 249 pDependencies: addr(dependency),
246 ) 250 )
247 checkVkResult device.vkCreateRenderPass(addr(renderPassCreateInfo), nil, addr(result)) 251 checkVkResult device.vkCreateRenderPass(addr(renderPassCreateInfo), nil, addr(result))
248 252
249 proc setupRenderPipeline[T](device: VkDevice, frameDimension: VkExtent2D, renderPass: VkRenderPass, vertexShader, fragmentShader: static string): RenderPipeline = 253 proc initRenderPipeline[VertextType, T](device: VkDevice, frameDimension: VkExtent2D, renderPass: VkRenderPass, vertexShader, fragmentShader: static string): RenderPipeline[T] =
250 # load shaders 254 # load shaders
251 result.shaders.add(device.initShaderProgram(VK_SHADER_STAGE_VERTEX_BIT, vertexShader)) 255 result.device = device
252 result.shaders.add(device.initShaderProgram(VK_SHADER_STAGE_FRAGMENT_BIT, fragmentShader)) 256 result.shaders.add(initShaderProgram[T](device, VK_SHADER_STAGE_VERTEX_BIT, vertexShader))
257 result.shaders.add(initShaderProgram[T](device, VK_SHADER_STAGE_FRAGMENT_BIT, fragmentShader))
253 258
254 var 259 var
255 # define which parts can be dynamic (pipeline is fixed after setup) 260 # define which parts can be dynamic (pipeline is fixed after setup)
256 dynamicStates = [VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR] 261 dynamicStates = [VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR]
257 dynamicState = VkPipelineDynamicStateCreateInfo( 262 dynamicState = VkPipelineDynamicStateCreateInfo(
258 sType: VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, 263 sType: VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
259 dynamicStateCount: uint32(dynamicStates.len), 264 dynamicStateCount: uint32(dynamicStates.len),
260 pDynamicStates: addr(dynamicStates[0]), 265 pDynamicStates: addr(dynamicStates[0]),
261 ) 266 )
262 vertexbindings = generateInputVertexBinding[T]() 267 vertexbindings = generateInputVertexBinding[VertextType]()
263 attributebindings = generateInputAttributeBinding[T]() 268 attributebindings = generateInputAttributeBinding[VertextType]()
264 269
265 # define input data format 270 # define input data format
266 vertexInputInfo = VkPipelineVertexInputStateCreateInfo( 271 vertexInputInfo = VkPipelineVertexInputStateCreateInfo(
267 sType: VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, 272 sType: VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
268 vertexBindingDescriptionCount: uint32(vertexbindings.len), 273 vertexBindingDescriptionCount: uint32(vertexbindings.len),
329 attachmentCount: 1, 334 attachmentCount: 1,
330 pAttachments: addr(colorBlendAttachment), 335 pAttachments: addr(colorBlendAttachment),
331 blendConstants: [0.0'f, 0.0'f, 0.0'f, 0.0'f], 336 blendConstants: [0.0'f, 0.0'f, 0.0'f, 0.0'f],
332 ) 337 )
333 338
334 # create pipeline 339 result.uniformLayout = device.createUniformDescriptorLayout(VkShaderStageFlags(VK_SHADER_STAGE_VERTEX_BIT), 0)
340 var
341 # "globals" that go into the shader, uniforms etc.
335 pipelineLayoutInfo = VkPipelineLayoutCreateInfo( 342 pipelineLayoutInfo = VkPipelineLayoutCreateInfo(
336 sType: VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 343 sType: VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
337 setLayoutCount: 0, 344 setLayoutCount: 1,
338 pSetLayouts: nil, 345 pSetLayouts: addr(result.uniformLayout),
339 pushConstantRangeCount: 0, 346 pushConstantRangeCount: 0,
340 pPushConstantRanges: nil, 347 pPushConstantRanges: nil,
341 ) 348 )
342 checkVkResult vkCreatePipelineLayout(device, addr(pipelineLayoutInfo), nil, addr(result.layout)) 349 checkVkResult vkCreatePipelineLayout(device, addr(pipelineLayoutInfo), nil, addr(result.layout))
343 350
441 for i in 0 ..< MAX_FRAMES_IN_FLIGHT: 448 for i in 0 ..< MAX_FRAMES_IN_FLIGHT:
442 checkVkResult device.vkCreateSemaphore(addr(semaphoreInfo), nil, addr(result[0][i])) 449 checkVkResult device.vkCreateSemaphore(addr(semaphoreInfo), nil, addr(result[0][i]))
443 checkVkResult device.vkCreateSemaphore(addr(semaphoreInfo), nil, addr(result[1][i])) 450 checkVkResult device.vkCreateSemaphore(addr(semaphoreInfo), nil, addr(result[1][i]))
444 checkVkResult device.vkCreateFence(addr(fenceInfo), nil, addr(result[2][i])) 451 checkVkResult device.vkCreateFence(addr(fenceInfo), nil, addr(result[2][i]))
445 452
446 proc igniteEngine*(): Engine = 453 proc igniteEngine*(windowTitle: string): Engine =
447 454
448 result.window = createWindow("Hello triangle") 455 result.window = createWindow(windowTitle)
449 456
450 # setup vulkan functions 457 # setup vulkan functions
451 vkLoad1_0() 458 vkLoad1_0()
452 vkLoad1_1() 459 vkLoad1_1()
453 vkLoad1_2() 460 vkLoad1_2()
486 result.vulkan.renderFinishedSemaphores, 493 result.vulkan.renderFinishedSemaphores,
487 result.vulkan.inFlightFences, 494 result.vulkan.inFlightFences,
488 ) = result.vulkan.device.device.setupSyncPrimitives() 495 ) = result.vulkan.device.device.setupSyncPrimitives()
489 496
490 497
491 proc setupPipeline*[T: object, U: uint16|uint32](engine: var Engine, scenedata: ref Thing, vertexShader, fragmentShader: static string) = 498 proc setupPipeline*[VertexType, UniformType, T: object, IndexType: uint16|uint32](engine: var Engine, scenedata: ref Thing, vertexShader, fragmentShader: static string): RenderPipeline[T] =
492 engine.currentscenedata = scenedata 499 engine.currentscenedata = scenedata
493 engine.vulkan.pipeline = setupRenderPipeline[T]( 500 result = initRenderPipeline[VertexType, T](
494 engine.vulkan.device.device, 501 engine.vulkan.device.device,
495 engine.vulkan.frameDimension, 502 engine.vulkan.frameDimension,
496 engine.vulkan.renderPass, 503 engine.vulkan.renderPass,
497 vertexShader, 504 vertexShader,
498 fragmentShader, 505 fragmentShader,
499 ) 506 )
500 var allmeshes: seq[Mesh[T]] 507 # vertex buffers
501 for mesh in partsOfType[ref Mesh[T]](engine.currentscenedata): 508 var allmeshes: seq[Mesh[VertexType]]
509 for mesh in partsOfType[ref Mesh[VertexType]](engine.currentscenedata):
502 allmeshes.add(mesh[]) 510 allmeshes.add(mesh[])
503 if allmeshes.len > 0: 511 if allmeshes.len > 0:
504 var ubermesh = createUberMesh(allmeshes) 512 var ubermesh = createUberMesh(allmeshes)
505 engine.vulkan.vertexBuffers.add createVertexBuffers(ubermesh, engine.vulkan.device.device, engine.vulkan.device.physicalDevice.device, engine.vulkan.commandPool, engine.vulkan.device.graphicsQueue) 513 result.vertexBuffers.add createVertexBuffers(ubermesh, engine.vulkan.device.device, engine.vulkan.device.physicalDevice.device, engine.vulkan.commandPool, engine.vulkan.device.graphicsQueue)
506 514
507 var allindexedmeshes: seq[IndexedMesh[T, U]] 515 # vertex buffers with indexes
508 for mesh in partsOfType[ref IndexedMesh[T, U]](engine.currentscenedata): 516 var allindexedmeshes: seq[IndexedMesh[VertexType, IndexType]]
517 for mesh in partsOfType[ref IndexedMesh[VertexType, IndexType]](engine.currentscenedata):
509 allindexedmeshes.add(mesh[]) 518 allindexedmeshes.add(mesh[])
510 if allindexedmeshes.len > 0: 519 if allindexedmeshes.len > 0:
511 var indexedubermesh = createUberMesh(allindexedmeshes) 520 var indexedubermesh = createUberMesh(allindexedmeshes)
512 engine.vulkan.indexedVertexBuffers.add createIndexedVertexBuffers(indexedubermesh, engine.vulkan.device.device, engine.vulkan.device.physicalDevice.device, engine.vulkan.commandPool, engine.vulkan.device.graphicsQueue) 521 result.indexedVertexBuffers.add createIndexedVertexBuffers(indexedubermesh, engine.vulkan.device.device, engine.vulkan.device.physicalDevice.device, engine.vulkan.commandPool, engine.vulkan.device.graphicsQueue)
513 522
514 proc recordCommandBuffer(renderPass: VkRenderPass, pipeline: VkPipeline, commandBuffer: VkCommandBuffer, framebuffer: VkFramebuffer, frameDimension: VkExtent2D, engine: var Engine) = 523 # uniform buffers
524 result.uniformBuffers = createUniformBuffers[MAX_FRAMES_IN_FLIGHT, UniformType](
525 engine.vulkan.device.device,
526 engine.vulkan.device.physicalDevice.device
527 )
528
529
530 proc runPipeline(commandBuffer: VkCommandBuffer, pipeline: RenderPipeline) =
531 vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipeline)
532
533 for (vertexBufferSet, vertexCount) in pipeline.vertexBuffers:
534 var
535 vertexBuffers: seq[VkBuffer]
536 offsets: seq[VkDeviceSize]
537 for buffer in vertexBufferSet:
538 vertexBuffers.add buffer.vkBuffer
539 offsets.add VkDeviceSize(0)
540
541 vkCmdBindVertexBuffers(commandBuffer, firstBinding=0'u32, bindingCount=2'u32, pBuffers=addr(vertexBuffers[0]), pOffsets=addr(offsets[0]))
542 vkCmdDraw(commandBuffer, vertexCount=vertexCount, instanceCount=1'u32, firstVertex=0'u32, firstInstance=0'u32)
543
544 for (vertexBufferSet, indexBuffer, indicesCount, indexType) in pipeline.indexedVertexBuffers:
545 var
546 vertexBuffers: seq[VkBuffer]
547 offsets: seq[VkDeviceSize]
548 for buffer in vertexBufferSet:
549 vertexBuffers.add buffer.vkBuffer
550 offsets.add VkDeviceSize(0)
551
552 vkCmdBindVertexBuffers(commandBuffer, firstBinding=0'u32, bindingCount=2'u32, pBuffers=addr(vertexBuffers[0]), pOffsets=addr(offsets[0]))
553 vkCmdBindIndexBuffer(commandBuffer, indexBuffer.vkBuffer, VkDeviceSize(0), indexType);
554 vkCmdDrawIndexed(commandBuffer, indicesCount, 1, 0, 0, 0);
555
556 proc recordCommandBuffer(renderPass: VkRenderPass, pipeline: RenderPipeline, commandBuffer: VkCommandBuffer, framebuffer: VkFramebuffer, frameDimension: VkExtent2D) =
515 var 557 var
516 beginInfo = VkCommandBufferBeginInfo( 558 beginInfo = VkCommandBufferBeginInfo(
517 sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 559 sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
518 pInheritanceInfo: nil, 560 pInheritanceInfo: nil,
519 ) 561 )
539 ) 581 )
540 scissor = VkRect2D( 582 scissor = VkRect2D(
541 offset: VkOffset2D(x: 0, y: 0), 583 offset: VkOffset2D(x: 0, y: 0),
542 extent: frameDimension 584 extent: frameDimension
543 ) 585 )
544 checkVkResult commandBuffer.vkBeginCommandBuffer(addr(beginInfo)) 586 checkVkResult vkBeginCommandBuffer(commandBuffer, addr(beginInfo))
545 commandBuffer.vkCmdBeginRenderPass(addr(renderPassInfo), VK_SUBPASS_CONTENTS_INLINE) 587 block:
546 commandBuffer.vkCmdSetViewport(firstViewport=0, viewportCount=1, addr(viewport)) 588 vkCmdBeginRenderPass(commandBuffer, addr(renderPassInfo), VK_SUBPASS_CONTENTS_INLINE)
547 commandBuffer.vkCmdSetScissor(firstScissor=0, scissorCount=1, addr(scissor)) 589 vkCmdSetViewport(commandBuffer, firstViewport=0, viewportCount=1, addr(viewport))
548 commandBuffer.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline) 590 vkCmdSetScissor(commandBuffer, firstScissor=0, scissorCount=1, addr(scissor))
549 591 runPipeline(commandBuffer, pipeline)
550 for (vertexBufferSet, vertexCount) in engine.vulkan.vertexBuffers: 592 vkCmdEndRenderPass(commandBuffer)
551 var 593 checkVkResult vkEndCommandBuffer(commandBuffer)
552 vertexBuffers: seq[VkBuffer] 594
553 offsets: seq[VkDeviceSize] 595 proc drawFrame(window: NativeWindow, vulkan: var Vulkan, currentFrame: int, resized: bool, pipeline: RenderPipeline) =
554 for buffer in vertexBufferSet: 596 checkVkResult vkWaitForFences(vulkan.device.device, 1, addr(vulkan.inFlightFences[currentFrame]), VK_TRUE, high(uint64))
555 vertexBuffers.add buffer.vkBuffer
556 offsets.add VkDeviceSize(0)
557
558 commandBuffer.vkCmdBindVertexBuffers(firstBinding=0'u32, bindingCount=2'u32, pBuffers=addr(vertexBuffers[0]), pOffsets=addr(offsets[0]))
559 commandBuffer.vkCmdDraw(vertexCount=vertexCount, instanceCount=1'u32, firstVertex=0'u32, firstInstance=0'u32)
560
561 for (vertexBufferSet, indexBuffer, indicesCount, indexType) in engine.vulkan.indexedVertexBuffers:
562 var
563 vertexBuffers: seq[VkBuffer]
564 offsets: seq[VkDeviceSize]
565 for buffer in vertexBufferSet:
566 vertexBuffers.add buffer.vkBuffer
567 offsets.add VkDeviceSize(0)
568
569 commandBuffer.vkCmdBindVertexBuffers(firstBinding=0'u32, bindingCount=2'u32, pBuffers=addr(vertexBuffers[0]), pOffsets=addr(offsets[0]))
570 commandBuffer.vkCmdBindIndexBuffer(indexBuffer.vkBuffer, VkDeviceSize(0), indexType);
571 commandBuffer.vkCmdDrawIndexed(indicesCount, 1, 0, 0, 0);
572 commandBuffer.vkCmdEndRenderPass()
573 checkVkResult commandBuffer.vkEndCommandBuffer()
574
575 proc drawFrame(window: NativeWindow, vulkan: var Vulkan, currentFrame: int, resized: bool, engine: var Engine) =
576 checkVkResult vulkan.device.device.vkWaitForFences(1, addr(vulkan.inFlightFences[currentFrame]), VK_TRUE, high(uint64))
577 var bufferImageIndex: uint32 597 var bufferImageIndex: uint32
578 let nextImageResult = vulkan.device.device.vkAcquireNextImageKHR( 598 let nextImageResult = vkAcquireNextImageKHR(
599 vulkan.device.device,
579 vulkan.swapchain.swapchain, 600 vulkan.swapchain.swapchain,
580 high(uint64), 601 high(uint64),
581 vulkan.imageAvailableSemaphores[currentFrame], 602 vulkan.imageAvailableSemaphores[currentFrame],
582 VkFence(0), 603 VkFence(0),
583 addr(bufferImageIndex) 604 addr(bufferImageIndex)
585 if nextImageResult == VK_ERROR_OUT_OF_DATE_KHR: 606 if nextImageResult == VK_ERROR_OUT_OF_DATE_KHR:
586 vulkan.frameDimension = window.getFrameDimension(vulkan.device.physicalDevice.device, vulkan.surface) 607 vulkan.frameDimension = window.getFrameDimension(vulkan.device.physicalDevice.device, vulkan.surface)
587 (vulkan.swapchain, vulkan.framebuffers) = vulkan.recreateSwapchain() 608 (vulkan.swapchain, vulkan.framebuffers) = vulkan.recreateSwapchain()
588 elif not (nextImageResult in [VK_SUCCESS, VK_SUBOPTIMAL_KHR]): 609 elif not (nextImageResult in [VK_SUCCESS, VK_SUBOPTIMAL_KHR]):
589 raise newException(Exception, "Vulkan error: vkAcquireNextImageKHR returned " & $nextImageResult) 610 raise newException(Exception, "Vulkan error: vkAcquireNextImageKHR returned " & $nextImageResult)
590 checkVkResult vulkan.device.device.vkResetFences(1, addr(vulkan.inFlightFences[currentFrame])) 611 checkVkResult vkResetFences(vulkan.device.device, 1, addr(vulkan.inFlightFences[currentFrame]))
591 612
592 checkVkResult vulkan.commandBuffers[currentFrame].vkResetCommandBuffer(VkCommandBufferResetFlags(0)) 613 checkVkResult vkResetCommandBuffer(vulkan.commandBuffers[currentFrame], VkCommandBufferResetFlags(0))
593 vulkan.renderPass.recordCommandBuffer(vulkan.pipeline.pipeline, vulkan.commandBuffers[currentFrame], vulkan.framebuffers[bufferImageIndex], vulkan.frameDimension, engine) 614 vulkan.renderPass.recordCommandBuffer(pipeline, vulkan.commandBuffers[currentFrame], vulkan.framebuffers[bufferImageIndex], vulkan.frameDimension)
594 var 615 var
595 waitSemaphores = [vulkan.imageAvailableSemaphores[currentFrame]] 616 waitSemaphores = [vulkan.imageAvailableSemaphores[currentFrame]]
596 waitStages = [VkPipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)] 617 waitStages = [VkPipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)]
597 signalSemaphores = [vulkan.renderFinishedSemaphores[currentFrame]] 618 signalSemaphores = [vulkan.renderFinishedSemaphores[currentFrame]]
598 submitInfo = VkSubmitInfo( 619 submitInfo = VkSubmitInfo(
621 if presentResult == VK_ERROR_OUT_OF_DATE_KHR or presentResult == VK_SUBOPTIMAL_KHR or resized: 642 if presentResult == VK_ERROR_OUT_OF_DATE_KHR or presentResult == VK_SUBOPTIMAL_KHR or resized:
622 vulkan.frameDimension = window.getFrameDimension(vulkan.device.physicalDevice.device, vulkan.surface) 643 vulkan.frameDimension = window.getFrameDimension(vulkan.device.physicalDevice.device, vulkan.surface)
623 (vulkan.swapchain, vulkan.framebuffers) = vulkan.recreateSwapchain() 644 (vulkan.swapchain, vulkan.framebuffers) = vulkan.recreateSwapchain()
624 645
625 646
626 proc fullThrottle*(engine: var Engine) = 647 proc run*(engine: var Engine, pipeline: RenderPipeline, globalUpdate: proc(engine: var Engine, dt: Duration)) =
627 var 648 var
628 killed = false 649 killed = false
629 currentFrame = 0 650 currentFrame = 0
630 resized = false 651 resized = false
652 lastUpdate = getTime()
631 653
632 while not killed: 654 while not killed:
655
656 # process input
633 for event in engine.window.pendingEvents(): 657 for event in engine.window.pendingEvents():
634 case event.eventType: 658 case event.eventType:
635 of Quit: 659 of Quit:
636 killed = true 660 killed = true
637 of ResizedWindow: 661 of ResizedWindow:
640 echo event 664 echo event
641 if event.key == Escape: 665 if event.key == Escape:
642 killed = true 666 killed = true
643 else: 667 else:
644 discard 668 discard
645 engine.window.drawFrame(engine.vulkan, currentFrame, resized, engine) 669
670 # game logic update
671 let
672 now = getTime()
673 dt = now - lastUpdate
674 lastUpdate = now
675 engine.globalUpdate(dt)
676 for entity in allEntities(engine.currentscenedata):
677 entity.update(dt)
678
679 # submit frame for drawing
680 engine.window.drawFrame(engine.vulkan, currentFrame, resized, pipeline)
646 resized = false 681 resized = false
647 currentFrame = (currentFrame + 1) mod MAX_FRAMES_IN_FLIGHT; 682 currentFrame = (currentFrame + 1) mod MAX_FRAMES_IN_FLIGHT;
648 checkVkResult engine.vulkan.device.device.vkDeviceWaitIdle() 683 checkVkResult vkDeviceWaitIdle(engine.vulkan.device.device)
649 684
650 proc trash*(engine: var Engine) = 685 proc trash*(pipeline: var RenderPipeline) =
651 for (bufferset, cnt) in engine.vulkan.vertexBuffers.mitems: 686 vkDestroyDescriptorSetLayout(pipeline.device, pipeline.uniformLayout, nil);
687 vkDestroyPipeline(pipeline.device, pipeline.pipeline, nil)
688 vkDestroyPipelineLayout(pipeline.device, pipeline.layout, nil)
689 for shader in pipeline.shaders:
690 vkDestroyShaderModule(pipeline.device, shader.shader.module, nil)
691
692 for (bufferset, cnt) in pipeline.vertexBuffers.mitems:
652 for buffer in bufferset.mitems: 693 for buffer in bufferset.mitems:
653 buffer.trash() 694 buffer.trash()
654 for (bufferset, indexbuffer, cnt, t) in engine.vulkan.indexedVertexBuffers.mitems: 695 for (bufferset, indexbuffer, cnt, t) in pipeline.indexedVertexBuffers.mitems:
655 indexbuffer.trash() 696 indexbuffer.trash()
656 for buffer in bufferset.mitems: 697 for buffer in bufferset.mitems:
657 buffer.trash() 698 buffer.trash()
699 for buffer in pipeline.uniformBuffers.mitems:
700 buffer.trash()
701
702 proc trash*(engine: var Engine) =
703 checkVkResult vkDeviceWaitIdle(engine.vulkan.device.device)
658 engine.vulkan.device.device.trash(engine.vulkan.swapchain, engine.vulkan.framebuffers) 704 engine.vulkan.device.device.trash(engine.vulkan.swapchain, engine.vulkan.framebuffers)
659 checkVkResult engine.vulkan.device.device.vkDeviceWaitIdle()
660 705
661 for i in 0 ..< MAX_FRAMES_IN_FLIGHT: 706 for i in 0 ..< MAX_FRAMES_IN_FLIGHT:
662 engine.vulkan.device.device.vkDestroySemaphore(engine.vulkan.imageAvailableSemaphores[i], nil) 707 engine.vulkan.device.device.vkDestroySemaphore(engine.vulkan.imageAvailableSemaphores[i], nil)
663 engine.vulkan.device.device.vkDestroySemaphore(engine.vulkan.renderFinishedSemaphores[i], nil) 708 engine.vulkan.device.device.vkDestroySemaphore(engine.vulkan.renderFinishedSemaphores[i], nil)
664 engine.vulkan.device.device.vkDestroyFence(engine.vulkan.inFlightFences[i], nil) 709 engine.vulkan.device.device.vkDestroyFence(engine.vulkan.inFlightFences[i], nil)
665 710
711 engine.vulkan.device.device.vkDestroyRenderPass(engine.vulkan.renderPass, nil)
666 engine.vulkan.device.device.vkDestroyCommandPool(engine.vulkan.commandPool, nil) 712 engine.vulkan.device.device.vkDestroyCommandPool(engine.vulkan.commandPool, nil)
667 engine.vulkan.device.device.vkDestroyPipeline(engine.vulkan.pipeline.pipeline, nil)
668 engine.vulkan.device.device.vkDestroyPipelineLayout(engine.vulkan.pipeline.layout, nil)
669 engine.vulkan.device.device.vkDestroyRenderPass(engine.vulkan.renderPass, nil)
670
671 for shader in engine.vulkan.pipeline.shaders:
672 engine.vulkan.device.device.vkDestroyShaderModule(shader.shader.module, nil)
673 713
674 engine.vulkan.instance.vkDestroySurfaceKHR(engine.vulkan.surface, nil) 714 engine.vulkan.instance.vkDestroySurfaceKHR(engine.vulkan.surface, nil)
675 engine.vulkan.device.device.vkDestroyDevice(nil) 715 engine.vulkan.device.device.vkDestroyDevice(nil)
676 when DEBUG_LOG: 716 when DEBUG_LOG:
677 engine.vulkan.instance.vkDestroyDebugUtilsMessengerEXT(engine.vulkan.debugMessenger, nil) 717 engine.vulkan.instance.vkDestroyDebugUtilsMessengerEXT(engine.vulkan.debugMessenger, nil)
678 engine.window.trash() 718 engine.window.trash()
679 engine.vulkan.instance.vkDestroyInstance(nil) 719 engine.vulkan.instance.vkDestroyInstance(nil) # needs to happen after window is trashed as the driver might have a hook registered for the window destruction