changeset 566:cc7ba46fe3c4

add: descriptors, better swapchain implementation
author Sam <sam@basx.dev>
date Fri, 24 Mar 2023 00:11:42 +0700
parents a0b01e84607d
children 05ac2455ff60
files src/semicongine/engine.nim src/semicongine/vulkan.nim src/semicongine/vulkan/buffer.nim src/semicongine/vulkan/descriptor.nim src/semicongine/vulkan/framebuffer.nim src/semicongine/vulkan/pipeline.nim src/semicongine/vulkan/shader.nim src/semicongine/vulkan/swapchain.nim src/semicongine/vulkan/syncing.nim src/semicongine/vulkan/vertex.nim tests/test_vulkan_wrapper.nim
diffstat 11 files changed, 250 insertions(+), 76 deletions(-) [+]
line wrap: on
line diff
--- a/src/semicongine/engine.nim	Mon Mar 20 23:48:46 2023 +0700
+++ b/src/semicongine/engine.nim	Fri Mar 24 00:11:42 2023 +0700
@@ -656,8 +656,7 @@
   vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
       pipeline.pipeline)
 
-  vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
-      pipeline.layout, 0, 1, addr(pipeline.descriptors[currentFrame]), 0, nil)
+  vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.layout, 0, 1, addr(pipeline.descriptors[currentFrame]), 0, nil)
 
   for (vertexBufferSet, indexed, indexBuffer, count, indexType) in pipeline.vertexBuffers:
     var
@@ -718,7 +717,9 @@
   checkVkResult vkEndCommandBuffer(commandBuffer)
 
 proc drawFrame(window: NativeWindow, vulkan: var Vulkan, currentFrame: int, resized: bool, pipeline: var RenderPipeline) =
+
   checkVkResult vkWaitForFences(vulkan.device.device, 1, addr(vulkan.inFlightFences[currentFrame]), VK_TRUE, high(uint64))
+
   var bufferImageIndex: uint32
   let nextImageResult = vkAcquireNextImageKHR(
     vulkan.device.device,
@@ -729,18 +730,19 @@
     addr(bufferImageIndex)
   )
   if nextImageResult == VK_ERROR_OUT_OF_DATE_KHR:
-    vulkan.frameSize = window.getFrameDimension(
-        vulkan.device.physicalDevice.device, vulkan.surface)
+    vulkan.frameSize = window.getFrameDimension(vulkan.device.physicalDevice.device, vulkan.surface)
     (vulkan.swapchain, vulkan.framebuffers) = vulkan.recreateSwapchain()
   elif not (nextImageResult in [VK_SUCCESS, VK_SUBOPTIMAL_KHR]):
-    raise newException(Exception, "Vulkan error: vkAcquireNextImageKHR returned " &
-        $nextImageResult)
+    raise newException(Exception, "Vulkan error: vkAcquireNextImageKHR returned " & $nextImageResult)
   checkVkResult vkResetFences(vulkan.device.device, 1, addr(vulkan.inFlightFences[currentFrame]))
 
-  checkVkResult vkResetCommandBuffer(vulkan.device.commandBuffers[currentFrame],
-      VkCommandBufferResetFlags(0))
-  vulkan.renderPass.recordCommandBuffer(pipeline, vulkan.device.commandBuffers[
-      currentFrame], vulkan.framebuffers[bufferImageIndex], vulkan.frameSize, currentFrame)
+  checkVkResult vkResetCommandBuffer(vulkan.device.commandBuffers[currentFrame], VkCommandBufferResetFlags(0))
+  vulkan.renderPass.recordCommandBuffer(
+    pipeline,
+    vulkan.device.commandBuffers[currentFrame],
+    vulkan.framebuffers[bufferImageIndex], vulkan.frameSize,
+    currentFrame
+  )
   var
     waitSemaphores = [vulkan.imageAvailableSemaphores[currentFrame]]
     waitStages = [VkPipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)]
@@ -767,11 +769,8 @@
     pResults: nil,
   )
   let presentResult = vkQueuePresentKHR(vulkan.device.presentationQueue, addr(presentInfo))
