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 |
