changeset 1200:5c6491f28dcd compiletime-tests

did: simplify some swapchain stuff, add many destructor calls
author sam <sam@basx.dev>
date Sun, 14 Jul 2024 19:15:43 +0700
parents ba1af13233ee
children d4a206b5e5b0
files semicongine/rendering.nim semicongine/rendering/renderer.nim semicongine/rendering/shaders.nim semicongine/rendering/swapchain.nim semicongine/rendering/vulkan_wrappers.nim test1.nim
diffstat 6 files changed, 88 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- a/semicongine/rendering.nim	Sat Jul 13 23:27:12 2024 +0700
+++ b/semicongine/rendering.nim	Sun Jul 14 19:15:43 2024 +0700
@@ -60,6 +60,8 @@
     imageAvailableSemaphore*: array[INFLIGHTFRAMES.int, VkSemaphore]
     renderFinishedSemaphore*: array[INFLIGHTFRAMES.int, VkSemaphore]
     commandBuffers: array[INFLIGHTFRAMES.int, VkCommandBuffer]
+    oldSwapchain: ref Swapchain
+    oldSwapchainCounter: int # swaps until old swapchain will be destroyed
 
 var vulkan*: VulkanGlobals
 
@@ -80,6 +82,8 @@
     vk: array[INFLIGHTFRAMES.int, VkDescriptorSet]
   Pipeline*[TShader] = object
     vk: VkPipeline
+    vertexShaderModule: VkShaderModule
+    fragmentShaderModule: VkShaderModule
     layout: VkPipelineLayout
     descriptorSetLayouts: array[DescriptorSetType, VkDescriptorSetLayout]
 
@@ -122,6 +126,8 @@
     descriptorPool: VkDescriptorPool
     memory: array[VK_MAX_MEMORY_TYPES.int, seq[MemoryBlock]]
     buffers: array[BufferType, seq[Buffer]]
+    images: seq[VkImage]
+    imageViews: seq[VkImageView]
 
 template ForDescriptorFields(shader: typed, fieldname, valuename, typename, countname, bindingNumber, body: untyped): untyped =
   var `bindingNumber` {.inject.} = 1'u32
@@ -295,4 +301,8 @@
   )
   result.graphicsQueue = svkGetDeviceQueue(result.device, result.graphicsQueueFamily, VK_QUEUE_GRAPHICS_BIT)
 
+proc DestroyVulkan*() =
+  vkDestroyDevice(vulkan.device, nil)
+  vkDestroyInstance(vulkan.instance, nil)
+
 vulkan = InitVulkan()
--- a/semicongine/rendering/renderer.nim	Sat Jul 13 23:27:12 2024 +0700
+++ b/semicongine/rendering/renderer.nim	Sun Jul 14 19:15:43 2024 +0700
@@ -321,6 +321,23 @@
   )
   checkVkResult vkCreateDescriptorPool(vulkan.device, addr(poolInfo), nil, addr(result.descriptorPool))
 
+proc DestroyRenderData*(renderData: RenderData) =
+  vkDestroyDescriptorPool(vulkan.device, renderData.descriptorPool, nil)
+
+  for buffers in renderData.buffers:
+    for buffer in buffers:
+      vkDestroyBuffer(vulkan.device, buffer.vk, nil)
+
+  for imageView in renderData.imageViews:
+    vkDestroyImageView(vulkan.device, imageView, nil)
+
+  for image in renderData.images:
+    vkDestroyImage(vulkan.device, image, nil)
+
+  for memoryBlocks in renderData.memory:
+    for memory in memoryBlocks:
+      vkFreeMemory(vulkan.device, memory.vk, nil)
+
 proc TransitionImageLayout(image: VkImage, oldLayout, newLayout: VkImageLayout) =
   var
     barrier = VkImageMemoryBarrier(
@@ -401,6 +418,7 @@
   let format = GetVkFormat(texture.depth, usage = usage)
 
   texture.vk = svkCreate2DImage(texture.width, texture.height, format, usage)
+  renderData.images.add texture.vk
   texture.sampler = createSampler()
 
   let memoryRequirements = texture.vk.svkGetImageMemoryRequirements()
@@ -435,6 +453,7 @@
 
   # imageview can only be created after memory is bound
   texture.imageview = svkCreate2DImageView(texture.vk, format)
+  renderData.imageViews.add texture.imageview
 
   # data transfer and layout transition
   TransitionImageLayout(texture.vk, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
@@ -471,20 +490,6 @@
         let `fieldvalue` {.inject.} = value
         body
 
-#[
-proc Bind[T](pipeline: Pipeline[T], commandBuffer: VkCommandBuffer, currentFrameInFlight: int) =
-  commandBuffer.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.vk)
-  commandBuffer.vkCmdBindDescriptorSets(
-    VK_PIPELINE_BIND_POINT_GRAPHICS,
-    pipeline.layout,
-    0,
-    1,
-    addr pipeline.descriptorSets[currentFrameInFlight],
-    0,
-    nil,
-  )
-  ]#
-
 proc AssertCompatible(TShader, TMesh, TInstance, TGlobals, TMaterial: typedesc) =
   var descriptorSetCount = 0
 
--- a/semicongine/rendering/shaders.nim	Sat Jul 13 23:27:12 2024 +0700
+++ b/semicongine/rendering/shaders.nim	Sun Jul 14 19:15:43 2024 +0700
@@ -1,8 +1,3 @@
-type
-  ShaderObject[TShader] = object
-    vertexShaderModule: VkShaderModule
-    fragmentShaderModule: VkShaderModule
-
 func GlslType[T: SupportedGPUType|Texture](value: T): string =
   when T is float32: "float"
   elif T is float64: "double"
@@ -263,7 +258,7 @@
     i += 4
 
 
-proc CompileShader[TShader](shader: static TShader): ShaderObject[TShader] =
+proc CompileShader[TShader](shader: static TShader): (VkShaderModule, VkShaderModule) =
   const (vertexShaderSource, fragmentShaderSource) = generateShaderSource(shader)
 
   let vertexBinary = compileGlslToSPIRV(VK_SHADER_STAGE_VERTEX_BIT, vertexShaderSource)
@@ -274,13 +269,13 @@
     codeSize: csize_t(vertexBinary.len * sizeof(uint32)),
     pCode: vertexBinary.ToCPointer,
   )
-  checkVkResult vulkan.device.vkCreateShaderModule(addr(createInfoVertex), nil, addr(result.vertexShaderModule))
+  checkVkResult vulkan.device.vkCreateShaderModule(addr(createInfoVertex), nil, addr(result[0]))
   var createInfoFragment = VkShaderModuleCreateInfo(
     sType: VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
     codeSize: csize_t(fragmentBinary.len * sizeof(uint32)),
     pCode: fragmentBinary.ToCPointer,
   )
-  checkVkResult vulkan.device.vkCreateShaderModule(addr(createInfoFragment), nil, addr(result.fragmentShaderModule))
+  checkVkResult vulkan.device.vkCreateShaderModule(addr(createInfoFragment), nil, addr(result[1]))
 
 template ForVertexDataFields(shader: typed, fieldname, valuename, isinstancename, body: untyped): untyped =
   for theFieldname, value in fieldPairs(shader):
@@ -306,7 +301,7 @@
   # create pipeline
 
   const shader = default(TShader)
-  let shaderObject = CompileShader(shader)
+  (result.vertexShaderModule, result.fragmentShaderModule) = CompileShader(shader)
 
   for theFieldname, value in fieldPairs(default(TShader)):
     when typeof(value) is DescriptorSet:
