/*
VulkanFramework
by John Ryland
Copyright (c) 2023
*/
////////////////////////////////////////////////////////////////////////////////////
// Vulkan Surface
#include "VulkanSurface.h"
#define GLFW_INCLUDE_NONE
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <memory>
#include <array>
namespace Vulkan {
Surface::Surface(Device& device, GLFWwindow* window)
: m_owner(device)
, m_surface(nullptr)
{
Create(window);
}
// virtual
Surface::~Surface()
{
Destroy();
}
// virtual
void Surface::Create(GLFWwindow* window)
{
if (!m_surface)
{
// Create Window Surface
m_owner.CheckResult(glfwCreateWindowSurface(m_owner.m_instance, window, m_owner.m_allocator, &m_surface));
// Check for WSI support
VkBool32 res;
vkGetPhysicalDeviceSurfaceSupportKHR(m_owner.m_physicalDevice, m_owner.m_graphicsQueueFamily, m_surface, &res);
m_owner.CheckResult((res == VK_TRUE) ? VK_SUCCESS : VK_ERROR_UNKNOWN, "Error no WSI support on physical device");
m_format = SelectFormat();
m_presentMode = SelectPresentMode();
}
}
// virtual
void Surface::Destroy()
{
if (m_surface)
{
vkDestroySurfaceKHR(m_owner.m_instance, m_surface, m_owner.m_allocator);
m_surface = nullptr;
}
}
// virtual
VkSurfaceFormatKHR Surface::SelectFormat()
{
uint32_t avail_count;
vkGetPhysicalDeviceSurfaceFormatsKHR(m_owner.m_physicalDevice, m_surface, &avail_count, nullptr);
auto avail_formats = std::make_unique<VkSurfaceFormatKHR[]>(avail_count);
vkGetPhysicalDeviceSurfaceFormatsKHR(m_owner.m_physicalDevice, m_surface, &avail_count, avail_formats.get());
if (avail_count == 1 && avail_formats[0].format == VK_FORMAT_UNDEFINED) // implies that any format is available
return VkSurfaceFormatKHR{ VK_FORMAT_B8G8R8A8_UNORM, VK_COLORSPACE_SRGB_NONLINEAR_KHR };
// Request several formats, the first found will be used
const VkFormat requestSurfaceImageFormat[] = { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM };
for (int request_i = 0; request_i < std::size(requestSurfaceImageFormat); ++request_i)
for (uint32_t avail_i = 0; avail_i < avail_count; ++avail_i)
if (avail_formats[avail_i].format == requestSurfaceImageFormat[request_i] && avail_formats[avail_i].colorSpace == VK_COLORSPACE_SRGB_NONLINEAR_KHR)
return avail_formats[avail_i];
return avail_formats[0];
}
// virtual
VkPresentModeKHR Surface::SelectPresentMode()
{
// Unlimited framerate
VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR };
// Request a certain mode and confirm that it is available. If not use VK_PRESENT_MODE_FIFO_KHR which is mandatory
uint32_t avail_count = 0;
vkGetPhysicalDeviceSurfacePresentModesKHR(m_owner.m_physicalDevice, m_surface, &avail_count, nullptr);
auto avail_modes = std::make_unique<VkPresentModeKHR[]>(avail_count);
vkGetPhysicalDeviceSurfacePresentModesKHR(m_owner.m_physicalDevice, m_surface, &avail_count, avail_modes.get());
for (int request_i = 0; request_i < std::size(present_modes); request_i++)
for (uint32_t avail_i = 0; avail_i < avail_count; avail_i++)
if (present_modes[request_i] == avail_modes[avail_i])
return present_modes[request_i];
return VK_PRESENT_MODE_FIFO_KHR; // Always available
}
} // Vulkan namespace