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) |