-
-  if presentResult == VK_ERROR_OUT_OF_DATE_KHR or presentResult ==
-      VK_SUBOPTIMAL_KHR or resized:
-    vulkan.frameSize = window.getFrameDimension(
-        vulkan.device.physicalDevice.device, vulkan.surface)
+  if presentResult == VK_ERROR_OUT_OF_DATE_KHR or presentResult == VK_SUBOPTIMAL_KHR or resized:
+    vulkan.frameSize = window.getFrameDimension(vulkan.device.physicalDevice.device, vulkan.surface)
     (vulkan.swapchain, vulkan.framebuffers) = vulkan.recreateSwapchain()
 
 
--- a/src/semicongine/vulkan.nim	Mon Mar 20 23:48:46 2023 +0700
+++ b/src/semicongine/vulkan.nim	Fri Mar 24 00:11:42 2023 +0700
@@ -31,6 +31,9 @@
 import ./vulkan/vertex
 export vertex
 
+import ./vulkan/descriptor
+export descriptor
+
 import ./vulkan/pipeline
 export pipeline
 
--- a/src/semicongine/vulkan/buffer.nim	Mon Mar 20 23:48:46 2023 +0700
+++ b/src/semicongine/vulkan/buffer.nim	Fri Mar 24 00:11:42 2023 +0700
@@ -2,10 +2,10 @@
 import ./device
 
 type
-  Buffer = object
-    device: Device
-    vk: VkBuffer
-    size: uint64
+  Buffer* = object
+    device*: Device
+    vk*: VkBuffer
+    size*: uint64
 
 # currently no support for extended structure and concurrent/shared use
 # (shardingMode = VK_SHARING_MODE_CONCURRENT not supported)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/semicongine/vulkan/descriptor.nim	Fri Mar 24 00:11:42 2023 +0700
