/// ============================================= // 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 [format, colorSpace] = surfaceFormats.front(); swapchainFormat = format; swapchainColorSpace = colorSpace; } vk::PresentModeKHR swapchainPresentMode = vk::PresentModeKHR::eFifo; for (const auto presentMode : presentModes) { if (presentMode == vk::PresentModeKHR::eMailbox) { swapchainPresentMode = presentMode; break; } } vk::Extent2D swapchainExtent; if (surfaceCapabilities.currentExtent.width != MaxValue) { swapchainExtent = surfaceCapabilities.currentExtent; } else { auto [width, height] = window->GetSize(); auto [minWidth, minHeight] = surfaceCapabilities.minImageExtent; auto [maxWidth, maxHeight] = surfaceCapabilities.maxImageExtent; swapchainExtent.width = glm::clamp(width, minWidth, maxWidth); swapchainExtent.height = glm::clamp(height, minHeight, maxHeight); } 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; }