Mercurial > games > semicongine
comparison semiconginev2/rendering/swapchain.nim @ 1218:56781cc0fc7c compiletime-tests
did: renamge main package
author | sam <sam@basx.dev> |
---|---|
date | Wed, 17 Jul 2024 21:01:37 +0700 |
parents | semicongine/rendering/swapchain.nim@e2901100a596 |
children | 5dcb503ef0c0 |
comparison
equal
deleted
inserted
replaced
1217:f819a874058f | 1218:56781cc0fc7c |
---|---|
1 const N_FRAMEBUFFERS = 3'u32 | |
2 | |
3 proc InitSwapchain*( | |
4 renderPass: VkRenderPass, | |
5 vSync: bool = false, | |
6 samples = VK_SAMPLE_COUNT_1_BIT, | |
7 oldSwapchain: ref Swapchain = nil, | |
8 ): Option[Swapchain] = | |
9 assert vulkan.instance.Valid, "Vulkan not initialized" | |
10 | |
11 var capabilities: VkSurfaceCapabilitiesKHR | |
12 checkVkResult vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vulkan.physicalDevice, vulkan.surface, addr(capabilities)) | |
13 let | |
14 format = DefaultSurfaceFormat() | |
15 width = capabilities.currentExtent.width | |
16 height = capabilities.currentExtent.height | |
17 | |
18 if width == 0 or height == 0: | |
19 return none(Swapchain) | |
20 | |
21 # following "count" is established according to vulkan specs | |
22 var minFramebufferCount = N_FRAMEBUFFERS | |
23 minFramebufferCount = max(minFramebufferCount, capabilities.minImageCount) | |
24 if capabilities.maxImageCount != 0: | |
25 minFramebufferCount = min(minFramebufferCount, capabilities.maxImageCount) | |
26 | |
27 # create swapchain | |
28 let hasTripleBuffering = VK_PRESENT_MODE_MAILBOX_KHR in svkGetPhysicalDeviceSurfacePresentModesKHR() | |
29 var swapchainCreateInfo = VkSwapchainCreateInfoKHR( | |
30 sType: VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, | |
31 surface: vulkan.surface, | |
32 minImageCount: minFramebufferCount, | |
33 imageFormat: format, | |
34 imageColorSpace: VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, # only one supported without special extensions | |
35 imageExtent: capabilities.currentExtent, | |
36 imageArrayLayers: 1, | |
37 imageUsage: toBits [VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT], | |
38 imageSharingMode: VK_SHARING_MODE_EXCLUSIVE, | |
39 preTransform: capabilities.currentTransform, | |
40 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, | |
42 clipped: true, | |
43 oldSwapchain: if oldSwapchain != nil: oldSwapchain.vk else: VkSwapchainKHR(0), | |
44 ) | |
45 var swapchain: Swapchain | |
46 if vkCreateSwapchainKHR(vulkan.device, addr(swapchainCreateInfo), nil, addr(swapchain.vk)) != VK_SUCCESS: | |
47 return none(Swapchain) | |
48 | |
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: | |
56 swapchain.oldSwapchainCounter = INFLIGHTFRAMES.int * 2 | |
57 | |
58 # create msaa image+view if desired | |
59 if samples != VK_SAMPLE_COUNT_1_BIT: | |
60 swapchain.msaaImage = svkCreate2DImage( | |
61 width = width, | |
62 height = height, | |
63 format = format, | |
64 usage = [VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT], | |
65 samples = samples, | |
66 ) | |
67 let requirements = svkGetImageMemoryRequirements(swapchain.msaaImage) | |
68 swapchain.msaaMemory = svkAllocateMemory( | |
69 requirements.size, | |
70 BestMemory(mappable = false, filter = requirements.memoryTypes) | |
71 ) | |
72 checkVkResult vkBindImageMemory( | |
73 vulkan.device, | |
74 swapchain.msaaImage, | |
75 swapchain.msaaMemory, | |
76 0, | |
77 ) | |
78 swapchain.msaaImageView = svkCreate2DImageView(swapchain.msaaImage, format) | |
79 | |
80 # create framebuffers | |
81 var actualNFramebuffers: uint32 | |
82 checkVkResult vkGetSwapchainImagesKHR(vulkan.device, swapchain.vk, addr(actualNFramebuffers), nil) | |
83 var framebuffers = newSeq[VkImage](actualNFramebuffers) | |
84 checkVkResult vkGetSwapchainImagesKHR(vulkan.device, swapchain.vk, addr(actualNFramebuffers), framebuffers.ToCPointer) | |
85 | |
86 for framebuffer in framebuffers: | |
87 swapchain.framebufferViews.add svkCreate2DImageView(framebuffer, format) | |
88 if samples == VK_SAMPLE_COUNT_1_BIT: | |
89 swapchain.framebuffers.add svkCreateFramebuffer(renderPass, width, height, [swapchain.framebufferViews[^1]]) | |
90 else: | |
91 swapchain.framebuffers.add svkCreateFramebuffer(renderPass, width, height, [swapchain.msaaImageView, swapchain.framebufferViews[^1]]) | |
92 | |
93 # create sync primitives | |
94 for i in 0 ..< INFLIGHTFRAMES: | |
95 swapchain.queueFinishedFence[i] = svkCreateFence(signaled = true) | |
96 swapchain.imageAvailableSemaphore[i] = svkCreateSemaphore() | |
97 swapchain.renderFinishedSemaphore[i] = svkCreateSemaphore() | |
98 | |
99 # command buffers | |
100 var commandPoolCreateInfo = VkCommandPoolCreateInfo( | |
101 sType: VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, | |
102 flags: toBits [VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT], | |
103 queueFamilyIndex: vulkan.graphicsQueueFamily, | |
104 ) | |
105 checkVkResult vkCreateCommandPool(vulkan.device, addr(commandPoolCreateInfo), nil, addr(swapchain.commandBufferPool)) | |
106 var allocInfo = VkCommandBufferAllocateInfo( | |
107 sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, | |
108 commandPool: swapchain.commandBufferPool, | |
109 level: VK_COMMAND_BUFFER_LEVEL_PRIMARY, | |
110 commandBufferCount: INFLIGHTFRAMES, | |
111 ) | |
112 checkVkResult vkAllocateCommandBuffers(vulkan.device, addr(allocInfo), swapchain.commandBuffers.ToCPointer) | |
113 | |
114 return some(swapchain) | |
115 | |
116 proc DestroySwapchain*(swapchain: Swapchain) = | |
117 | |
118 if swapchain.samples != VK_SAMPLE_COUNT_1_BIT: | |
119 vkDestroyImageView(vulkan.device, swapchain.msaaImageView, nil) | |
120 vkDestroyImage(vulkan.device, swapchain.msaaImage, nil) | |
121 vkFreeMemory(vulkan.device, swapchain.msaaMemory, nil) | |
122 | |
123 for fence in swapchain.queueFinishedFence: | |
124 vkDestroyFence(vulkan.device, fence, nil) | |
125 | |
126 for semaphore in swapchain.imageAvailableSemaphore: | |
127 vkDestroySemaphore(vulkan.device, semaphore, nil) | |
128 | |
129 for semaphore in swapchain.renderFinishedSemaphore: | |
130 vkDestroySemaphore(vulkan.device, semaphore, nil) | |
131 | |
132 for imageView in swapchain.framebufferViews: | |
133 vkDestroyImageView(vulkan.device, imageView, nil) | |
134 | |
135 for framebuffer in swapchain.framebuffers: | |
136 vkDestroyFramebuffer(vulkan.device, framebuffer, nil) | |
137 | |
138 vkDestroyCommandPool(vulkan.device, swapchain.commandBufferPool, nil) | |
139 | |
140 vkDestroySwapchainKHR(vulkan.device, swapchain.vk, nil) | |
141 | |
142 proc TryAcquireNextImage(swapchain: var Swapchain): Option[VkFramebuffer] = | |
143 if not swapchain.queueFinishedFence[swapchain.currentFiF].Await(100_000_000): | |
144 return none(VkFramebuffer) | |
145 | |
146 let nextImageResult = vkAcquireNextImageKHR( | |
147 vulkan.device, | |
148 swapchain.vk, | |
149 high(uint64), | |
150 swapchain.imageAvailableSemaphore[swapchain.currentFiF], | |
151 VkFence(0), | |
152 addr(swapchain.currentFramebufferIndex), | |
153 ) | |
154 | |
155 swapchain.queueFinishedFence[swapchain.currentFiF].svkResetFences() | |
156 | |
157 if nextImageResult != VK_SUCCESS: | |
158 return none(VkFramebuffer) | |
159 return some(swapchain.framebuffers[swapchain.currentFramebufferIndex]) | |
160 | |
161 proc Swap(swapchain: var Swapchain, commandBuffer: VkCommandBuffer): bool = | |
162 var | |
163 waitStage = VkPipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT) | |
164 submitInfo = VkSubmitInfo( | |
165 sType: VK_STRUCTURE_TYPE_SUBMIT_INFO, | |
166 waitSemaphoreCount: 1, | |
167 pWaitSemaphores: addr(swapchain.imageAvailableSemaphore[swapchain.currentFiF]), | |
168 pWaitDstStageMask: addr(waitStage), | |
169 commandBufferCount: 1, | |
170 pCommandBuffers: addr(commandBuffer), | |
171 signalSemaphoreCount: 1, | |
172 pSignalSemaphores: addr(swapchain.renderFinishedSemaphore[swapchain.currentFiF]), | |
173 ) | |
174 checkVkResult vkQueueSubmit( | |
175 queue = vulkan.graphicsQueue, | |
176 submitCount = 1, | |
177 pSubmits = addr(submitInfo), | |
178 fence = swapchain.queueFinishedFence[swapchain.currentFiF] | |
179 ) | |
180 | |
181 var presentInfo = VkPresentInfoKHR( | |
182 sType: VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, | |
183 waitSemaphoreCount: 1, | |
184 pWaitSemaphores: addr(swapchain.renderFinishedSemaphore[swapchain.currentFiF]), | |
185 swapchainCount: 1, | |
186 pSwapchains: addr(swapchain.vk), | |
187 pImageIndices: addr(swapchain.currentFramebufferIndex), | |
188 pResults: nil, | |
189 ) | |
190 let presentResult = vkQueuePresentKHR(vulkan.graphicsQueue, addr(presentInfo)) | |
191 | |
192 if swapchain.oldSwapchain != nil: | |
193 dec swapchain.oldSwapchainCounter | |
194 if swapchain.oldSwapchainCounter <= 0: | |
195 DestroySwapchain(swapchain.oldSwapchain[]) | |
196 swapchain.oldSwapchain = nil | |
197 | |
198 if presentResult != VK_SUCCESS: | |
199 return false | |
200 | |
201 swapchain.currentFiF = (uint32(swapchain.currentFiF) + 1) mod INFLIGHTFRAMES | |
202 return true | |
203 | |
204 proc Recreate(swapchain: Swapchain): Option[Swapchain] = | |
205 var oldSwapchain = new Swapchain | |
206 oldSwapchain[] = swapchain | |
207 InitSwapchain( | |
208 renderPass = swapchain.renderPass, | |
209 vSync = swapchain.vSync, | |
210 samples = swapchain.samples, | |
211 oldSwapchain = oldSwapchain, | |
212 ) | |
213 | |
214 template WithNextFrame*(swapchain: var Swapchain, framebufferName, commandBufferName, body: untyped): untyped = | |
215 var maybeFramebuffer = TryAcquireNextImage(swapchain) | |
216 if maybeFramebuffer.isSome: | |
217 block: | |
218 let `framebufferName` {.inject.} = maybeFramebuffer.get | |
219 let `commandBufferName` {.inject.} = swapchain.commandBuffers[swapchain.currentFiF] | |
220 let beginInfo = VkCommandBufferBeginInfo( | |
221 sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, | |
222 flags: VkCommandBufferUsageFlags(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT), | |
223 ) | |
224 checkVkResult vkResetCommandBuffer(`commandBufferName`, VkCommandBufferResetFlags(0)) | |
225 checkVkResult vkBeginCommandBuffer(`commandBufferName`, addr(beginInfo)) | |
226 | |
227 body | |
228 | |
229 checkVkResult vkEndCommandBuffer(`commandBufferName`) | |
230 discard Swap(swapchain = swapchain, commandBuffer = `commandBufferName`) | |
231 else: | |
232 let maybeNewSwapchain = Recreate(swapchain) | |
233 if maybeNewSwapchain.isSome: | |
234 swapchain = maybeNewSwapchain.get | |
235 |