Program Listing for File VkScopedSwapChain.cpp¶
↰ Return to documentation for file (Source\Azura\RenderSystem\Src\Vulkan\VkScopedSwapChain.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<VkPresentModeKHR>& 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<VkSurfaceFormatKHR>& 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<U32>::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<VkImage> 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<VkScopedImage>& VkScopedSwapChain::GetAllImages() const {
return m_images;
}
} // namespace Vulkan
} // namespace Azura