Implement swapchain creation

This commit is contained in:
Bill Currie 2019-07-11 00:58:14 +09:00
parent 4eb6cf6f9e
commit c0bc5cfad6
6 changed files with 166 additions and 1 deletions

View file

@ -62,6 +62,14 @@ INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
#else
INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
(vkCreateDebugUtilsMessengerEXT, VK_EXT_DEBUG_UTILS_EXTENSION_NAME)
INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
(vkGetPhysicalDeviceSurfaceSupportKHR, VK_KHR_SURFACE_EXTENSION_NAME)
INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
(vkGetPhysicalDeviceSurfacePresentModesKHR, VK_KHR_SURFACE_EXTENSION_NAME)
INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
(vkGetPhysicalDeviceSurfaceCapabilitiesKHR, VK_KHR_SURFACE_EXTENSION_NAME)
INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
(vkGetPhysicalDeviceSurfaceFormatsKHR, VK_KHR_SURFACE_EXTENSION_NAME)
#endif
#undef INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
@ -79,4 +87,11 @@ DEVICE_LEVEL_VULKAN_FUNCTION (vkGetDeviceQueue)
#define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(function, extension)
#endif
DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
(vkCreateSwapchainKHR, VK_KHR_SURFACE_EXTENSION_NAME)
DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
(vkDestroySwapchainKHR, VK_KHR_SURFACE_EXTENSION_NAME)
DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
(vkGetSwapchainImagesKHR, VK_KHR_SURFACE_EXTENSION_NAME)
#undef DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION

View file

