Mercurial > games > semicongine
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 |