# HG changeset patch # User Sam # Date 1678121421 -25200 # Node ID baaa620887b46048e3744d5b4a475d5ca07c70d2 # Parent affa6571a2c986a73cd40aaa22ac0b124655ba0e add: more vulkan objects diff -r affa6571a2c9 -r baaa620887b4 src/semicongine/engine.nim --- a/src/semicongine/engine.nim Thu Mar 02 23:16:45 2023 +0700 +++ b/src/semicongine/engine.nim Mon Mar 06 23:50:21 2023 +0700 @@ -278,11 +278,9 @@ dependency = VkSubpassDependency( srcSubpass: VK_SUBPASS_EXTERNAL, dstSubpass: 0, - srcStageMask: VkPipelineStageFlags( - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT), + srcStageMask: VkPipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT), srcAccessMask: VkAccessFlags(0), - dstStageMask: VkPipelineStageFlags( - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT), + dstStageMask: VkPipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT), dstAccessMask: VkAccessFlags(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT), ) renderPassCreateInfo = VkRenderPassCreateInfo( diff -r affa6571a2c9 -r baaa620887b4 src/semicongine/math.nim --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/semicongine/math.nim Mon Mar 06 23:50:21 2023 +0700 @@ -0,0 +1,8 @@ +import std/math +export math + +import ./math/vector +export vector + +import ./math/matrix +export matrix diff -r affa6571a2c9 -r baaa620887b4 src/semicongine/math/vector.nim --- a/src/semicongine/math/vector.nim Thu Mar 02 23:16:45 2023 +0700 +++ b/src/semicongine/math/vector.nim Mon Mar 06 23:50:21 2023 +0700 @@ -5,8 +5,7 @@ import std/typetraits import std/tables -export math - +import ../vulkan/api type TVec2*[T: SomeNumber] = array[2, T] @@ -271,3 +270,6 @@ makeRandomInit(TVec2) makeRandomInit(TVec3) makeRandomInit(TVec4) + +converter Vec2VkExtent*(vec: TVec2[uint32]): VkExtent2D = VkExtent2D(width: vec[0], height: vec[1]) +converter Vec3VkExtent*(vec: TVec2[uint32]): VkExtent3D = VkExtent3D(width: vec[0], height: vec[1], depth: vec[2]) diff -r affa6571a2c9 -r baaa620887b4 src/semicongine/vulkan.nim --- a/src/semicongine/vulkan.nim Thu Mar 02 23:16:45 2023 +0700 +++ b/src/semicongine/vulkan.nim Mon Mar 06 23:50:21 2023 +0700 @@ -13,6 +13,18 @@ import ./vulkan/swapchain export swapchain +import ./vulkan/renderpass +export renderpass + +import ./vulkan/framebuffer +export framebuffer + +import ./vulkan/commandbuffer +export commandbuffer + +import ./vulkan/syncing +export syncing + import ./vulkan/buffer export buffer diff -r affa6571a2c9 -r baaa620887b4 src/semicongine/vulkan/commandbuffer.nim --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/semicongine/vulkan/commandbuffer.nim Mon Mar 06 23:50:21 2023 +0700 @@ -0,0 +1,37 @@ +import ./api +import ./device +import ./physicaldevice +import ./utils + +type + CommandPool = object + vk*: VkCommandPool + family*: QueueFamily + buffers: seq[VkCommandBuffer] + device: Device + +proc createCommandPool*(device: Device, family: QueueFamily, nBuffers: int): CommandPool = + assert device.vk.valid + var createInfo = VkCommandPoolCreateInfo( + sType: VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + flags: toBits [VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT], + queueFamilyIndex: family.index, + ) + result.family = family + result.device = device + checkVkResult device.vk.vkCreateCommandPool(addr(createInfo), nil, addr(result.vk)) + + var allocInfo = VkCommandBufferAllocateInfo( + sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + commandPool: result.vk, + level: VK_COMMAND_BUFFER_LEVEL_PRIMARY, + commandBufferCount: uint32(nBuffers), + ) + result.buffers = newSeq[VkCommandBuffer](nBuffers) + checkVkResult device.vk.vkAllocateCommandBuffers(addr(allocInfo), result.buffers.toCPointer) + +proc destroy*(commandpool: var CommandPool) = + assert commandpool.device.vk.valid + assert commandpool.vk.valid + commandpool.device.vk.vkDestroyCommandPool(commandpool.vk, nil) + commandpool.vk.reset diff -r affa6571a2c9 -r baaa620887b4 src/semicongine/vulkan/device.nim --- a/src/semicongine/vulkan/device.nim Thu Mar 02 23:16:45 2023 +0700 +++ b/src/semicongine/vulkan/device.nim Mon Mar 06 23:50:21 2023 +0700 @@ -14,6 +14,7 @@ queues*: Table[QueueFamily, Queue] Queue* = object vk*: VkQueue + family*: QueueFamily presentation: bool graphics: bool @@ -68,7 +69,7 @@ for family in deviceQueues.keys: var queue: VkQueue vkGetDeviceQueue(result.vk, family.index, 0, addr queue) - result.queues[family] = Queue(vk: queue, presentation: family.hasPresentation(physicalDevice.surface), graphics: family.hasGraphics()) + result.queues[family] = Queue(vk: queue, family: family, presentation: family.hasPresentation(physicalDevice.surface), graphics: family.hasGraphics()) func firstGraphicsQueue*(device: Device): Option[Queue] = assert device.vk.valid diff -r affa6571a2c9 -r baaa620887b4 src/semicongine/vulkan/framebuffer.nim --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/semicongine/vulkan/framebuffer.nim Mon Mar 06 23:50:21 2023 +0700 @@ -0,0 +1,36 @@ +import ./api +import ./device +import ./renderpass +import ./utils +import ./image +import ../math + +type + Framebuffer* = object + vk*: VkFramebuffer + device*: Device + +proc createFramebuffer*(device: Device, renderpass: RenderPass, attachments: openArray[ImageView], dimension: TVec2[uint32]): Framebuffer = + assert device.vk.valid + assert renderpass.vk.valid + var theattachments: seq[VkImageView] + for a in attachments: + assert a.vk.valid + theattachments.add a.vk + var framebufferInfo = VkFramebufferCreateInfo( + sType: VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + renderPass: renderPass.vk, + attachmentCount: uint32(theattachments.len), + pAttachments: theattachments.toCPointer, + width: dimension[0], + height: dimension[1], + layers: 1, + ) + result.device = device + checkVkResult device.vk.vkCreateFramebuffer(addr(framebufferInfo), nil, addr(result.vk)) + +proc destroy*(framebuffer: var Framebuffer) = + assert framebuffer.device.vk.valid + assert framebuffer.vk.valid + framebuffer.device.vk.vkDestroyFramebuffer(framebuffer.vk, nil) + framebuffer.vk.reset diff -r affa6571a2c9 -r baaa620887b4 src/semicongine/vulkan/renderpass.nim --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/semicongine/vulkan/renderpass.nim Mon Mar 06 23:50:21 2023 +0700 @@ -0,0 +1,113 @@ +import std/options + +import ./api +import ./utils +import ./device + +type + Subpass* = object + flags: VkSubpassDescriptionFlags + pipelineBindPoint: VkPipelineBindPoint + inputs: seq[VkAttachmentReference] + outputs: seq[VkAttachmentReference] + resolvers: seq[VkAttachmentReference] + depthStencil: Option[VkAttachmentReference] + preserves: seq[uint32] + RenderPass* = object + vk*: VkRenderPass + device: Device + +proc createRenderPass*( + device: Device, + attachments: var seq[VkAttachmentDescription], + subpasses: var seq[Subpass], + dependencies: var seq[VkSubpassDependency] +): RenderPass = + assert device.vk.valid + + var subpassesList = newSeq[VkSubpassDescription](subpasses.len) + for subpass in subpasses.mitems: + subpassesList.add VkSubpassDescription( + flags: subpass.flags, + pipelineBindPoint: subpass.pipelineBindPoint, + inputAttachmentCount: uint32(subpass.inputs.len), + pInputAttachments: subpass.inputs.toCPointer, + colorAttachmentCount: uint32(subpass.outputs.len), + pColorAttachments: subpass.outputs.toCPointer, + pResolveAttachments: subpass.resolvers.toCPointer, + pDepthStencilAttachment: if subpass.depthStencil.isSome: addr(subpass.depthStencil.get) else: nil, + preserveAttachmentCount: uint32(subpass.preserves.len), + pPreserveAttachments: subpass.preserves.toCPointer, + ) + + var createInfo = VkRenderPassCreateInfo( + sType: VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + attachmentCount: uint32(attachments.len), + pAttachments: attachments.toCPointer, + subpassCount: uint32(subpassesList.len), + pSubpasses: subpassesList.toCPointer, + dependencyCount: uint32(dependencies.len), + pDependencies: dependencies.toCPointer, + ) + result.device = device + checkVkResult device.vk.vkCreateRenderPass(addr(createInfo), nil, addr(result.vk)) + +proc createRenderAttachment( + format: VkFormat, + flags = VkAttachmentDescriptionFlags(0), + samples = VK_SAMPLE_COUNT_1_BIT, + loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + storeOp = VK_ATTACHMENT_STORE_OP_STORE, + stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + finalLayout = VK_IMAGE_LAYOUT_GENERAL, +): auto = + VkAttachmentDescription( + format: format, + flags: flags, + samples: samples, + loadOp: loadOp, + storeOp: storeOp, + stencilLoadOp: stencilLoadOp, + stencilStoreOp: stencilStoreOp, + initialLayout: initialLayout, + finalLayout: finalLayout, + ) + +proc simpleForwardRenderPass*(device: Device, format: VkFormat): RenderPass = + assert device.vk.valid + var + attachments = @[createRenderAttachment( + format = format, + samples = VK_SAMPLE_COUNT_1_BIT, + loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + storeOp = VK_ATTACHMENT_STORE_OP_STORE, + stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + )] + subpasses = @[ + Subpass( + pipelineBindPoint: VK_PIPELINE_BIND_POINT_GRAPHICS, + outputs: @[VkAttachmentReference(attachment: 0, layout: VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)] + ) + ] + dependencies = @[ + VkSubpassDependency( + srcSubpass: VK_SUBPASS_EXTERNAL, + dstSubpass: 0, + srcStageMask: toBits [VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT], + srcAccessMask: VkAccessFlags(0), + dstStageMask: toBits [VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT], + dstAccessMask: toBits [VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT], + ) + ] + device.createRenderPass(attachments = attachments, subpasses = subpasses, dependencies = dependencies) + +proc destroy*(renderpass: var RenderPass) = + assert renderpass.device.vk.valid + assert renderpass.vk.valid + renderpass.device.vk.vkDestroyRenderPass(renderpass.vk, nil) + renderpass.vk.reset diff -r affa6571a2c9 -r baaa620887b4 src/semicongine/vulkan/swapchain.nim --- a/src/semicongine/vulkan/swapchain.nim Thu Mar 02 23:16:45 2023 +0700 +++ b/src/semicongine/vulkan/swapchain.nim Mon Mar 06 23:50:21 2023 +0700 @@ -3,17 +3,23 @@ import ./device import ./physicaldevice import ./image +import ../math type Swapchain = object vk*: VkSwapchainKHR device*: Device - images*: seq[Image] imageviews*: seq[ImageView] - format: VkFormat + format*: VkFormat + dimension*: TVec2[uint32] -proc createSwapchain*(device: Device, surfaceFormat: VkSurfaceFormatKHR, nBuffers=3'u32, presentationMode: VkPresentModeKHR=VK_PRESENT_MODE_MAILBOX_KHR): (Swapchain, VkResult) = +proc createSwapchain*( + device: Device, + surfaceFormat: VkSurfaceFormatKHR, + nBuffers=3'u32, + presentationMode: VkPresentModeKHR=VK_PRESENT_MODE_MAILBOX_KHR +): (Swapchain, VkResult) = assert device.vk.valid assert device.physicalDevice.vk.valid var capabilities = device.physicalDevice.getSurfaceCapabilities() @@ -44,7 +50,10 @@ clipped: true, ) var - swapchain = Swapchain(device: device, format: surfaceFormat.format) + swapchain = Swapchain( + device: device, + format: surfaceFormat.format, + dimension: TVec2[uint32]([capabilities.currentExtent.width, capabilities.currentExtent.height])) createResult = device.vk.vkCreateSwapchainKHR(addr(createInfo), nil, addr(swapchain.vk)) if createResult == VK_SUCCESS: @@ -54,7 +63,6 @@ checkVkResult device.vk.vkGetSwapchainImagesKHR(swapChain.vk, addr(nImages), images.toCPointer) for vkimage in images: let image = Image(vk: vkimage, format: surfaceFormat.format, device: device) - swapChain.images.add image swapChain.imageviews.add image.createImageView() return (swapchain, createResult) diff -r affa6571a2c9 -r baaa620887b4 src/semicongine/vulkan/syncing.nim --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/semicongine/vulkan/syncing.nim Mon Mar 06 23:50:21 2023 +0700 @@ -0,0 +1,37 @@ +import ./api +import ./device + +type + Semaphore = object + vk*: VkSemaphore + device: Device + Fence = object + vk*: VkFence + device: Device + +proc createSemaphore(device: Device): Semaphore = + assert device.vk.valid + var semaphoreInfo = VkSemaphoreCreateInfo(sType: VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO) + result.device = device + checkVkResult device.vk.vkCreateSemaphore(addr(semaphoreInfo), nil, addr(result.vk)) + +proc createFence(device: Device): Fence = + assert device.vk.valid + var fenceInfo = VkFenceCreateInfo( + sType: VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + flags: toBits [VK_FENCE_CREATE_SIGNALED_BIT] + ) + result.device = device + checkVkResult device.vk.vkCreateFence(addr(fenceInfo), nil, addr(result.vk)) + +proc destroy(semaphore: var Semaphore) = + assert semaphore.device.vk.valid + assert semaphore.vk.valid + semaphore.device.vk.vkDestroySemaphore(semaphore.vk, nil) + semaphore.vk.reset + +proc destroy(fence: var Fence) = + assert fence.device.vk.valid + assert fence.vk.valid + fence.device.vk.vkDestroyFence(fence.vk, nil) + fence.vk.reset diff -r affa6571a2c9 -r baaa620887b4 tests/test_vulkan_wrapper.nim --- a/tests/test_vulkan_wrapper.nim Thu Mar 02 23:16:45 2023 +0700 +++ b/tests/test_vulkan_wrapper.nim Mon Mar 06 23:50:21 2023 +0700 @@ -2,6 +2,7 @@ import semicongine/vulkan import semicongine/platform/window +import semicongine/math when isMainModule: @@ -53,15 +54,26 @@ selectedPhysicalDevice.filterForGraphicsPresentationQueues() ) - echo "Created device ", device.physicalDevice.name + # setup render pipeline var (swapchain, res) = device.createSwapchain(device.physicalDevice.getSurfaceFormats().filterSurfaceFormat()) if res != VK_SUCCESS: raise newException(Exception, "Unable to create swapchain") + var renderpass = device.simpleForwardRenderPass(swapchain.format) + var framebuffers: seq[Framebuffer] + for imageview in swapchain.imageviews: + framebuffers.add device.createFramebuffer(renderpass, [imageview], swapchain.dimension) + + # todo: could be create inside "device", but it would be nice to have nim v2 with support for circular dependencies first + var commandPool = device.createCommandPool(family=device.firstGraphicsQueue().get().family, nBuffers=1) echo "All successfull" echo "Start cleanup" + commandPool.destroy() # cleanup + for fb in framebuffers.mitems: + fb.destroy() + renderpass.destroy() swapchain.destroy() device.destroy()