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)