@@ -0,0 +1,132 @@
+import std/enumerate
+
+import ./api
+import ./device
+import ./buffer
+import ./utils
+
+type
+  Descriptor* = object # "fields" of a DescriptorSet
+    thetype*: VkDescriptorType
+    count*: uint32
+    stages*: seq[VkShaderStageFlagBits]
+    itemsize*: uint32
+  DescriptorSetLayout* = object # "type description of a DescriptorSet
+    device: Device
+    vk*: VkDescriptorSetLayout
+    descriptors: seq[Descriptor]
+  DescriptorSet* = object # "instance" of a DescriptorSetLayout
+    vk*: VkDescriptorSet
+    layout: DescriptorSetLayout
+  DescriptorPool* = object # required for allocation of DescriptorSet
+    device: Device
+    vk*: VkDescriptorPool
+    maxSets*: uint32 # maximum number of allocatable descriptor sets
+    counts*: seq[(VkDescriptorType, uint32)] # maximum number for each descriptor type to allocate
+
+
+proc createDescriptorSetLayout*(device: Device, descriptors: seq[Descriptor]): DescriptorSetLayout =
+  assert device.vk.valid
+
+  result.device = device
+  result.descriptors = descriptors
+
+  var layoutbindings: seq[VkDescriptorSetLayoutBinding]
+  for i, descriptor in enumerate(descriptors):
+    layoutbindings.add VkDescriptorSetLayoutBinding(
+      binding: uint32(i),
+      descriptorType: descriptor.thetype,
+      descriptorCount: descriptor.count,
+      stageFlags: toBits descriptor.stages,
+      pImmutableSamplers: nil,
+    )
+  var layoutCreateInfo = VkDescriptorSetLayoutCreateInfo(
+    sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
+    bindingCount: uint32(layoutbindings.len),
+    pBindings: layoutbindings.toCPointer
+  )
+  checkVkResult vkCreateDescriptorSetLayout(device.vk, addr(layoutCreateInfo), nil, addr(result.vk))
+
+proc destroy*(descriptorSetLayout: var DescriptorSetLayout) =
+  assert descriptorSetLayout.device.vk.valid
+  assert descriptorSetLayout.vk.valid
+  descriptorSetLayout.device.vk.vkDestroyDescriptorSetLayout(descriptorSetLayout.vk, nil)
+  descriptorSetLayout.vk.reset
+
+
+proc createDescriptorSetPool*(device: Device, counts: seq[(VkDescriptorType, uint32)], maxSets = 1000'u32): DescriptorPool =
+  assert device.vk.valid
+
+  result.device = device
+  result.maxSets = maxSets
+  result.counts = counts
+
+  var poolSizes: seq[VkDescriptorPoolSize]
+  for (thetype, count) in result.counts:
+    poolSizes.add VkDescriptorPoolSize(thetype: thetype, descriptorCount: count)
+  var poolInfo = VkDescriptorPoolCreateInfo(
+    sType: VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
+    poolSizeCount: uint32(poolSizes.len),
+    pPoolSizes: poolSizes.toCPointer,
+    maxSets: result.maxSets,
+  )
+  checkVkResult vkCreateDescriptorPool(result.device.vk, addr(poolInfo), nil, addr(result.vk))
+
+proc reset*(pool: DescriptorPool) =
+  assert pool.device.vk.valid
+  assert pool.vk.valid
+  checkVkResult vkResetDescriptorPool(pool.device.vk, pool.vk, VkDescriptorPoolResetFlags(0))
+
+proc destroy*(pool: var DescriptorPool) =
+  assert pool.device.vk.valid
+  assert pool.vk.valid
+  pool.device.vk.vkDestroyDescriptorPool(pool.vk, nil)
+  pool.vk.reset
+
+proc allocateDescriptorSet*(pool: DescriptorPool, layout: DescriptorSetLayout, nframes: uint32): seq[DescriptorSet] =
+  assert pool.device.vk.valid
+  assert pool.vk.valid
+  assert layout.device.vk.valid
+  assert layout.vk.valid
+
+  var layouts: seq[VkDescriptorSetLayout]
+  var descriptorSets = newSeq[VkDescriptorSet](nframes)
+  for i in 0 ..< nframes:
+    layouts.add layout.vk
+  var allocInfo = VkDescriptorSetAllocateInfo(
+    sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
+    descriptorPool: pool.vk,
+    descriptorSetCount: uint32(layouts.len),
+    pSetLayouts: layouts.toCPointer,
+  )
+
+  checkVkResult vkAllocateDescriptorSets(pool.device.vk, addr(allocInfo), descriptorSets.toCPointer)
+  for descriptorSet in descriptorSets:
+    result.add DescriptorSet(vk: descriptorSet, layout: layout)
+
+proc setDescriptorSet*(descriptorSet: DescriptorSet, buffer: Buffer, bindingBase=0'u32) =
+  # assumes descriptors of the descriptorSet are arranged interleaved in buffer
+  assert descriptorSet.layout.device.vk.valid
+  assert descriptorSet.layout.vk.valid
+  assert descriptorSet.vk.valid
+  assert buffer.device.vk.valid
+  assert buffer.vk.valid
+
+  var descriptorSetWrites: seq[VkWriteDescriptorSet]
+
+  var offset = VkDeviceSize(0)
+  var i = bindingBase
+  for descriptor in descriptorSet.layout.descriptors:
+    let length = VkDeviceSize(descriptor.itemsize * descriptor.count)
+    var bufferInfo = VkDescriptorBufferInfo(buffer: buffer.vk, offset: offset, range: length)
+    descriptorSetWrites.add VkWriteDescriptorSet(
+        sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+        dstSet: descriptorSet.vk,
+        dstBinding: i,
+        dstArrayElement: 0,
+        descriptorType: descriptor.thetype,
+        descriptorCount: descriptor.count,
+        pBufferInfo: addr(bufferInfo),
+      )
+    offset += length
+  descriptorSet.layout.device.vk.vkUpdateDescriptorSets(uint32(descriptorSetWrites.len), descriptorSetWrites.toCPointer, 0, nil)
--- a/src/semicongine/vulkan/framebuffer.nim	Mon Mar 20 23:48:46 2023 +0700
+++ b/src/semicongine/vulkan/framebuffer.nim	Fri Mar 24 00:11:42 2023 +0700
@@ -1,14 +1,15 @@
 import ./api
 import ./device
-import ./renderpass
 import ./utils
 import ./image
+import ./renderpass
+
 import ../math
 
 type
   Framebuffer* = object
+    device*: Device
     vk*: VkFramebuffer
-    device*: Device
 
 proc createFramebuffer*(device: Device, renderPass: RenderPass, attachments: openArray[ImageView], dimension: TVec2[uint32]): Framebuffer =
   assert device.vk.valid
--- a/src/semicongine/vulkan/pipeline.nim	Mon Mar 20 23:48:46 2023 +0700
+++ b/src/semicongine/vulkan/pipeline.nim	Fri Mar 24 00:11:42 2023 +0700
@@ -1,16 +1,16 @@
 import ./api
 import ./utils
 import ./renderpass
-import ./vertex
 import ./device
 import ./shader
+import ./descriptor
 
 type
-  Pipeline = object
+  Pipeline* = object
     device: Device
     vk*: VkPipeline
     layout: VkPipelineLayout
-    descriptorLayout: VkDescriptorSetLayout
+    descriptorSetLayout*: DescriptorSetLayout
 
 
 proc createPipeline*[VertexShader: Shader, FragmentShader: Shader](renderPass: RenderPass, vertexShader: VertexShader, fragmentShader: FragmentShader): Pipeline =
@@ -18,42 +18,46 @@
   assert renderPass.device.vk.valid
   assert vertexShader.stage == VK_SHADER_STAGE_VERTEX_BIT
   assert fragmentShader.stage == VK_SHADER_STAGE_FRAGMENT_BIT
-  result.device = renderPass.device
 
-  var descriptorType: VkDescriptorType
-  var bindingNumber = 0'u32
-  var arrayLen = 1
-  var shaderStage: seq[VkShaderStageFlagBits]
-  var layoutbinding = VkDescriptorSetLayoutBinding(
-    binding: bindingNumber,
-    descriptorType: descriptorType,
-    descriptorCount: uint32(arrayLen),
-    stageFlags: toBits shaderStage,
-    pImmutableSamplers: nil,
-  )
-  var descriptorLayoutBinding: seq[VkDescriptorSetLayoutBinding] = @[layoutbinding]
-  var layoutCreateInfo = VkDescriptorSetLayoutCreateInfo(
-    sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
-    bindingCount: uint32(descriptorLayoutBinding.len),
-    pBindings: descriptorLayoutBinding.toCPointer
-  )
-  checkVkResult vkCreateDescriptorSetLayout(
-    renderPass.device.vk,
-    addr(layoutCreateInfo),
-    nil,
-    addr(result.descriptorLayout),
-  )
+  result.device = renderPass.device
+  
+  var descriptors = @[Descriptor(
+    thetype: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+    count: 1,
+    stages: @[VK_SHADER_STAGE_VERTEX_BIT],
+    itemsize: uint32(sizeof(shaderUniforms(vertexShader)))
+  )]
+  when shaderUniforms(vertexShader) is shaderUniforms(fragmentShader):
+    descriptors[0].stages.add VK_SHADER_STAGE_FRAGMENT_BIT
+  else:
+    descriptors.add Descriptor(
+      thetype: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+      count: 1,
+      stages: @[VK_SHADER_STAGE_FRAGMENT_BIT],
+      itemsize: uint32(sizeof(shaderUniforms(fragmentShader)))
+    )
+  result.descriptorSetLayout = renderPass.device.createDescriptorSetLayout(descriptors)
+
+  #[
+  Descriptor
+    thetype: VkDescriptorType
+    count: uint32
+    stages: seq[VkShaderStageFlagBits]
+    itemsize: uint32
+  ]#
+
+  # TODO: Push constants
   # var pushConstant = VkPushConstantRange(
     # stageFlags: toBits shaderStage,
     # offset: 0,
     # size: 0,
   # )
-  var descriptorSets: seq[VkDescriptorSetLayout] = @[result.descriptorLayout]
+  var descriptorSetLayouts: seq[VkDescriptorSetLayout] = @[result.descriptorSetLayout.vk]
   # var pushConstants: seq[VkPushConstantRange] = @[pushConstant]
   var pipelineLayoutInfo = VkPipelineLayoutCreateInfo(
       sType: VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
-      setLayoutCount: uint32(descriptorSets.len),
-      pSetLayouts: descriptorSets.toCPointer,
+      setLayoutCount: uint32(descriptorSetLayouts.len),
+      pSetLayouts: descriptorSetLayouts.toCPointer,
       # pushConstantRangeCount: uint32(pushConstants.len),
       # pPushConstantRanges: pushConstants.toCPointer,
     )
@@ -151,11 +155,11 @@
   assert pipeline.device.vk.valid
   assert pipeline.vk.valid
   assert pipeline.layout.valid
-  assert pipeline.descriptorLayout.valid
+  assert pipeline.descriptorSetLayout.vk.valid
 
-  pipeline.device.vk.vkDestroyDescriptorSetLayout(pipeline.descriptorLayout, nil)
+  pipeline.descriptorSetLayout.destroy()
   pipeline.device.vk.vkDestroyPipelineLayout(pipeline.layout, nil)
   pipeline.device.vk.vkDestroyPipeline(pipeline.vk, nil)
-  pipeline.descriptorLayout.reset()
+  pipeline.descriptorSetLayout.reset()
   pipeline.layout.reset()
   pipeline.vk.reset()
--- a/src/semicongine/vulkan/shader.nim	Mon Mar 20 23:48:46 2023 +0700
+++ b/src/semicongine/vulkan/shader.nim	Fri Mar 24 00:11:42 2023 +0700
@@ -1,3 +1,4 @@
+import std/typetraits
 import std/macros
 import std/os
 import std/enumerate
@@ -24,6 +25,10 @@
     vk*: VkShaderModule
     entrypoint*: string
 
+template shaderInput*[Inputs, Uniforms, Outputs](shader: Shader[Inputs, Uniforms, Outputs]): typedesc = Inputs
+template shaderOutputs*[Inputs, Uniforms, Outputs](shader: Shader[Inputs, Uniforms, Outputs]): typedesc = Outputs
+template shaderUniforms*[Inputs, Uniforms, Outputs](shader: Shader[Inputs, Uniforms, Outputs]): typedesc = Uniforms
+
 
 proc compileGLSLToSPIRV*(stage: VkShaderStageFlagBits, shaderSource: string, entrypoint: string): seq[uint32] {.compileTime.} =
 
--- a/src/semicongine/vulkan/swapchain.nim	Mon Mar 20 23:48:46 2023 +0700
+++ b/src/semicongine/vulkan/swapchain.nim	Fri Mar 24 00:11:42 2023 +0700
@@ -3,28 +3,42 @@
 import ./device
 import ./physicaldevice
 import ./image
+import ./renderpass
+import ./framebuffer
+import ./syncing
+
 import ../math
 
 type
   Swapchain = object
+    device*: Device
     vk*: VkSwapchainKHR
-    device*: Device
-    imageviews*: seq[ImageView]
     format*: VkFormat
     dimension*: TVec2[uint32]
+    nImages*: uint32
+    imageviews*: seq[ImageView]
+    framebuffers*: seq[Framebuffer]
+    nInFlight*: uint32
+    inFlightFences: seq[Fence]
+    imageAvailableSemaphores*: seq[Semaphore]
+    renderFinishedSemaphores*: seq[Semaphore]
 
 
 proc createSwapchain*(
   device: Device,
+  renderPass: RenderPass,
   surfaceFormat: VkSurfaceFormatKHR,
-  nBuffers=3'u32,
+  desiredNumberOfImages=3'u32,
+  framesInFlight=2'u32,
   presentationMode: VkPresentModeKHR=VK_PRESENT_MODE_MAILBOX_KHR
 ): (Swapchain, VkResult) =
   assert device.vk.valid
   assert device.physicalDevice.vk.valid
+  assert renderPass.vk.valid
+
   var capabilities = device.physicalDevice.getSurfaceCapabilities()
 
-  var imageCount = nBuffers
+  var imageCount = desiredNumberOfImages
   # following is according to vulkan specs
   if presentationMode in [VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR, VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR]:
     imageCount = 1
@@ -53,17 +67,26 @@
     swapchain = Swapchain(
       device: device,
       format: surfaceFormat.format,
-      dimension: TVec2[uint32]([capabilities.currentExtent.width, capabilities.currentExtent.height]))
+      nInFlight: framesInFlight,
+      dimension: TVec2[uint32]([capabilities.currentExtent.width, capabilities.currentExtent.height])
+    )
     createResult = device.vk.vkCreateSwapchainKHR(addr(createInfo), nil, addr(swapchain.vk))
 
   if createResult == VK_SUCCESS:
     var nImages: uint32
     checkVkResult device.vk.vkGetSwapchainImagesKHR(swapChain.vk, addr(nImages), nil)
