Mercurial > games > semicongine
comparison src/engine.nim @ 18:90e117952f74
add: basic vertex buffer functionality
| author | Sam <sam@basx.dev> |
|---|---|
| date | Thu, 05 Jan 2023 01:16:48 +0700 |
| parents | b40466fa446a |
| children |
comparison
equal
deleted
inserted
replaced
| 17:b40466fa446a | 18:90e117952f74 |
|---|---|
| 9 import ./window | 9 import ./window |
| 10 import ./events | 10 import ./events |
| 11 import ./math/vector | 11 import ./math/vector |
| 12 import ./shader | 12 import ./shader |
| 13 import ./vertex | 13 import ./vertex |
| 14 import ./buffer | |
| 14 | 15 |
| 15 import ./glslang/glslang | 16 import ./glslang/glslang |
| 16 | 17 |
| 17 const MAX_FRAMES_IN_FLIGHT = 2 | 18 const MAX_FRAMES_IN_FLIGHT = 2 |
| 18 const DEBUG_LOG = not defined(release) | 19 const DEBUG_LOG = not defined(release) |
| 24 type | 25 type |
| 25 MyVertex = object | 26 MyVertex = object |
| 26 position: VertexAttribute[Vec2[float32]] | 27 position: VertexAttribute[Vec2[float32]] |
| 27 color: VertexAttribute[Vec3[float32]] | 28 color: VertexAttribute[Vec3[float32]] |
| 28 | 29 |
| 29 const vertices = [ | 30 var vertices = ( |
| 30 (Vec2([ 0.0'f32, -0.5'f32]), Vec3([1.0'f32, 0.0'f32, 0.0'f32])), | |
| 31 (Vec2([ 0.5'f32, 0.5'f32]), Vec3([0.0'f32, 1.0'f32, 0.0'f32])), | |
| 32 (Vec2([-0.5'f32, 0.5'f32]), Vec3([0.0'f32, 0.0'f32, 1.0'f32])) | |
| 33 ] | |
| 34 | |
| 35 | |
| 36 proc getBindingDescription(binding: int): auto = | |
| 37 VkVertexInputBindingDescription( | |
| 38 binding: uint32(binding), | |
| 39 stride: uint32(sizeof(vertices[0])), | |
| 40 inputRate: VK_VERTEX_INPUT_RATE_VERTEX, # VK_VERTEX_INPUT_RATE_INSTANCE for instances | |
| 41 ) | |
| 42 | |
| 43 proc getAttributeDescriptions(binding: int): auto = | |
| 44 [ | 31 [ |
| 45 VkVertexInputAttributeDescription( | 32 Vec2([-0.5'f32, -0.5'f32]), |
| 46 binding: 0'u32, | 33 Vec2([ 0.5'f32, 0.5'f32]), |
| 47 location: 0, | 34 Vec2([-0.5'f32, 0.5'f32]), |
| 48 format: VK_FORMAT_R32G32_SFLOAT, | 35 |
| 49 offset: 0, | 36 Vec2([ 0.0'f32, -0.7'f32]), |
| 50 ), | 37 Vec2([ 0.6'f32, 0.1'f32]), |
| 51 VkVertexInputAttributeDescription( | 38 Vec2([ 0.3'f32, 0.4'f32]), |
| 52 binding: 0'u32, | 39 ], |
| 53 location: 1, | 40 [ |
| 54 format: VK_FORMAT_R32G32B32_SFLOAT, | 41 Vec3([1.0'f32, 1.0'f32, 0.0'f32]), |
| 55 offset: uint32(sizeof(Vec2)), # use offsetOf? | 42 Vec3([0.0'f32, 1.0'f32, 0.0'f32]), |
| 56 ), | 43 Vec3([0.0'f32, 1.0'f32, 1.0'f32]), |
| 44 | |
| 45 Vec3([1.0'f32, 1.0'f32, 0.0'f32]), | |
| 46 Vec3([1.0'f32, 0.0'f32, 0.0'f32]), | |
| 47 Vec3([0.0'f32, 1.0'f32, 1.0'f32]), | |
| 57 ] | 48 ] |
| 49 ) | |
| 58 | 50 |
| 59 var vertexShaderCode = """ | 51 var vertexShaderCode = """ |
| 60 #version 450 | 52 #version 450 |
| 61 | 53 |
| 62 layout(location = 0) in vec2 inPosition; | 54 layout(location = 0) in vec2 inPosition; |
| 79 | 71 |
| 80 const VULKAN_VERSION = VK_MAKE_API_VERSION(0'u32, 1'u32, 2'u32, 0'u32) | 72 const VULKAN_VERSION = VK_MAKE_API_VERSION(0'u32, 1'u32, 2'u32, 0'u32) |
| 81 | 73 |
| 82 type | 74 type |
| 83 Device = object | 75 Device = object |
| 76 device: VkDevice | |
| 84 physicalDevice: PhysicalDevice | 77 physicalDevice: PhysicalDevice |
| 85 graphicsQueueFamily: uint32 | 78 graphicsQueueFamily: uint32 |
| 86 presentationQueueFamily: uint32 | 79 presentationQueueFamily: uint32 |
| 87 device: VkDevice | |
| 88 graphicsQueue: VkQueue | 80 graphicsQueue: VkQueue |
| 89 presentationQueue: VkQueue | 81 presentationQueue: VkQueue |
| 90 Swapchain = object | 82 Swapchain = object |
| 91 swapchain: VkSwapchainKHR | 83 swapchain: VkSwapchainKHR |
| 92 images: seq[VkImage] | 84 images: seq[VkImage] |
| 121 commandPool*: VkCommandPool | 113 commandPool*: VkCommandPool |
| 122 commandBuffers*: array[MAX_FRAMES_IN_FLIGHT, VkCommandBuffer] | 114 commandBuffers*: array[MAX_FRAMES_IN_FLIGHT, VkCommandBuffer] |
| 123 imageAvailableSemaphores*: array[MAX_FRAMES_IN_FLIGHT, VkSemaphore] | 115 imageAvailableSemaphores*: array[MAX_FRAMES_IN_FLIGHT, VkSemaphore] |
| 124 renderFinishedSemaphores*: array[MAX_FRAMES_IN_FLIGHT, VkSemaphore] | 116 renderFinishedSemaphores*: array[MAX_FRAMES_IN_FLIGHT, VkSemaphore] |
| 125 inFlightFences*: array[MAX_FRAMES_IN_FLIGHT, VkFence] | 117 inFlightFences*: array[MAX_FRAMES_IN_FLIGHT, VkFence] |
| 118 bufferA*: Buffer | |
| 119 bufferB*: Buffer | |
| 126 Engine* = object | 120 Engine* = object |
| 127 vulkan*: Vulkan | 121 vulkan*: Vulkan |
| 128 window: NativeWindow | 122 window: NativeWindow |
| 129 | 123 |
| 130 proc getAllPhysicalDevices(instance: VkInstance, surface: VkSurfaceKHR): seq[PhysicalDevice] = | 124 proc getAllPhysicalDevices(instance: VkInstance, surface: VkSurfaceKHR): seq[PhysicalDevice] = |
| 540 ( | 534 ( |
| 541 result.vulkan.imageAvailableSemaphores, | 535 result.vulkan.imageAvailableSemaphores, |
| 542 result.vulkan.renderFinishedSemaphores, | 536 result.vulkan.renderFinishedSemaphores, |
| 543 result.vulkan.inFlightFences, | 537 result.vulkan.inFlightFences, |
| 544 ) = result.vulkan.device.device.setupSyncPrimitives() | 538 ) = result.vulkan.device.device.setupSyncPrimitives() |
| 545 | 539 result.vulkan.bufferA = result.vulkan.device.device.InitBuffer(result.vulkan.device.physicalDevice.device, uint64(sizeof(vertices[0])), VertexBuffer) |
| 546 | 540 result.vulkan.bufferB = result.vulkan.device.device.InitBuffer(result.vulkan.device.physicalDevice.device, uint64(sizeof(vertices[1])), VertexBuffer) |
| 547 proc recordCommandBuffer(renderPass: VkRenderPass, pipeline: VkPipeline, commandBuffer: VkCommandBuffer, framebuffer: VkFramebuffer, frameDimension: VkExtent2D) = | 541 var d: pointer |
| 542 result.vulkan.bufferA.withMapping(d): | |
| 543 copyMem(d, addr(vertices[0]), sizeof(vertices[0])) | |
| 544 result.vulkan.bufferB.withMapping(d): | |
| 545 copyMem(d, addr(vertices[1]), sizeof(vertices[1])) | |
| 546 | |
| 547 | |
| 548 proc recordCommandBuffer(renderPass: VkRenderPass, pipeline: VkPipeline, commandBuffer: VkCommandBuffer, framebuffer: VkFramebuffer, frameDimension: VkExtent2D, engine: var Engine) = | |
| 548 var | 549 var |
| 549 beginInfo = VkCommandBufferBeginInfo( | 550 beginInfo = VkCommandBufferBeginInfo( |
| 550 sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, | 551 sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, |
| 551 pInheritanceInfo: nil, | 552 pInheritanceInfo: nil, |
| 552 ) | 553 ) |
| 574 offset: VkOffset2D(x: 0, y: 0), | 575 offset: VkOffset2D(x: 0, y: 0), |
| 575 extent: frameDimension | 576 extent: frameDimension |
| 576 ) | 577 ) |
| 577 checkVkResult commandBuffer.vkBeginCommandBuffer(addr(beginInfo)) | 578 checkVkResult commandBuffer.vkBeginCommandBuffer(addr(beginInfo)) |
| 578 commandBuffer.vkCmdBeginRenderPass(addr(renderPassInfo), VK_SUBPASS_CONTENTS_INLINE) | 579 commandBuffer.vkCmdBeginRenderPass(addr(renderPassInfo), VK_SUBPASS_CONTENTS_INLINE) |
| 579 commandBuffer.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline) | |
| 580 commandBuffer.vkCmdSetViewport(firstViewport=0, viewportCount=1, addr(viewport)) | 580 commandBuffer.vkCmdSetViewport(firstViewport=0, viewportCount=1, addr(viewport)) |
| 581 commandBuffer.vkCmdSetScissor(firstScissor=0, scissorCount=1, addr(scissor)) | 581 commandBuffer.vkCmdSetScissor(firstScissor=0, scissorCount=1, addr(scissor)) |
| 582 commandBuffer.vkCmdDraw(vertexCount=3, instanceCount=1, firstVertex=0, firstInstance=0) | 582 commandBuffer.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline) |
| 583 | |
| 584 var | |
| 585 vertexBuffers = [engine.vulkan.bufferA.vkBuffer, engine.vulkan.bufferB.vkBuffer] | |
| 586 offsets = [VkDeviceSize(0), VkDeviceSize(0)] | |
| 587 commandBuffer.vkCmdBindVertexBuffers(firstBinding=0'u32, bindingCount=2'u32, pBuffers=addr(vertexBuffers[0]), pOffsets=addr(offsets[0])) | |
| 588 commandBuffer.vkCmdDraw(vertexCount=uint32(vertices[0].len), instanceCount=1'u32, firstVertex=0'u32, firstInstance=0'u32) | |
| 583 commandBuffer.vkCmdEndRenderPass() | 589 commandBuffer.vkCmdEndRenderPass() |
| 584 checkVkResult commandBuffer.vkEndCommandBuffer() | 590 checkVkResult commandBuffer.vkEndCommandBuffer() |
| 585 | 591 |
| 586 proc drawFrame(window: NativeWindow, vulkan: var Vulkan, currentFrame: int, resized: bool) = | 592 proc drawFrame(window: NativeWindow, vulkan: var Vulkan, currentFrame: int, resized: bool, engine: var Engine) = |
| 587 checkVkResult vulkan.device.device.vkWaitForFences(1, addr(vulkan.inFlightFences[currentFrame]), VK_TRUE, high(uint64)) | 593 checkVkResult vulkan.device.device.vkWaitForFences(1, addr(vulkan.inFlightFences[currentFrame]), VK_TRUE, high(uint64)) |
| 588 var bufferImageIndex: uint32 | 594 var bufferImageIndex: uint32 |
| 589 let nextImageResult = vulkan.device.device.vkAcquireNextImageKHR( | 595 let nextImageResult = vulkan.device.device.vkAcquireNextImageKHR( |
| 590 vulkan.swapchain.swapchain, | 596 vulkan.swapchain.swapchain, |
| 591 high(uint64), | 597 high(uint64), |
| 599 elif not (nextImageResult in [VK_SUCCESS, VK_SUBOPTIMAL_KHR]): | 605 elif not (nextImageResult in [VK_SUCCESS, VK_SUBOPTIMAL_KHR]): |
| 600 raise newException(Exception, "Vulkan error: vkAcquireNextImageKHR returned " & $nextImageResult) | 606 raise newException(Exception, "Vulkan error: vkAcquireNextImageKHR returned " & $nextImageResult) |
| 601 checkVkResult vulkan.device.device.vkResetFences(1, addr(vulkan.inFlightFences[currentFrame])) | 607 checkVkResult vulkan.device.device.vkResetFences(1, addr(vulkan.inFlightFences[currentFrame])) |
| 602 | 608 |
| 603 checkVkResult vulkan.commandBuffers[currentFrame].vkResetCommandBuffer(VkCommandBufferResetFlags(0)) | 609 checkVkResult vulkan.commandBuffers[currentFrame].vkResetCommandBuffer(VkCommandBufferResetFlags(0)) |
| 604 vulkan.renderPass.recordCommandBuffer(vulkan.pipeline.pipeline, vulkan.commandBuffers[currentFrame], vulkan.framebuffers[bufferImageIndex], vulkan.frameDimension) | 610 vulkan.renderPass.recordCommandBuffer(vulkan.pipeline.pipeline, vulkan.commandBuffers[currentFrame], vulkan.framebuffers[bufferImageIndex], vulkan.frameDimension, engine) |
| 605 var | 611 var |
| 606 waitSemaphores = [vulkan.imageAvailableSemaphores[currentFrame]] | 612 waitSemaphores = [vulkan.imageAvailableSemaphores[currentFrame]] |
| 607 waitStages = [VkPipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)] | 613 waitStages = [VkPipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)] |
| 608 signalSemaphores = [vulkan.renderFinishedSemaphores[currentFrame]] | 614 signalSemaphores = [vulkan.renderFinishedSemaphores[currentFrame]] |
| 609 submitInfo = VkSubmitInfo( | 615 submitInfo = VkSubmitInfo( |
| 651 echo event | 657 echo event |
| 652 if event.key == Escape: | 658 if event.key == Escape: |
| 653 killed = true | 659 killed = true |
| 654 else: | 660 else: |
| 655 discard | 661 discard |
| 656 engine.window.drawFrame(engine.vulkan, currentFrame, resized) | 662 engine.window.drawFrame(engine.vulkan, currentFrame, resized, engine) |
| 657 resized = false | 663 resized = false |
| 658 currentFrame = (currentFrame + 1) mod MAX_FRAMES_IN_FLIGHT; | 664 currentFrame = (currentFrame + 1) mod MAX_FRAMES_IN_FLIGHT; |
| 659 checkVkResult engine.vulkan.device.device.vkDeviceWaitIdle() | 665 checkVkResult engine.vulkan.device.device.vkDeviceWaitIdle() |
| 660 | 666 |
| 661 proc trash*(engine: Engine) = | 667 proc trash*(engine: var Engine) = |
| 668 `=destroy` engine.vulkan.bufferA | |
| 669 `=destroy` engine.vulkan.bufferB | |
| 662 engine.vulkan.device.device.trash(engine.vulkan.swapchain, engine.vulkan.framebuffers) | 670 engine.vulkan.device.device.trash(engine.vulkan.swapchain, engine.vulkan.framebuffers) |
| 663 checkVkResult engine.vulkan.device.device.vkDeviceWaitIdle() | 671 checkVkResult engine.vulkan.device.device.vkDeviceWaitIdle() |
| 664 | 672 |
| 665 for i in 0 ..< MAX_FRAMES_IN_FLIGHT: | 673 for i in 0 ..< MAX_FRAMES_IN_FLIGHT: |
| 666 engine.vulkan.device.device.vkDestroySemaphore(engine.vulkan.imageAvailableSemaphores[i], nil) | 674 engine.vulkan.device.device.vkDestroySemaphore(engine.vulkan.imageAvailableSemaphores[i], nil) |
