mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-29 23:52:22 +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
|
#define __QF_Vulkan_cvars_h
|
||||||
|
|
||||||
extern struct cvar_s *vulkan_use_validation;
|
extern struct cvar_s *vulkan_use_validation;
|
||||||
|
extern struct cvar_s *vulkan_presentation_mode;
|
||||||
|
|
||||||
#endif//__QF_Vulkan_cvars_h
|
#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)
|
#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(function, extension)
|
||||||
#endif
|
#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
|
INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
|
||||||
(vkCreateDebugUtilsMessengerEXT, VK_EXT_DEBUG_UTILS_EXTENSION_NAME)
|
(vkCreateDebugUtilsMessengerEXT, VK_EXT_DEBUG_UTILS_EXTENSION_NAME)
|
||||||
INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
|
INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
|
||||||
|
@ -70,10 +48,38 @@ INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
|
||||||
(vkGetPhysicalDeviceSurfaceCapabilitiesKHR, VK_KHR_SURFACE_EXTENSION_NAME)
|
(vkGetPhysicalDeviceSurfaceCapabilitiesKHR, VK_KHR_SURFACE_EXTENSION_NAME)
|
||||||
INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
|
INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
|
||||||
(vkGetPhysicalDeviceSurfaceFormatsKHR, VK_KHR_SURFACE_EXTENSION_NAME)
|
(vkGetPhysicalDeviceSurfaceFormatsKHR, VK_KHR_SURFACE_EXTENSION_NAME)
|
||||||
#endif
|
|
||||||
|
|
||||||
#undef INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION
|
#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
|
#ifndef DEVICE_LEVEL_VULKAN_FUNCTION
|
||||||
#define DEVICE_LEVEL_VULKAN_FUNCTION(function)
|
#define DEVICE_LEVEL_VULKAN_FUNCTION(function)
|
||||||
#endif
|
#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"
|
#include "QF/Vulkan/cvars.h"
|
||||||
|
|
||||||
|
#ifndef VK_NO_PROTOTYPES
|
||||||
|
#define VK_NO_PROTOTYPES
|
||||||
|
#endif
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
struct vulkan_ctx_s;
|
struct vulkan_ctx_s;
|
||||||
void Vulkan_CreateSwapchain (struct vulkan_ctx_s *ctx);
|
void Vulkan_CreateSwapchain (struct vulkan_ctx_s *ctx);
|
||||||
void Vulkan_CreateDevice (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
|
#endif
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
struct VulkanInstance_s;
|
|
||||||
typedef struct vulkan_ctx_s {
|
typedef struct vulkan_ctx_s {
|
||||||
void (*load_vulkan) (struct vulkan_ctx_s *ctx);
|
void (*load_vulkan) (struct vulkan_ctx_s *ctx);
|
||||||
void (*unload_vulkan) (struct vulkan_ctx_s *ctx);
|
void (*unload_vulkan) (struct vulkan_ctx_s *ctx);
|
||||||
|
|
||||||
const char **required_extensions;
|
const char **required_extensions;
|
||||||
int (*extension_enabled) (struct VulkanInstance_s *inst,
|
|
||||||
const char *ext);
|
|
||||||
struct vulkan_presentation_s *presentation;
|
struct vulkan_presentation_s *presentation;
|
||||||
int (*get_presentation_support) (struct vulkan_ctx_s *ctx,
|
int (*get_presentation_support) (struct vulkan_ctx_s *ctx,
|
||||||
VkPhysicalDevice physicalDevice,
|
VkPhysicalDevice physicalDevice,
|
||||||
|
@ -22,14 +19,10 @@ typedef struct vulkan_ctx_s {
|
||||||
void (*create_window) (struct vulkan_ctx_s *ctx);
|
void (*create_window) (struct vulkan_ctx_s *ctx);
|
||||||
VkSurfaceKHR (*create_surface) (struct vulkan_ctx_s *ctx);
|
VkSurfaceKHR (*create_surface) (struct vulkan_ctx_s *ctx);
|
||||||
|
|
||||||
struct VulkanInstance_s *vtx;
|
struct qfv_instance_s *instance;
|
||||||
struct VulkanDevice_s *dev;
|
struct qfv_device_s *device;
|
||||||
VkInstance instance;
|
struct qfv_swapchain_s *swapchain;
|
||||||
VkPhysicalDevice physDevice;
|
VkSurfaceKHR surface; //FIXME surface = window, so "contains" swapchain
|
||||||
VkDevice device;
|
|
||||||
VkSwapchainKHR swapchain;
|
|
||||||
int32_t numSwapchainImages;
|
|
||||||
VkImage *swapchainImages;
|
|
||||||
#define EXPORTED_VULKAN_FUNCTION(fname) PFN_##fname fname;
|
#define EXPORTED_VULKAN_FUNCTION(fname) PFN_##fname fname;
|
||||||
#define GLOBAL_LEVEL_VULKAN_FUNCTION(fname) PFN_##fname fname;
|
#define GLOBAL_LEVEL_VULKAN_FUNCTION(fname) PFN_##fname fname;
|
||||||
#include "QF/Vulkan/funclist.h"
|
#include "QF/Vulkan/funclist.h"
|
||||||
|
|
|
@ -37,7 +37,9 @@
|
||||||
#include "QF/plugin/vid_render.h"
|
#include "QF/plugin/vid_render.h"
|
||||||
|
|
||||||
#include "QF/Vulkan/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 "QF/Vulkan/swapchain.h"
|
||||||
|
|
||||||
#include "mod_internal.h"
|
#include "mod_internal.h"
|
||||||
#include "r_internal.h"
|
#include "r_internal.h"
|
||||||
|
@ -150,20 +152,20 @@ vulkan_vid_render_choose_visual (void)
|
||||||
{
|
{
|
||||||
Vulkan_CreateDevice (vulkan_ctx);
|
Vulkan_CreateDevice (vulkan_ctx);
|
||||||
vulkan_ctx->choose_visual (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
|
static void
|
||||||
vulkan_vid_render_create_context (void)
|
vulkan_vid_render_create_context (void)
|
||||||
{
|
{
|
||||||
vulkan_ctx->create_window (vulkan_ctx);
|
vulkan_ctx->create_window (vulkan_ctx);
|
||||||
vulkan_ctx->dev->surface = vulkan_ctx->create_surface (vulkan_ctx);
|
vulkan_ctx->surface = vulkan_ctx->create_surface (vulkan_ctx);
|
||||||
Sys_Printf ("%p\n", vulkan_ctx->dev->surface);
|
Sys_Printf ("%p\n", vulkan_ctx->surface);
|
||||||
Vulkan_CreateSwapchain (vulkan_ctx);
|
Vulkan_CreateSwapchain (vulkan_ctx);
|
||||||
Sys_Printf ("%p %d", vulkan_ctx->swapchain,
|
Sys_Printf ("%p %d", vulkan_ctx->swapchain->swapchain,
|
||||||
vulkan_ctx->numSwapchainImages);
|
vulkan_ctx->swapchain->numImages);
|
||||||
for (int32_t i = 0; i < vulkan_ctx->numSwapchainImages; i++) {
|
for (int32_t i = 0; i < vulkan_ctx->swapchain->numImages; i++) {
|
||||||
Sys_Printf (" %p", vulkan_ctx->swapchainImages[i]);
|
Sys_Printf (" %p", vulkan_ctx->swapchain->images[i]);
|
||||||
}
|
}
|
||||||
Sys_Printf ("\n");
|
Sys_Printf ("\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,9 @@ AM_CFLAGS= @PREFER_PIC@
|
||||||
AM_CPPFLAGS= -I$(top_srcdir)/include -DVK_NO_PROTOTYPES
|
AM_CPPFLAGS= -I$(top_srcdir)/include -DVK_NO_PROTOTYPES
|
||||||
|
|
||||||
vulkan_src = \
|
vulkan_src = \
|
||||||
init.c \
|
device.c \
|
||||||
|
instance.c \
|
||||||
|
swapchain.c \
|
||||||
util.c \
|
util.c \
|
||||||
vulkan_draw.c \
|
vulkan_draw.c \
|
||||||
vulkan_vid_common.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)
|
new_strset (const char * const *strings)
|
||||||
{
|
{
|
||||||
hashtab_t *tab = Hash_NewTable (61, strset_get_key, 0, 0);
|
hashtab_t *tab = Hash_NewTable (61, strset_get_key, 0, 0);
|
||||||
for ( ; *strings; strings++) {
|
for ( ; strings && *strings; strings++) {
|
||||||
Hash_Add (tab, (void *) *strings);
|
Hash_Add (tab, (void *) *strings);
|
||||||
}
|
}
|
||||||
return (strset_t *) tab;
|
return (strset_t *) tab;
|
||||||
}
|
}
|
||||||
void del_strset (strset_t *strset)
|
|
||||||
|
void
|
||||||
|
del_strset (strset_t *strset)
|
||||||
{
|
{
|
||||||
Hash_DelTable ((hashtab_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;
|
return Hash_Find ((hashtab_t *) strset, str) != 0;
|
||||||
}
|
}
|
||||||
|
@ -92,18 +102,12 @@ merge_strings (const char **out, const char * const *in1,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
prune_strings (const char * const *reference, const char **strings,
|
prune_strings (strset_t *strset, const char **strings, uint32_t *count)
|
||||||
uint32_t *count)
|
|
||||||
{
|
{
|
||||||
for (int i = *count; i-- > 0; ) {
|
hashtab_t *tab = (hashtab_t *) strset;
|
||||||
const char *str = strings[i];
|
|
||||||
const char * const *ref;
|
for (uint32_t i = *count; i-- > 0; ) {
|
||||||
for (ref = reference; *ref; ref++) {
|
if (!Hash_Find (tab, strings[i])) {
|
||||||
if (!strcmp (*ref, str)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!*ref) {
|
|
||||||
memmove (strings + i, strings + i + 1,
|
memmove (strings + i, strings + i + 1,
|
||||||
(--(*count) - i) * sizeof (const char **));
|
(--(*count) - i) * sizeof (const char **));
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,15 +2,17 @@
|
||||||
#define __util_h
|
#define __util_h
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct strset_s strset_t;
|
||||||
|
|
||||||
int count_strings (const char * const *str);
|
int count_strings (const char * const *str);
|
||||||
void merge_strings (const char **out, const char * const *in1,
|
void merge_strings (const char **out, const char * const *in1,
|
||||||
const char * const *in2);
|
const char * const *in2);
|
||||||
void prune_strings (const char * const *reference, const char **strings,
|
void prune_strings (strset_t *strset, const char **strings, uint32_t *count);
|
||||||
uint32_t *count);
|
|
||||||
|
|
||||||
typedef struct strset_s strset_t;
|
|
||||||
strset_t *new_strset (const char * const *strings);
|
strset_t *new_strset (const char * const *strings);
|
||||||
void del_strset (strset_t *strset);
|
void del_strset (strset_t *strset);
|
||||||
|
void strset_add (strset_t *strset, const char *str);
|
||||||
int strset_contains (strset_t *strset, const char *str);
|
int strset_contains (strset_t *strset, const char *str);
|
||||||
|
|
||||||
#endif//__util_h
|
#endif//__util_h
|
||||||
|
|
|
@ -49,7 +49,8 @@
|
||||||
#include "QF/va.h"
|
#include "QF/va.h"
|
||||||
#include "QF/vid.h"
|
#include "QF/vid.h"
|
||||||
#include "QF/Vulkan/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 "compat.h"
|
||||||
#include "d_iface.h"
|
#include "d_iface.h"
|
||||||
|
@ -58,7 +59,7 @@
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
static cvar_t *vulkan_presentation_mode;
|
cvar_t *vulkan_presentation_mode;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
vulkan_presentation_mode_f (cvar_t *var)
|
vulkan_presentation_mode_f (cvar_t *var)
|
||||||
|
@ -77,8 +78,8 @@ vulkan_presentation_mode_f (cvar_t *var)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
Vulkan_Init_Cvars ()
|
Vulkan_Init_Cvars (void)
|
||||||
{
|
{
|
||||||
vulkan_use_validation = Cvar_Get ("vulkan_use_validation", "1", CVAR_NONE,
|
vulkan_use_validation = Cvar_Get ("vulkan_use_validation", "1", CVAR_NONE,
|
||||||
0,
|
0,
|
||||||
|
@ -102,251 +103,30 @@ static const char *device_extensions[] = {
|
||||||
0,
|
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
|
void
|
||||||
Vulkan_Init_Common (vulkan_ctx_t *ctx)
|
Vulkan_Init_Common (vulkan_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
Sys_Printf ("Vulkan_Init_Common\n");
|
Sys_Printf ("Vulkan_Init_Common\n");
|
||||||
Vulkan_Init_Cvars ();
|
Vulkan_Init_Cvars ();
|
||||||
|
|
||||||
ctx->vtx = Vulkan_CreateInstance (ctx, PACKAGE_STRING, 0x000702ff, 0, instance_extensions);//FIXME version
|
ctx->instance = QFV_CreateInstance (ctx, PACKAGE_STRING, 0x000702ff, 0, instance_extensions);//FIXME version
|
||||||
ctx->instance = ctx->vtx->instance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Vulkan_Shutdown_Common (vulkan_ctx_t *ctx)
|
Vulkan_Shutdown_Common (vulkan_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
Vulkan_DestroyInstance (ctx->vtx);
|
QFV_DestroyInstance (ctx->instance);
|
||||||
ctx->vtx = 0;
|
ctx->instance = 0;
|
||||||
ctx->unload_vulkan (ctx);
|
ctx->unload_vulkan (ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Vulkan_CreateDevice (vulkan_ctx_t *ctx)
|
Vulkan_CreateDevice (vulkan_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
VulkanInstance_t *inst = ctx->vtx;
|
ctx->device = QFV_CreateDevice (ctx, device_extensions);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Vulkan_CreateSwapchain (vulkan_ctx_t *ctx)
|
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/set.h"
|
||||||
#include "QF/sys.h"
|
#include "QF/sys.h"
|
||||||
|
|
||||||
|
#include "QF/Vulkan/instance.h"
|
||||||
|
|
||||||
#include "context_x11.h"
|
#include "context_x11.h"
|
||||||
#include "vid_internal.h"
|
#include "vid_internal.h"
|
||||||
#include "vid_vulkan.h"
|
#include "vid_vulkan.h"
|
||||||
|
@ -61,7 +63,7 @@
|
||||||
static cvar_t *vulkan_library_name;
|
static cvar_t *vulkan_library_name;
|
||||||
|
|
||||||
typedef struct vulkan_presentation_s {
|
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"
|
#include "QF/Vulkan/funclist.h"
|
||||||
|
|
||||||
Display *display;
|
Display *display;
|
||||||
|
@ -115,12 +117,12 @@ x11_vulkan_init_presentation (vulkan_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
ctx->presentation = calloc (1, sizeof (vulkan_presentation_t));
|
ctx->presentation = calloc (1, sizeof (vulkan_presentation_t));
|
||||||
vulkan_presentation_t *pres = ctx->presentation;
|
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) \
|
#define PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION(name, ext) \
|
||||||
if (ctx->extension_enabled (ctx->vtx, ext)) { \
|
if (instance->extension_enabled (instance, ext)) { \
|
||||||
pres->name = (PFN_##name) ctx->vkGetInstanceProcAddr (instance, \
|
pres->name = (PFN_##name) ctx->vkGetInstanceProcAddr (inst, #name); \
|
||||||
#name); \
|
|
||||||
if (!pres->name) { \
|
if (!pres->name) { \
|
||||||
Sys_Error ("Couldn't find instance-level function %s", #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)
|
x11_vulkan_create_surface (vulkan_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
vulkan_presentation_t *pres = ctx->presentation;
|
vulkan_presentation_t *pres = ctx->presentation;
|
||||||
|
VkInstance inst = ctx->instance->instance;
|
||||||
VkSurfaceKHR surface;
|
VkSurfaceKHR surface;
|
||||||
VkXlibSurfaceCreateInfoKHR createInfo = {
|
VkXlibSurfaceCreateInfoKHR createInfo = {
|
||||||
.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
|
.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
|
||||||
|
@ -190,7 +193,7 @@ x11_vulkan_create_surface (vulkan_ctx_t *ctx)
|
||||||
.window = pres->window
|
.window = pres->window
|
||||||
};
|
};
|
||||||
|
|
||||||
if (pres->vkCreateXlibSurfaceKHR (ctx->instance, &createInfo, 0, &surface)
|
if (pres->vkCreateXlibSurfaceKHR (inst, &createInfo, 0, &surface)
|
||||||
!= VK_SUCCESS) {
|
!= VK_SUCCESS) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue