Files
inferno-hart/src/graphics/swapchain.cpp
2023-12-03 00:08:22 +00:00

209 lines
7.1 KiB
C++

#include "swapchain.hpp"
#include "graphics.hpp"
#include "device.hpp"
#include "image.hpp"
#include "yolo/yolo.hpp"
namespace inferno::graphics {
struct SwapChainSupportDetails {
VkSurfaceCapabilitiesKHR Capabilities;
std::vector<VkSurfaceFormatKHR> Formats;
std::vector<VkPresentModeKHR> PresentModes;
};
SwapChainSupportDetails device_get_swapchain_support(
GraphicsDevice* g, VkPhysicalDevice device)
{
SwapChainSupportDetails details;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
device, g->VulkanSurface, &details.Capabilities);
uint32_t formatCount;
vkGetPhysicalDeviceSurfaceFormatsKHR(device, g->VulkanSurface, &formatCount, nullptr);
if (formatCount != 0) {
details.Formats.resize(formatCount);
vkGetPhysicalDeviceSurfaceFormatsKHR(
device, g->VulkanSurface, &formatCount, details.Formats.data());
}
uint32_t presentModeCount;
vkGetPhysicalDeviceSurfacePresentModesKHR(
device, g->VulkanSurface, &presentModeCount, nullptr);
if (presentModeCount != 0) {
details.PresentModes.resize(presentModeCount);
vkGetPhysicalDeviceSurfacePresentModesKHR(
device, g->VulkanSurface, &presentModeCount, details.PresentModes.data());
}
return details;
}
VkSurfaceFormatKHR device_choose_swap_surface_format(
const std::vector<VkSurfaceFormatKHR>& availableFormats)
{
for (const auto& availableFormat : availableFormats) {
if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB
&& availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
return availableFormat;
}
}
return availableFormats[0];
}
VkPresentModeKHR device_choose_swap_present_mode(
const std::vector<VkPresentModeKHR>& availablePresentModes)
{
for (const auto& availablePresentMode : availablePresentModes) {
if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
return availablePresentMode;
}
}
return VK_PRESENT_MODE_FIFO_KHR;
}
VkExtent2D device_choose_swap_extent(
const VkSurfaceCapabilitiesKHR& capabilities, int width, int height)
{
if (capabilities.currentExtent.width != UINT32_MAX) {
yolo::info("Surface size: {}x{}", capabilities.currentExtent.width,
capabilities.currentExtent.height);
return capabilities.currentExtent;
} else {
VkExtent2D actualExtent = { (uint32_t)width, (uint32_t)height };
yolo::info("Surface size: {}x{}", width, height);
actualExtent.width = std::max(capabilities.minImageExtent.width,
std::min(capabilities.maxImageExtent.width, actualExtent.width));
actualExtent.height = std::max(capabilities.minImageExtent.height,
std::min(capabilities.maxImageExtent.height, actualExtent.height));
return actualExtent;
}
}
SwapChain* swapchain_create(GraphicsDevice* device, glm::ivec2 surface_size)
{
SwapChain* swapchain = new SwapChain();
SwapChainSupportDetails swapChainSupport
= device_get_swapchain_support(device, device->VulkanPhysicalDevice);
VkSurfaceFormatKHR surfaceFormat
= device_choose_swap_surface_format(swapChainSupport.Formats);
VkPresentModeKHR presentMode
= device_choose_swap_present_mode(swapChainSupport.PresentModes);
yolo::debug("Surface format: {}", surfaceFormat.format);
VkExtent2D extent = device_choose_swap_extent(
swapChainSupport.Capabilities, surface_size.x, surface_size.y);
swapchain->Extent = extent;
uint32_t imageCount = swapChainSupport.Capabilities.minImageCount + 1;
if (swapChainSupport.Capabilities.maxImageCount > 0
&& imageCount > swapChainSupport.Capabilities.maxImageCount) {
imageCount = swapChainSupport.Capabilities.maxImageCount;
}
VkSwapchainCreateInfoKHR createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
createInfo.surface = device->VulkanSurface;
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;
QueueFamilyIndices indices
= device_get_queue_families(device, device->VulkanPhysicalDevice);
uint32_t queueFamilyIndices[]
= { indices.graphicsFamily.value(), indices.presentFamily.value() };
if (indices.graphicsFamily != indices.presentFamily) {
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
createInfo.queueFamilyIndexCount = 2;
createInfo.pQueueFamilyIndices = queueFamilyIndices;
} else {
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.queueFamilyIndexCount = 0; // Optional
createInfo.pQueueFamilyIndices = nullptr; // Optional
}
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 (vkCreateSwapchainKHR(
device->VulkanDevice, &createInfo, nullptr, &swapchain->Handle)
!= VK_SUCCESS) {
yolo::error("failed to create swap chain!");
exit(1);
}
yolo::info("Swap chain created");
vkGetSwapchainImagesKHR(
device->VulkanDevice, swapchain->Handle, &imageCount, nullptr);
swapchain->Images.resize(imageCount);
vkGetSwapchainImagesKHR(
device->VulkanDevice, swapchain->Handle, &imageCount, swapchain->Images.data());
swapchain->ImageFormat = surfaceFormat.format;
swapchain->Device = device;
swapchain_image_view_create(swapchain);
return swapchain;
}
void swapchain_cleanup(SwapChain* swapchain)
{
for (auto imageView : swapchain->ImageViews) {
vkDestroyImageView(swapchain->Device->VulkanDevice, imageView, nullptr);
}
vkDestroySwapchainKHR(swapchain->Device->VulkanDevice, swapchain->Handle, nullptr);
delete swapchain;
}
void swapchain_image_view_create(SwapChain* swapchain)
{
swapchain->ImageViews.resize(swapchain->Images.size());
for (size_t i = 0; i < swapchain->Images.size(); i++) {
swapchain->ImageViews[i] = create_image_view(swapchain->Device,
swapchain->Images[i], swapchain->ImageFormat, VK_IMAGE_ASPECT_COLOR_BIT);
}
VkFormat depthFormat = find_depth_format(swapchain->Device);
swapchain->DepthFormat = depthFormat;
create_image(swapchain->Device, swapchain->Extent.width, swapchain->Extent.height,
depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, swapchain->depthImage,
swapchain->depthImageMemory);
swapchain->DepthImageView = create_image_view(
swapchain->Device, swapchain->depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
}
void swapchain_recreate(SwapChain* swapchain)
{
vkDeviceWaitIdle(swapchain->Device->VulkanDevice);
GraphicsDevice* device = swapchain->Device;
swapchain_cleanup(swapchain);
swapchain = swapchain_create(device, device->SurfaceSize);
}
}