From 6937e5588865e7a24a759f879ce90ff982904994 Mon Sep 17 00:00:00 2001 From: Kevin Trogant Date: Wed, 25 Oct 2023 23:24:04 +0200 Subject: [PATCH] feat: create vulkan swapchain --- meson.build | 2 + pch/vk_pch.h | 10 ++ src/renderer/vk/gpu.h | 24 +++++ src/renderer/vk/init.c | 20 +++- src/renderer/vk/swapchain.c | 198 ++++++++++++++++++++++++++++++++++++ src/renderer/vk/swapchain.h | 24 +++++ 6 files changed, 277 insertions(+), 1 deletion(-) create mode 100644 src/renderer/vk/swapchain.c create mode 100644 src/renderer/vk/swapchain.h diff --git a/meson.build b/meson.build index 20ee6ea..79541a7 100644 --- a/meson.build +++ b/meson.build @@ -78,8 +78,10 @@ if vk_dep.found() vk_renderer_lib = library('vyvk', # Project Sources 'src/renderer/vk/gpu.h', + 'src/renderer/vk/swapchain.h', 'src/renderer/vk/init.c', + 'src/renderer/vk/swapchain.c', 'src/renderer/vk/gfx_pipelines.c', # Contrib Sources diff --git a/pch/vk_pch.h b/pch/vk_pch.h index e69de29..ee6fba0 100644 --- a/pch/vk_pch.h +++ b/pch/vk_pch.h @@ -0,0 +1,10 @@ +#include + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#if defined(VY_USE_XLIB) +#include +#endif diff --git a/src/renderer/vk/gpu.h b/src/renderer/vk/gpu.h index 8de3996..ec75cc2 100644 --- a/src/renderer/vk/gpu.h +++ b/src/renderer/vk/gpu.h @@ -3,6 +3,25 @@ #include + +#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 { VkInstance instance; VkDebugUtilsMessengerEXT messenger; @@ -13,6 +32,11 @@ typedef struct { VkQueue graphics_queue; VkQueue compute_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; VkPhysicalDeviceProperties phys_device_props; diff --git a/src/renderer/vk/init.c b/src/renderer/vk/init.c index f974599..83fdb1e 100644 --- a/src/renderer/vk/init.c +++ b/src/renderer/vk/init.c @@ -4,6 +4,7 @@ #define VY_VK_DONT_DEFINE_GPU_GLOBAL #include "gpu.h" +#include "swapchain.h" #include "runtime/config.h" #include "runtime/renderer_api.h" @@ -81,9 +82,14 @@ DebugUtilsMessengerCb(VkDebugUtilsMessageSeverityFlagBitsEXT severity, return VK_FALSE; } +extern vy_cvar r_VkPreferredSwapchainImages; +extern vy_cvar r_VkPreferMailboxMode; + VY_DLLEXPORT void vyRegisterCVars(void) { vyRegisterCVAR(&r_VkEnableAPIAllocTracking); vyRegisterCVAR(&r_VkPhysDeviceName); + vyRegisterCVAR(&r_VkPreferredSwapchainImages); + vyRegisterCVAR(&r_VkPreferMailboxMode); } static int CreateInstance(void) { @@ -178,6 +184,8 @@ static int CreateInstance(void) { static int CreateSurface(const vy_renderer_init_info *info) { #ifdef _WIN32 + g_gpu.native_window.hInstance = info->hInstance; + g_gpu.native_window.hWnd = info->hWnd; VkWin32SurfaceCreateInfoKHR surface_info = { .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, .hinstance = info->hInstance, @@ -191,6 +199,8 @@ static int CreateSurface(const vy_renderer_init_info *info) { else return -100; #elif defined(VY_USE_XLIB_KHR) + g_gpu.native_window.display = info->display; + g_gpu.native_window.window = info->window; VkXlibSurfaceCreateInfoKHR surface_info = { .sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, .dpy = info->display, @@ -395,6 +405,10 @@ static int CreateDevice(void) { vy_queue_indices queue_indices = 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; uint32_t distinct_queue_count = 1; @@ -482,6 +496,9 @@ VY_DLLEXPORT int vyInit(const vy_renderer_init_info *info) { if (res != 0) return res; res = CreateDevice(); + if (res != 0) + return res; + res = vyCreateSwapchain(); if (res != 0) return res; @@ -490,7 +507,8 @@ VY_DLLEXPORT int vyInit(const vy_renderer_init_info *info) { VY_DLLEXPORT void vyShutdown(void) { vyLog("vk", "Shutdown"); - + vkDeviceWaitIdle(g_gpu.device); + vyDestroySwapchain(); vkDestroyDevice(g_gpu.device, g_gpu.alloc_cb); vkDestroySurfaceKHR(g_gpu.instance, g_gpu.surface, g_gpu.alloc_cb); vkDestroyInstance(g_gpu.instance, g_gpu.alloc_cb); diff --git a/src/renderer/vk/swapchain.c b/src/renderer/vk/swapchain.c new file mode 100644 index 0000000..dab05bd --- /dev/null +++ b/src/renderer/vk/swapchain.c @@ -0,0 +1,198 @@ +#define VY_VK_DONT_DEFINE_SWAPCHAIN_GLOBAL +#include "swapchain.h" +#include "gpu.h" + +#include "runtime/config.h" + +#include + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#elif defined(VY_USE_XLIB) +#include +#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); +} \ No newline at end of file diff --git a/src/renderer/vk/swapchain.h b/src/renderer/vk/swapchain.h new file mode 100644 index 0000000..3f47b7f --- /dev/null +++ b/src/renderer/vk/swapchain.h @@ -0,0 +1,24 @@ +#ifndef VY_VK_SWAPCHAIN_H +#define VY_VK_SWAPCHAIN_H + +#include + +#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