+    swapchain.nImages = nImages
     var images = newSeq[VkImage](nImages)
     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.imageviews.add image.createImageView()
+      let imageview = image.createImageView()
+      swapChain.imageviews.add imageview
+      swapChain.framebuffers.add swapchain.device.createFramebuffer(renderPass, [imageview], swapchain.dimension)
+    for i in 0 ..< swapchain.nInFlight:
+      swapchain.inFlightFences.add device.createFence()
+      swapchain.imageAvailableSemaphores.add device.createSemaphore()
+      swapchain.renderFinishedSemaphores.add device.createSemaphore()
 
   return (swapchain, createResult)
 
@@ -77,6 +100,17 @@
 proc destroy*(swapchain: var Swapchain) =
   assert swapchain.vk.valid
   for imageview in swapchain.imageviews.mitems:
+    assert imageview.vk.valid
     imageview.destroy()
+  for framebuffer in swapchain.framebuffers.mitems:
+    assert framebuffer.vk.valid
+    framebuffer.destroy()
+  for i in 0 ..< swapchain.nInFlight:
+    assert swapchain.inFlightFences[i].vk.valid
+    assert swapchain.imageAvailableSemaphores[i].vk.valid
+    assert swapchain.renderFinishedSemaphores[i].vk.valid
+    swapchain.inFlightFences[i].destroy()
+    swapchain.imageAvailableSemaphores[i].destroy()
+    swapchain.renderFinishedSemaphores[i].destroy()
   swapchain.device.vk.vkDestroySwapchainKHR(swapchain.vk, nil)
   swapchain.vk.reset()
