Mercurial > games > semicongine
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/semiconginev2/old/vulkan/swapchain.nim Wed Jul 17 21:01:37 2024 +0700 @@ -0,0 +1,224 @@ +import std/options +import std/strformat +import std/logging + +import ../core +import ./device +import ./physicaldevice +import ./image +import ./framebuffer +import ./syncing + +type + Swapchain* = object + device*: Device + vk*: VkSwapchainKHR + dimension*: TVec2[uint32] + nFramebuffers*: uint32 + currentInFlight*: int + currentFramebufferIndex: uint32 + samples: VkSampleCountFlagBits + colorImage: VulkanImage + colorImageView: ImageView + framebufferViews*: seq[ImageView] + framebuffers*: seq[Framebuffer] + queueFinishedFence*: seq[Fence] + imageAvailableSemaphore*: seq[Semaphore] + renderFinishedSemaphore*: seq[Semaphore] + # required for recreation: + renderPass: VkRenderPass + surfaceFormat: VkSurfaceFormatKHR + inFlightFrames*: int + presentQueue: Queue + vSync: bool + + +proc CreateSwapchain*( + device: Device, + renderPass: VkRenderPass, + surfaceFormat: VkSurfaceFormatKHR, + inFlightFrames: int, + samples: VkSampleCountFlagBits, + desiredFramebufferCount = 3'u32, + oldSwapchain = VkSwapchainKHR(0), + vSync = false, +): Option[Swapchain] = + assert device.vk.Valid + assert device.physicalDevice.vk.Valid + assert renderPass.Valid + assert inFlightFrames > 0 + + var capabilities = device.physicalDevice.GetSurfaceCapabilities() + if capabilities.currentExtent.width == 0 or capabilities.currentExtent.height == 0: + return none(Swapchain) + + var minFramebufferCount = desiredFramebufferCount + + # following is according to vulkan specs + minFramebufferCount = max(minFramebufferCount, capabilities.minImageCount) + if capabilities.maxImageCount != 0: + minFramebufferCount = min(minFramebufferCount, capabilities.maxImageCount) + let hasTripleBuffering = VK_PRESENT_MODE_MAILBOX_KHR in device.physicalDevice.GetSurfacePresentModes() + var createInfo = VkSwapchainCreateInfoKHR( + sType: VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + surface: device.physicalDevice.surface, + minImageCount: minFramebufferCount, + imageFormat: surfaceFormat.format, + imageColorSpace: surfaceFormat.colorSpace, + imageExtent: capabilities.currentExtent, + imageArrayLayers: 1, + imageUsage: toBits [VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT], + # VK_SHARING_MODE_CONCURRENT no supported currently + imageSharingMode: VK_SHARING_MODE_EXCLUSIVE, + preTransform: capabilities.currentTransform, + compositeAlpha: VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, # only used for blending with other windows, can be opaque + presentMode: if (vSync or not hasTripleBuffering): VK_PRESENT_MODE_FIFO_KHR else: VK_PRESENT_MODE_MAILBOX_KHR, + clipped: true, + oldSwapchain: oldSwapchain, + ) + var + swapchain = Swapchain( + device: device, + surfaceFormat: surfaceFormat, + dimension: TVec2[uint32]([capabilities.currentExtent.width, capabilities.currentExtent.height]), + inFlightFrames: inFlightFrames, + renderPass: renderPass, + vSync: vSync, + samples: samples, + ) + + if samples != VK_SAMPLE_COUNT_1_BIT: + swapchain.colorImage = device.CreateImage( + width = capabilities.currentExtent.width, + height = capabilities.currentExtent.height, + depth = 4, + samples = samples, + format = surfaceFormat.format, + usage = [VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT], + ) + swapchain.colorImageView = swapchain.colorImage.CreateImageView() + + if device.vk.vkCreateSwapchainKHR(addr createInfo, nil, addr swapchain.vk) == VK_SUCCESS: + + checkVkResult device.vk.vkGetSwapchainImagesKHR(swapchain.vk, addr swapchain.nFramebuffers, nil) + var framebuffers = newSeq[VkImage](swapchain.nFramebuffers) + checkVkResult device.vk.vkGetSwapchainImagesKHR(swapchain.vk, addr swapchain.nFramebuffers, framebuffers.ToCPointer) + for framebuffer in framebuffers: + let framebufferView = VulkanImage(vk: framebuffer, format: surfaceFormat.format, device: device).CreateImageView() + swapchain.framebufferViews.add framebufferView + if samples == VK_SAMPLE_COUNT_1_BIT: + swapchain.framebuffers.add device.CreateFramebuffer(renderPass, [framebufferView], swapchain.dimension) + else: + swapchain.framebuffers.add device.CreateFramebuffer(renderPass, [swapchain.colorImageView, framebufferView], swapchain.dimension) + for i in 0 ..< swapchain.inFlightFrames: + swapchain.queueFinishedFence.add device.CreateFence() + swapchain.imageAvailableSemaphore.add device.CreateSemaphore() + swapchain.renderFinishedSemaphore.add device.CreateSemaphore() + debug &"Created swapchain with: {swapchain.nFramebuffers} framebuffers, {inFlightFrames} in-flight frames, {swapchain.dimension.x}x{swapchain.dimension.y}" + assert device.FirstPresentationQueue().isSome, "No present queue found" + swapchain.presentQueue = device.FirstPresentationQueue().get + + result = some(swapchain) + else: + result = none(Swapchain) + +proc CurrentFramebuffer*(swapchain: Swapchain): Framebuffer = + assert swapchain.device.vk.Valid + assert swapchain.vk.Valid + swapchain.framebuffers[swapchain.currentFramebufferIndex] + +proc AcquireNextFrame*(swapchain: var Swapchain): bool = + assert swapchain.device.vk.Valid + assert swapchain.vk.Valid + + swapchain.queueFinishedFence[swapchain.currentInFlight].Await() + + let nextImageResult = swapchain.device.vk.vkAcquireNextImageKHR( + swapchain.vk, + high(uint64), + swapchain.imageAvailableSemaphore[swapchain.currentInFlight].vk, + VkFence(0), + addr swapchain.currentFramebufferIndex, + ) + + swapchain.queueFinishedFence[swapchain.currentInFlight].Reset() + + return nextImageResult == VK_SUCCESS + +proc Swap*(swapchain: var Swapchain, queue: Queue, commandBuffer: VkCommandBuffer): bool = + assert swapchain.device.vk.Valid + assert swapchain.vk.Valid + assert queue.vk.Valid + + var + waitSemaphores = [swapchain.imageAvailableSemaphore[swapchain.currentInFlight].vk] + waitStages = [VkPipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)] + submitInfo = VkSubmitInfo( + sType: VK_STRUCTURE_TYPE_SUBMIT_INFO, + waitSemaphoreCount: 1, + pWaitSemaphores: waitSemaphores.ToCPointer, + pWaitDstStageMask: waitStages.ToCPointer, + commandBufferCount: 1, + pCommandBuffers: addr commandBuffer, + signalSemaphoreCount: 1, + pSignalSemaphores: addr swapchain.renderFinishedSemaphore[swapchain.currentInFlight].vk, + ) + checkVkResult queue.vk.vkQueueSubmit( + submitCount = 1, + pSubmits = addr submitInfo, + fence = swapchain.queueFinishedFence[swapchain.currentInFlight].vk + ) + + var presentInfo = VkPresentInfoKHR( + sType: VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + waitSemaphoreCount: 1, + pWaitSemaphores: addr swapchain.renderFinishedSemaphore[swapchain.currentInFlight].vk, + swapchainCount: 1, + pSwapchains: addr swapchain.vk, + pImageIndices: addr swapchain.currentFramebufferIndex, + pResults: nil, + ) + let presentResult = vkQueuePresentKHR(swapchain.presentQueue.vk, addr presentInfo) + if presentResult != VK_SUCCESS: + return false + + return true + + +proc Destroy*(swapchain: var Swapchain) = + assert swapchain.vk.Valid + + for imageview in swapchain.framebufferViews.mitems: + assert imageview.vk.Valid + imageview.Destroy() + for framebuffer in swapchain.framebuffers.mitems: + assert framebuffer.vk.Valid + framebuffer.Destroy() + if swapchain.colorImage.vk.Valid: + swapchain.colorImage.Destroy() + if swapchain.colorImageView.vk.Valid: + swapchain.colorImageView.Destroy() + for i in 0 ..< swapchain.inFlightFrames: + assert swapchain.queueFinishedFence[i].vk.Valid + assert swapchain.imageAvailableSemaphore[i].vk.Valid + assert swapchain.renderFinishedSemaphore[i].vk.Valid + swapchain.queueFinishedFence[i].Destroy() + swapchain.imageAvailableSemaphore[i].Destroy() + swapchain.renderFinishedSemaphore[i].Destroy() + + swapchain.device.vk.vkDestroySwapchainKHR(swapchain.vk, nil) + swapchain.vk.Reset() + +proc Recreate*(swapchain: var Swapchain): Option[Swapchain] = + assert swapchain.vk.Valid + assert swapchain.device.vk.Valid + result = CreateSwapchain( + device = swapchain.device, + renderPass = swapchain.renderPass, + surfaceFormat = swapchain.surfaceFormat, + desiredFramebufferCount = swapchain.nFramebuffers, + inFlightFrames = swapchain.inFlightFrames, + oldSwapchain = swapchain.vk, + vSync = swapchain.vSync, + samples = swapchain.samples, + )