@@ -343,13 +338,13 @@
     VkPipelineShaderStageCreateInfo(
       sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
       stage: VK_SHADER_STAGE_VERTEX_BIT,
-      module: shaderObject.vertexShaderModule,
+      module: result.vertexShaderModule,
       pName: "main",
     ),
     VkPipelineShaderStageCreateInfo(
       sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
       stage: VK_SHADER_STAGE_FRAGMENT_BIT,
-      module: shaderObject.fragmentShaderModule,
+      module: result.fragmentShaderModule,
       pName: "main",
     ),
   ]
@@ -465,3 +460,6 @@
     addr(result.vk)
   )
 
+proc DestroyPipeline*(pipeline: Pipeline) =
+  vkDestroyShaderModule(vulkan.device, pipeline.vertexShaderModule, nil)
+  vkDestroyShaderModule(vulkan.device, pipeline.fragmentShaderModule, nil)
--- a/semicongine/rendering/swapchain.nim	Sat Jul 13 23:27:12 2024 +0700
+++ b/semicongine/rendering/swapchain.nim	Sun Jul 14 19:15:43 2024 +0700
@@ -4,7 +4,7 @@
   renderPass: VkRenderPass,
   vSync: bool = false,
   samples = VK_SAMPLE_COUNT_1_BIT,
-  oldSwapchain = VkSwapchainKHR(0),
+  oldSwapchain: ref Swapchain = nil,
 ): Option[Swapchain] =
   assert vulkan.instance.Valid
 
@@ -40,7 +40,7 @@
     compositeAlpha: VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,  # only used for blending with other windows, can be opaque
     presentMode: if (vSync or not hasTripleBuffering): VK_PRESENT_MODE_FIFO_KHR else: VK_PRESENT_MODE_MAILBOX_KHR,
     clipped: true,
-    oldSwapchain: oldSwapchain,
+    oldSwapchain: if oldSwapchain != nil: oldSwapchain.vk else: VkSwapchainKHR(0),
   )
   var swapchain: Swapchain
   if vkCreateSwapchainKHR(vulkan.device, addr(swapchainCreateInfo), nil, addr(swapchain.vk)) != VK_SUCCESS:
@@ -51,6 +51,9 @@
   swapchain.renderPass = renderPass
   swapchain.vSync = vSync
   swapchain.samples = samples
+  swapchain.oldSwapchain = oldSwapchain
+  if swapchain.oldSwapchain != nil:
+    swapchain.oldSwapchainCounter = INFLIGHTFRAMES.int * 2
 
   # create msaa image+view if desired
   if samples != VK_SAMPLE_COUNT_1_BIT:
@@ -109,8 +112,24 @@
 
   return some(swapchain)
 
+proc DestroySwapchain*(swapchain: Swapchain) =
+
+  for fence in swapchain.queueFinishedFence:
+    vkDestroyFence(vulkan.device, fence, nil)
+
+  for semaphore in swapchain.imageAvailableSemaphore:
+    vkDestroySemaphore(vulkan.device, semaphore, nil)
+
+  for semaphore in swapchain.renderFinishedSemaphore:
+    vkDestroySemaphore(vulkan.device, semaphore, nil)
+
+  for imageView in swapchain.framebufferViews:
+    vkDestroyImageView(vulkan.device, imageView, nil)
+
+  vkDestroyCommandPool(vulkan.device, swapchain.commandBufferPool, nil)
+
 proc TryAcquireNextImage(swapchain: var Swapchain): Option[VkFramebuffer] =
-  if not swapchain.queueFinishedFence[swapchain.currentFiF].Await(1_000_000_000):
+  if not swapchain.queueFinishedFence[swapchain.currentFiF].Await(100_000_000):
     return none(VkFramebuffer)
 
   let nextImageResult = vkAcquireNextImageKHR(
@@ -158,6 +177,14 @@
     pResults: nil,
   )
   let presentResult = vkQueuePresentKHR(vulkan.graphicsQueue, addr(presentInfo))
