comparison 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
comparison
equal deleted inserted replaced
1228:4e465583ea32 1229:5dcb503ef0c0
1 const N_FRAMEBUFFERS = 3'u32 1 const N_FRAMEBUFFERS = 3'u32
2 2
3 proc InitSwapchain*( 3 proc InitSwapchain*(
4 renderPass: VkRenderPass, 4 renderPass: RenderPass,
5 vSync: bool = false, 5 vSync: bool = false,
6 samples = VK_SAMPLE_COUNT_1_BIT, 6 oldSwapchain: Swapchain = nil,
7 oldSwapchain: ref Swapchain = nil,
8 ): Option[Swapchain] = 7 ): Option[Swapchain] =
9 assert vulkan.instance.Valid, "Vulkan not initialized" 8 assert vulkan.instance.Valid, "Vulkan not initialized"
10 9
11 var capabilities: VkSurfaceCapabilitiesKHR 10 var capabilities: VkSurfaceCapabilitiesKHR
12 checkVkResult vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vulkan.physicalDevice, vulkan.surface, addr(capabilities)) 11 checkVkResult vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vulkan.physicalDevice, vulkan.surface, addr(capabilities))
13 let 12 let
14 format = DefaultSurfaceFormat()
15 width = capabilities.currentExtent.width 13 width = capabilities.currentExtent.width
16 height = capabilities.currentExtent.height 14 height = capabilities.currentExtent.height
17 15
18 if width == 0 or height == 0: 16 if width == 0 or height == 0:
19 return none(Swapchain) 17 return none(Swapchain)
28 let hasTripleBuffering = VK_PRESENT_MODE_MAILBOX_KHR in svkGetPhysicalDeviceSurfacePresentModesKHR() 26 let hasTripleBuffering = VK_PRESENT_MODE_MAILBOX_KHR in svkGetPhysicalDeviceSurfacePresentModesKHR()
29 var swapchainCreateInfo = VkSwapchainCreateInfoKHR( 27 var swapchainCreateInfo = VkSwapchainCreateInfoKHR(
30 sType: VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, 28 sType: VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
31 surface: vulkan.surface, 29 surface: vulkan.surface,
32 minImageCount: minFramebufferCount, 30 minImageCount: minFramebufferCount,
33 imageFormat: format, 31 imageFormat: SURFACE_FORMAT,
34 imageColorSpace: VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, # only one supported without special extensions 32 imageColorSpace: VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, # only one supported without special extensions
35 imageExtent: capabilities.currentExtent, 33 imageExtent: capabilities.currentExtent,
36 imageArrayLayers: 1, 34 imageArrayLayers: 1,
37 imageUsage: toBits [VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT], 35 imageUsage: toBits [VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT],
38 imageSharingMode: VK_SHARING_MODE_EXCLUSIVE, 36 imageSharingMode: VK_SHARING_MODE_EXCLUSIVE,
40 compositeAlpha: VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, # only used for blending with other windows, can be opaque 38 compositeAlpha: VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, # only used for blending with other windows, can be opaque
41 presentMode: if (vSync or not hasTripleBuffering): VK_PRESENT_MODE_FIFO_KHR else: VK_PRESENT_MODE_MAILBOX_KHR, 39 presentMode: if (vSync or not hasTripleBuffering): VK_PRESENT_MODE_FIFO_KHR else: VK_PRESENT_MODE_MAILBOX_KHR,
42 clipped: true, 40 clipped: true,
43 oldSwapchain: if oldSwapchain != nil: oldSwapchain.vk else: VkSwapchainKHR(0), 41 oldSwapchain: if oldSwapchain != nil: oldSwapchain.vk else: VkSwapchainKHR(0),
44 ) 42 )
45 var swapchain: Swapchain 43 var swapchain = Swapchain(
44 width: width,
45 height: height,
46 renderPass: renderPass,
47 vSync: vSync,
48 oldSwapchain: oldSwapchain,
49 )
50
46 if vkCreateSwapchainKHR(vulkan.device, addr(swapchainCreateInfo), nil, addr(swapchain.vk)) != VK_SUCCESS: 51 if vkCreateSwapchainKHR(vulkan.device, addr(swapchainCreateInfo), nil, addr(swapchain.vk)) != VK_SUCCESS:
47 return none(Swapchain) 52 return none(Swapchain)
48 53
49 swapchain.width = width
50 swapchain.height = height
51 swapchain.renderPass = renderPass
52 swapchain.vSync = vSync
53 swapchain.samples = samples
54 swapchain.oldSwapchain = oldSwapchain
55 if swapchain.oldSwapchain != nil: 54 if swapchain.oldSwapchain != nil:
56 swapchain.oldSwapchainCounter = INFLIGHTFRAMES.int * 2 55 swapchain.oldSwapchainCounter = INFLIGHTFRAMES.int * 2
57 56
57 # create depth buffer image+view if desired
58 if renderPass.depthBuffer:
59 swapchain.depthImage = svkCreate2DImage(
60 width = width,
61 height = height,
62 format = DEPTH_FORMAT,
63 usage = [VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT],
64 samples = renderPass.samples,
65 )
66 let requirements = svkGetImageMemoryRequirements(swapchain.depthImage)
67 swapchain.depthMemory = svkAllocateMemory(
68 requirements.size,
69 BestMemory(mappable = false, filter = requirements.memoryTypes)
70 )
71 checkVkResult vkBindImageMemory(
72 vulkan.device,
73 swapchain.depthImage,
74 swapchain.depthMemory,
75 0,
76 )
77 swapchain.depthImageView = svkCreate2DImageView(
78 image = swapchain.depthImage,
79 format = DEPTH_FORMAT,
80 aspect = VK_IMAGE_ASPECT_DEPTH_BIT
81 )
82
58 # create msaa image+view if desired 83 # create msaa image+view if desired
59 if samples != VK_SAMPLE_COUNT_1_BIT: 84 if renderPass.samples != VK_SAMPLE_COUNT_1_BIT:
60 swapchain.msaaImage = svkCreate2DImage( 85 swapchain.msaaImage = svkCreate2DImage(
61 width = width, 86 width = width,
62 height = height, 87 height = height,
63 format = format, 88 format = SURFACE_FORMAT,
64 usage = [VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT], 89 usage = [VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT],
65 samples = samples, 90 samples = renderPass.samples,
66 ) 91 )
67 let requirements = svkGetImageMemoryRequirements(swapchain.msaaImage) 92 let requirements = svkGetImageMemoryRequirements(swapchain.msaaImage)
68 swapchain.msaaMemory = svkAllocateMemory( 93 swapchain.msaaMemory = svkAllocateMemory(
69 requirements.size, 94 requirements.size,
70 BestMemory(mappable = false, filter = requirements.memoryTypes) 95 BestMemory(mappable = false, filter = requirements.memoryTypes)
73 vulkan.device, 98 vulkan.device,
74 swapchain.msaaImage, 99 swapchain.msaaImage,
75 swapchain.msaaMemory, 100 swapchain.msaaMemory,
76 0, 101 0,
77 ) 102 )
78 swapchain.msaaImageView = svkCreate2DImageView(swapchain.msaaImage, format) 103 swapchain.msaaImageView = svkCreate2DImageView(image = swapchain.msaaImage, format = SURFACE_FORMAT)
79 104
80 # create framebuffers 105 # create framebuffers
81 var actualNFramebuffers: uint32 106 var actualNFramebuffers: uint32
82 checkVkResult vkGetSwapchainImagesKHR(vulkan.device, swapchain.vk, addr(actualNFramebuffers), nil) 107 checkVkResult vkGetSwapchainImagesKHR(vulkan.device, swapchain.vk, addr(actualNFramebuffers), nil)
83 var framebuffers = newSeq[VkImage](actualNFramebuffers) 108 var framebuffers = newSeq[VkImage](actualNFramebuffers)
84 checkVkResult vkGetSwapchainImagesKHR(vulkan.device, swapchain.vk, addr(actualNFramebuffers), framebuffers.ToCPointer) 109 checkVkResult vkGetSwapchainImagesKHR(vulkan.device, swapchain.vk, addr(actualNFramebuffers), framebuffers.ToCPointer)
85 110
86 for framebuffer in framebuffers: 111 for framebuffer in framebuffers:
87 swapchain.framebufferViews.add svkCreate2DImageView(framebuffer, format) 112 swapchain.framebufferViews.add svkCreate2DImageView(framebuffer, SURFACE_FORMAT)
88 if samples == VK_SAMPLE_COUNT_1_BIT: 113 var attachments: seq[VkImageView]
89 swapchain.framebuffers.add svkCreateFramebuffer(renderPass, width, height, [swapchain.framebufferViews[^1]]) 114 if renderPass.samples == VK_SAMPLE_COUNT_1_BIT:
115 if renderPass.depthBuffer:
116 attachments = @[swapchain.framebufferViews[^1], swapchain.depthImageView]
117 else:
118 attachments = @[swapchain.framebufferViews[^1]]
90 else: 119 else:
91 swapchain.framebuffers.add svkCreateFramebuffer(renderPass, width, height, [swapchain.msaaImageView, swapchain.framebufferViews[^1]]) 120 if renderPass.depthBuffer:
121 attachments = @[swapchain.msaaImageView, swapchain.depthImageView, swapchain.framebufferViews[^1]]
122 else:
123 attachments = @[swapchain.msaaImageView, swapchain.framebufferViews[^1]]
124
125 swapchain.framebuffers.add svkCreateFramebuffer(
126 renderpass = renderPass.vk,
127 width = width,
128 height = height,
129 attachments = attachments,
130 )
92 131
93 # create sync primitives 132 # create sync primitives
94 for i in 0 ..< INFLIGHTFRAMES: 133 for i in 0 ..< INFLIGHTFRAMES:
95 swapchain.queueFinishedFence[i] = svkCreateFence(signaled = true) 134 swapchain.queueFinishedFence[i] = svkCreateFence(signaled = true)
96 swapchain.imageAvailableSemaphore[i] = svkCreateSemaphore() 135 swapchain.imageAvailableSemaphore[i] = svkCreateSemaphore()
113 152
114 return some(swapchain) 153 return some(swapchain)
115 154
116 proc DestroySwapchain*(swapchain: Swapchain) = 155 proc DestroySwapchain*(swapchain: Swapchain) =
117 156
118 if swapchain.samples != VK_SAMPLE_COUNT_1_BIT: 157 if swapchain.msaaImage.Valid:
119 vkDestroyImageView(vulkan.device, swapchain.msaaImageView, nil) 158 vkDestroyImageView(vulkan.device, swapchain.msaaImageView, nil)
120 vkDestroyImage(vulkan.device, swapchain.msaaImage, nil) 159 vkDestroyImage(vulkan.device, swapchain.msaaImage, nil)
121 vkFreeMemory(vulkan.device, swapchain.msaaMemory, nil) 160 vkFreeMemory(vulkan.device, swapchain.msaaMemory, nil)
122 161
162 if swapchain.depthImage.Valid:
163 vkDestroyImageView(vulkan.device, swapchain.depthImageView, nil)
164 vkDestroyImage(vulkan.device, swapchain.depthImage, nil)
165 vkFreeMemory(vulkan.device, swapchain.depthMemory, nil)
166
123 for fence in swapchain.queueFinishedFence: 167 for fence in swapchain.queueFinishedFence:
124 vkDestroyFence(vulkan.device, fence, nil) 168 vkDestroyFence(vulkan.device, fence, nil)
125 169
126 for semaphore in swapchain.imageAvailableSemaphore: 170 for semaphore in swapchain.imageAvailableSemaphore:
127 vkDestroySemaphore(vulkan.device, semaphore, nil) 171 vkDestroySemaphore(vulkan.device, semaphore, nil)
137 181
138 vkDestroyCommandPool(vulkan.device, swapchain.commandBufferPool, nil) 182 vkDestroyCommandPool(vulkan.device, swapchain.commandBufferPool, nil)
139 183
140 vkDestroySwapchainKHR(vulkan.device, swapchain.vk, nil) 184 vkDestroySwapchainKHR(vulkan.device, swapchain.vk, nil)
141 185
142 proc TryAcquireNextImage(swapchain: var Swapchain): Option[VkFramebuffer] = 186 proc TryAcquireNextImage(swapchain: Swapchain): Option[VkFramebuffer] =
143 if not swapchain.queueFinishedFence[swapchain.currentFiF].Await(100_000_000): 187 if not swapchain.queueFinishedFence[swapchain.currentFiF].Await(100_000_000):
144 return none(VkFramebuffer) 188 return none(VkFramebuffer)
145 189
146 let nextImageResult = vkAcquireNextImageKHR( 190 let nextImageResult = vkAcquireNextImageKHR(
147 vulkan.device, 191 vulkan.device,
156 200
157 if nextImageResult != VK_SUCCESS: 201 if nextImageResult != VK_SUCCESS:
158 return none(VkFramebuffer) 202 return none(VkFramebuffer)
159 return some(swapchain.framebuffers[swapchain.currentFramebufferIndex]) 203 return some(swapchain.framebuffers[swapchain.currentFramebufferIndex])
160 204
161 proc Swap(swapchain: var Swapchain, commandBuffer: VkCommandBuffer): bool = 205 proc Swap(swapchain: Swapchain, commandBuffer: VkCommandBuffer): bool =
162 var 206 var
163 waitStage = VkPipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT) 207 waitStage = VkPipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)
164 submitInfo = VkSubmitInfo( 208 submitInfo = VkSubmitInfo(
165 sType: VK_STRUCTURE_TYPE_SUBMIT_INFO, 209 sType: VK_STRUCTURE_TYPE_SUBMIT_INFO,
166 waitSemaphoreCount: 1, 210 waitSemaphoreCount: 1,
190 let presentResult = vkQueuePresentKHR(vulkan.graphicsQueue, addr(presentInfo)) 234 let presentResult = vkQueuePresentKHR(vulkan.graphicsQueue, addr(presentInfo))
191 235
192 if swapchain.oldSwapchain != nil: 236 if swapchain.oldSwapchain != nil:
193 dec swapchain.oldSwapchainCounter 237 dec swapchain.oldSwapchainCounter
194 if swapchain.oldSwapchainCounter <= 0: 238 if swapchain.oldSwapchainCounter <= 0:
195 DestroySwapchain(swapchain.oldSwapchain[]) 239 DestroySwapchain(swapchain.oldSwapchain)
196 swapchain.oldSwapchain = nil 240 swapchain.oldSwapchain = nil
197 241
198 if presentResult != VK_SUCCESS: 242 if presentResult != VK_SUCCESS:
199 return false 243 return false
200 244
201 swapchain.currentFiF = (uint32(swapchain.currentFiF) + 1) mod INFLIGHTFRAMES 245 swapchain.currentFiF = (uint32(swapchain.currentFiF) + 1) mod INFLIGHTFRAMES
202 return true 246 return true
203 247
204 proc Recreate(swapchain: Swapchain): Option[Swapchain] = 248 proc Recreate(swapchain: Swapchain): Option[Swapchain] =
205 var oldSwapchain = new Swapchain
206 oldSwapchain[] = swapchain
207 InitSwapchain( 249 InitSwapchain(
208 renderPass = swapchain.renderPass, 250 renderPass = swapchain.renderPass,
209 vSync = swapchain.vSync, 251 vSync = swapchain.vSync,
210 samples = swapchain.samples, 252 oldSwapchain = swapchain,
211 oldSwapchain = oldSwapchain, 253 )
212 ) 254
213 255 template WithNextFrame*(theSwapchain: var Swapchain, framebufferName, commandBufferName, body: untyped): untyped =
214 template WithNextFrame*(swapchain: var Swapchain, framebufferName, commandBufferName, body: untyped): untyped = 256 var maybeFramebuffer = TryAcquireNextImage(theSwapchain)
215 var maybeFramebuffer = TryAcquireNextImage(swapchain)
216 if maybeFramebuffer.isSome: 257 if maybeFramebuffer.isSome:
217 block: 258 block:
218 let `framebufferName` {.inject.} = maybeFramebuffer.get 259 let `framebufferName` {.inject.} = maybeFramebuffer.get
219 let `commandBufferName` {.inject.} = swapchain.commandBuffers[swapchain.currentFiF] 260 let `commandBufferName` {.inject.} = theSwapchain.commandBuffers[theSwapchain.currentFiF]
220 let beginInfo = VkCommandBufferBeginInfo( 261 let beginInfo = VkCommandBufferBeginInfo(
221 sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 262 sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
222 flags: VkCommandBufferUsageFlags(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT), 263 flags: VkCommandBufferUsageFlags(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT),
223 ) 264 )
224 checkVkResult vkResetCommandBuffer(`commandBufferName`, VkCommandBufferResetFlags(0)) 265 checkVkResult vkResetCommandBuffer(`commandBufferName`, VkCommandBufferResetFlags(0))
225 checkVkResult vkBeginCommandBuffer(`commandBufferName`, addr(beginInfo)) 266 checkVkResult vkBeginCommandBuffer(`commandBufferName`, addr(beginInfo))
226 267
227 body 268 body
228 269
229 checkVkResult vkEndCommandBuffer(`commandBufferName`) 270 checkVkResult vkEndCommandBuffer(`commandBufferName`)
230 discard Swap(swapchain = swapchain, commandBuffer = `commandBufferName`) 271 discard Swap(swapchain = theSwapchain, commandBuffer = `commandBufferName`)
231 else: 272 else:
232 let maybeNewSwapchain = Recreate(swapchain) 273 let maybeNewSwapchain = Recreate(theSwapchain)
233 if maybeNewSwapchain.isSome: 274 if maybeNewSwapchain.isSome:
234 swapchain = maybeNewSwapchain.get 275 theSwapchain = maybeNewSwapchain.get
235 276