mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-09 04:38:30 +09:00
133 lines
5.2 KiB
C++
133 lines
5.2 KiB
C++
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/SwapchainManager.cpp
|
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
|
// Licensed under the GNU Lesser General Public License v3.0:
|
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
// End of Source File Header
|
|
|
|
#include "SwapchainManager.h"
|
|
#include "VulkanContext.h"
|
|
|
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
|
SwapchainManager::SwapchainManager(VulkanContext& ctx) : Ctx(ctx) {}
|
|
SwapchainManager::~SwapchainManager() {
|
|
Cleanup();
|
|
}
|
|
|
|
void SwapchainManager::Initialize() {
|
|
CreateSwapchainInternal();
|
|
CreateImageViews();
|
|
ImagesInFlight.resize(Images.size(), VK_NULL_HANDLE);
|
|
}
|
|
|
|
void SwapchainManager::Recreate() {
|
|
DestroyImageViews();
|
|
if (Swapchain != VK_NULL_HANDLE) {
|
|
vkDestroySwapchainKHR(Ctx.GetDevice(), Swapchain, nullptr);
|
|
Swapchain = VK_NULL_HANDLE;
|
|
}
|
|
CreateSwapchainInternal();
|
|
CreateImageViews();
|
|
ImagesInFlight.resize(Images.size(), VK_NULL_HANDLE);
|
|
|
|
Framebuffers.clear();
|
|
MGLOG_D("Swapchain recreated");
|
|
}
|
|
|
|
void SwapchainManager::Cleanup() {
|
|
for (auto fb : Framebuffers)
|
|
if (fb != VK_NULL_HANDLE) vkDestroyFramebuffer(Ctx.GetDevice(), fb, nullptr);
|
|
Framebuffers.clear();
|
|
DestroyImageViews();
|
|
if (Swapchain != VK_NULL_HANDLE) {
|
|
vkDestroySwapchainKHR(Ctx.GetDevice(), Swapchain, nullptr);
|
|
Swapchain = VK_NULL_HANDLE;
|
|
}
|
|
}
|
|
|
|
void SwapchainManager::SetFramebuffers(std::vector<VkFramebuffer>&& fbs) {
|
|
Framebuffers = std::move(fbs);
|
|
}
|
|
|
|
VkPresentModeKHR SwapchainManager::QueryPossiblePresentMode() {
|
|
const auto& surface = Ctx.GetSurface();
|
|
const auto& phys = Ctx.GetPhysicalDevice();
|
|
Uint32 modeCount;
|
|
vkGetPhysicalDeviceSurfacePresentModesKHR(phys, surface, &modeCount, NULL);
|
|
|
|
Vector<VkPresentModeKHR> modes(modeCount);
|
|
vkGetPhysicalDeviceSurfacePresentModesKHR(phys, surface, &modeCount, modes.data());
|
|
VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
|
|
|
|
for (auto m : modes) {
|
|
if (m == VK_PRESENT_MODE_MAILBOX_KHR) {
|
|
presentMode = m;
|
|
break;
|
|
}
|
|
if (m == VK_PRESENT_MODE_IMMEDIATE_KHR) {
|
|
presentMode = m;
|
|
}
|
|
}
|
|
|
|
return presentMode;
|
|
}
|
|
|
|
void SwapchainManager::CreateSwapchainInternal() {
|
|
VkSurfaceCapabilitiesKHR caps;
|
|
VK_VERIFY(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(Ctx.GetPhysicalDevice(), Ctx.GetSurface(), &caps),
|
|
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
|
|
|
|
Extent = caps.currentExtent;
|
|
ImageFormat = VK_FORMAT_R8G8B8A8_UNORM;
|
|
|
|
VkSwapchainCreateInfoKHR sci{VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR};
|
|
sci.surface = Ctx.GetSurface();
|
|
sci.minImageCount = std::max<uint32_t>(2, caps.minImageCount);
|
|
sci.imageFormat = ImageFormat;
|
|
sci.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
|
|
sci.imageExtent = Extent;
|
|
sci.imageArrayLayers = 1;
|
|
sci.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
|
sci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
sci.preTransform = caps.currentTransform;
|
|
sci.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
|
sci.presentMode = QueryPossiblePresentMode();
|
|
|
|
VK_VERIFY(vkCreateSwapchainKHR(Ctx.GetDevice(), &sci, nullptr, &Swapchain), "vkCreateSwapchainKHR");
|
|
|
|
uint32_t count = 0;
|
|
VK_VERIFY(vkGetSwapchainImagesKHR(Ctx.GetDevice(), Swapchain, &count, nullptr),
|
|
"vkGetSwapchainImagesKHR count");
|
|
Images.resize(count);
|
|
VK_VERIFY(vkGetSwapchainImagesKHR(Ctx.GetDevice(), Swapchain, &count, Images.data()),
|
|
"vkGetSwapchainImagesKHR images");
|
|
MGLOG_D("Swapchain created (%u images)", count);
|
|
}
|
|
|
|
void SwapchainManager::CreateImageViews() {
|
|
DestroyImageViews();
|
|
ImageViews.resize(Images.size());
|
|
for (size_t i = 0; i < Images.size(); ++i) {
|
|
VkImageViewCreateInfo ivci{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
|
|
ivci.image = Images[i];
|
|
ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
ivci.format = ImageFormat;
|
|
ivci.components = {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B,
|
|
VK_COMPONENT_SWIZZLE_A};
|
|
ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
ivci.subresourceRange.baseMipLevel = 0;
|
|
ivci.subresourceRange.levelCount = 1;
|
|
ivci.subresourceRange.baseArrayLayer = 0;
|
|
ivci.subresourceRange.layerCount = 1;
|
|
VK_VERIFY(vkCreateImageView(Ctx.GetDevice(), &ivci, nullptr, &ImageViews[i]), "vkCreateImageView");
|
|
}
|
|
MGLOG_D("ImageViews created");
|
|
}
|
|
|
|
void SwapchainManager::DestroyImageViews() {
|
|
for (auto iv : ImageViews)
|
|
if (iv != VK_NULL_HANDLE) vkDestroyImageView(Ctx.GetDevice(), iv, nullptr);
|
|
ImageViews.clear();
|
|
}
|
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|