diff semiconginev2/rendering/swapchain.nim @ 1229:5dcb503ef0c0

did: refactor renderpass a bit, enable depth buffering and msaa on offscreen-rendering
author sam <sam@basx.dev>
date Thu, 18 Jul 2024 21:32:41 +0700
parents 56781cc0fc7c
children 69489a678141
line wrap: on
line diff
--- a/semiconginev2/rendering/swapchain.nim	Thu Jul 18 16:33:24 2024 +0700
+++ b/semiconginev2/rendering/swapchain.nim	Thu Jul 18 21:32:41 2024 +0700
@@ -1,17 +1,15 @@
 const N_FRAMEBUFFERS = 3'u32
 
 proc InitSwapchain*(
-  renderPass: VkRenderPass,
+  renderPass: RenderPass,
   vSync: bool = false,
-  samples = VK_SAMPLE_COUNT_1_BIT,
-  oldSwapchain: ref Swapchain = nil,
+  oldSwapchain: Swapchain = nil,
 ): Option[Swapchain] =
   assert vulkan.instance.Valid, "Vulkan not initialized"
 
   var capabilities: VkSurfaceCapabilitiesKHR
   checkVkResult vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vulkan.physicalDevice, vulkan.surface, addr(capabilities))
   let
-    format = DefaultSurfaceFormat()
     width = capabilities.currentExtent.width
     height = capabilities.currentExtent.height
 
@@ -30,7 +28,7 @@
     sType: VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
     surface: vulkan.surface,
     minImageCount: minFramebufferCount,
-    imageFormat: format,
+    imageFormat: SURFACE_FORMAT,
     imageColorSpace: VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, # only one supported without special extensions
     imageExtent: capabilities.currentExtent,
     imageArrayLayers: 1,
@@ -42,27 +40,54 @@
     clipped: true,
     oldSwapchain: if oldSwapchain != nil: oldSwapchain.vk else: VkSwapchainKHR(0),
   )
-  var swapchain: Swapchain
+  var swapchain = Swapchain(
+    width: width,
+    height: height,
+    renderPass: renderPass,
+    vSync: vSync,
+    oldSwapchain: oldSwapchain,
+  )
+
   if vkCreateSwapchainKHR(vulkan.device, addr(swapchainCreateInfo), nil, addr(swapchain.vk)) != VK_SUCCESS:
     return none(Swapchain)
 
-  swapchain.width = width
-  swapchain.height = height
-  swapchain.renderPass = renderPass
-  swapchain.vSync = vSync
-  swapchain.samples = samples
-  swapchain.oldSwapchain = oldSwapchain
   if swapchain.oldSwapchain != nil:
     swapchain.oldSwapchainCounter = INFLIGHTFRAMES.int * 2
 
+  # create depth buffer image+view if desired
+  if renderPass.depthBuffer:
+    swapchain.depthImage = svkCreate2DImage(
+      width = width,
+      height = height,
+      format = DEPTH_FORMAT,
+      usage = [VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT],
+      samples = renderPass.samples,
+    )
+    let requirements = svkGetImageMemoryRequirements(swapchain.depthImage)
+    swapchain.depthMemory = svkAllocateMemory(
+      requirements.size,
+      BestMemory(mappable = false, filter = requirements.memoryTypes)
+    )
+    checkVkResult vkBindImageMemory(
+      vulkan.device,
+      swapchain.depthImage,
+      swapchain.depthMemory,
+      0,
+    )
+    swapchain.depthImageView = svkCreate2DImageView(
+      image = swapchain.depthImage,
+      format = DEPTH_FORMAT,
+      aspect = VK_IMAGE_ASPECT_DEPTH_BIT
+    )
+
   # create msaa image+view if desired
-  if samples != VK_SAMPLE_COUNT_1_BIT:
+  if renderPass.samples != VK_SAMPLE_COUNT_1_BIT:
     swapchain.msaaImage = svkCreate2DImage(
       width = width,
       height = height,
-      format = format,
+      format = SURFACE_FORMAT,
       usage = [VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT],
-      samples = samples,
+      samples = renderPass.samples,
     )
     let requirements = svkGetImageMemoryRequirements(swapchain.msaaImage)
     swapchain.msaaMemory = svkAllocateMemory(
@@ -75,7 +100,7 @@
       swapchain.msaaMemory,
       0,
     )
-    swapchain.msaaImageView = svkCreate2DImageView(swapchain.msaaImage, format)
+    swapchain.msaaImageView = svkCreate2DImageView(image = swapchain.msaaImage, format = SURFACE_FORMAT)
 
   # create framebuffers
   var actualNFramebuffers: uint32
@@ -84,11 +109,25 @@
   checkVkResult vkGetSwapchainImagesKHR(vulkan.device, swapchain.vk, addr(actualNFramebuffers), framebuffers.ToCPointer)
 
   for framebuffer in framebuffers:
