Completely rework the vulkan related api

Things don't work yet, but this feels much cleaner.
This commit is contained in:
Bill Currie 2019-07-12 13:15:25 +09:00
parent b5828bc2ce
commit 75f19f7243
18 changed files with 817 additions and 804 deletions

View file

@ -2,5 +2,6 @@
#define __QF_Vulkan_cvars_h
extern struct cvar_s *vulkan_use_validation;
extern struct cvar_s *vulkan_presentation_mode;
#endif//__QF_Vulkan_cvars_h

View file

@ -0,0 +1,26 @@
#ifndef __QF_Vulkan_device_h
#define __QF_Vulkan_device_h
typedef struct qfv_devfuncs_s {
#define DEVICE_LEVEL_VULKAN_FUNCTION(name) PFN_##name name;
#define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name,ext) PFN_##name name;
#include "QF/Vulkan/funclist.h"
} qfv_devfuncs_t;
struct qfv_instance_s;
typedef struct qfv_device_s {
VkDevice dev;
VkPhysicalDevice physDev;
qfv_devfuncs_t *funcs;
int32_t queueFamily;
VkQueue queue;
struct strset_s *enabled_extensions;
int (*extension_enabled) (struct qfv_device_s *inst,
const char *ext);
} qfv_device_t;
struct vulkan_ctx_s;
qfv_device_t *QFV_CreateDevice(struct vulkan_ctx_s *ctx,
const char **extensions);
#endif//__QF_Vulkan_swapchain_h

View file

@ -38,28 +38,6 @@ INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceMemoryProperties)
#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(function, extension)
#endif
#if defined(VK_USE_PLATFORM_XLIB_KHR)
INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
(vkGetPhysicalDeviceXlibPresentationSupportKHR,
VK_KHR_XLIB_SURFACE_EXTENSION_NAME)
INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
(vkCreateXlibSurfaceKHR,
VK_KHR_XLIB_SURFACE_EXTENSION_NAME)
#elif defined(VK_USE_PLATFORM_WIN32_KHR)
INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
(vkGetPhysicalDeviceWin32PresentationSupportKHR,
VK_KHR_WIN32_SURFACE_EXTENSION_NAME)
INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
(vkCreateWin32SurfaceKHR,
VK_KHR_WIN32_SURFACE_EXTENSION_NAME)
#elif defined(VK_USE_PLATFORM_XCB_KHR)
INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
(vkGetPhysicalDeviceXcbPresentationSupportKHR,
VK_KHR_XCB_SURFACE_EXTENSION_NAME)
INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
(vkCreateXcbSurfaceKHR,
VK_KHR_XCB_SURFACE_EXTENSION_NAME)
#else
INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
(vkCreateDebugUtilsMessengerEXT, VK_EXT_DEBUG_UTILS_EXTENSION_NAME)
INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
@ -70,10 +48,38 @@ 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
#ifndef PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION
#define PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION(function, extension)
#endif
#if defined(VK_USE_PLATFORM_XLIB_KHR)
PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION
(vkGetPhysicalDeviceXlibPresentationSupportKHR,
VK_KHR_XLIB_SURFACE_EXTENSION_NAME)
PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION
(vkCreateXlibSurfaceKHR,
VK_KHR_XLIB_SURFACE_EXTENSION_NAME)
#elif defined(VK_USE_PLATFORM_WIN32_KHR)
PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION
(vkGetPhysicalDeviceWin32PresentationSupportKHR,
VK_KHR_WIN32_SURFACE_EXTENSION_NAME)
PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION
(vkCreateWin32SurfaceKHR,
VK_KHR_WIN32_SURFACE_EXTENSION_NAME)
#elif defined(VK_USE_PLATFORM_XCB_KHR)
PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION
(vkGetPhysicalDeviceXcbPresentationSupportKHR,
VK_KHR_XCB_SURFACE_EXTENSION_NAME)
PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION
(vkCreateXcbSurfaceKHR,
VK_KHR_XCB_SURFACE_EXTENSION_NAME)
#endif
#undef PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION
#ifndef DEVICE_LEVEL_VULKAN_FUNCTION
#define DEVICE_LEVEL_VULKAN_FUNCTION(function)
#endif

View file

