Mercurial > games > semicongine
comparison semiconginev2/old/vulkan/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/old/vulkan/swapchain.nim@397c681f9c0c | 
| children | 
   comparison
  equal
  deleted
  inserted
  replaced
| 1217:f819a874058f | 1218:56781cc0fc7c | 
|---|---|
| 1 import std/options | |
| 2 import std/strformat | |
| 3 import std/logging | |
| 4 | |
| 5 import ../core | |
| 6 import ./device | |
| 7 import ./physicaldevice | |
| 8 import ./image | |
| 9 import ./framebuffer | |
| 10 import ./syncing | |
| 11 | |
| 12 type | |
| 13 Swapchain* = object | |
| 14 device*: Device | |
| 15 vk*: VkSwapchainKHR | |
| 16 dimension*: TVec2[uint32] | |
| 17 nFramebuffers*: uint32 | |
| 18 currentInFlight*: int | |
| 19 currentFramebufferIndex: uint32 | |
| 20 samples: VkSampleCountFlagBits | |
| 21 colorImage: VulkanImage | |
| 22 colorImageView: ImageView | |
| 23 framebufferViews*: seq[ImageView] | |
| 24 framebuffers*: seq[Framebuffer] | |
| 25 queueFinishedFence*: seq[Fence] | |
| 26 imageAvailableSemaphore*: seq[Semaphore] | |
| 27 renderFinishedSemaphore*: seq[Semaphore] | |
| 28 # required for recreation: | |
| 29 renderPass: VkRenderPass | |
| 30 surfaceFormat: VkSurfaceFormatKHR | |
| 31 inFlightFrames*: int | |
| 32 presentQueue: Queue | |
| 33 vSync: bool | |
| 34 | |
| 35 | |
| 36 proc CreateSwapchain*( | |
| 37 device: Device, | |
| 38 renderPass: VkRenderPass, | |
| 39 surfaceFormat: VkSurfaceFormatKHR, | |
| 40 inFlightFrames: int, | |
| 41 samples: VkSampleCountFlagBits, | |
| 42 desiredFramebufferCount = 3'u32, | |
| 43 oldSwapchain = VkSwapchainKHR(0), | |
| 44 vSync = false, | |
| 45 ): Option[Swapchain] = | |
| 46 assert device.vk.Valid | |
| 47 assert device.physicalDevice.vk.Valid | |
| 48 assert renderPass.Valid | |
| 49 assert inFlightFrames > 0 | |
| 50 | |
| 51 var capabilities = device.physicalDevice.GetSurfaceCapabilities() | |
| 52 if capabilities.currentExtent.width == 0 or capabilities.currentExtent.height == 0: | |
| 53 return none(Swapchain) | |
| 54 | |
| 55 var minFramebufferCount = desiredFramebufferCount | |
| 56 | |
| 57 # following is according to vulkan specs | |
| 58 minFramebufferCount = max(minFramebufferCount, capabilities.minImageCount) | |
| 59 if capabilities.maxImageCount != 0: | |
| 60 minFramebufferCount = min(minFramebufferCount, capabilities.maxImageCount) | |
| 61 let hasTripleBuffering = VK_PRESENT_MODE_MAILBOX_KHR in device.physicalDevice.GetSurfacePresentModes() | |
| 62 var createInfo = VkSwapchainCreateInfoKHR( | |
| 63 sType: VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, | |
| 64 surface: device.physicalDevice.surface, | |
| 65 minImageCount: minFramebufferCount, | |
| 66 imageFormat: surfaceFormat.format, | |
| 67 imageColorSpace: surfaceFormat.colorSpace, | |
| 68 imageExtent: capabilities.currentExtent, | |
| 69 imageArrayLayers: 1, | |
| 70 imageUsage: toBits [VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT], | |
| 71 # VK_SHARING_MODE_CONCURRENT no supported currently | |
| 72 imageSharingMode: VK_SHARING_MODE_EXCLUSIVE, | |
| 73 preTransform: capabilities.currentTransform, | |
| 74 compositeAlpha: VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, # only used for blending with other windows, can be opaque | |
| 75 presentMode: if (vSync or not hasTripleBuffering): VK_PRESENT_MODE_FIFO_KHR else: VK_PRESENT_MODE_MAILBOX_KHR, | |
| 76 clipped: true, | |
| 77 oldSwapchain: oldSwapchain, | |
| 78 ) | |
| 79 var | |
| 80 swapchain = Swapchain( | |
| 81 device: device, | |
| 82 surfaceFormat: surfaceFormat, | |
| 83 dimension: TVec2[uint32]([capabilities.currentExtent.width, capabilities.currentExtent.height]), | |
| 84 inFlightFrames: inFlightFrames, | |
| 85 renderPass: renderPass, | |
| 86 vSync: vSync, | |
| 87 samples: samples, | |
| 88 ) | |
| 89 | |
| 90 if samples != VK_SAMPLE_COUNT_1_BIT: | |
| 91 swapchain.colorImage = device.CreateImage( | |
| 92 width = capabilities.currentExtent.width, | |
| 93 height = capabilities.currentExtent.height, | |
| 94 depth = 4, | |
| 95 samples = samples, | |
| 96 format = surfaceFormat.format, | |
| 97 usage = [VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT], | |
| 98 ) | |
| 99 swapchain.colorImageView = swapchain.colorImage.CreateImageView() | |
| 100 | |
| 101 if device.vk.vkCreateSwapchainKHR(addr createInfo, nil, addr swapchain.vk) == VK_SUCCESS: | |
| 102 | |
| 103 checkVkResult device.vk.vkGetSwapchainImagesKHR(swapchain.vk, addr swapchain.nFramebuffers, nil) | |
| 104 var framebuffers = newSeq[VkImage](swapchain.nFramebuffers) | |
| 105 checkVkResult device.vk.vkGetSwapchainImagesKHR(swapchain.vk, addr swapchain.nFramebuffers, framebuffers.ToCPointer) | |
| 106 for framebuffer in framebuffers: | |
| 107 let framebufferView = VulkanImage(vk: framebuffer, format: surfaceFormat.format, device: device).CreateImageView() | |
| 108 swapchain.framebufferViews.add framebufferView | |
| 109 if samples == VK_SAMPLE_COUNT_1_BIT: | |
| 110 swapchain.framebuffers.add device.CreateFramebuffer(renderPass, [framebufferView], swapchain.dimension) | |
| 111 else: | |
| 112 swapchain.framebuffers.add device.CreateFramebuffer(renderPass, [swapchain.colorImageView, framebufferView], swapchain.dimension) | |
| 113 for i in 0 ..< swapchain.inFlightFrames: | |
| 114 swapchain.queueFinishedFence.add device.CreateFence() | |
| 115 swapchain.imageAvailableSemaphore.add device.CreateSemaphore() | |
| 116 swapchain.renderFinishedSemaphore.add device.CreateSemaphore() | |
| 117 debug &"Created swapchain with: {swapchain.nFramebuffers} framebuffers, {inFlightFrames} in-flight frames, {swapchain.dimension.x}x{swapchain.dimension.y}" | |
| 118 assert device.FirstPresentationQueue().isSome, "No present queue found" | |
| 119 swapchain.presentQueue = device.FirstPresentationQueue().get | |
| 120 | |
| 121 result = some(swapchain) | |
| 122 else: | |
| 123 result = none(Swapchain) | |
| 124 | |
| 125 proc CurrentFramebuffer*(swapchain: Swapchain): Framebuffer = | |
| 126 assert swapchain.device.vk.Valid | |
| 127 assert swapchain.vk.Valid | |
| 128 swapchain.framebuffers[swapchain.currentFramebufferIndex] | |
| 129 | |
| 130 proc AcquireNextFrame*(swapchain: var Swapchain): bool = | |
| 131 assert swapchain.device.vk.Valid | |
| 132 assert swapchain.vk.Valid | |
| 133 | |
| 134 swapchain.queueFinishedFence[swapchain.currentInFlight].Await() | |
| 135 | |
| 136 let nextImageResult = swapchain.device.vk.vkAcquireNextImageKHR( | |
| 137 swapchain.vk, | |
| 138 high(uint64), | |
| 139 swapchain.imageAvailableSemaphore[swapchain.currentInFlight].vk, | |
| 140 VkFence(0), | |
| 141 addr swapchain.currentFramebufferIndex, | |
| 142 ) | |
| 143 | |
| 144 swapchain.queueFinishedFence[swapchain.currentInFlight].Reset() | |
| 145 | |
| 146 return nextImageResult == VK_SUCCESS | |
| 147 | |
| 148 proc Swap*(swapchain: var Swapchain, queue: Queue, commandBuffer: VkCommandBuffer): bool = | |
| 149 assert swapchain.device.vk.Valid | |
| 150 assert swapchain.vk.Valid | |
| 151 assert queue.vk.Valid | |
| 152 | |
| 153 var | |
| 154 waitSemaphores = [swapchain.imageAvailableSemaphore[swapchain.currentInFlight].vk] | |
| 155 waitStages = [VkPipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)] | |
| 156 submitInfo = VkSubmitInfo( | |
| 157 sType: VK_STRUCTURE_TYPE_SUBMIT_INFO, | |
| 158 waitSemaphoreCount: 1, | |
| 159 pWaitSemaphores: waitSemaphores.ToCPointer, | |
| 160 pWaitDstStageMask: waitStages.ToCPointer, | |
| 161 commandBufferCount: 1, | |
| 162 pCommandBuffers: addr commandBuffer, | |
| 163 signalSemaphoreCount: 1, | |
| 164 pSignalSemaphores: addr swapchain.renderFinishedSemaphore[swapchain.currentInFlight].vk, | |
| 165 ) | |
| 166 checkVkResult queue.vk.vkQueueSubmit( | |
| 167 submitCount = 1, | |
| 168 pSubmits = addr submitInfo, | |
| 169 fence = swapchain.queueFinishedFence[swapchain.currentInFlight].vk | |
| 170 ) | |
| 171 | |
| 172 var presentInfo = VkPresentInfoKHR( | |
| 173 sType: VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, | |
| 174 waitSemaphoreCount: 1, | |
| 175 pWaitSemaphores: addr swapchain.renderFinishedSemaphore[swapchain.currentInFlight].vk, | |
| 176 swapchainCount: 1, | |
| 177 pSwapchains: addr swapchain.vk, | |
| 178 pImageIndices: addr swapchain.currentFramebufferIndex, | |
| 179 pResults: nil, | |
| 180 ) | |
| 181 let presentResult = vkQueuePresentKHR(swapchain.presentQueue.vk, addr presentInfo) | |
| 182 if presentResult != VK_SUCCESS: | |
| 183 return false | |
| 184 | |
| 185 return true | |
| 186 | |
| 187 | |
| 188 proc Destroy*(swapchain: var Swapchain) = | |
| 189 assert swapchain.vk.Valid | |
| 190 | |
| 191 for imageview in swapchain.framebufferViews.mitems: | |
| 192 assert imageview.vk.Valid | |
| 193 imageview.Destroy() | |
| 194 for framebuffer in swapchain.framebuffers.mitems: | |
| 195 assert framebuffer.vk.Valid | |
| 196 framebuffer.Destroy() | |
| 197 if swapchain.colorImage.vk.Valid: | |
| 198 swapchain.colorImage.Destroy() | |
| 199 if swapchain.colorImageView.vk.Valid: | |
| 200 swapchain.colorImageView.Destroy() | |
| 201 for i in 0 ..< swapchain.inFlightFrames: | |
| 202 assert swapchain.queueFinishedFence[i].vk.Valid | |
| 203 assert swapchain.imageAvailableSemaphore[i].vk.Valid | |
| 204 assert swapchain.renderFinishedSemaphore[i].vk.Valid | |
| 205 swapchain.queueFinishedFence[i].Destroy() | |
| 206 swapchain.imageAvailableSemaphore[i].Destroy() | |
| 207 swapchain.renderFinishedSemaphore[i].Destroy() | |
| 208 | |
| 209 swapchain.device.vk.vkDestroySwapchainKHR(swapchain.vk, nil) | |
| 210 swapchain.vk.Reset() | |
| 211 | |
| 212 proc Recreate*(swapchain: var Swapchain): Option[Swapchain] = | |
| 213 assert swapchain.vk.Valid | |
| 214 assert swapchain.device.vk.Valid | |
| 215 result = CreateSwapchain( | |
| 216 device = swapchain.device, | |
| 217 renderPass = swapchain.renderPass, | |
| 218 surfaceFormat = swapchain.surfaceFormat, | |
| 219 desiredFramebufferCount = swapchain.nFramebuffers, | |
| 220 inFlightFrames = swapchain.inFlightFrames, | |
| 221 oldSwapchain = swapchain.vk, | |
| 222 vSync = swapchain.vSync, | |
| 223 samples = swapchain.samples, | |
| 224 ) | 
