feat: create vulkan swapchain
This commit is contained in:
parent
904a26374b
commit
6937e55888
@ -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
|
||||
|
10
pch/vk_pch.h
10
pch/vk_pch.h
@ -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
|
@ -3,6 +3,25 @@
|
||||
|
||||
#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 {
|
||||
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;
|
||||
|
@ -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);
|
||||
|
198
src/renderer/vk/swapchain.c
Normal file
198
src/renderer/vk/swapchain.c
Normal 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);
|
||||
}
|
24
src/renderer/vk/swapchain.h
Normal file
24
src/renderer/vk/swapchain.h
Normal 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
|
Loading…
Reference in New Issue
Block a user