@ -1,88 +0,0 @@
/*
Copyright (C) 2019 Bill Currie <bill@taniwha.org>
Author: Bill Currie
Date: 2019/6/29
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifndef __QF_Vulkan_init_h
#define __QF_Vulkan_init_h
#include <vulkan/vulkan.h>
#include "QF/qtypes.h"
typedef struct VulkanDevice_s {
VkDevice device;
int32_t queueFamily;
VkQueue queue;
VkSurfaceKHR surface;
#define DEVICE_LEVEL_VULKAN_FUNCTION(name) PFN_##name name;
#define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name,ext) PFN_##name name;
#include "QF/Vulkan/funclist.h"
} VulkanDevice_t;
typedef struct {
VkPhysicalDevice device;
VkPhysicalDeviceFeatures features;
VkPhysicalDeviceProperties properties;
uint32_t numLayers;
VkLayerProperties *layers;
uint32_t numExtensions;
VkExtensionProperties *extensions;
VkPhysicalDeviceMemoryProperties memory;
uint32_t numQueueFamilies;
VkQueueFamilyProperties *queueFamilies;
} VulkanPhysDevice_t;
typedef struct VulkanInstance_s {
VkInstance instance;
struct strset_s *enabled_extensions;
int (*extension_enabled) (struct VulkanInstance_s *inst,
const char *ext);
VkDebugUtilsMessengerEXT debug_callback;
uint32_t numDevices;
VulkanPhysDevice_t *devices;
#define INSTANCE_LEVEL_VULKAN_FUNCTION(name) PFN_##name name;
#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name,ext) PFN_##name name;
#include "QF/Vulkan/funclist.h"
} VulkanInstance_t;
extern const char * const vulkanValidationLayers[];
void Vulkan_Init_Cvars (void);
struct vulkan_ctx_s;
VulkanInstance_t *Vulkan_CreateInstance (struct vulkan_ctx_s *ctx,
const char *appName,
uint32_t appVersion,
const char **layers,
const char **extensions);
void Vulkan_DestroyInstance (VulkanInstance_t *instance);
int Vulkan_ExtensionsSupported (const VkExtensionProperties *extensions,
int numExtensions,
const char * const *requested);
int Vulkan_LayersSupported (const VkLayerProperties *extensions,
int numLayers,
const char * const *requested);
#endif // __QF_Vulkan_init_h

View file

@ -0,0 +1,55 @@
/*
Copyright (C) 2019 Bill Currie <bill@taniwha.org>
Author: Bill Currie
Date: 2019/6/29
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifndef __QF_Vulkan_instance_h
#define __QF_Vulkan_instance_h
#include <vulkan/vulkan.h>
#include "QF/qtypes.h"
typedef struct qfv_instfuncs_s {
#define INSTANCE_LEVEL_VULKAN_FUNCTION(name) PFN_##name name;
#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name,ext) PFN_##name name;
#include "QF/Vulkan/funclist.h"
} qfv_instfuncs_t;
typedef struct qfv_instance_s {
VkInstance instance;
qfv_instfuncs_t *funcs;
struct strset_s *enabled_extensions;
int (*extension_enabled) (struct qfv_instance_s *inst,
const char *ext);
} qfv_instance_t;
struct vulkan_ctx_s;
qfv_instance_t *QFV_CreateInstance (struct vulkan_ctx_s *ctx,
const char *appName,
uint32_t appVersion,
const char **layers,
const char **extensions);
void QFV_DestroyInstance (qfv_instance_t *instance);
#endif // __QF_Vulkan_instance_h

View file

@ -30,6 +30,11 @@
#include "QF/Vulkan/cvars.h"
#ifndef VK_NO_PROTOTYPES
#define VK_NO_PROTOTYPES
#endif
#include <vulkan/vulkan.h>
struct vulkan_ctx_s;
void Vulkan_CreateSwapchain (struct vulkan_ctx_s *ctx);
void Vulkan_CreateDevice (struct vulkan_ctx_s *ctx);

View file

@ -0,0 +1,17 @@
#ifndef __QF_Vulkan_swapchain_h
#define __QF_Vulkan_swapchain_h
typedef struct qfv_swapchain_s {
VkDevice dev;
struct qfv_devfuncs_s *funcs;
VkSurfaceKHR surface;
VkSwapchainKHR swapchain;
int32_t numImages;
VkImage *images;
} qfv_swapchain_t;
struct vulkan_ctx_s;
qfv_swapchain_t *QFV_CreateSwapchain (struct vulkan_ctx_s *ctx,
VkSwapchainKHR old_swapchain);
#endif//__QF_Vulkan_swapchain_h

View file

@ -6,14 +6,11 @@
#endif
#include <vulkan/vulkan.h>
struct VulkanInstance_s;
typedef struct vulkan_ctx_s {
void (*load_vulkan) (struct vulkan_ctx_s *ctx);
void (*unload_vulkan) (struct vulkan_ctx_s *ctx);
const char **required_extensions;
int (*extension_enabled) (struct VulkanInstance_s *inst,
const char *ext);
struct vulkan_presentation_s *presentation;
int (*get_presentation_support) (struct vulkan_ctx_s *ctx,
VkPhysicalDevice physicalDevice,
@ -22,14 +19,10 @@ typedef struct vulkan_ctx_s {
void (*create_window) (struct vulkan_ctx_s *ctx);
VkSurfaceKHR (*create_surface) (struct vulkan_ctx_s *ctx);
struct VulkanInstance_s *vtx;
struct VulkanDevice_s *dev;
VkInstance instance;
VkPhysicalDevice physDevice;
VkDevice device;
VkSwapchainKHR swapchain;
int32_t numSwapchainImages;
VkImage *swapchainImages;
struct qfv_instance_s *instance;
struct qfv_device_s *device;
struct qfv_swapchain_s *swapchain;
VkSurfaceKHR surface; //FIXME surface = window, so "contains" swapchain
#define EXPORTED_VULKAN_FUNCTION(fname) PFN_##fname fname;
#define GLOBAL_LEVEL_VULKAN_FUNCTION(fname) PFN_##fname fname;
#include "QF/Vulkan/funclist.h"

View file

@ -37,7 +37,9 @@
#include "QF/plugin/vid_render.h"
#include "QF/Vulkan/qf_vid.h"
#include "QF/Vulkan/init.h"
#include "QF/Vulkan/device.h"
#include "QF/Vulkan/instance.h"
#include "QF/Vulkan/swapchain.h"
#include "mod_internal.h"
#include "r_internal.h"
@ -150,20 +152,20 @@ vulkan_vid_render_choose_visual (void)
{
Vulkan_CreateDevice (vulkan_ctx);
vulkan_ctx->choose_visual (vulkan_ctx);
Sys_Printf ("%p %p\n", vulkan_ctx->dev->device, vulkan_ctx->dev->queue);
Sys_Printf ("%p %p\n", vulkan_ctx->device->dev, vulkan_ctx->device->queue);
}
static void
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_ctx->surface = vulkan_ctx->create_surface (vulkan_ctx);
Sys_Printf ("%p\n", vulkan_ctx->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 ("%p %d", vulkan_ctx->swapchain->swapchain,
vulkan_ctx->swapchain->numImages);
for (int32_t i = 0; i < vulkan_ctx->swapchain->numImages; i++) {
Sys_Printf (" %p", vulkan_ctx->swapchain->images[i]);
}
Sys_Printf ("\n");
}

View file

@ -4,7 +4,9 @@ AM_CFLAGS= @PREFER_PIC@
AM_CPPFLAGS= -I$(top_srcdir)/include -DVK_NO_PROTOTYPES
vulkan_src = \
init.c \
device.c \
instance.c \
swapchain.c \
util.c \
vulkan_draw.c \
vulkan_vid_common.c

View file

@ -0,0 +1,211 @@
/*
vid_common_vulkan.c
Common Vulkan video driver functions
Copyright (C) 1996-1997 Id Software, Inc.
Copyright (C) 2019 Bill Currie <bill@taniwha.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_MATH_H
# include <math.h>
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#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"
#include "QF/va.h"
#include "QF/vid.h"
#include "QF/Vulkan/qf_vid.h"
#include "QF/Vulkan/device.h"
#include "QF/Vulkan/instance.h"
#include "compat.h"
#include "d_iface.h"
#include "r_internal.h"
#include "vid_vulkan.h"
#include "util.h"
static int
count_bits (uint32_t val)
{
int bits = 0;
while (val) {
bits += val & 1;
val >>= 1;
}
return bits;
}
static int
find_queue_family (qfv_instance_t *instance, VkPhysicalDevice dev,
uint32_t flags)
{
qfv_instfuncs_t *funcs = instance->funcs;
uint32_t numFamilies;
VkQueueFamilyProperties *queueFamilies;
int best_diff = 32;
uint32_t family = -1;
funcs->vkGetPhysicalDeviceQueueFamilyProperties (dev, &numFamilies, 0);
queueFamilies = alloca (numFamilies * sizeof (*queueFamilies));
funcs->vkGetPhysicalDeviceQueueFamilyProperties (dev, &numFamilies,
queueFamilies);
for (uint32_t i = 0; i < numFamilies; i++) {
VkQueueFamilyProperties *queue = &queueFamilies[i];
if ((queue->queueFlags & flags) == flags) {
int diff = count_bits (queue->queueFlags & ~flags);
if (diff < best_diff) {
best_diff = diff;
family = i;
}
}
}
return family;
}
static void
load_device_funcs (qfv_instance_t *inst, qfv_device_t *dev)
{
qfv_instfuncs_t *ifunc = inst->funcs;
qfv_devfuncs_t *dfunc = dev->funcs;
VkDevice device = dev->dev;
#define DEVICE_LEVEL_VULKAN_FUNCTION(name) \
dfunc->name = (PFN_##name) ifunc->vkGetDeviceProcAddr (device, #name); \
if (!dfunc->name) { \
Sys_Error ("Couldn't find device level function %s", #name); \
}
#define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name, ext) \
if (dev->extension_enabled (dev, ext)) { \
dfunc->name = (PFN_##name) ifunc->vkGetDeviceProcAddr (device, #name); \
if (!dfunc->name) { \
Sys_Printf ("Couldn't find device level function %s", #name); \
} \
}
#include "QF/Vulkan/funclist.h"
}
static int
device_extension_enabled (qfv_device_t *device, const char *ext)
{
return strset_contains (device->enabled_extensions, ext);
}
qfv_device_t *
QFV_CreateDevice (vulkan_ctx_t *ctx, const char **extensions)
{
uint32_t nlay = 1; // ensure alloca doesn't see 0 and terminated
uint32_t next = count_strings (extensions) + 1; // ensure terminated
//if (vulkan_use_validation->int_val) {
// nlay += count_strings (vulkanValidationLayers);
//}
const char **lay = alloca (nlay * sizeof (const char *));
const char **ext = alloca (next * sizeof (const char *));
// ensure there are null pointers so merge_strings can act as append
// since it does not add a null, but also make sure the counts reflect
// actual numbers
memset (lay, 0, nlay-- * sizeof (const char *));
memset (ext, 0, next-- * sizeof (const char *));
merge_strings (ext, extensions, 0);
//if (vulkan_use_validation->int_val) {
// merge_strings (lay, lay, vulkanValidationLayers);
//}
qfv_instance_t *inst = ctx->instance;
VkInstance instance = inst->instance;
qfv_instfuncs_t *ifunc = inst->funcs;
uint32_t numDevices;
ifunc->vkEnumeratePhysicalDevices (instance, &numDevices, 0);
VkPhysicalDevice *devices = alloca (numDevices * sizeof (*devices));
ifunc->vkEnumeratePhysicalDevices (instance, &numDevices, devices);
for (uint32_t i = 0; i < numDevices; i++) {
VkPhysicalDevice physdev = devices[i];
/*
if (!Vulkan_LayersSupported (phys->layers, phys->numLayers, lay)) {
continue;
}
if (!Vulkan_ExtensionsSupported (phys->extensions, phys->numExtensions,
ext)) {
continue;
}
*/
int family = find_queue_family (inst, physdev, VK_QUEUE_GRAPHICS_BIT);
if (family < 0) {
continue;
}
if (!ctx->get_presentation_support (ctx, physdev, family)) {
continue;
}
float priority = 1;
VkDeviceQueueCreateInfo qCreateInfo = {
VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, 0, 0,
family, 1, &priority
};
VkPhysicalDeviceFeatures features;
VkDeviceCreateInfo dCreateInfo = {
VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 0, 0,
1, &qCreateInfo,
nlay, lay,
next, ext,
&features
};
memset (&features, 0, sizeof (features));
qfv_device_t *device = calloc (1, sizeof (qfv_device_t)
+ sizeof (qfv_devfuncs_t));
device->funcs = (qfv_devfuncs_t *) (device + 1);
if (ifunc->vkCreateDevice (physdev, &dCreateInfo, 0,
&device->dev) == VK_SUCCESS) {
qfv_devfuncs_t *dfunc = device->funcs;
device->physDev = physdev;
load_device_funcs (inst, device);
device->queueFamily = family;
dfunc->vkGetDeviceQueue (device->dev, family, 0, &device->queue);
device->enabled_extensions = new_strset (ext);
device->extension_enabled = device_extension_enabled;
ctx->device = device;
return device;
}
free (device);
}
return 0;
}