--- a/src/semicongine/vulkan/syncing.nim	Mon Mar 20 23:48:46 2023 +0700
+++ b/src/semicongine/vulkan/syncing.nim	Fri Mar 24 00:11:42 2023 +0700
@@ -2,10 +2,10 @@
 import ./device
 
 type
-  Semaphore = object
+  Semaphore* = object
     vk*: VkSemaphore
     device: Device
-  Fence = object
+  Fence* = object
     vk*: VkFence
     device: Device
 
--- a/src/semicongine/vulkan/vertex.nim	Mon Mar 20 23:48:46 2023 +0700
+++ b/src/semicongine/vulkan/vertex.nim	Fri Mar 24 00:11:42 2023 +0700
@@ -1,10 +1,3 @@
-import std/tables
-import std/macros
-
-import ../math
-import ./api
-
-
 # add pragma to fields of the VertexType that represent per instance attributes
 template PerInstance*() {.pragma.}
 
--- a/tests/test_vulkan_wrapper.nim	Mon Mar 20 23:48:46 2023 +0700
+++ b/tests/test_vulkan_wrapper.nim	Fri Mar 24 00:11:42 2023 +0700
@@ -65,13 +65,14 @@
   )
 
   # setup render pipeline
-  var (swapchain, res) = device.createSwapchain(device.physicalDevice.getSurfaceFormats().filterSurfaceFormat())
+  var surfaceFormat = device.physicalDevice.getSurfaceFormats().filterSurfaceFormat()
+  var renderpass = device.simpleForwardRenderPass(surfaceFormat.format)
+  var (swapchain, res) = device.createSwapchain(renderpass, surfaceFormat)
   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)
+  # 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
@@ -86,11 +87,15 @@
   var fragmentshader = createShader[FragmentInput, void, Pixel](device, VK_SHADER_STAGE_FRAGMENT_BIT, "main", fragmentBinary)
 
   var pipeline = renderpass.createPipeline(vertexshader, fragmentshader)
+  var descriptorPool = device.createDescriptorSetPool(@[(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1'u32)])
+  var descriptorSet = descriptorPool.allocateDescriptorSet(pipeline.descriptorSetLayout, 1)
 
   echo "All successfull"
   echo "Start cleanup"
 
   # cleanup
+  checkVkResult device.vk.vkDeviceWaitIdle()
+  descriptorPool.destroy()
   vertexshader.destroy()
   fragmentshader.destroy()
   pipeline.destroy()
@@ -98,8 +103,6 @@
   imageAvailable.destroy()
   renderFinished.destroy()
   commandPool.destroy()
-  for fb in framebuffers.mitems:
-    fb.destroy()
   renderpass.destroy()
   swapchain.destroy()
   device.destroy()