Orange/src/Orange/Render/Swapchain.cpp

115 lines
4.5 KiB
C++
Raw Normal View History

2022-08-04 03:00:54 +01:00
#include <Orange/Core/Log.h>
#include <Orange/Render/Swapchain.h>
#include <Orange/Render/VulkanHelpers.h>
#include <Orange/Render/Window.h>
namespace orange
{
static Result<VkSurfaceFormatKHR> ChooseSwapChainFormat(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
{
SmallVector<VkSurfaceFormatKHR, 32> surfaceFormats;
if (!VkEnumerate(vkGetPhysicalDeviceSurfaceFormatsKHR, surfaceFormats, physicalDevice, surface))
{
log::err("Surface supports no formats");
return Result<VkSurfaceFormatKHR>::Error(BasicErrorCode::NotFound);
}
for (auto& surfaceFormat : surfaceFormats)
{
if (surfaceFormat.format == VK_FORMAT_B8G8R8A8_UNORM && surfaceFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
return Result<VkSurfaceFormatKHR>::Success(surfaceFormat);
}
return Result<VkSurfaceFormatKHR>::Error(BasicErrorCode::NotFound);
}
static VkPresentModeKHR ChoosePresentMode(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
{
SmallVector<VkPresentModeKHR, 32> presentModes;
VkEnumerate(vkGetPhysicalDeviceSurfacePresentModesKHR, presentModes, physicalDevice, surface);
for (auto& presentMode : presentModes) { if (presentMode == VK_PRESENT_MODE_MAILBOX_KHR) return presentMode; }
for (auto& presentMode : presentModes) { if (presentMode == VK_PRESENT_MODE_IMMEDIATE_KHR) return presentMode; }
return VK_PRESENT_MODE_FIFO_KHR;
}
static VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities)
{
if (capabilities.currentExtent.width != ~0u)
return capabilities.currentExtent;
uint32_t width = 1280;
uint32_t height = 720;
return VkExtent2D
{
Clamp(width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width),
Clamp(height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height)
};
}
static uint32_t ChooseImageCount(const VkSurfaceCapabilitiesKHR& capabilities)
{
uint32_t imageCount = 3;
if (capabilities.minImageCount != 0)
imageCount = Max(imageCount, capabilities.minImageCount);
if (capabilities.maxImageCount != 0)
imageCount = Min(imageCount, capabilities.maxImageCount);
return imageCount;
}
Result<Swapchain> Swapchain::Create(RenderContext& context, VkSurfaceKHR surface)
{
VkSurfaceCapabilitiesKHR capabilities;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(context.PhysicalDevice(), surface, &capabilities);
Result<VkSurfaceFormatKHR> r_format = ChooseSwapChainFormat(context.PhysicalDevice(), surface);
if (!r_format)
return Result<Swapchain>::ForwardError(r_format);
const VkExtent2D extent = ChooseSwapExtent(capabilities);
VkSwapchainCreateInfoKHR swapchainInfo =
{
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
.surface = surface,
.minImageCount = ChooseImageCount(capabilities),
.imageFormat = r_format->format,
.imageColorSpace = r_format->colorSpace,
.imageExtent = extent,
.imageArrayLayers = 1,
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
.preTransform = capabilities.currentTransform,
.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
.presentMode = ChoosePresentMode(context.PhysicalDevice(), surface),
.clipped = VK_TRUE,
.oldSwapchain = VK_NULL_HANDLE, // TODO
};
VkSwapchainKHR swapchain = VK_NULL_HANDLE;
if (vkCreateSwapchainKHR(context.Device(), &swapchainInfo, nullptr, &swapchain) != VK_SUCCESS)
{
log::err("Failed to create swapchain");
return Result<Swapchain>::Error();
}
return Result<Swapchain>::Success(context.Device(), surface, extent, swapchain);
}
Swapchain::Swapchain(VkDevice device, VkSurfaceKHR surface, VkExtent2D extent, VkSwapchainKHR swapchain)
: m_device{ device }, m_surface{ surface }, m_extent{ extent }, m_swapchain{ swapchain }
{
VkEnumerate(vkGetSwapchainImagesKHR, m_images, m_device, m_swapchain);
}
Swapchain::~Swapchain()
{
vkDestroySwapchainKHR(m_device, m_swapchain, nullptr);
}
}