Files
mxl-multiviewer/Swapchain.cpp
T
2026-05-18 00:03:06 +03:00

328 lines
7.6 KiB
C++

#include "Swapchain.hpp"
#include <algorithm>
#include <iostream>
#include <stdexcept>
namespace
{
const char* presentModeName(VkPresentModeKHR mode)
{
switch (mode)
{
case VK_PRESENT_MODE_FIFO_KHR:
return "fifo";
case VK_PRESENT_MODE_MAILBOX_KHR:
return "mailbox";
case VK_PRESENT_MODE_IMMEDIATE_KHR:
return "immediate";
default:
return "other";
}
}
}
Swapchain::Swapchain(
VkDevice device,
VkPhysicalDevice physicalDevice,
VkSurfaceKHR surface,
VkRenderPass renderPass,
VkPresentModeKHR preferredPresentMode,
uint32_t windowWidth,
uint32_t windowHeight)
: m_device(device)
, m_physicalDevice(physicalDevice)
, m_surface(surface)
, m_preferredPresentMode(preferredPresentMode)
{
createSwapchain(windowWidth, windowHeight);
createImageViews();
createFramebuffers(renderPass);
std::cout << "Swapchain created ("
<< m_imageCount << " images)"
<< std::endl;
}
Swapchain::~Swapchain()
{
destroy();
}
void Swapchain::recreate(
VkRenderPass renderPass,
uint32_t windowWidth,
uint32_t windowHeight)
{
destroy();
createSwapchain(windowWidth, windowHeight);
createImageViews();
createFramebuffers(renderPass);
std::cout << "Swapchain recreated ("
<< m_imageCount << " images)"
<< std::endl;
}
void Swapchain::createSwapchain(
uint32_t windowWidth,
uint32_t windowHeight)
{
SwapchainSupportDetails support =
querySwapchainSupport(
m_physicalDevice,
m_surface
);
m_surfaceFormat = support.formats[0];
for (const auto& availableFormat :
support.formats)
{
if (availableFormat.format ==
VK_FORMAT_B8G8R8A8_SRGB &&
availableFormat.colorSpace ==
VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
{
m_surfaceFormat = availableFormat;
break;
}
}
m_presentMode = VK_PRESENT_MODE_FIFO_KHR;
for (const auto& availablePresentMode :
support.presentModes)
{
if (availablePresentMode == m_preferredPresentMode)
{
m_presentMode = availablePresentMode;
break;
}
}
m_extent.width = windowWidth;
m_extent.height = windowHeight;
m_imageCount =
support.capabilities.minImageCount + 1;
if (support.capabilities.maxImageCount > 0 &&
m_imageCount >
support.capabilities.maxImageCount)
{
m_imageCount =
support.capabilities.maxImageCount;
}
VkSwapchainCreateInfoKHR swapchainInfo{};
swapchainInfo.sType =
VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
swapchainInfo.surface = m_surface;
swapchainInfo.minImageCount = m_imageCount;
swapchainInfo.imageFormat =
m_surfaceFormat.format;
swapchainInfo.imageColorSpace =
m_surfaceFormat.colorSpace;
swapchainInfo.imageExtent = m_extent;
swapchainInfo.imageArrayLayers = 1;
swapchainInfo.imageUsage =
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
QueueFamilyIndices indices =
findQueueFamilies(
m_physicalDevice,
m_surface
);
uint32_t queueFamilyIndices[] =
{
*indices.graphicsFamily,
*indices.presentFamily
};
if (*indices.graphicsFamily !=
*indices.presentFamily)
{
swapchainInfo.imageSharingMode =
VK_SHARING_MODE_CONCURRENT;
swapchainInfo.queueFamilyIndexCount = 2;
swapchainInfo.pQueueFamilyIndices =
queueFamilyIndices;
}
else
{
swapchainInfo.imageSharingMode =
VK_SHARING_MODE_EXCLUSIVE;
}
swapchainInfo.preTransform =
support.capabilities.currentTransform;
swapchainInfo.compositeAlpha =
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
swapchainInfo.presentMode = m_presentMode;
swapchainInfo.clipped = VK_TRUE;
if (vkCreateSwapchainKHR(
m_device,
&swapchainInfo,
nullptr,
&m_swapchain) != VK_SUCCESS)
{
throw std::runtime_error(
"Failed to create swapchain"
);
}
vkGetSwapchainImagesKHR(
m_device,
m_swapchain,
&m_imageCount,
nullptr
);
m_swapchainImages.resize(m_imageCount);
vkGetSwapchainImagesKHR(
m_device,
m_swapchain,
&m_imageCount,
m_swapchainImages.data()
);
std::cout << "Present mode: "
<< presentModeName(m_presentMode)
<< std::endl;
}
void Swapchain::createImageViews()
{
m_imageViews.resize(m_swapchainImages.size());
for (size_t i = 0;
i < m_swapchainImages.size();
++i)
{
VkImageViewCreateInfo viewInfo{};
viewInfo.sType =
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.image = m_swapchainImages[i];
viewInfo.viewType =
VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format =
m_surfaceFormat.format;
viewInfo.components.r =
VK_COMPONENT_SWIZZLE_IDENTITY;
viewInfo.components.g =
VK_COMPONENT_SWIZZLE_IDENTITY;
viewInfo.components.b =
VK_COMPONENT_SWIZZLE_IDENTITY;
viewInfo.components.a =
VK_COMPONENT_SWIZZLE_IDENTITY;
viewInfo.subresourceRange.aspectMask =
VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.subresourceRange.baseMipLevel = 0;
viewInfo.subresourceRange.levelCount = 1;
viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = 1;
if (vkCreateImageView(
m_device,
&viewInfo,
nullptr,
&m_imageViews[i]) != VK_SUCCESS)
{
throw std::runtime_error(
"Failed to create image view"
);
}
}
std::cout << "Image views created"
<< std::endl;
}
void Swapchain::createFramebuffers(
VkRenderPass renderPass)
{
m_framebuffers.resize(m_imageViews.size());
for (size_t i = 0;
i < m_imageViews.size();
++i)
{
VkImageView attachments[] =
{
m_imageViews[i]
};
VkFramebufferCreateInfo fbInfo{};
fbInfo.sType =
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
fbInfo.renderPass = renderPass;
fbInfo.attachmentCount = 1;
fbInfo.pAttachments = attachments;
fbInfo.width = m_extent.width;
fbInfo.height = m_extent.height;
fbInfo.layers = 1;
if (vkCreateFramebuffer(
m_device,
&fbInfo,
nullptr,
&m_framebuffers[i]) != VK_SUCCESS)
{
throw std::runtime_error(
"Failed to create framebuffer"
);
}
}
std::cout << "Framebuffers created"
<< std::endl;
}
void Swapchain::destroy()
{
if (m_swapchain == VK_NULL_HANDLE)
{
return;
}
for (VkFramebuffer fb : m_framebuffers)
{
vkDestroyFramebuffer(
m_device,
fb,
nullptr
);
}
m_framebuffers.clear();
for (VkImageView view : m_imageViews)
{
vkDestroyImageView(
m_device,
view,
nullptr
);
}
m_imageViews.clear();
m_swapchainImages.clear();
vkDestroySwapchainKHR(
m_device,
m_swapchain,
nullptr
);
m_swapchain = VK_NULL_HANDLE;
}
void Swapchain::release()
{
destroy();
}