pleascach/Renderer/Swapchain.cpp

166 lines
4.9 KiB
C++

#include <Renderer/Swapchain.hpp>
#include <Window/Window.hpp>
#include <Memory/Memory.hpp>
#include <Memory/Image.hpp>
#include <util/log.hpp>
/* TODO: Make solution that doesn't involve using GLFW directly here for minimization */
#include <GLFW/glfw3.h>
Swapchain::Swapchain(Window& win, vk::Device dev, vk::PhysicalDevice phys_dev, const vk::SurfaceKHR& surface, RenderPass render_pass)
: win(win), dev(dev), phys_dev(phys_dev), surface(surface), render_pass(render_pass) {
create();
}
Swapchain::Capabilities::Capabilities(vk::PhysicalDevice phys_dev, vk::SurfaceKHR surface) {
surface_caps = phys_dev.getSurfaceCapabilitiesKHR(surface);
formats = phys_dev.getSurfaceFormatsKHR(surface);
present_modes = phys_dev.getSurfacePresentModesKHR(surface);
}
vk::Extent2D Swapchain::Capabilities::chooseExtent(vk::Extent2D extent) {
if (surface_caps.currentExtent.width != UINT32_MAX)
return surface_caps.currentExtent;
extent.width = std::clamp(extent.width, surface_caps.minImageExtent.width, surface_caps.maxImageExtent.width);
extent.height = std::clamp(extent.height, surface_caps.minImageExtent.height, surface_caps.maxImageExtent.height);
return extent;
}
vk::SurfaceFormatKHR Swapchain::Capabilities::chooseFormat() {
for (const auto& format : formats) {
if (format.format == vk::Format::eB8G8R8A8Snorm && format.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear)
return format;
}
return formats[0];
}
void Swapchain::create(vk::SwapchainKHR old_swapchain) {
Capabilities caps(phys_dev, surface);
extent = caps.chooseExtent(win.getDimensions());
auto sFormat = caps.chooseFormat();
format = sFormat.format;
auto swap_info = vk::SwapchainCreateInfoKHR {
.surface = surface,
.minImageCount = caps.surface_caps.minImageCount,
.imageFormat = format,
.imageColorSpace = sFormat.colorSpace,
.imageExtent = extent,
.imageArrayLayers = 1,
.imageUsage = vk::ImageUsageFlagBits::eColorAttachment,
.imageSharingMode = vk::SharingMode::eExclusive,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
.preTransform = vk::SurfaceTransformFlagBitsKHR::eIdentity,
/* see if this allows see through windows on Wayland */
.compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque,
/* waits for refresh (V-Sync), consider playing with relaxed fifo later on*/
.presentMode = vk::PresentModeKHR::eFifo,
.clipped = VK_TRUE,
.oldSwapchain = old_swapchain,
};
Log::info("Swapchain recreated with %d minImageCount\n", swap_info.minImageCount);
swapchain = dev.createSwapchainKHR(swap_info);
images = dev.getSwapchainImagesKHR(swapchain);
depth_image = std::make_unique<Image>(phys_dev, dev, vk::Extent3D { extent.width, extent.height, 1 }, vk::Format::eD16Unorm,
vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eDepthStencilAttachment, vk::MemoryPropertyFlagBits::eDeviceLocal);
auto depth_view_info = vk::ImageViewCreateInfo {
.image = depth_image->image,
.viewType = vk::ImageViewType::e2D,
.format = vk::Format::eD16Unorm,
.components = {
.r = vk::ComponentSwizzle::eR,
.g = vk::ComponentSwizzle::eG,
.b = vk::ComponentSwizzle::eB,
.a = vk::ComponentSwizzle::eA,
},
.subresourceRange = {
.aspectMask = vk::ImageAspectFlagBits::eDepth,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
};
depth_image_view = dev.createImageView(depth_view_info);
views.resize(images.size());
framebuffers.resize(images.size());
for (size_t i = 0; i < views.size(); i++) {
auto color_image_info = vk::ImageViewCreateInfo {
.image = images[i],
.viewType = vk::ImageViewType::e2D,
.format = format,
.components = {
.r = vk::ComponentSwizzle::eR,
.g = vk::ComponentSwizzle::eG,
.b = vk::ComponentSwizzle::eB,
.a = vk::ComponentSwizzle::eA,
},
.subresourceRange = {
.aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
}
};
views[i] = dev.createImageView(color_image_info);
vk::ImageView attachments[] = { views[i], depth_image_view };
auto framebuffer_info = vk::FramebufferCreateInfo {
.renderPass = render_pass,
.attachmentCount = static_cast<uint32_t>(std::size(attachments)),
.pAttachments = attachments,
.width = extent.width,
.height = extent.height,
.layers = 1,
};
framebuffers[i] = dev.createFramebuffer(framebuffer_info);
}
}
void Swapchain::recreate() {
vk::Extent2D ext;
do {
ext = win.getDimensions();
glfwWaitEvents();
} while (!ext.width || !ext.height);
dev.waitIdle();
cleanup();
auto save = swapchain;
create(swapchain);
dev.destroySwapchainKHR(save);
}
void Swapchain::cleanup() {
dev.waitIdle();
for(auto& fb : framebuffers)
dev.destroyFramebuffer(fb);
for (auto& view : views)
dev.destroyImageView(view);
dev.destroyImageView(depth_image_view);
depth_image->cleanup();
}
Swapchain::~Swapchain() {
cleanup();
dev.destroySwapchainKHR(swapchain);
}