From 75f19f724373afb7e6fa0bc00fdda6815f3eb127 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 12 Jul 2019 13:15:25 +0900 Subject: [PATCH] Completely rework the vulkan related api Things don't work yet, but this feels much cleaner. --- include/QF/Vulkan/cvars.h | 1 + include/QF/Vulkan/device.h | 26 ++ include/QF/Vulkan/funclist.h | 52 ++- include/QF/Vulkan/init.h | 88 ---- include/QF/Vulkan/instance.h | 55 +++ include/QF/Vulkan/qf_vid.h | 5 + include/QF/Vulkan/swapchain.h | 17 + include/vid_vulkan.h | 15 +- libs/video/renderer/vid_render_vulkan.c | 18 +- libs/video/renderer/vulkan/Makefile.am | 4 +- libs/video/renderer/vulkan/device.c | 211 +++++++++ libs/video/renderer/vulkan/init.c | 420 ------------------ libs/video/renderer/vulkan/instance.c | 266 +++++++++++ libs/video/renderer/vulkan/swapchain.c | 148 ++++++ libs/video/renderer/vulkan/util.c | 32 +- libs/video/renderer/vulkan/util.h | 8 +- .../video/renderer/vulkan/vulkan_vid_common.c | 238 +--------- libs/video/targets/vid_x11_vulkan.c | 17 +- 18 files changed, 817 insertions(+), 804 deletions(-) create mode 100644 include/QF/Vulkan/device.h delete mode 100644 include/QF/Vulkan/init.h create mode 100644 include/QF/Vulkan/instance.h create mode 100644 include/QF/Vulkan/swapchain.h create mode 100644 libs/video/renderer/vulkan/device.c delete mode 100644 libs/video/renderer/vulkan/init.c create mode 100644 libs/video/renderer/vulkan/instance.c create mode 100644 libs/video/renderer/vulkan/swapchain.c diff --git a/include/QF/Vulkan/cvars.h b/include/QF/Vulkan/cvars.h index b6110e353..706bc44de 100644 --- a/include/QF/Vulkan/cvars.h +++ b/include/QF/Vulkan/cvars.h @@ -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 diff --git a/include/QF/Vulkan/device.h b/include/QF/Vulkan/device.h new file mode 100644 index 000000000..ae0c26ffc --- /dev/null +++ b/include/QF/Vulkan/device.h @@ -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 diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index 8418aeb6a..719335699 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.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 diff --git a/include/QF/Vulkan/init.h b/include/QF/Vulkan/init.h deleted file mode 100644 index 0988dd25a..000000000 --- a/include/QF/Vulkan/init.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - Copyright (C) 2019 Bill Currie - - 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 - -#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 diff --git a/include/QF/Vulkan/instance.h b/include/QF/Vulkan/instance.h new file mode 100644 index 000000000..1cc05d6cf --- /dev/null +++ b/include/QF/Vulkan/instance.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2019 Bill Currie + + 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 + +#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 diff --git a/include/QF/Vulkan/qf_vid.h b/include/QF/Vulkan/qf_vid.h index fe04da536..bfa543c46 100644 --- a/include/QF/Vulkan/qf_vid.h +++ b/include/QF/Vulkan/qf_vid.h @@ -30,6 +30,11 @@ #include "QF/Vulkan/cvars.h" +#ifndef VK_NO_PROTOTYPES +#define VK_NO_PROTOTYPES +#endif +#include + struct vulkan_ctx_s; void Vulkan_CreateSwapchain (struct vulkan_ctx_s *ctx); void Vulkan_CreateDevice (struct vulkan_ctx_s *ctx); diff --git a/include/QF/Vulkan/swapchain.h b/include/QF/Vulkan/swapchain.h new file mode 100644 index 000000000..71d0b6d75 --- /dev/null +++ b/include/QF/Vulkan/swapchain.h @@ -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 diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index fabaa088b..9cfb3ad8a 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -6,14 +6,11 @@ #endif #include -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" diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 46d475917..506406394 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -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"); } diff --git a/libs/video/renderer/vulkan/Makefile.am b/libs/video/renderer/vulkan/Makefile.am index b134d1f91..e59e29551 100644 --- a/libs/video/renderer/vulkan/Makefile.am +++ b/libs/video/renderer/vulkan/Makefile.am @@ -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 diff --git a/libs/video/renderer/vulkan/device.c b/libs/video/renderer/vulkan/device.c new file mode 100644 index 000000000..1579c0633 --- /dev/null +++ b/libs/video/renderer/vulkan/device.c @@ -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 + + 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 +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#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; +} diff --git a/libs/video/renderer/vulkan/init.c b/libs/video/renderer/vulkan/init.c deleted file mode 100644 index 2ba5bfc06..000000000 --- a/libs/video/renderer/vulkan/init.c +++ /dev/null @@ -1,420 +0,0 @@ -/* - init.c - - Copyright (C) 2019 Bill Currie - - 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 -#endif -#ifdef HAVE_STRINGS_H -# include -#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; -} diff --git a/libs/video/renderer/vulkan/instance.c b/libs/video/renderer/vulkan/instance.c new file mode 100644 index 000000000..74b0ea756 --- /dev/null +++ b/libs/video/renderer/vulkan/instance.c @@ -0,0 +1,266 @@ +/* + init.c + + Copyright (C) 2019 Bill Currie + + 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 +#endif +#ifdef HAVE_STRINGS_H +# include +#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); +} diff --git a/libs/video/renderer/vulkan/swapchain.c b/libs/video/renderer/vulkan/swapchain.c new file mode 100644 index 000000000..91f8280c9 --- /dev/null +++ b/libs/video/renderer/vulkan/swapchain.c @@ -0,0 +1,148 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#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; +} diff --git a/libs/video/renderer/vulkan/util.c b/libs/video/renderer/vulkan/util.c index 09e1b146a..854557e95 100644 --- a/libs/video/renderer/vulkan/util.c +++ b/libs/video/renderer/vulkan/util.c @@ -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 **)); } diff --git a/libs/video/renderer/vulkan/util.h b/libs/video/renderer/vulkan/util.h index a15aac4c8..ae87b8096 100644 --- a/libs/video/renderer/vulkan/util.h +++ b/libs/video/renderer/vulkan/util.h @@ -2,15 +2,17 @@ #define __util_h #include + +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 diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 22ce1d71e..f7988c26c 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -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; } diff --git a/libs/video/targets/vid_x11_vulkan.c b/libs/video/targets/vid_x11_vulkan.c index 812e74dad..cd228b051 100644 --- a/libs/video/targets/vid_x11_vulkan.c +++ b/libs/video/targets/vid_x11_vulkan.c @@ -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; }