project-aster/aster/swapchain.cpp

111 lines
3.7 KiB
C++

/// =============================================
// Aster: swapchain.cpp
// Copyright (c) 2020-2024 Anish Bhobe
// ==============================================
#include "swapchain.h"
#include "device.h"
#include "physical_device.h"
#include "window.h"
Swapchain::Swapchain(const Window *window, const Device *device, NameString &&name)
: m_Device(device)
, m_Name(std::move(name))
{
this->Create(window);
}
Swapchain::~Swapchain()
{
if (m_Swapchain)
{
m_Device->m_Device.destroy(m_Swapchain, nullptr);
m_Swapchain = nullptr;
DEBUG("Swapchain '{}' destroyed.", m_Name);
}
}
void
Swapchain::Create(const Window *window)
{
auto surfaceCapabilities = GetSurfaceCapabilities(m_Device->m_PhysicalDevice, window->m_Surface);
auto surfaceFormats = GetSurfaceFormats(m_Device->m_PhysicalDevice, window->m_Surface);
auto presentModes = GetSurfacePresentModes(m_Device->m_PhysicalDevice, window->m_Surface);
vk::Format swapchainFormat = vk::Format::eUndefined;
vk::ColorSpaceKHR swapchainColorSpace = vk::ColorSpaceKHR::eSrgbNonlinear;
for (auto [format, colorSpace] : surfaceFormats)
{
if (format == vk::Format::eB8G8R8A8Srgb && colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear)
{
swapchainFormat = format;
swapchainColorSpace = colorSpace;
}
}
if (swapchainFormat == vk::Format::eUndefined)
{
WARN("Preferred Swapchain format not found. Falling back.");
auto surfaceFormat = surfaceFormats.front();
swapchainFormat = surfaceFormat.format;
swapchainColorSpace = surfaceFormat.colorSpace;
}
vk::PresentModeKHR swapchainPresentMode = vk::PresentModeKHR::eFifo;
for (auto presentMode : presentModes)
{
if (presentMode == vk::PresentModeKHR::eMailbox)
{
swapchainPresentMode = presentMode;
break;
}
}
vk::Extent2D swapchainExtent;
if (surfaceCapabilities.currentExtent.width != MaxValue<u32>)
{
swapchainExtent = surfaceCapabilities.currentExtent;
}
else
{
vk::Extent2D extent = window->GetSize();
vk::Extent2D minExtent = surfaceCapabilities.minImageExtent;
vk::Extent2D maxExtent = surfaceCapabilities.maxImageExtent;
swapchainExtent.width = glm::clamp(extent.width, minExtent.width, maxExtent.width);
swapchainExtent.height = glm::clamp(extent.height, minExtent.height, maxExtent.height);
}
u32 swapchainImageCount = 3;
if (surfaceCapabilities.maxImageCount > 0)
{
swapchainImageCount =
glm::clamp(swapchainImageCount, surfaceCapabilities.minImageCount, surfaceCapabilities.maxImageCount);
}
// TODO: Note that different queues might need the images to be shared.
const vk::SwapchainCreateInfoKHR swapchainCreateInfo = {
.surface = window->m_Surface,
.minImageCount = swapchainImageCount,
.imageFormat = swapchainFormat,
.imageColorSpace = swapchainColorSpace,
.imageExtent = swapchainExtent,
.imageArrayLayers = 1,
.imageUsage = vk::ImageUsageFlagBits::eColorAttachment,
.imageSharingMode = vk::SharingMode::eExclusive,
.preTransform = surfaceCapabilities.currentTransform,
.compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque,
.presentMode = swapchainPresentMode,
.clipped = true,
.oldSwapchain = m_Swapchain,
};
vk::SwapchainKHR swapchain;
vk::Result result = m_Device->m_Device.createSwapchainKHR(&swapchainCreateInfo, nullptr, &swapchain);
ERROR_IF(failed(result), "Swapchain {} creation failed. Cause {}", m_Name, result)
THEN_ABORT(result)
ELSE_DEBUG("Created Swapchain '{}'", m_Name);
m_Swapchain = swapchain;
}