View file

@ -1,420 +0,0 @@
/*
init.c
Copyright (C) 2019 Bill Currie <bill@taniwha.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include "QF/cvar.h"
#include "QF/dstring.h"
#include "QF/input.h"
#include "QF/qargs.h"
#include "QF/quakefs.h"
#include "QF/sys.h"
#include "QF/va.h"
#include "QF/vid.h"
#include "QF/Vulkan/init.h"
#include "vid_vulkan.h"
#include "util.h"
cvar_t *vulkan_use_validation;
static uint32_t numLayers;
static VkLayerProperties *instanceLayerProperties;
static const char **instanceLayerNames;
static uint32_t numExtensions;
static VkExtensionProperties *instanceExtensionProperties;
static const char **instanceExtensionNames;
const char * const vulkanValidationLayers[] = {
"VK_LAYER_LUNARG_standard_validation",
0,
};
static const char * const debugExtensions[] = {
VK_EXT_DEBUG_UTILS_EXTENSION_NAME,
0,
};
static const char * const device_types[] = {
"other",
"integrated gpu",
"discrete gpu",
"virtual gpu",
"cpu",
};
static void
get_instance_layers_and_extensions (vulkan_ctx_t *ctx)
{
uint32_t i;
VkLayerProperties *properties;
VkExtensionProperties *extensions;
ctx->vkEnumerateInstanceLayerProperties (&numLayers, 0);
properties = malloc (numLayers * sizeof (VkLayerProperties));
ctx->vkEnumerateInstanceLayerProperties (&numLayers, properties);
instanceLayerNames = (const char **) malloc ((numLayers + 1)
* sizeof (const char **));
for (i = 0; i < numLayers; i++) {
instanceLayerNames[i] = properties[i].layerName;
}
instanceLayerNames[i] = 0;
ctx->vkEnumerateInstanceExtensionProperties (0, &numExtensions, 0);
extensions = malloc (numExtensions * sizeof (VkLayerProperties));
ctx->vkEnumerateInstanceExtensionProperties (0, &numExtensions,
extensions);
instanceExtensionNames = (const char **) malloc ((numExtensions + 1)
* sizeof (const char **));
for (i = 0; i < numExtensions; i++) {
instanceExtensionNames[i] = extensions[i].extensionName;
}
instanceExtensionNames[i] = 0;
if (developer->int_val & SYS_VULKAN) {
for (i = 0; i < numLayers; i++) {
Sys_Printf ("%s %x %u %s\n",
properties[i].layerName,
properties[i].specVersion,
properties[i].implementationVersion,
properties[i].description);
}
for (i = 0; i < numExtensions; i++) {
Sys_Printf ("%d %s\n",
extensions[i].specVersion,
extensions[i].extensionName);
}
}
instanceLayerProperties = properties;
instanceExtensionProperties = extensions;
}
static void
init_physdev (VulkanInstance_t *instance, VkPhysicalDevice dev, VulkanPhysDevice_t *physdev)
{
physdev->device = dev;
instance->vkGetPhysicalDeviceProperties (dev, &physdev->properties);
instance->vkEnumerateDeviceLayerProperties (dev, &physdev->numLayers, 0);
physdev->layers = malloc (physdev->numLayers * sizeof (VkLayerProperties));
instance->vkEnumerateDeviceLayerProperties (dev, &physdev->numLayers,
physdev->layers);
instance->vkEnumerateDeviceExtensionProperties (dev, 0,
&physdev->numExtensions,
0);
physdev->extensions = malloc (physdev->numExtensions
* sizeof (VkExtensionProperties));
instance->vkEnumerateDeviceExtensionProperties (dev, 0,
&physdev->numExtensions,
physdev->extensions);
instance->vkGetPhysicalDeviceFeatures (dev, &physdev->features);
instance->vkGetPhysicalDeviceMemoryProperties (dev, &physdev->memory);
instance->vkGetPhysicalDeviceQueueFamilyProperties (dev,
&physdev->numQueueFamilies,
0);
physdev->queueFamilies = malloc (physdev->numQueueFamilies
* sizeof (VkQueueFamilyProperties));
instance->vkGetPhysicalDeviceQueueFamilyProperties (dev,
&physdev->numQueueFamilies,
physdev->queueFamilies);
if (developer->int_val & SYS_VULKAN) {
VkPhysicalDeviceProperties *prop = &physdev->properties;
Sys_Printf ("dev: %p\n", dev);
Sys_Printf (" %x %x\n", prop->apiVersion, prop->driverVersion);
Sys_Printf (" %x %x\n", prop->vendorID, prop->deviceID);
Sys_Printf (" %s: %s\n", device_types[prop->deviceType],
prop->deviceName);
for (uint32_t i = 0; i < physdev->numLayers; i++) {
Sys_Printf (" %s %x %u %s\n",
physdev->layers[i].layerName,
physdev->layers[i].specVersion,
physdev->layers[i].implementationVersion,
physdev->layers[i].description);
}
for (uint32_t i = 0; i < physdev->numExtensions; i++) {
Sys_Printf (" %u %s\n",
physdev->extensions[i].specVersion,
physdev->extensions[i].extensionName);
}
Sys_Printf (" memory types:\n");
for (uint32_t i = 0; i < physdev->memory.memoryTypeCount; i++) {
Sys_Printf (" %x %d\n",
physdev->memory.memoryTypes[i].propertyFlags,
physdev->memory.memoryTypes[i].heapIndex);
}
Sys_Printf (" memory heaps:\n");
for (uint32_t i = 0; i < physdev->memory.memoryHeapCount; i++) {
Sys_Printf (" %x %ld\n",
physdev->memory.memoryHeaps[i].flags,
physdev->memory.memoryHeaps[i].size);
}
Sys_Printf (" queue families:\n");
for (uint32_t i = 0; i < physdev->numQueueFamilies; i++) {
VkQueueFamilyProperties *queue = &physdev->queueFamilies[i];
VkExtent3D gran = queue->minImageTransferGranularity;
Sys_Printf (" %x %3d %3d [%d %d %d]\n",
queue->queueFlags,
queue->queueCount,
queue->timestampValidBits,
gran.width, gran.height, gran.depth);
}
}
}
static int
instance_extension_enabled (VulkanInstance_t *inst, const char *ext)
{
return strset_contains (inst->enabled_extensions, ext);
}
static int message_severities =
VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
static int message_types =
VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
static VKAPI_ATTR VkBool32 VKAPI_CALL
debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT* callbackData,
void *data)
{
const char *msgSev = "";
if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) {
msgSev = "verbose: ";
}
if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) {
msgSev = "info: ";
}
if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
msgSev = "warning: ";
}
if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
msgSev = "error: ";
}
fprintf (stderr, "validation layer: %s%s\n", msgSev, callbackData->pMessage);
return VK_FALSE;
}
static void
setup_debug_callback (VulkanInstance_t *instance)
{
VkDebugUtilsMessengerCreateInfoEXT createInfo = {
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
.messageSeverity = message_severities,
.messageType = message_types,
.pfnUserCallback = debug_callback,
.pUserData = instance,
};
instance->vkCreateDebugUtilsMessengerEXT(instance->instance, &createInfo,
0, &instance->debug_callback);
}
static void
load_instance_funcs (vulkan_ctx_t *ctx)
{
VulkanInstance_t *vtx = ctx->vtx;
VkInstance instance = vtx->instance;
#define INSTANCE_LEVEL_VULKAN_FUNCTION(name) \
vtx->name = (PFN_##name) ctx->vkGetInstanceProcAddr (instance, #name); \
if (!vtx->name) { \
Sys_Error ("Couldn't find instance level function %s", #name); \
}
#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name, ext) \
if (vtx->extension_enabled (vtx, ext)) { \
vtx->name = (PFN_##name) ctx->vkGetInstanceProcAddr (instance, \
#name); \
if (!vtx->name) { \
Sys_Error ("Couldn't find instance level function %s", #name); \
} \
}
#include "QF/Vulkan/funclist.h"
}
VulkanInstance_t *
Vulkan_CreateInstance (vulkan_ctx_t *ctx,
const char *appName, uint32_t appVersion,
const char **layers, const char **extensions)
{
VkApplicationInfo appInfo = {
VK_STRUCTURE_TYPE_APPLICATION_INFO, 0,
appName, appVersion,
PACKAGE_STRING, 0x000702ff, //FIXME version
VK_API_VERSION_1_0,
};
VkInstanceCreateInfo createInfo = {
VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 0, 0,
&appInfo,
0, 0,
0, 0,
};
VkResult res;
VkInstance instance;
uint32_t numDev, i;
VkPhysicalDevice *devices;
VulkanInstance_t *inst;
if (!instanceLayerProperties) {
get_instance_layers_and_extensions (ctx);
}
uint32_t nlay = count_strings (layers) + 1;
uint32_t next = count_strings (extensions)
+ count_strings (ctx->required_extensions) + 1;
if (vulkan_use_validation->int_val) {
nlay += count_strings (vulkanValidationLayers);
next += count_strings (debugExtensions);
}
const char **lay = alloca (nlay * sizeof (const char *));
const char **ext = alloca (next * sizeof (const char *));
// ensure there are null pointers so merge_strings can act as append
// since it does not add a null
memset (lay, 0, nlay-- * sizeof (const char *));
memset (ext, 0, next-- * sizeof (const char *));
merge_strings (lay, layers, 0);
merge_strings (ext, extensions, ctx->required_extensions);
if (vulkan_use_validation->int_val) {
merge_strings (lay, lay, vulkanValidationLayers);
merge_strings (ext, ext, debugExtensions);
}
prune_strings (instanceLayerNames, lay, &nlay);
prune_strings (instanceExtensionNames, ext, &next);
lay[nlay] = 0;
ext[next] = 0;
createInfo.enabledLayerCount = nlay;
createInfo.ppEnabledLayerNames = lay;
createInfo.enabledExtensionCount = next;
createInfo.ppEnabledExtensionNames = ext;
res = ctx->vkCreateInstance (&createInfo, 0, &instance);
if (res != VK_SUCCESS) {
Sys_Error ("unable to create vulkan instance\n");
}
inst = malloc (sizeof(VulkanInstance_t));
inst->instance = instance;
inst->enabled_extensions = new_strset (ext);
inst->extension_enabled = instance_extension_enabled;
ctx->extension_enabled = instance_extension_enabled;
ctx->vtx = inst;
load_instance_funcs (ctx);
if (vulkan_use_validation->int_val) {
setup_debug_callback (inst);
}
res = inst->vkEnumeratePhysicalDevices (instance, &numDev, 0);
if (res != VK_SUCCESS) {
Sys_Error ("unable to query vulkan device count: %d\n", res);
}
devices = malloc(numDev * sizeof (VkPhysicalDevice));
res = inst->vkEnumeratePhysicalDevices (instance, &numDev, devices);
if (res != VK_SUCCESS) {
Sys_Error ("unable to query vulkan device properties: %d\n", res);
}
inst->numDevices = numDev;
inst->devices = malloc (numDev * sizeof (VulkanPhysDevice_t));
for (i = 0; i < numDev; i++) {
init_physdev (inst, devices[i], &inst->devices[i]);
}
return inst;
}
void
Vulkan_DestroyInstance (VulkanInstance_t *instance)
{
for (uint32_t i = 0; i < instance->numDevices; i++) {
free (instance->devices[i].queueFamilies);
free (instance->devices[i].extensions);
free (instance->devices[i].layers);
}
free (instance->devices);
instance->vkDestroyInstance (instance->instance, 0);
free (instance);
}
int
Vulkan_LayersSupported (const VkLayerProperties *layers,
int numLayers,
const char * const *requested)
{
while (*requested) {
int i;
for (i = 0; i < numLayers; i++) {
if (!strcmp (*requested, layers[i].layerName)) {
break;
}
}
if (i == numLayers) {
// requested layer not found
break;
}
requested++;
}
return !*requested;
}
int
Vulkan_ExtensionsSupported (const VkExtensionProperties *extensions,
int numExtensions,
const char * const *requested)
{
while (*requested) {
int i;
for (i = 0; i < numExtensions; i++) {
if (!strcmp (*requested, extensions[i].extensionName)) {
break;
}
}
if (i == numExtensions) {
// requested extension not found
break;
}
requested++;
}
return !*requested;
}

View file

@ -0,0 +1,266 @@
/*
init.c
Copyright (C) 2019 Bill Currie <bill@taniwha.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include "QF/cvar.h"
#include "QF/dstring.h"
#include "QF/input.h"
#include "QF/qargs.h"
#include "QF/quakefs.h"
#include "QF/sys.h"
#include "QF/va.h"
#include "QF/vid.h"
#include "QF/Vulkan/instance.h"
#include "vid_vulkan.h"
#include "util.h"
cvar_t *vulkan_use_validation;
static uint32_t numLayers;
static VkLayerProperties *instanceLayerProperties;
static strset_t *instanceLayers;
static uint32_t numExtensions;
static VkExtensionProperties *instanceExtensionProperties;
static strset_t *instanceExtensions;
const char * const vulkanValidationLayers[] = {
"VK_LAYER_LUNARG_standard_validation",
0,
};
static const char * const debugExtensions[] = {
VK_EXT_DEBUG_UTILS_EXTENSION_NAME,
0,
};
static void
get_instance_layers_and_extensions (vulkan_ctx_t *ctx)
{
uint32_t i;
VkLayerProperties *layers;
VkExtensionProperties *extensions;
ctx->vkEnumerateInstanceLayerProperties (&numLayers, 0);
layers = malloc (numLayers * sizeof (VkLayerProperties));
ctx->vkEnumerateInstanceLayerProperties (&numLayers, layers);
instanceLayers = new_strset (0);
for (i = 0; i < numLayers; i++) {
strset_add (instanceLayers, layers[i].layerName);
}
ctx->vkEnumerateInstanceExtensionProperties (0, &numExtensions, 0);
extensions = malloc (numExtensions * sizeof (VkLayerProperties));
ctx->vkEnumerateInstanceExtensionProperties (0, &numExtensions,
extensions);
instanceExtensions = new_strset (0);
for (i = 0; i < numExtensions; i++) {
strset_add (instanceExtensions, extensions[i].extensionName);
}
if (developer->int_val & SYS_VULKAN) {
for (i = 0; i < numLayers; i++) {
Sys_Printf ("%s %x %u %s\n",
layers[i].layerName,
layers[i].specVersion,
layers[i].implementationVersion,
layers[i].description);
}
for (i = 0; i < numExtensions; i++) {
Sys_Printf ("%d %s\n",
extensions[i].specVersion,
extensions[i].extensionName);
}
}
instanceLayerProperties = layers;
instanceExtensionProperties = extensions;
}
static int
instance_extension_enabled (qfv_instance_t *inst, const char *ext)
{
return strset_contains (inst->enabled_extensions, ext);
}
static int message_severities =
VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
static int message_types =
VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
static VKAPI_ATTR VkBool32 VKAPI_CALL
debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT* callbackData,
void *data)
{
const char *msgSev = "";
if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) {
msgSev = "verbose: ";
}
if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) {
msgSev = "info: ";
}
if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
msgSev = "warning: ";
}
if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
msgSev = "error: ";
}
fprintf (stderr, "validation layer: %s%s\n", msgSev, callbackData->pMessage);
return VK_FALSE;
}
static void
setup_debug_callback (qfv_instance_t *instance)
{
VkDebugUtilsMessengerEXT debug_callback_handle;
VkDebugUtilsMessengerCreateInfoEXT createInfo = {
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
.messageSeverity = message_severities,
.messageType = message_types,
.pfnUserCallback = debug_callback,
.pUserData = instance,
};
instance->funcs->vkCreateDebugUtilsMessengerEXT(instance->instance,
&createInfo, 0,
&debug_callback_handle);
}
static void
load_instance_funcs (vulkan_ctx_t *ctx)
{
qfv_instance_t *instance = ctx->instance;
qfv_instfuncs_t *funcs = instance->funcs;
VkInstance inst = instance->instance;
#define INSTANCE_LEVEL_VULKAN_FUNCTION(name) \
funcs->name = (PFN_##name) ctx->vkGetInstanceProcAddr (inst, #name); \
if (!funcs->name) { \
Sys_Error ("Couldn't find instance level function %s", #name); \
}
#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name, ext) \
if (instance->extension_enabled (instance, ext)) { \
funcs->name = (PFN_##name) ctx->vkGetInstanceProcAddr (inst, #name); \
if (!funcs->name) { \
Sys_Error ("Couldn't find instance level function %s", #name); \
} \
}
#include "QF/Vulkan/funclist.h"
}
qfv_instance_t *
QFV_CreateInstance (vulkan_ctx_t *ctx,
const char *appName, uint32_t appVersion,
const char **layers, const char **extensions)
{
VkApplicationInfo appInfo = {
VK_STRUCTURE_TYPE_APPLICATION_INFO, 0,
appName, appVersion,
PACKAGE_STRING, 0x000702ff, //FIXME version
VK_API_VERSION_1_0,
};
VkInstanceCreateInfo createInfo = {
VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 0, 0,
&appInfo,
0, 0,
0, 0,
};
VkResult res;
VkInstance instance;
if (!instanceLayerProperties) {
get_instance_layers_and_extensions (ctx);
}
uint32_t nlay = count_strings (layers) + 1;
uint32_t next = count_strings (extensions)
+ count_strings (ctx->required_extensions) + 1;
if (vulkan_use_validation->int_val) {
nlay += count_strings (vulkanValidationLayers);
next += count_strings (debugExtensions);
}
const char **lay = alloca (nlay * sizeof (const char *));
const char **ext = alloca (next * sizeof (const char *));
// ensure there are null pointers so merge_strings can act as append
// since it does not add a null
memset (lay, 0, nlay-- * sizeof (const char *));
memset (ext, 0, next-- * sizeof (const char *));
merge_strings (lay, layers, 0);
merge_strings (ext, extensions, ctx->required_extensions);
if (vulkan_use_validation->int_val) {
merge_strings (lay, lay, vulkanValidationLayers);
merge_strings (ext, ext, debugExtensions);
}
prune_strings (instanceLayers, lay, &nlay);
prune_strings (instanceExtensions, ext, &next);
lay[nlay] = 0;
ext[next] = 0;
createInfo.enabledLayerCount = nlay;
createInfo.ppEnabledLayerNames = lay;
createInfo.enabledExtensionCount = next;
createInfo.ppEnabledExtensionNames = ext;
res = ctx->vkCreateInstance (&createInfo, 0, &instance);
if (res != VK_SUCCESS) {
Sys_Error ("unable to create vulkan instance\n");
}
qfv_instance_t *inst = malloc (sizeof(qfv_instance_t)
+ sizeof (qfv_instfuncs_t));
inst->instance = instance;
inst->funcs = (qfv_instfuncs_t *)(inst + 1);
inst->enabled_extensions = new_strset (ext);
inst->extension_enabled = instance_extension_enabled;
ctx->instance = inst;
load_instance_funcs (ctx);
if (vulkan_use_validation->int_val) {
setup_debug_callback (inst);
}
return inst;
}
void
QFV_DestroyInstance (qfv_instance_t *instance)
{
instance->funcs->vkDestroyInstance (instance->instance, 0);
free (instance);
}

View file

@ -0,0 +1,148 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_MATH_H
# include <math.h>
#endif
#include "QF/cvar.h"
#include "QF/mathlib.h"
#include "QF/sys.h"
#include "QF/Vulkan/qf_vid.h"
#include "QF/Vulkan/cvars.h"
#include "QF/Vulkan/device.h"
#include "QF/Vulkan/instance.h"
#include "QF/Vulkan/swapchain.h"
#include "compat.h"
#include "d_iface.h"
#include "r_internal.h"
#include "vid_vulkan.h"
#include "util.h"
qfv_swapchain_t *
QFV_CreateSwapchain (vulkan_ctx_t *ctx, VkSwapchainKHR old_swapchain)
{
qfv_instfuncs_t *ifuncs = ctx->instance->funcs;
qfv_devfuncs_t *dfuncs = ctx->device->funcs;
VkBool32 supported;
ifuncs->vkGetPhysicalDeviceSurfaceSupportKHR (ctx->device->physDev,
ctx->device->queueFamily,
ctx->surface,
&supported);
if (!supported) {
Sys_Error ("unsupported surface for swapchain");
}
uint32_t numModes;
VkPresentModeKHR *modes;
VkPresentModeKHR useMode = VK_PRESENT_MODE_FIFO_KHR;;
ifuncs->vkGetPhysicalDeviceSurfacePresentModesKHR (ctx->device->physDev,
ctx->surface,
&numModes, 0);
modes = alloca (numModes * sizeof (VkPresentModeKHR));
ifuncs->vkGetPhysicalDeviceSurfacePresentModesKHR (ctx->device->physDev,
ctx->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;
ifuncs->vkGetPhysicalDeviceSurfaceCapabilitiesKHR (ctx->device->physDev,
ctx->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;
ifuncs->vkGetPhysicalDeviceSurfaceFormatsKHR (ctx->device->physDev,
ctx->surface,
&numFormats, 0);
VkSurfaceFormatKHR *formats = alloca (numFormats * sizeof (*formats));
ifuncs->vkGetPhysicalDeviceSurfaceFormatsKHR (ctx->device->physDev,
ctx->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->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,
old_swapchain
};
VkDevice device = ctx->device->dev;
VkSwapchainKHR swapchain;
dfuncs->vkCreateSwapchainKHR (device, &createInfo, 0, &swapchain);
if (old_swapchain != swapchain) {
dfuncs->vkDestroySwapchainKHR (device, old_swapchain, 0);
}
dfuncs->vkGetSwapchainImagesKHR (device, swapchain, &numImages, 0);
qfv_swapchain_t *sc = malloc (sizeof (qfv_swapchain_t)
+ numImages * sizeof (VkImage));
sc->dev = device;
sc->funcs = ctx->device->funcs;
sc->surface = ctx->surface;
sc->swapchain = swapchain;
sc->numImages = numImages;
sc->images = (VkImage *) (sc + 1);
dfuncs->vkGetSwapchainImagesKHR (device, swapchain, &numImages,
sc->images);
return sc;
}

View file

@ -47,17 +47,27 @@ strset_t *
new_strset (const char * const *strings)
{
hashtab_t *tab = Hash_NewTable (61, strset_get_key, 0, 0);
for ( ; *strings; strings++) {
for ( ; strings && *strings; strings++) {
Hash_Add (tab, (void *) *strings);
}
return (strset_t *) tab;
}
void del_strset (strset_t *strset)
void
del_strset (strset_t *strset)
{
Hash_DelTable ((hashtab_t *) strset);
}
int strset_contains (strset_t *strset, const char *str)
void
strset_add (strset_t *strset, const char *str)
{
hashtab_t *tab = (hashtab_t *) strset;
Hash_Add (tab, (void *) str);
}
int
strset_contains (strset_t *strset, const char *str)
{
return Hash_Find ((hashtab_t *) strset, str) != 0;
}
@ -92,18 +102,12 @@ merge_strings (const char **out, const char * const *in1,
}
void
prune_strings (const char * const *reference, const char **strings,
uint32_t *count)
prune_strings (strset_t *strset, const char **strings, uint32_t *count)
{
for (int i = *count; i-- > 0; ) {
const char *str = strings[i];
const char * const *ref;
for (ref = reference; *ref; ref++) {
if (!strcmp (*ref, str)) {
break;
}
}
if (!*ref) {
hashtab_t *tab = (hashtab_t *) strset;
for (uint32_t i = *count; i-- > 0; ) {
if (!Hash_Find (tab, strings[i])) {
memmove (strings + i, strings + i + 1,
(--(*count) - i) * sizeof (const char **));
}

View file

@ -2,15 +2,17 @@
#define __util_h
#include <stdint.h>
typedef struct strset_s strset_t;
int count_strings (const char * const *str);
void merge_strings (const char **out, const char * const *in1,
const char * const *in2);
void prune_strings (const char * const *reference, const char **strings,
uint32_t *count);
void prune_strings (strset_t *strset, const char **strings, uint32_t *count);
typedef struct strset_s strset_t;
strset_t *new_strset (const char * const *strings);
void del_strset (strset_t *strset);
void strset_add (strset_t *strset, const char *str);
int strset_contains (strset_t *strset, const char *str);
#endif//__util_h

View file

@ -49,7 +49,8 @@
#include "QF/va.h"
#include "QF/vid.h"
#include "QF/Vulkan/qf_vid.h"
#include "QF/Vulkan/init.h"
#include "QF/Vulkan/device.h"
#include "QF/Vulkan/instance.h"
#include "compat.h"
#include "d_iface.h"
@ -58,7 +59,7 @@
#include "util.h"
static cvar_t *vulkan_presentation_mode;
cvar_t *vulkan_presentation_mode;
static void
vulkan_presentation_mode_f (cvar_t *var)
@ -77,8 +78,8 @@ vulkan_presentation_mode_f (cvar_t *var)
}
}
void
Vulkan_Init_Cvars ()
static void
Vulkan_Init_Cvars (void)
{
vulkan_use_validation = Cvar_Get ("vulkan_use_validation", "1", CVAR_NONE,
0,
@ -102,251 +103,30 @@ static const char *device_extensions[] = {
0,
};
static int
count_bits (uint32_t val)
{
int bits = 0;
while (val) {
bits += val & 1;
val >>= 1;
}
return bits;
}
static int
find_queue_family (VulkanPhysDevice_t *dev, uint32_t flags)
{
int best_diff = 32;
uint32_t family = -1;
for (uint32_t i = 0; i < dev->numQueueFamilies; i++) {
VkQueueFamilyProperties *queue = &dev->queueFamilies[i];
if ((queue->queueFlags & flags) == flags) {
int diff = count_bits (queue->queueFlags & ~flags);
if (diff < best_diff) {
best_diff = diff;
family = i;
}
}
}
return family;
}
static void
load_device_funcs (VulkanInstance_t *inst, VulkanDevice_t *dev)
{
#define DEVICE_LEVEL_VULKAN_FUNCTION(name) \
dev->name = (PFN_##name) inst->vkGetDeviceProcAddr (dev->device, #name); \
if (!dev->name) { \
Sys_Error ("Couldn't find device level function %s", #name); \
}
#define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name, ext) \
if (inst->extension_enabled (inst, ext)) { \
dev->name = (PFN_##name) inst->vkGetDeviceProcAddr (dev->device, \
#name); \
if (!dev->name) { \
Sys_Printf ("Couldn't find device level function %s", #name); \
} \
}
#include "QF/Vulkan/funclist.h"
}
void
Vulkan_Init_Common (vulkan_ctx_t *ctx)
{
Sys_Printf ("Vulkan_Init_Common\n");
Vulkan_Init_Cvars ();
ctx->vtx = Vulkan_CreateInstance (ctx, PACKAGE_STRING, 0x000702ff, 0, instance_extensions);//FIXME version
ctx->instance = ctx->vtx->instance;
ctx->instance = QFV_CreateInstance (ctx, PACKAGE_STRING, 0x000702ff, 0, instance_extensions);//FIXME version
}
void
Vulkan_Shutdown_Common (vulkan_ctx_t *ctx)
{
Vulkan_DestroyInstance (ctx->vtx);
ctx->vtx = 0;
QFV_DestroyInstance (ctx->instance);
ctx->instance = 0;
ctx->unload_vulkan (ctx);
}
void
Vulkan_CreateDevice (vulkan_ctx_t *ctx)
{
VulkanInstance_t *inst = ctx->vtx;
uint32_t nlay = 1; // ensure alloca doesn't see 0 and terminated
uint32_t next = count_strings (device_extensions) + 1; // ensure terminated
if (vulkan_use_validation->int_val) {
nlay += count_strings (vulkanValidationLayers);
}
const char **lay = alloca (nlay * sizeof (const char *));
const char **ext = alloca (next * sizeof (const char *));
// ensure there are null pointers so merge_strings can act as append
// since it does not add a null, but also make sure the counts reflect
// actual numbers
memset (lay, 0, nlay-- * sizeof (const char *));
memset (ext, 0, next-- * sizeof (const char *));
merge_strings (ext, device_extensions, 0);
if (vulkan_use_validation->int_val) {
merge_strings (lay, lay, vulkanValidationLayers);
}
for (uint32_t i = 0; i < inst->numDevices; i++) {
VulkanPhysDevice_t *phys = &inst->devices[i];
if (!Vulkan_LayersSupported (phys->layers, phys->numLayers, lay)) {
continue;
}
if (!Vulkan_ExtensionsSupported (phys->extensions, phys->numExtensions,
ext)) {
continue;
}
int family = find_queue_family (phys, VK_QUEUE_GRAPHICS_BIT);
if (family < 0) {
continue;
}
if (!ctx->get_presentation_support (ctx, phys->device, family)) {
continue;
}
float priority = 1;
VkDeviceQueueCreateInfo qCreateInfo = {
VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, 0, 0,
family, 1, &priority
};
VkPhysicalDeviceFeatures features;
VkDeviceCreateInfo dCreateInfo = {
VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 0, 0,
1, &qCreateInfo,
nlay, lay,
next, ext,
&features
};
memset (&features, 0, sizeof (features));
VulkanDevice_t *device = calloc (1, sizeof (VulkanDevice_t));
if (inst->vkCreateDevice (phys->device, &dCreateInfo, 0,
&device->device) == VK_SUCCESS) {
load_device_funcs (inst, device);
device->vkGetDeviceQueue (device->device, family,
0, &device->queue);
ctx->dev = device;
ctx->device = device->device;
ctx->physDevice = phys->device;
device->queueFamily = family;
return;
}
}
ctx->device = QFV_CreateDevice (ctx, device_extensions);
}
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;
}

View file

@ -54,6 +54,8 @@
#include "QF/set.h"
#include "QF/sys.h"
#include "QF/Vulkan/instance.h"
#include "context_x11.h"
#include "vid_internal.h"
#include "vid_vulkan.h"
@ -61,7 +63,7 @@
static cvar_t *vulkan_library_name;
typedef struct vulkan_presentation_s {
#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name,ext) PFN_##name name;
#define PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION(name,ext) PFN_##name name;
#include "QF/Vulkan/funclist.h"
Display *display;
@ -115,12 +117,12 @@ x11_vulkan_init_presentation (vulkan_ctx_t *ctx)
{
ctx->presentation = calloc (1, sizeof (vulkan_presentation_t));
vulkan_presentation_t *pres = ctx->presentation;
VkInstance instance = ctx->instance;
qfv_instance_t *instance = ctx->instance;
VkInstance inst = instance->instance;
#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name, ext) \
if (ctx->extension_enabled (ctx->vtx, ext)) { \
pres->name = (PFN_##name) ctx->vkGetInstanceProcAddr (instance, \
#name); \
#define PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION(name, ext) \
if (instance->extension_enabled (instance, ext)) { \
pres->name = (PFN_##name) ctx->vkGetInstanceProcAddr (inst, #name); \
if (!pres->name) { \
Sys_Error ("Couldn't find instance-level function %s", #name); \
} \
@ -182,6 +184,7 @@ static VkSurfaceKHR
x11_vulkan_create_surface (vulkan_ctx_t *ctx)
{
vulkan_presentation_t *pres = ctx->presentation;
VkInstance inst = ctx->instance->instance;
VkSurfaceKHR surface;
VkXlibSurfaceCreateInfoKHR createInfo = {
.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
@ -190,7 +193,7 @@ x11_vulkan_create_surface (vulkan_ctx_t *ctx)
.window = pres->window
};
if (pres->vkCreateXlibSurfaceKHR (ctx->instance, &createInfo, 0, &surface)
if (pres->vkCreateXlibSurfaceKHR (inst, &createInfo, 0, &surface)
!= VK_SUCCESS) {
return 0;
}