mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-22 12:31:10 +00:00
Completely rework the vulkan related api
Things don't work yet, but this feels much cleaner.
This commit is contained in:
parent
b5828bc2ce
commit
75f19f7243
18 changed files with 817 additions and 804 deletions
|
@ -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
|
||||
|
|
26
include/QF/Vulkan/device.h
Normal file
26
include/QF/Vulkan/device.h
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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
|
55
include/QF/Vulkan/instance.h
Normal file
55
include/QF/Vulkan/instance.h
Normal 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
|
|
@ -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);
|
||||
|
|
17
include/QF/Vulkan/swapchain.h
Normal file
17
include/QF/Vulkan/swapchain.h
Normal 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
|
|
@ -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"
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
211
libs/video/renderer/vulkan/device.c
Normal file
211
libs/video/renderer/vulkan/device.c
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
}
|
266
libs/video/renderer/vulkan/instance.c
Normal file
266
libs/video/renderer/vulkan/instance.c
Normal 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);
|
||||
}
|
148
libs/video/renderer/vulkan/swapchain.c
Normal file
148
libs/video/renderer/vulkan/swapchain.c
Normal 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;
|
||||
}
|
|
@ -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 **));
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue