328 lines
7.6 KiB
C++
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();
|
|
}
|