feat: create vulkan swapchain

This commit is contained in:
Kevin Trogant 2023-10-25 23:24:04 +02:00
parent 904a26374b
commit 6937e55888
6 changed files with 277 additions and 1 deletions

View File

@ -78,8 +78,10 @@ if vk_dep.found()
vk_renderer_lib = library('vyvk', vk_renderer_lib = library('vyvk',
# Project Sources # Project Sources
'src/renderer/vk/gpu.h', 'src/renderer/vk/gpu.h',
'src/renderer/vk/swapchain.h',
'src/renderer/vk/init.c', 'src/renderer/vk/init.c',
'src/renderer/vk/swapchain.c',
'src/renderer/vk/gfx_pipelines.c', 'src/renderer/vk/gfx_pipelines.c',
# Contrib Sources # Contrib Sources

View File

@ -0,0 +1,10 @@
#include <volk/volk.h>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#endif
#if defined(VY_USE_XLIB)
#include <X11/Xlib.h>
#endif

View File

@ -3,6 +3,25 @@
#include <volk/volk.h> #include <volk/volk.h>
#ifdef _WIN32
struct HINSTANCE__;
struct HWND__;
#elif defined(VY_USE_XLIB)
struct _XDisplay;
#endif
typedef struct {
#ifdef _WIN32
struct HINSTANCE__ *hInstance;
struct HWND__ *hWnd;
#elif defined(VY_USE_XLIB)
struct _XDisplay *display;
unsigned long window;
#endif
} vy_native_window;
typedef struct { typedef struct {
VkInstance instance; VkInstance instance;
VkDebugUtilsMessengerEXT messenger; VkDebugUtilsMessengerEXT messenger;
@ -13,6 +32,11 @@ typedef struct {
VkQueue graphics_queue; VkQueue graphics_queue;
VkQueue compute_queue; VkQueue compute_queue;
VkQueue present_queue; VkQueue present_queue;
uint32_t graphics_family;
uint32_t compute_family;
uint32_t present_family;
vy_native_window native_window;
VkPhysicalDeviceDescriptorIndexingProperties descriptor_indexing_props; VkPhysicalDeviceDescriptorIndexingProperties descriptor_indexing_props;
VkPhysicalDeviceProperties phys_device_props; VkPhysicalDeviceProperties phys_device_props;

View File

@ -4,6 +4,7 @@
#define VY_VK_DONT_DEFINE_GPU_GLOBAL #define VY_VK_DONT_DEFINE_GPU_GLOBAL
#include "gpu.h" #include "gpu.h"
#include "swapchain.h"
#include "runtime/config.h" #include "runtime/config.h"
#include "runtime/renderer_api.h" #include "runtime/renderer_api.h"
@ -81,9 +82,14 @@ DebugUtilsMessengerCb(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
return VK_FALSE; return VK_FALSE;
} }
extern vy_cvar r_VkPreferredSwapchainImages;
extern vy_cvar r_VkPreferMailboxMode;
VY_DLLEXPORT void vyRegisterCVars(void) { VY_DLLEXPORT void vyRegisterCVars(void) {
vyRegisterCVAR(&r_VkEnableAPIAllocTracking); vyRegisterCVAR(&r_VkEnableAPIAllocTracking);
vyRegisterCVAR(&r_VkPhysDeviceName); vyRegisterCVAR(&r_VkPhysDeviceName);
vyRegisterCVAR(&r_VkPreferredSwapchainImages);
vyRegisterCVAR(&r_VkPreferMailboxMode);
} }
static int CreateInstance(void) { static int CreateInstance(void) {
@ -178,6 +184,8 @@ static int CreateInstance(void) {
static int CreateSurface(const vy_renderer_init_info *info) { static int CreateSurface(const vy_renderer_init_info *info) {
#ifdef _WIN32 #ifdef _WIN32
g_gpu.native_window.hInstance = info->hInstance;
g_gpu.native_window.hWnd = info->hWnd;
VkWin32SurfaceCreateInfoKHR surface_info = { VkWin32SurfaceCreateInfoKHR surface_info = {
.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR,
.hinstance = info->hInstance, .hinstance = info->hInstance,
@ -191,6 +199,8 @@ static int CreateSurface(const vy_renderer_init_info *info) {
else else
return -100; return -100;
#elif defined(VY_USE_XLIB_KHR) #elif defined(VY_USE_XLIB_KHR)
g_gpu.native_window.display = info->display;
g_gpu.native_window.window = info->window;
VkXlibSurfaceCreateInfoKHR surface_info = { VkXlibSurfaceCreateInfoKHR surface_info = {
.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, .sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
.dpy = info->display, .dpy = info->display,
@ -395,6 +405,10 @@ static int CreateDevice(void) {
vy_queue_indices queue_indices = vy_queue_indices queue_indices =
RetrieveQueueIndices(g_gpu.phys_device, g_gpu.surface); RetrieveQueueIndices(g_gpu.phys_device, g_gpu.surface);
g_gpu.compute_family = queue_indices.compute;
g_gpu.graphics_family = queue_indices.graphics;
g_gpu.present_family = queue_indices.present;
float priority = 1.f; float priority = 1.f;
uint32_t distinct_queue_count = 1; uint32_t distinct_queue_count = 1;
@ -482,6 +496,9 @@ VY_DLLEXPORT int vyInit(const vy_renderer_init_info *info) {
if (res != 0) if (res != 0)
return res; return res;
res = CreateDevice(); res = CreateDevice();
if (res != 0)
return res;
res = vyCreateSwapchain();
if (res != 0) if (res != 0)
return res; return res;
@ -490,7 +507,8 @@ VY_DLLEXPORT int vyInit(const vy_renderer_init_info *info) {
VY_DLLEXPORT void vyShutdown(void) { VY_DLLEXPORT void vyShutdown(void) {
vyLog("vk", "Shutdown"); vyLog("vk", "Shutdown");
vkDeviceWaitIdle(g_gpu.device);
vyDestroySwapchain();
vkDestroyDevice(g_gpu.device, g_gpu.alloc_cb); vkDestroyDevice(g_gpu.device, g_gpu.alloc_cb);
vkDestroySurfaceKHR(g_gpu.instance, g_gpu.surface, g_gpu.alloc_cb); vkDestroySurfaceKHR(g_gpu.instance, g_gpu.surface, g_gpu.alloc_cb);
vkDestroyInstance(g_gpu.instance, g_gpu.alloc_cb); vkDestroyInstance(g_gpu.instance, g_gpu.alloc_cb);

198
src/renderer/vk/swapchain.c Normal file
View File

@ -0,0 +1,198 @@
#define VY_VK_DONT_DEFINE_SWAPCHAIN_GLOBAL
#include "swapchain.h"
#include "gpu.h"
#include "runtime/config.h"
#include <stdlib.h>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#elif defined(VY_USE_XLIB)
#include <X11/Xlib.h>
#endif
VY_CVAR_I(r_VkPreferredSwapchainImages,
"Preferred number of swapchain iamges. [2/3] Default: 2",
2);
VY_CVAR_I(r_VkPreferMailboxMode,
"Prefer mailbox present mode over fifo mode. [0/1] Default: 0",
1);
typedef struct {
VkPresentModeKHR present_mode;
VkSurfaceFormatKHR surface_format;
VkExtent2D extent;
VkSurfaceTransformFlagsKHR pre_transform;
} vy_device_swapchain_parameters;
static vy_device_swapchain_parameters DetermineSwapchainParameters(void) {
vy_device_swapchain_parameters params;
/* determine presentation mode. FIFO should always be available */
params.present_mode = VK_PRESENT_MODE_FIFO_KHR;
if (r_VkPreferMailboxMode.i) {
VkPresentModeKHR modes[6];
uint32_t count = 6;
vkGetPhysicalDeviceSurfacePresentModesKHR(g_gpu.phys_device,
g_gpu.surface,
&count,
modes);
for (uint32_t i = 0; i < count; ++i) {
if (modes[i] == VK_PRESENT_MODE_MAILBOX_KHR)
params.present_mode = VK_PRESENT_MODE_MAILBOX_KHR;
}
}
/* Determine surface format */
VkSurfaceFormatKHR formats[64];
uint32_t format_count = 64;
vkGetPhysicalDeviceSurfaceFormatsKHR(g_gpu.phys_device,
g_gpu.surface,
&format_count,
formats);
params.surface_format = formats[0];
for (uint32_t i = 0; i < format_count; ++i) {
if (formats[i].format == VK_FORMAT_B8G8R8A8_SRGB &&
formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
params.surface_format = formats[i];
break;
}
}
/* get extent */
VkSurfaceCapabilitiesKHR capabilities;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(g_gpu.phys_device,
g_gpu.surface,
&capabilities);
if (capabilities.currentExtent.width != UINT32_MAX) {
params.extent = capabilities.currentExtent;
} else {
#ifdef _WIN32
RECT client_area;
GetClientRect(g_gpu.native_window.hWnd, &client_area);
params.extent.width = (uint32_t)client_area.right;
params.extent.height = (uint32_t)client_area.bottom;
#else
XWindowAttributes attribs;
XGetWindowAttributes(g_gpu.native_window.display,
g_gpu.native_window.window,
&attribs);
params.extent.width = (uint32_t)attribs.width;
params.extent.height = (uint32_t)attribs.height;
#endif
}
params.pre_transform = capabilities.currentTransform;
return params;
}
vy_swapchain g_swapchain;
int vyCreateSwapchain(void) {
vy_device_swapchain_parameters device_params =
DetermineSwapchainParameters();
uint32_t image_count = r_VkPreferredSwapchainImages.i;
if (image_count < 2)
image_count = 2;
else if (image_count > 3)
image_count = 3;
VkSwapchainCreateInfoKHR swapchain_info = {
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
.surface = g_gpu.surface,
.presentMode = device_params.present_mode,
.imageFormat = device_params.surface_format.format,
.imageColorSpace = device_params.surface_format.colorSpace,
.imageExtent = device_params.extent,
.preTransform = device_params.pre_transform,
.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
.clipped = VK_TRUE,
.minImageCount = image_count,
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
.imageArrayLayers = 1,
.oldSwapchain = VK_NULL_HANDLE,
};
uint32_t queue_families[] = {g_gpu.graphics_family, g_gpu.present_family};
if (g_gpu.present_family != g_gpu.graphics_family) {
swapchain_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
swapchain_info.pQueueFamilyIndices = queue_families;
swapchain_info.queueFamilyIndexCount = 2;
} else {
swapchain_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
swapchain_info.pQueueFamilyIndices = NULL;
swapchain_info.queueFamilyIndexCount = 0;
}
if (vkCreateSwapchainKHR(g_gpu.device,
&swapchain_info,
g_gpu.alloc_cb,
&g_swapchain.swapchain) != VK_SUCCESS) {
vyReportError("vk", "Failed to create the swapchain");
return -50;
}
g_swapchain.format = device_params.surface_format.format;
/* Retrieve images */
g_swapchain.image_count = 0;
vkGetSwapchainImagesKHR(g_gpu.device,
g_swapchain.swapchain,
&g_swapchain.image_count,
NULL);
if (g_swapchain.image_count > VY_VK_MAX_SWAPCHAIN_IMAGES) {
vyReportError("vk",
"Unsupported number of swapchain images: %u",
g_swapchain.image_count);
return -51;
}
vkGetSwapchainImagesKHR(g_gpu.device,
g_swapchain.swapchain,
&g_swapchain.image_count,
g_swapchain.images);
/* Create image views */
for (uint32_t i = 0; i < g_swapchain.image_count; ++i) {
VkImageViewCreateInfo view_info = {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = g_swapchain.images[i],
.format = g_swapchain.format,
.viewType = VK_IMAGE_VIEW_TYPE_2D,
.components = {
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
.g = VK_COMPONENT_SWIZZLE_IDENTITY,
.b = VK_COMPONENT_SWIZZLE_IDENTITY,
.a = VK_COMPONENT_SWIZZLE_IDENTITY,
},
.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseArrayLayer = 0,
.layerCount = 1,
.baseMipLevel = 0,
.levelCount = 1,
},
};
if (vkCreateImageView(g_gpu.device,
&view_info,
g_gpu.alloc_cb,
&g_swapchain.image_views[i]) != VK_SUCCESS) {
vyReportError("vk",
"Failed to create an image view for the swapchain.");
return -52;
}
}
return 0;
}
void vyDestroySwapchain(void) {
for (uint32_t i = 0; i < g_swapchain.image_count; ++i) {
vkDestroyImageView(g_gpu.device,
g_swapchain.image_views[i],
g_gpu.alloc_cb);
}
vkDestroySwapchainKHR(g_gpu.device, g_swapchain.swapchain, g_gpu.alloc_cb);
}

View File

@ -0,0 +1,24 @@
#ifndef VY_VK_SWAPCHAIN_H
#define VY_VK_SWAPCHAIN_H
#include <volk/volk.h>
#define VY_VK_MAX_SWAPCHAIN_IMAGES 3
typedef struct {
VkSwapchainKHR swapchain;
VkImage images[VY_VK_MAX_SWAPCHAIN_IMAGES];
VkImageView image_views[VY_VK_MAX_SWAPCHAIN_IMAGES];
uint32_t image_count;
VkFormat format;
} vy_swapchain;
#ifndef VY_VK_DONT_DEFINE_SWAPCHAIN_GLOBAL
extern vy_swapchain g_swapchain;
#endif
int vyCreateSwapchain(void);
void vyDestroySwapchain(void);
#endif