+
+  if swapchain.oldSwapchain != nil:
+    dec swapchain.oldSwapchainCounter
+    if swapchain.oldSwapchainCounter <= 0:
+      DestroySwapchain(swapchain.oldSwapchain[])
+      swapchain.oldSwapchain = nil
+
+
   if presentResult != VK_SUCCESS:
     return false
 
@@ -165,31 +192,18 @@
   return true
 
 proc Recreate(swapchain: Swapchain): Option[Swapchain] =
-  echo "Recreating swapchain"
+  var oldSwapchain = new Swapchain
+  oldSwapchain[] = swapchain
   InitSwapchain(
     renderPass = swapchain.renderPass,
     vSync = swapchain.vSync,
     samples = swapchain.samples,
-    oldSwapchain = swapchain.vk,
+    oldSwapchain = oldSwapchain,
   )
 
 template WithNextFrame*(swapchain: var Swapchain, framebufferName, commandBufferName, body: untyped): untyped =
-
-  var nextFrameReady = true
-
   var maybeFramebuffer = TryAcquireNextImage(swapchain)
-  if not maybeFramebuffer.isSome:
-    let maybeNewSwapchain = Recreate(swapchain)
-    # unable to recreate swapchain
-    if not maybeNewSwapchain.isSome:
-      nextFrameReady = false
-    else:
-      swapchain = maybeNewSwapchain.get
-      maybeFramebuffer = TryAcquireNextImage(swapchain)
-      if not maybeFramebuffer.isSome:
-        nextFrameReady = false
-
-  if nextFrameReady:
+  if maybeFramebuffer.isSome:
     block:
       let `framebufferName` {.inject.} = maybeFramebuffer.get
       let `commandBufferName` {.inject.} = swapchain.commandBuffers[swapchain.currentFiF]
@@ -203,7 +217,9 @@
       body
 
       checkVkResult vkEndCommandBuffer(`commandBufferName`)
-      if not Swap(swapchain = swapchain, commandBuffer = `commandBufferName`):
-        let maybeNewSwapchain = Recreate(swapchain)
-        if maybeNewSwapchain.isSome:
-          swapchain = maybeNewSwapchain.get
+      discard Swap(swapchain = swapchain, commandBuffer = `commandBufferName`)
+  else:
+    let maybeNewSwapchain = Recreate(swapchain)
+    if maybeNewSwapchain.isSome:
+      swapchain = maybeNewSwapchain.get
+
--- a/semicongine/rendering/vulkan_wrappers.nim	Sat Jul 13 23:27:12 2024 +0700
+++ b/semicongine/rendering/vulkan_wrappers.nim	Sun Jul 14 19:15:43 2024 +0700
@@ -270,6 +270,7 @@
     var fence = svkCreateFence()
     checkVkResult vkQueueSubmit(vulkan.graphicsQueue, 1, addr(submitInfo), fence)
     discard fence.Await()
+    vkDestroyFence(vulkan.device, fence, nil)
     vkDestroyCommandPool(vulkan.device, commandBufferPool, nil)
 
 template WithStagingBuffer*[T: (VkBuffer, uint64)|(VkImage, uint32, uint32)](
--- a/test1.nim	Sat Jul 13 23:27:12 2024 +0700
+++ b/test1.nim	Sun Jul 14 19:15:43 2024 +0700
@@ -116,5 +116,13 @@
 while UpdateInputs():
   WithNextFrame(swapchain, framebuffer, commandbuffer):
     WithRenderPass(mainRenderpass, framebuffer, commandbuffer, swapchain.width, swapchain.height, NewVec4f(1, 0, 0, 0)):
-      # echo (getMonoTime() - t).inMicroseconds.float / 1000.0
+      vkCmdBindPipeline(commandbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline1.vk)
+      echo (getMonoTime() - t).inMicroseconds.float / 1000.0
       t = getMonoTime()
+
+DestroyPipeline(pipeline1)
+
+DestroyRenderData(renderdata)
+checkVkResult vkDeviceWaitIdle(vulkan.device)
+DestroySwapchain(swapchain)
+DestroyVulkan()