.. _program_listing_file_Source_Azura_RenderSystem_Src_Vulkan_VkScopedSwapChain.cpp: Program Listing for File VkScopedSwapChain.cpp ============================================== |exhale_lsh| :ref:`Return to documentation for file ` (``Source\Azura\RenderSystem\Src\Vulkan\VkScopedSwapChain.cpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #include "Vulkan/VkScopedSwapChain.h" #include "Vulkan/VkTypes.h" #include "Vulkan/VkCore.h" #include "Generic/Renderer.h" #include "Vulkan/VkTypeMapping.h" #include "Vulkan/VkMacros.h" #include "Memory/MemoryFactory.h" namespace Azura { namespace Vulkan { namespace { VkPresentModeKHR ChooseSwapPresentMode(const Containers::Vector& availablePresentModes) { VkPresentModeKHR bestMode = VK_PRESENT_MODE_FIFO_KHR; for (const auto& availablePresentMode : availablePresentModes) { if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) { return availablePresentMode; } if (availablePresentMode == VK_PRESENT_MODE_IMMEDIATE_KHR) { bestMode = availablePresentMode; } } return bestMode; } VkSurfaceFormatKHR ChooseSwapSurfaceFormat(const Containers::Vector& availableFormats, const SwapChainRequirements& requirement, const Log& log_VulkanRenderSystem) { const auto format = ToVkFormat(requirement.m_format); VERIFY_OPT(log_VulkanRenderSystem, format, "Unknown Format"); const auto colorSpace = ToVkColorSpaceKHR(requirement.m_colorSpace); VERIFY_OPT(log_VulkanRenderSystem, colorSpace, "Unknown Colorspace"); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Checking for %d availableFormats", availableFormats.GetSize()); // no preferred format if (availableFormats.GetSize() == 1 && availableFormats[0].format == VK_FORMAT_UNDEFINED) { return {format.value(), colorSpace.value()}; } for (const auto& availableFormat : availableFormats) { if (availableFormat.format == format.value() && availableFormat.colorSpace == colorSpace.value()) { return availableFormat; } } throw std::runtime_error("Cannot get proper required swapchain format"); } VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, const SwapChainRequirements& requirement) { if (capabilities.currentExtent.width != std::numeric_limits::max()) { return capabilities.currentExtent; } VkExtent2D actualExtent = {requirement.m_extent.m_width, requirement.m_extent.m_height}; actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height)); return actualExtent; } } // namespace VkScopedSwapChain::VkScopedSwapChain(Memory::Allocator& allocator, Log logger) : log_VulkanRenderSystem(std::move(logger)), m_swapChain(), m_extent(), m_surfaceFormat(), m_images(allocator), m_depthImage(log_VulkanRenderSystem) { } void VkScopedSwapChain::Create(VkDevice device, VkPhysicalDevice physicalDevice, VkQueue graphicsQueue, VkCommandPool graphicsCommandPool, VkSurfaceKHR surface, const VkQueueIndices& queueIndices, const SwapChainDeviceSupport& swapChainSupport, const SwapChainRequirements& swapChainRequirement, const VkPhysicalDeviceMemoryProperties& physicalDeviceMemoryProperties) { STACK_ALLOCATOR(Temporary, Memory::MonotonicAllocator, 1024); m_hasDepthSupport = swapChainRequirement.m_depthFormat != RawStorageFormat::UNKNOWN; const VkPresentModeKHR presentMode = ChooseSwapPresentMode(swapChainSupport.m_presentModes); m_surfaceFormat = ChooseSwapSurfaceFormat(swapChainSupport.m_formats, swapChainRequirement, log_VulkanRenderSystem); m_extent = ChooseSwapExtent(swapChainSupport.m_capabilities, swapChainRequirement); // TODO(vasumahesh1): Need requirement? // Set Queue Length of SwapChain m_imageCount = swapChainSupport.m_capabilities.minImageCount + 1; if (swapChainSupport.m_capabilities.maxImageCount > 0 && m_imageCount > swapChainSupport.m_capabilities.maxImageCount) { m_imageCount = swapChainSupport.m_capabilities.maxImageCount; } VkSwapchainCreateInfoKHR createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; createInfo.surface = surface; createInfo.minImageCount = m_imageCount; createInfo.imageFormat = m_surfaceFormat.format; createInfo.imageColorSpace = m_surfaceFormat.colorSpace; createInfo.imageExtent = m_extent; createInfo.imageArrayLayers = 1; createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; // TODO(vasumahesh1): Possible bug if Graphics Queue is not the same as Present Queue. How to handle? if (queueIndices.m_transferFamily != -1 && queueIndices.m_isTransferQueueRequired) { createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; createInfo.queueFamilyIndexCount = queueIndices.GetActiveSize(); createInfo.pQueueFamilyIndices = queueIndices.GetIndicesArray().data(); } else { createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; createInfo.queueFamilyIndexCount = 0; createInfo.pQueueFamilyIndices = nullptr; } createInfo.preTransform = swapChainSupport.m_capabilities.currentTransform; createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; createInfo.presentMode = presentMode; createInfo.clipped = VK_TRUE; createInfo.oldSwapchain = VK_NULL_HANDLE; VERIFY_VK_OP(log_VulkanRenderSystem, vkCreateSwapchainKHR(device, &createInfo, nullptr, &m_swapChain), "Failed to create swap chain"); vkGetSwapchainImagesKHR(device, m_swapChain, &m_imageCount, nullptr); m_images.Reserve(m_imageCount); Containers::Vector tempImages{Containers::ContainerExtent{m_imageCount}, allocatorTemporary}; vkGetSwapchainImagesKHR(device, m_swapChain, &m_imageCount, tempImages.Data()); TextureDesc swapChainDesc = {}; swapChainDesc.m_arrayLayers = 1; swapChainDesc.m_mipLevels = 1; swapChainDesc.m_bounds.m_width = m_extent.width; swapChainDesc.m_bounds.m_height = m_extent.height; swapChainDesc.m_bounds.m_depth = 1; swapChainDesc.m_format = swapChainRequirement.m_format; swapChainDesc.m_type = ImageType::Image2D; for (U32 idx = 0; idx < m_imageCount; ++idx) { auto scopedImage = VkScopedImage(device, swapChainDesc, tempImages[idx], log_VulkanRenderSystem); scopedImage.CreateImageView(ImageViewType::ImageView2D); m_images.PushBack(scopedImage); } if (!m_hasDepthSupport) { LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Depth Format Not Supplied; Will not create Depth Attachment Image"); return; } // Check if Depth Format is supported by Device or not. const bool depthFormatCheck = VkCore::QueryFormatFeatureSupport( physicalDevice, VkCore::GetVkFormat(swapChainRequirement. m_depthFormat, log_VulkanRenderSystem), [](const VkFormatProperties& prop) -> bool { return (prop.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT ) == VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT; }); VERIFY_TRUE(log_VulkanRenderSystem, depthFormatCheck, "Depth Format Not Supported"); TextureDesc depthDesc = swapChainDesc; depthDesc.m_format = swapChainRequirement.m_depthFormat; depthDesc.m_arrayLayers = 1; depthDesc.m_mipLevels = 1; depthDesc.m_size = GetFormatSize(swapChainRequirement.m_depthFormat) * swapChainDesc.m_bounds.m_width * swapChainDesc.m_bounds.m_height; m_depthImage.Create(device, depthDesc, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, physicalDeviceMemoryProperties); m_depthImage.CreateImageView(ImageViewType::ImageView2D); VkCommandBuffer depthCommandBuffer = VkCore::CreateCommandBuffer(device, graphicsCommandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, log_VulkanRenderSystem); VkCore::BeginCommandBuffer(depthCommandBuffer, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, log_VulkanRenderSystem); const ImageTransition layoutUndefined{ VK_IMAGE_LAYOUT_UNDEFINED, 0, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT }; const ImageTransition layoutDepth{ VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT }; m_depthImage.TransitionLayout(depthCommandBuffer, layoutUndefined, layoutDepth); // Flush & Wait VkCore::FlushCommandBuffer(device, depthCommandBuffer, graphicsQueue, log_VulkanRenderSystem); vkFreeCommandBuffers(device, graphicsCommandPool, 1, &depthCommandBuffer); } void VkScopedSwapChain::CleanUp(VkDevice device) { // Swapchains have a different cleanup compared to VkScopedImage for (const auto& image : m_images) { vkDestroyImageView(device, image.View(), nullptr); } if (m_hasDepthSupport) { m_depthImage.CleanUp(); } vkDestroySwapchainKHR(device, m_swapChain, nullptr); } VkSwapchainKHR VkScopedSwapChain::Real() const { return m_swapChain; } VkFormat VkScopedSwapChain::GetSurfaceFormat() const { return m_surfaceFormat.format; } VkFormat VkScopedSwapChain::GetDepthFormat() const { return m_depthImage.GetRealFormat(); } bool VkScopedSwapChain::HasDepthSupport() const { return m_hasDepthSupport; } const VkExtent2D& VkScopedSwapChain::GetExtent() const { return m_extent; } const VkScopedImage& VkScopedSwapChain::GetImage(int frameIdx) const { return m_images[frameIdx]; } const VkScopedImage& VkScopedSwapChain::GetDepthImage() const { return m_depthImage; } const Containers::Vector& VkScopedSwapChain::GetAllImages() const { return m_images; } } // namespace Vulkan } // namespace Azura