115 lines
4.5 KiB
C++
115 lines
4.5 KiB
C++
|
#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);
|
||
|
}
|
||
|
}
|