-    swapchain.framebufferViews.add svkCreate2DImageView(framebuffer, format)
-    if samples == VK_SAMPLE_COUNT_1_BIT:
-      swapchain.framebuffers.add svkCreateFramebuffer(renderPass, width, height, [swapchain.framebufferViews[^1]])
+    swapchain.framebufferViews.add svkCreate2DImageView(framebuffer, SURFACE_FORMAT)
+    var attachments: seq[VkImageView]
+    if renderPass.samples == VK_SAMPLE_COUNT_1_BIT:
+      if renderPass.depthBuffer:
+        attachments = @[swapchain.framebufferViews[^1], swapchain.depthImageView]
+      else:
+        attachments = @[swapchain.framebufferViews[^1]]
     else:
-      swapchain.framebuffers.add svkCreateFramebuffer(renderPass, width, height, [swapchain.msaaImageView, swapchain.framebufferViews[^1]])
+      if renderPass.depthBuffer:
+        attachments = @[swapchain.msaaImageView, swapchain.depthImageView, swapchain.framebufferViews[^1]]
+      else:
+        attachments = @[swapchain.msaaImageView, swapchain.framebufferViews[^1]]
+
+    swapchain.framebuffers.add svkCreateFramebuffer(
+      renderpass = renderPass.vk,
+      width = width,
+      height = height,
+      attachments = attachments,
+    )
 
   # create sync primitives
   for i in 0 ..< INFLIGHTFRAMES:
@@ -115,11 +154,16 @@
 
 proc DestroySwapchain*(swapchain: Swapchain) =
 
-  if swapchain.samples != VK_SAMPLE_COUNT_1_BIT:
+  if swapchain.msaaImage.Valid:
     vkDestroyImageView(vulkan.device, swapchain.msaaImageView, nil)
     vkDestroyImage(vulkan.device, swapchain.msaaImage, nil)
     vkFreeMemory(vulkan.device, swapchain.msaaMemory, nil)
 
+  if swapchain.depthImage.Valid:
+    vkDestroyImageView(vulkan.device, swapchain.depthImageView, nil)
+    vkDestroyImage(vulkan.device, swapchain.depthImage, nil)
+    vkFreeMemory(vulkan.device, swapchain.depthMemory, nil)
+
   for fence in swapchain.queueFinishedFence:
     vkDestroyFence(vulkan.device, fence, nil)
 
@@ -139,7 +183,7 @@
 
   vkDestroySwapchainKHR(vulkan.device, swapchain.vk, nil)
 
-proc TryAcquireNextImage(swapchain: var Swapchain): Option[VkFramebuffer] =
+proc TryAcquireNextImage(swapchain: Swapchain): Option[VkFramebuffer] =
   if not swapchain.queueFinishedFence[swapchain.currentFiF].Await(100_000_000):
     return none(VkFramebuffer)
 
@@ -158,7 +202,7 @@
     return none(VkFramebuffer)
   return some(swapchain.framebuffers[swapchain.currentFramebufferIndex])
 
-proc Swap(swapchain: var Swapchain, commandBuffer: VkCommandBuffer): bool =
+proc Swap(swapchain: Swapchain, commandBuffer: VkCommandBuffer): bool =
   var
     waitStage = VkPipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)
     submitInfo = VkSubmitInfo(
@@ -192,7 +236,7 @@
   if swapchain.oldSwapchain != nil:
     dec swapchain.oldSwapchainCounter
     if swapchain.oldSwapchainCounter <= 0:
-      DestroySwapchain(swapchain.oldSwapchain[])
+      DestroySwapchain(swapchain.oldSwapchain)
       swapchain.oldSwapchain = nil
 
   if presentResult != VK_SUCCESS:
@@ -202,21 +246,18 @@
   return true
 
 proc Recreate(swapchain: Swapchain): Option[Swapchain] =
-  var oldSwapchain = new Swapchain
-  oldSwapchain[] = swapchain
   InitSwapchain(
     renderPass = swapchain.renderPass,
     vSync = swapchain.vSync,
-    samples = swapchain.samples,
-    oldSwapchain = oldSwapchain,
+    oldSwapchain = swapchain,
   )
 
-template WithNextFrame*(swapchain: var Swapchain, framebufferName, commandBufferName, body: untyped): untyped =
-  var maybeFramebuffer = TryAcquireNextImage(swapchain)
+template WithNextFrame*(theSwapchain: var Swapchain, framebufferName, commandBufferName, body: untyped): untyped =
+  var maybeFramebuffer = TryAcquireNextImage(theSwapchain)
   if maybeFramebuffer.isSome:
     block:
       let `framebufferName` {.inject.} = maybeFramebuffer.get
-      let `commandBufferName` {.inject.} = swapchain.commandBuffers[swapchain.currentFiF]
+      let `commandBufferName` {.inject.} = theSwapchain.commandBuffers[theSwapchain.currentFiF]
       let beginInfo = VkCommandBufferBeginInfo(
         sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
         flags: VkCommandBufferUsageFlags(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT),
@@ -227,9 +268,9 @@
       body
 
       checkVkResult vkEndCommandBuffer(`commandBufferName`)
-      discard Swap(swapchain = swapchain, commandBuffer = `commandBufferName`)
+      discard Swap(swapchain = theSwapchain, commandBuffer = `commandBufferName`)
   else:
-    let maybeNewSwapchain = Recreate(swapchain)
+    let maybeNewSwapchain = Recreate(theSwapchain)
     if maybeNewSwapchain.isSome:
-      swapchain = maybeNewSwapchain.get
+      theSwapchain = maybeNewSwapchain.get