Mercurial > games > semicongine
comparison src/zamikongine/engine.nim @ 28:b1b05d4efb52
big refactoring, part1
author | Sam <sam@basx.dev> |
---|---|
date | Sat, 14 Jan 2023 14:08:00 +0700 |
parents | 71bbe11d8de8 |
children | 9edca5dc4e93 |
comparison
equal
deleted
inserted
replaced
27:8cb2d96ac28e | 28:b1b05d4efb52 |
---|---|
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 |