@ -32,6 +32,7 @@
typedef struct VulkanDevice_s {
VkDevice device;
int32_t queueFamily;
VkQueue queue;
VkSurfaceKHR surface;

View file

@ -31,6 +31,7 @@
#include "QF/Vulkan/cvars.h"
struct vulkan_ctx_s;
void Vulkan_CreateSwapchain (struct vulkan_ctx_s *ctx);
void Vulkan_CreateDevice (struct vulkan_ctx_s *ctx);
void Vulkan_Init_Common (struct vulkan_ctx_s *ctx);
void Vulkan_Shutdown_Common (struct vulkan_ctx_s *ctx);

View file

@ -27,6 +27,9 @@ typedef struct vulkan_ctx_s {
VkInstance instance;
VkPhysicalDevice physDevice;
VkDevice device;
VkSwapchainKHR swapchain;
int32_t numSwapchainImages;
VkImage *swapchainImages;
#define EXPORTED_VULKAN_FUNCTION(fname) PFN_##fname fname;
#define GLOBAL_LEVEL_VULKAN_FUNCTION(fname) PFN_##fname fname;
#include "QF/Vulkan/funclist.h"

View file

@ -159,6 +159,13 @@ vulkan_vid_render_create_context (void)
vulkan_ctx->create_window (vulkan_ctx);
vulkan_ctx->dev->surface = vulkan_ctx->create_surface (vulkan_ctx);
Sys_Printf ("%p\n", vulkan_ctx->dev->surface);
Vulkan_CreateSwapchain (vulkan_ctx);
Sys_Printf ("%p %d", vulkan_ctx->swapchain,
vulkan_ctx->numSwapchainImages);
for (int32_t i = 0; i < vulkan_ctx->numSwapchainImages; i++) {
Sys_Printf (" %p", vulkan_ctx->swapchainImages[i]);
}
Sys_Printf ("\n");
}
static void

View file

@ -42,6 +42,7 @@
#include "QF/cvar.h"
#include "QF/dstring.h"
#include "QF/input.h"
#include "QF/mathlib.h"
#include "QF/qargs.h"
#include "QF/quakefs.h"
#include "QF/sys.h"
@ -57,6 +58,25 @@
#include "util.h"
static cvar_t *vulkan_presentation_mode;
static void
vulkan_presentation_mode_f (cvar_t *var)
{
if (!strcmp (var->string, "immediate")) {
var->int_val = VK_PRESENT_MODE_IMMEDIATE_KHR;
} else if (!strcmp (var->string, "fifo")) {
var->int_val = VK_PRESENT_MODE_FIFO_KHR;
} else if (!strcmp (var->string, "relaxed")) {
var->int_val = VK_PRESENT_MODE_FIFO_RELAXED_KHR;
} else if (!strcmp (var->string, "mailbox")) {
var->int_val = VK_PRESENT_MODE_MAILBOX_KHR;
} else {
Sys_Printf ("Invalid presentation mode, using fifo\n");
var->int_val = VK_PRESENT_MODE_FIFO_KHR;
}
}
void
Vulkan_Init_Cvars ()
{
@ -65,6 +85,11 @@ Vulkan_Init_Cvars ()
"enable LunarG Standard Validation "
"Layer if available (requires instance "
"restart).");
// FIXME implement fallback choices (instead of just fifo)
vulkan_presentation_mode = Cvar_Get ("vulkan_presentation_mode", "mailbox",
CVAR_NONE, vulkan_presentation_mode_f,
"desired presentation mode (may fall "
"back to fifo).");
}
static const char *instance_extensions[] = {
@ -118,7 +143,7 @@ load_device_funcs (VulkanInstance_t *inst, VulkanDevice_t *dev)
}
#define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name, ext) \
if (inst->extension_enabled (vtx, ext)) { \
if (inst->extension_enabled (inst, ext)) { \
dev->name = (PFN_##name) inst->vkGetDeviceProcAddr (dev->device, \
#name); \
if (!dev->name) { \
@ -208,7 +233,120 @@ Vulkan_CreateDevice (vulkan_ctx_t *ctx)
ctx->dev = device;
ctx->device = device->device;
ctx->physDevice = phys->device;
device->queueFamily = family;
return;
}
}
}
void
Vulkan_CreateSwapchain (vulkan_ctx_t *ctx)
{
VkBool32 supported;
ctx->vtx->vkGetPhysicalDeviceSurfaceSupportKHR (ctx->physDevice,
ctx->dev->queueFamily,
ctx->dev->surface,
&supported);
if (!supported) {
Sys_Error ("unsupported surface for swapchain");
}
uint32_t numModes;
VkPresentModeKHR *modes;
VkPresentModeKHR useMode = VK_PRESENT_MODE_FIFO_KHR;;
ctx->vtx->vkGetPhysicalDeviceSurfacePresentModesKHR (ctx->physDevice,
ctx->dev->surface,
&numModes, 0);
modes = alloca (numModes * sizeof (VkPresentModeKHR));
ctx->vtx->vkGetPhysicalDeviceSurfacePresentModesKHR (ctx->physDevice,
ctx->dev->surface,
&numModes, modes);
for (uint32_t i = 0; i < numModes; i++) {
if ((int) modes[i] == vulkan_presentation_mode->int_val) {
useMode = modes[i];
}
}
Sys_MaskPrintf (SYS_VULKAN, "presentation mode: %d (%d)\n", useMode,
vulkan_presentation_mode->int_val);
VkSurfaceCapabilitiesKHR surfCaps;
ctx->vtx->vkGetPhysicalDeviceSurfaceCapabilitiesKHR (ctx->physDevice,
ctx->dev->surface,
&surfCaps);
uint32_t numImages = surfCaps.minImageCount + 1;
if (surfCaps.maxImageCount > 0 && numImages > surfCaps.maxImageCount) {
numImages = surfCaps.maxImageCount;
}
VkExtent2D imageSize = {viddef.width, viddef.height};
if (surfCaps.currentExtent.width == ~0u) {
imageSize.width = bound (surfCaps.minImageExtent.width,
imageSize.width,
surfCaps.maxImageExtent.width);
imageSize.height = bound (surfCaps.minImageExtent.height,
imageSize.height,
surfCaps.maxImageExtent.height);
} else {
imageSize = surfCaps.currentExtent;
}
Sys_MaskPrintf (SYS_VULKAN, "%d [%d, %d]\n", numImages,
imageSize.width, imageSize.height);
VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
imageUsage &= surfCaps.supportedUsageFlags;
VkSurfaceTransformFlagBitsKHR surfTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
uint32_t numFormats;
ctx->vtx->vkGetPhysicalDeviceSurfaceFormatsKHR (ctx->physDevice,
ctx->dev->surface,
&numFormats, 0);
VkSurfaceFormatKHR *formats = alloca (numFormats * sizeof (*formats));
ctx->vtx->vkGetPhysicalDeviceSurfaceFormatsKHR (ctx->physDevice,
ctx->dev->surface,
&numFormats, formats);
VkSurfaceFormatKHR useFormat = {VK_FORMAT_R8G8B8A8_UNORM,
VK_COLOR_SPACE_SRGB_NONLINEAR_KHR};
if (numFormats > 1) {
uint32_t i;
for (i = 0; i < numFormats; i++) {
if (formats[i].format == useFormat.format
&& formats[i].colorSpace == useFormat.colorSpace) {
break;
}
}
if (i == numFormats) {
useFormat = formats[0];
}
} else if (numFormats == 1 && formats[0].format != VK_FORMAT_UNDEFINED) {
useFormat = formats[0];
}
VkSwapchainCreateInfoKHR createInfo = {
VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, 0, 0,
ctx->dev->surface,
numImages,
useFormat.format, useFormat.colorSpace,
imageSize,
1, // array layers
imageUsage,
VK_SHARING_MODE_EXCLUSIVE,
0, 0,
surfTransform,
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
useMode,
VK_TRUE,
ctx->swapchain
};
VkSwapchainKHR swapchain;
ctx->dev->vkCreateSwapchainKHR (ctx->device, &createInfo, 0, &swapchain);
if (ctx->swapchain != swapchain) {
ctx->dev->vkDestroySwapchainKHR (ctx->device, ctx->swapchain, 0);
}
ctx->swapchain = swapchain;
ctx->dev->vkGetSwapchainImagesKHR (ctx->device, swapchain, &numImages, 0);
ctx->swapchainImages = malloc (numImages * sizeof (*ctx->swapchainImages));
ctx->dev->vkGetSwapchainImagesKHR (ctx->device, swapchain, &numImages,
ctx->swapchainImages);
ctx->numSwapchainImages = numImages;
}