cleaning renderpass, framebuffers and swapchain code, setting all vulkan resources to NULL after destroy

This commit is contained in:
Kbz-8
2023-11-18 17:25:30 +01:00
parent c583f1abc8
commit f6201014aa
23 changed files with 435 additions and 299 deletions

View File

@@ -1,43 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* vk_framebuffer.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:18:06 by maldavid #+# #+# */
/* Updated: 2023/11/08 20:36:54 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <volk.h>
#include <renderer/core/render_core.h>
#include <renderer/renderer.h>
namespace mlx
{
void FrameBuffer::init(Renderer& renderer, ImageView& image)
{
VkImageView attachments[] = { image() };
VkFramebufferCreateInfo framebufferInfo{};
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
framebufferInfo.renderPass = renderer.getRenderPass().get();
framebufferInfo.attachmentCount = 1;
framebufferInfo.pAttachments = attachments;
framebufferInfo.width = renderer.getSwapChain()._swapChainExtent.width;
framebufferInfo.height = renderer.getSwapChain()._swapChainExtent.height;
framebufferInfo.layers = 1;
if(vkCreateFramebuffer(Render_Core::get().getDevice().get(), &framebufferInfo, nullptr, &_framebuffer) != VK_SUCCESS)
core::error::report(e_kind::fatal_error, "Vulkan : failed to create a framebuffer");
#ifdef DEBUG
core::error::report(e_kind::message, "Vulkan : created new framebuffer");
#endif
}
void FrameBuffer::destroy() noexcept
{
vkDestroyFramebuffer(Render_Core::get().getDevice().get(), _framebuffer, nullptr);
}
}

View File

@@ -1,34 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* vk_framebuffer.h :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:19:44 by maldavid #+# #+# */
/* Updated: 2022/12/18 19:53:00 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#ifndef __MLX_VK_FRAMEBUFFER__
#define __MLX_VK_FRAMEBUFFER__
#include <volk.h>
namespace mlx
{
class FrameBuffer
{
public:
void init(class Renderer& renderer, class ImageView& image);
void destroy() noexcept;
inline VkFramebuffer& operator()() noexcept { return _framebuffer; }
inline VkFramebuffer& get() noexcept { return _framebuffer; }
private:
VkFramebuffer _framebuffer = VK_NULL_HANDLE;
};
}
#endif // __MLX_VK_FRAMEBUFFER__

View File

@@ -1,47 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* vk_imageview.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:20:49 by maldavid #+# #+# */
/* Updated: 2023/11/08 20:37:17 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include "vk_swapchain.h"
#include "vk_imageview.h"
#include <renderer/core/render_core.h>
namespace mlx
{
void ImageView::init(SwapChain& swapchain, VkImage& image)
{
VkImageViewCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
createInfo.image = image;
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
createInfo.format = swapchain._swapChainImageFormat;
createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
createInfo.subresourceRange.baseMipLevel = 0;
createInfo.subresourceRange.levelCount = 1;
createInfo.subresourceRange.baseArrayLayer = 0;
createInfo.subresourceRange.layerCount = 1;
if(vkCreateImageView(Render_Core::get().getDevice().get(), &createInfo, nullptr, &_image) != VK_SUCCESS)
core::error::report(e_kind::fatal_error, "Vulkan : failed to create an image view");
#ifdef DEBUG
core::error::report(e_kind::message, "Vulkan : created new swapchain image view");
#endif
}
void ImageView::destroy() noexcept
{
vkDestroyImageView(Render_Core::get().getDevice().get(), _image, nullptr);
}
}

View File

@@ -1,34 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* vk_imageview.h :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:20:19 by maldavid #+# #+# */
/* Updated: 2022/12/18 19:54:44 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#ifndef __MLX_VK_IMAGE_VIEW__
#define __MLX_VK_IMAGE_VIEW__
#include <volk.h>
namespace mlx
{
class ImageView
{
public:
void init(class SwapChain& swapchain, VkImage& image);
void destroy() noexcept;
inline VkImageView& operator()() noexcept { return _image; }
inline VkImageView& get() noexcept { return _image; }
private:
VkImageView _image = VK_NULL_HANDLE;
};
}
#endif // __MLX_VK_IMAGE_VIEW__

View File

@@ -1,90 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* vk_render_pass.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:21:36 by maldavid #+# #+# */
/* Updated: 2023/11/08 20:37:32 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include "vk_render_pass.h"
#include <renderer/core/render_core.h>
#include <renderer/renderer.h>
namespace mlx
{
static const VkClearValue clearColor = { 0.0f, 0.0f, 0.0f, 1.0f };
void RenderPass::init(Renderer* renderer)
{
_renderer = renderer;
VkAttachmentDescription colorAttachment{};
colorAttachment.format = renderer->getSwapChain()._swapChainImageFormat;
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkAttachmentReference colorAttachmentRef{};
colorAttachmentRef.attachment = 0;
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpass{};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachmentRef;
VkRenderPassCreateInfo renderPassInfo{};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo.attachmentCount = 1;
renderPassInfo.pAttachments = &colorAttachment;
renderPassInfo.subpassCount = 1;
renderPassInfo.pSubpasses = &subpass;
if(vkCreateRenderPass(Render_Core::get().getDevice().get(), &renderPassInfo, nullptr, &_renderPass) != VK_SUCCESS)
core::error::report(e_kind::fatal_error, "Vulkan : failed to create render pass");
#ifdef DEBUG
core::error::report(e_kind::message, "Vulkan : created new render pass");
#endif
}
void RenderPass::begin()
{
if(_is_running)
return;
VkRenderPassBeginInfo renderPassInfo{};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = _renderPass;
renderPassInfo.framebuffer = _renderer->getSwapChain()._framebuffers[_renderer->getImageIndex()].get();
renderPassInfo.renderArea.offset = { 0, 0 };
renderPassInfo.renderArea.extent = _renderer->getSwapChain()._swapChainExtent;
renderPassInfo.clearValueCount = 1;
renderPassInfo.pClearValues = &clearColor;
vkCmdBeginRenderPass(_renderer->getActiveCmdBuffer().get(), &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
_is_running = true;
}
void RenderPass::end()
{
if(!_is_running)
return;
vkCmdEndRenderPass(_renderer->getActiveCmdBuffer().get());
_is_running = false;
}
void RenderPass::destroy() noexcept
{
vkDestroyRenderPass(Render_Core::get().getDevice().get(), _renderPass, nullptr);
}
}

View File

@@ -1,39 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* vk_render_pass.h :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:22:00 by maldavid #+# #+# */
/* Updated: 2022/12/18 20:33:28 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#ifndef __MLX_VK_RENDER_PASS__
#define __MLX_VK_RENDER_PASS__
#include <volk.h>
namespace mlx
{
class RenderPass
{
public:
void init(class Renderer* renderer);
void destroy() noexcept;
void begin();
void end();
inline VkRenderPass& operator()() noexcept { return _renderPass; }
inline VkRenderPass& get() noexcept { return _renderPass; }
private:
VkRenderPass _renderPass = VK_NULL_HANDLE;
class Renderer* _renderer = nullptr;
bool _is_running = false;
};
}
#endif // __MLX_VK_RENDER_PASS__

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:22:28 by maldavid #+# #+# */
/* Updated: 2023/11/08 20:37:53 by maldavid ### ########.fr */
/* Updated: 2023/11/18 17:15:10 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -18,141 +18,137 @@
namespace mlx
{
void SwapChain::init(Renderer* renderer)
{
void SwapChain::init(Renderer* renderer)
{
VkDevice device = Render_Core::get().getDevice().get();
_renderer = renderer;
_swapChainSupport = querySwapChainSupport(Render_Core::get().getDevice().getPhysicalDevice());
_swapChainSupport = querySwapChainSupport(Render_Core::get().getDevice().getPhysicalDevice());
VkSurfaceFormatKHR surfaceFormat = renderer->getSurface().chooseSwapSurfaceFormat(_swapChainSupport.formats);
VkPresentModeKHR presentMode = chooseSwapPresentMode(_swapChainSupport.presentModes);
_extent = chooseSwapExtent(_swapChainSupport.capabilities);
VkSurfaceFormatKHR surfaceFormat = renderer->getSurface().chooseSwapSurfaceFormat(_swapChainSupport.formats);
VkPresentModeKHR presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; // change this to set vsync (if the driver supports it)
VkExtent2D extent = chooseSwapExtent(_swapChainSupport.capabilities);
uint32_t imageCount = _swapChainSupport.capabilities.minImageCount + 1;
if(_swapChainSupport.capabilities.maxImageCount > 0 && imageCount > _swapChainSupport.capabilities.maxImageCount)
imageCount = _swapChainSupport.capabilities.maxImageCount;
uint32_t imageCount = _swapChainSupport.capabilities.minImageCount + 1;
if(_swapChainSupport.capabilities.maxImageCount > 0 && imageCount > _swapChainSupport.capabilities.maxImageCount)
imageCount = _swapChainSupport.capabilities.maxImageCount;
Queues::QueueFamilyIndices indices = Render_Core::get().getQueue().findQueueFamilies(Render_Core::get().getDevice().getPhysicalDevice(), renderer->getSurface().get());
uint32_t queueFamilyIndices[] = { indices.graphicsFamily.value(), indices.presentFamily.value() };
VkSwapchainCreateInfoKHR createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
createInfo.surface = renderer->getSurface().get();
createInfo.minImageCount = imageCount;
createInfo.imageFormat = surfaceFormat.format;
createInfo.imageColorSpace = surfaceFormat.colorSpace;
createInfo.imageExtent = extent;
createInfo.imageArrayLayers = 1;
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
Queues::QueueFamilyIndices indices = Render_Core::get().getQueue().findQueueFamilies(Render_Core::get().getDevice().getPhysicalDevice(), renderer->getSurface().get());
uint32_t queueFamilyIndices[] = {indices.graphicsFamily.value(), indices.presentFamily.value()};
if(indices.graphicsFamily != indices.presentFamily)
VkSwapchainCreateInfoKHR createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
createInfo.surface = renderer->getSurface().get();
createInfo.minImageCount = imageCount;
createInfo.imageFormat = surfaceFormat.format;
createInfo.imageColorSpace = surfaceFormat.colorSpace;
createInfo.imageExtent = _extent;
createInfo.imageArrayLayers = 1;
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
createInfo.preTransform = _swapChainSupport.capabilities.currentTransform;
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
createInfo.presentMode = presentMode;
createInfo.clipped = VK_TRUE;
createInfo.oldSwapchain = VK_NULL_HANDLE;
if(indices.graphicsFamily != indices.presentFamily)
{
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
createInfo.queueFamilyIndexCount = 2;
createInfo.pQueueFamilyIndices = queueFamilyIndices;
}
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
createInfo.queueFamilyIndexCount = 2;
createInfo.pQueueFamilyIndices = queueFamilyIndices;
}
else
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.preTransform = _swapChainSupport.capabilities.currentTransform;
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
createInfo.presentMode = presentMode;
createInfo.clipped = VK_TRUE;
if(vkCreateSwapchainKHR(device, &createInfo, nullptr, &_swapChain) != VK_SUCCESS)
core::error::report(e_kind::fatal_error, "Vulkan : failed to create the swapchain");
createInfo.oldSwapchain = VK_NULL_HANDLE;
std::vector<VkImage> tmp;
vkGetSwapchainImagesKHR(device, _swapChain, &imageCount, nullptr);
_images.resize(imageCount);
tmp.resize(imageCount);
vkGetSwapchainImagesKHR(device, _swapChain, &imageCount, tmp.data());
VkDevice device = Render_Core::get().getDevice().get();
for(int i = 0; i < imageCount; i++)
{
_images[i].create(tmp[i], surfaceFormat.format, _extent.width, _extent.height);
_images[i].transitionLayout(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
_images[i].createImageView(VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT);
}
if(vkCreateSwapchainKHR(device, &createInfo, nullptr, &_swapChain) != VK_SUCCESS)
core::error::report(e_kind::fatal_error, "Vulkan : failed to create swapchain");
_swapChainImageFormat = surfaceFormat.format;
#ifdef DEBUG
core::error::report(e_kind::message, "Vulkan : created new swapchain");
#endif
}
vkGetSwapchainImagesKHR(device, _swapChain, &imageCount, nullptr);
_swapChainImages.resize(imageCount);
vkGetSwapchainImagesKHR(device, _swapChain, &imageCount, _swapChainImages.data());
SwapChain::SwapChainSupportDetails SwapChain::querySwapChainSupport(VkPhysicalDevice device)
{
SwapChain::SwapChainSupportDetails details;
VkSurfaceKHR surface = _renderer->getSurface().get();
_swapChainImageFormat = surfaceFormat.format;
_swapChainExtent = extent;
if(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities) != VK_SUCCESS)
core::error::report(e_kind::fatal_error, "Vulkan : unable to retrieve surface capabilities");
_imageViews.resize(_swapChainImages.size());
uint32_t formatCount = 0;
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
for(size_t i = 0; i < _swapChainImages.size(); i++)
_imageViews[i].init(*this, _swapChainImages[i]);
}
if(formatCount != 0)
{
details.formats.resize(formatCount);
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());
}
void SwapChain::initFB()
{
_framebuffers.resize(_imageViews.size());
uint32_t presentModeCount;
vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);
for(size_t i = 0; i < _imageViews.size(); i++)
_framebuffers[i].init(*_renderer, _imageViews[i]);
}
if(presentModeCount != 0)
{
details.presentModes.resize(presentModeCount);
vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());
}
SwapChain::SwapChainSupportDetails SwapChain::querySwapChainSupport(VkPhysicalDevice device)
{
SwapChain::SwapChainSupportDetails details;
VkSurfaceKHR surface = _renderer->getSurface().get();
return details;
}
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);
VkPresentModeKHR SwapChain::chooseSwapPresentMode([[maybe_unused]] const std::vector<VkPresentModeKHR>& availablePresentModes)
{
// in the future, you may choose to activate vsync or not
return VK_PRESENT_MODE_IMMEDIATE_KHR;
}
uint32_t formatCount = 0;
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
VkExtent2D SwapChain::chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities)
{
if(capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max())
return capabilities.currentExtent;
if(formatCount != 0)
{
details.formats.resize(formatCount);
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());
}
return details;
}
int width, height;
SDL_Vulkan_GetDrawableSize(_renderer->getWindow()->getNativeWindow(), &width, &height);
VkExtent2D SwapChain::chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities)
{
if(capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max())
return capabilities.currentExtent;
VkExtent2D actualExtent = { static_cast<uint32_t>(width), static_cast<uint32_t>(height) };
int width, height;
SDL_Vulkan_GetDrawableSize(_renderer->getWindow()->getNativeWindow(), &width, &height);
actualExtent.width = std::clamp(actualExtent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
actualExtent.height = std::clamp(actualExtent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
VkExtent2D actualExtent = { static_cast<uint32_t>(width), static_cast<uint32_t>(height) };
return actualExtent;
}
actualExtent.width = std::clamp(actualExtent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
actualExtent.height = std::clamp(actualExtent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
void SwapChain::recreate()
{
destroy();
init(_renderer);
}
return actualExtent;
}
void SwapChain::recreate()
{
destroyFB();
destroy();
_renderer->getRenderPass().destroy();
init(_renderer);
_renderer->getRenderPass().init(_renderer);
initFB();
}
void SwapChain::destroyFB() noexcept
{
vkDeviceWaitIdle(Render_Core::get().getDevice().get());
for(size_t i = 0; i < _framebuffers.size(); i++)
_framebuffers[i].destroy();
}
void SwapChain::destroy() noexcept
{
vkDeviceWaitIdle(Render_Core::get().getDevice().get());
for(size_t i = 0; i < _imageViews.size(); i++)
_imageViews[i].destroy();
if(_swapChain != VK_NULL_HANDLE)
vkDestroySwapchainKHR(Render_Core::get().getDevice().get(), _swapChain, nullptr);
_swapChain = VK_NULL_HANDLE;
}
void SwapChain::destroy() noexcept
{
if(_swapChain == VK_NULL_HANDLE)
return;
vkDeviceWaitIdle(Render_Core::get().getDevice().get());
vkDestroySwapchainKHR(Render_Core::get().getDevice().get(), _swapChain, nullptr);
_swapChain = VK_NULL_HANDLE;
for(Image& img : _images)
{
img.destroyImageView();
img.destroyCmdPool();
}
}
}

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:23:27 by maldavid #+# #+# */
/* Updated: 2022/12/18 22:08:36 by maldavid ### ########.fr */
/* Updated: 2023/11/18 17:15:18 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -15,15 +15,12 @@
#include <vector>
#include <volk.h>
#include "vk_imageview.h"
#include "vk_framebuffer.h"
#include <renderer/images/vk_image.h>
namespace mlx
{
class SwapChain
{
friend class FrameBuffer;
friend class ImageView;
friend class GraphicPipeline;
friend class RenderPass;
friend class Renderer;
@@ -33,32 +30,36 @@ namespace mlx
{
VkSurfaceCapabilitiesKHR capabilities;
std::vector<VkSurfaceFormatKHR> formats;
std::vector<VkPresentModeKHR> presentModes;
};
public:
SwapChain() = default;
void init(class Renderer* renderer);
void initFB();
void destroy() noexcept;
void destroyFB() noexcept;
void recreate();
void destroy() noexcept;
SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device);
VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities);
SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device);
VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities);
VkPresentModeKHR chooseSwapPresentMode([[maybe_unused]] const std::vector<VkPresentModeKHR> &availablePresentModes);
inline SwapChainSupportDetails getSupport() noexcept { return _swapChainSupport; }
inline VkSwapchainKHR& operator()() noexcept { return _swapChain; }
inline VkSwapchainKHR& get() noexcept { return _swapChain; }
inline FrameBuffer& getFrameBuffer(int i) { return _framebuffers[i]; }
inline size_t getImagesNumber() const noexcept { return _swapChainImages.size(); }
inline VkSwapchainKHR get() noexcept { return _swapChain; }
inline VkSwapchainKHR operator()() noexcept { return _swapChain; }
inline size_t getImagesNumber() const noexcept { return _images.size(); }
inline Image& getImage(std::size_t i) noexcept { return _images[i]; }
inline SwapChainSupportDetails getSupport() noexcept { return _swapChainSupport; }
inline VkExtent2D getExtent() noexcept { return _extent; }
inline VkFormat getImagesFormat() const noexcept { return _swapChainImageFormat; }
~SwapChain() = default;
private:
SwapChainSupportDetails _swapChainSupport;
std::vector<VkImage> _swapChainImages;
std::vector<FrameBuffer> _framebuffers;
std::vector<ImageView> _imageViews;
VkSwapchainKHR _swapChain;
VkFormat _swapChainImageFormat;
VkExtent2D _swapChainExtent;
SwapChainSupportDetails _swapChainSupport;
VkSwapchainKHR _swapChain;
std::vector<Image> _images;
VkFormat _swapChainImageFormat;
VkExtent2D _extent;
class Renderer* _renderer = nullptr;
};
}