Swapchain creation
This commit is contained in:
@ -1,8 +1,9 @@
|
|||||||
#include "hk21/game/gpu.hpp"
|
#include "hk21/game/gpu.hpp"
|
||||||
|
|
||||||
#include <asl/buffer.hpp>
|
#include <asl/buffer.hpp>
|
||||||
#include <asl/log/log.hpp>
|
|
||||||
#include <asl/format.hpp>
|
#include <asl/format.hpp>
|
||||||
|
#include <asl/option.hpp>
|
||||||
|
#include <asl/log/log.hpp>
|
||||||
|
|
||||||
#include <SDL3/SDL_vulkan.h>
|
#include <SDL3/SDL_vulkan.h>
|
||||||
|
|
||||||
@ -70,47 +71,6 @@
|
|||||||
namespace gpu
|
namespace gpu
|
||||||
{
|
{
|
||||||
|
|
||||||
class GpuImpl : public Gpu
|
|
||||||
{
|
|
||||||
bool m_destroyed{};
|
|
||||||
|
|
||||||
VkInstance m_instance;
|
|
||||||
VkSurfaceKHR m_surface;
|
|
||||||
uint32_t m_queue_family_index;
|
|
||||||
VkDevice m_device;
|
|
||||||
VkQueue m_queue;
|
|
||||||
|
|
||||||
public:
|
|
||||||
GpuImpl(
|
|
||||||
VkInstance instance,
|
|
||||||
VkSurfaceKHR surface,
|
|
||||||
uint32_t queue_family_index,
|
|
||||||
VkDevice device,
|
|
||||||
VkQueue queue)
|
|
||||||
: m_instance{instance}
|
|
||||||
, m_surface{surface}
|
|
||||||
, m_queue_family_index{queue_family_index}
|
|
||||||
, m_device{device}
|
|
||||||
, m_queue{queue}
|
|
||||||
{}
|
|
||||||
|
|
||||||
ASL_DELETE_COPY_MOVE(GpuImpl);
|
|
||||||
|
|
||||||
~GpuImpl() override
|
|
||||||
{
|
|
||||||
ASL_ASSERT(m_destroyed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroy() override
|
|
||||||
{
|
|
||||||
ASL_ASSERT(!m_destroyed);
|
|
||||||
m_destroyed = true;
|
|
||||||
vkDestroyDevice(m_device, VK_ALLOCATOR);
|
|
||||||
vkDestroySurfaceKHR(m_instance, m_surface, VK_ALLOCATOR);
|
|
||||||
vkDestroyInstance(m_instance, VK_ALLOCATOR);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static uint32_t kTargetVersionMajor = 1;
|
static uint32_t kTargetVersionMajor = 1;
|
||||||
static uint32_t kTargetVersionMinor = 3;
|
static uint32_t kTargetVersionMinor = 3;
|
||||||
static uint32_t kTargetVersion = VK_MAKE_API_VERSION(0, kTargetVersionMajor, kTargetVersionMinor, 0); // NOLINT
|
static uint32_t kTargetVersion = VK_MAKE_API_VERSION(0, kTargetVersionMajor, kTargetVersionMinor, 0); // NOLINT
|
||||||
@ -220,6 +180,7 @@ static asl::status_or<PhysicalDeviceInfo> find_physical_device(VkInstance instan
|
|||||||
VkPhysicalDeviceProperties prps;
|
VkPhysicalDeviceProperties prps;
|
||||||
vkGetPhysicalDeviceProperties(physical_device, &prps);
|
vkGetPhysicalDeviceProperties(physical_device, &prps);
|
||||||
|
|
||||||
|
// @Todo Add from_zstr to asl::string_view
|
||||||
asl::string_view name{prps.deviceName, asl::strlen(prps.deviceName)};
|
asl::string_view name{prps.deviceName, asl::strlen(prps.deviceName)};
|
||||||
|
|
||||||
if (prps.apiVersion < kTargetVersion)
|
if (prps.apiVersion < kTargetVersion)
|
||||||
@ -294,6 +255,166 @@ static asl::status_or<VkDevice> create_device(VkPhysicalDevice physical_device,
|
|||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class GpuImpl : public Gpu
|
||||||
|
{
|
||||||
|
bool m_destroyed{};
|
||||||
|
|
||||||
|
VkInstance m_instance;
|
||||||
|
VkPhysicalDevice m_physical_device;
|
||||||
|
VkSurfaceKHR m_surface;
|
||||||
|
uint32_t m_queue_family_index;
|
||||||
|
VkDevice m_device;
|
||||||
|
VkQueue m_queue;
|
||||||
|
|
||||||
|
asl::option<VkSwapchainKHR> m_swapchain;
|
||||||
|
asl::buffer<VkImage> m_swapchain_images;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GpuImpl(
|
||||||
|
VkInstance instance,
|
||||||
|
VkPhysicalDevice physical_device,
|
||||||
|
VkSurfaceKHR surface,
|
||||||
|
uint32_t queue_family_index,
|
||||||
|
VkDevice device,
|
||||||
|
VkQueue queue)
|
||||||
|
: m_instance{instance}
|
||||||
|
, m_physical_device{physical_device}
|
||||||
|
, m_surface{surface}
|
||||||
|
, m_queue_family_index{queue_family_index}
|
||||||
|
, m_device{device}
|
||||||
|
, m_queue{queue}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ASL_DELETE_COPY_MOVE(GpuImpl);
|
||||||
|
|
||||||
|
~GpuImpl() override
|
||||||
|
{
|
||||||
|
ASL_ASSERT(m_destroyed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy() override
|
||||||
|
{
|
||||||
|
ASL_ASSERT(!m_destroyed);
|
||||||
|
m_destroyed = true;
|
||||||
|
|
||||||
|
if (m_swapchain.has_value())
|
||||||
|
{
|
||||||
|
vkDestroySwapchainKHR(m_device, m_swapchain.value(), VK_ALLOCATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
vkDestroyDevice(m_device, VK_ALLOCATOR);
|
||||||
|
vkDestroySurfaceKHR(m_instance, m_surface, VK_ALLOCATOR);
|
||||||
|
vkDestroyInstance(m_instance, VK_ALLOCATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
asl::status create_swapchain(uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
uint32_t count{};
|
||||||
|
VkSurfaceCapabilitiesKHR caps{};
|
||||||
|
VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_physical_device, m_surface, &caps);
|
||||||
|
if (res != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
return asl::runtime_error("Couldn't retrieve Vulkan surface capabitilies: {}", res);
|
||||||
|
}
|
||||||
|
|
||||||
|
asl::buffer<VkSurfaceFormatKHR> formats;
|
||||||
|
vkGetPhysicalDeviceSurfaceFormatsKHR(m_physical_device, m_surface, &count, nullptr);
|
||||||
|
formats.resize_zero(count);
|
||||||
|
res = vkGetPhysicalDeviceSurfaceFormatsKHR(m_physical_device, m_surface, &count, formats.data());
|
||||||
|
if (res != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
return asl::runtime_error("Couldn't retrieve Vulkan surface formats: {}", res);
|
||||||
|
}
|
||||||
|
|
||||||
|
asl::buffer<VkPresentModeKHR> present_modes;
|
||||||
|
vkGetPhysicalDeviceSurfacePresentModesKHR(m_physical_device, m_surface, &count, nullptr);
|
||||||
|
present_modes.resize_zero(count);
|
||||||
|
res = vkGetPhysicalDeviceSurfacePresentModesKHR(m_physical_device, m_surface, &count, present_modes.data());
|
||||||
|
if (res != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
return asl::runtime_error("Couldn't retrieve Vulkan surface present modes: {}", res);
|
||||||
|
}
|
||||||
|
|
||||||
|
asl::option<VkSurfaceFormatKHR> format;
|
||||||
|
for (const auto& f: formats)
|
||||||
|
{
|
||||||
|
if (f.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR &&
|
||||||
|
(f.format == VK_FORMAT_B8G8R8_UNORM ||
|
||||||
|
f.format == VK_FORMAT_B8G8R8A8_UNORM ||
|
||||||
|
f.format == VK_FORMAT_R8G8B8_UNORM ||
|
||||||
|
f.format == VK_FORMAT_R8G8B8A8_UNORM))
|
||||||
|
{
|
||||||
|
format = f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!format.has_value())
|
||||||
|
{
|
||||||
|
return asl::runtime_error("Couldn't find suitable Vulkan surface format");
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR;
|
||||||
|
for (const auto& p: present_modes)
|
||||||
|
{
|
||||||
|
if (p == VK_PRESENT_MODE_MAILBOX_KHR)
|
||||||
|
{
|
||||||
|
present_mode = p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSwapchainCreateInfoKHR create_info{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.flags = 0,
|
||||||
|
.surface = m_surface,
|
||||||
|
.minImageCount = asl::min(asl::max(2U, caps.minImageCount), caps.maxImageCount),
|
||||||
|
.imageFormat = format.value().format,
|
||||||
|
.imageColorSpace = format.value().colorSpace,
|
||||||
|
.imageExtent = {
|
||||||
|
.width = asl::min(asl::max(width, caps.minImageExtent.width), caps.maxImageExtent.width),
|
||||||
|
.height = asl::min(asl::max(height, caps.minImageExtent.height), caps.maxImageExtent.height),
|
||||||
|
},
|
||||||
|
.imageArrayLayers = 1,
|
||||||
|
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
||||||
|
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||||
|
.queueFamilyIndexCount = 1,
|
||||||
|
.pQueueFamilyIndices = &m_queue_family_index,
|
||||||
|
.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
|
||||||
|
.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
||||||
|
.presentMode = present_mode,
|
||||||
|
.clipped = VK_TRUE,
|
||||||
|
.oldSwapchain = VK_NULL_HANDLE,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkSwapchainKHR swapchain{};
|
||||||
|
res = vkCreateSwapchainKHR(m_device, &create_info, VK_ALLOCATOR, &swapchain);
|
||||||
|
if (res != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
return asl::runtime_error("Couldn't create Vulkan swapchain: {}", res);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_swapchain = swapchain;
|
||||||
|
|
||||||
|
vkGetSwapchainImagesKHR(m_device, m_swapchain.value(), &count, nullptr);
|
||||||
|
m_swapchain_images.resize_zero(count);
|
||||||
|
res = vkGetSwapchainImagesKHR(m_device, m_swapchain.value(), &count, m_swapchain_images.data());
|
||||||
|
if (res != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
return asl::runtime_error("Couldn't retrieve Vulkan swapchain images: {}", res);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASL_LOG_INFO("Vulkan swapchain created ({}x{} with {} images)",
|
||||||
|
create_info.imageExtent.width,
|
||||||
|
create_info.imageExtent.height,
|
||||||
|
m_swapchain_images.size());
|
||||||
|
|
||||||
|
return asl::ok();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
asl::status_or<asl::box<Gpu>> init(SDL_Window* window)
|
asl::status_or<asl::box<Gpu>> init(SDL_Window* window)
|
||||||
{
|
{
|
||||||
auto instance = create_instance();
|
auto instance = create_instance();
|
||||||
@ -313,12 +434,21 @@ asl::status_or<asl::box<Gpu>> init(SDL_Window* window)
|
|||||||
VkQueue queue{};
|
VkQueue queue{};
|
||||||
vkGetDeviceQueue(device.value(), physical_device_info.value().queue_family_index, 0, &queue);
|
vkGetDeviceQueue(device.value(), physical_device_info.value().queue_family_index, 0, &queue);
|
||||||
|
|
||||||
return asl::make_box<GpuImpl>(
|
auto gpu = asl::make_box<GpuImpl>(
|
||||||
instance.value(),
|
instance.value(),
|
||||||
|
physical_device_info.value().physical_device,
|
||||||
surface.value(),
|
surface.value(),
|
||||||
physical_device_info.value().queue_family_index,
|
physical_device_info.value().queue_family_index,
|
||||||
device.value(),
|
device.value(),
|
||||||
queue);
|
queue);
|
||||||
|
|
||||||
|
int window_width{};
|
||||||
|
int window_height{};
|
||||||
|
SDL_GetWindowSizeInPixels(window, &window_width, &window_height);
|
||||||
|
auto s = gpu->create_swapchain(static_cast<uint32_t>(window_width), static_cast<uint32_t>(window_height));
|
||||||
|
ASL_TRY(s);
|
||||||
|
|
||||||
|
return gpu;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gpu
|
} // namespace gpu
|
||||||
|
@ -9,8 +9,16 @@
|
|||||||
FN(vkGetPhysicalDeviceProperties) \
|
FN(vkGetPhysicalDeviceProperties) \
|
||||||
FN(vkGetPhysicalDeviceQueueFamilyProperties) \
|
FN(vkGetPhysicalDeviceQueueFamilyProperties) \
|
||||||
FN(vkCreateDevice) \
|
FN(vkCreateDevice) \
|
||||||
FN(vkGetDeviceProcAddr)
|
FN(vkGetDeviceProcAddr) \
|
||||||
|
FN(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) \
|
||||||
|
FN(vkGetPhysicalDeviceSurfaceFormatsKHR) \
|
||||||
|
FN(vkGetPhysicalDeviceSurfacePresentModesKHR)
|
||||||
|
|
||||||
#define VULKAN_DEVICE_FNS \
|
#define VULKAN_DEVICE_FNS \
|
||||||
FN(vkDestroyDevice) \
|
FN(vkDestroyDevice) \
|
||||||
FN(vkGetDeviceQueue)
|
FN(vkGetDeviceQueue) \
|
||||||
|
FN(vkCreateSwapchainKHR) \
|
||||||
|
FN(vkDestroySwapchainKHR) \
|
||||||
|
FN(vkGetSwapchainImagesKHR) \
|
||||||
|
FN(vkAcquireNextImageKHR) \
|
||||||
|
FN(vkQueuePresentKHR)
|
||||||
|
Reference in New Issue
Block a user