create vulkan instance; fix instance extension ref api

This commit is contained in:
Ivan Avdeev 2021-01-09 16:05:55 -08:00
parent fa683fb882
commit 0dcedece06
4 changed files with 227 additions and 29 deletions

View File

@ -142,7 +142,7 @@ typedef uint64_t vulkan_non_dispatchable_handle_t;
typedef void* vulkan_handle_t;
// FIXME END MAXIMUM DUMB
int VK_GetInstanceExtensions( const char ***pNames );
int VK_GetInstanceExtensions( unsigned int count, const char **pNames );
void *VK_GetVkGetInstanceProcAddr( void );
vulkan_non_dispatchable_handle_t VK_CreateSurface( vulkan_handle_t vkInstance );

View File

@ -965,23 +965,15 @@ int GL_GetAttribute( int attr, int *val )
#define EGL_LIB NULL
#endif
int VK_GetInstanceExtensions( const char ***pNames )
int VK_GetInstanceExtensions( unsigned int count, const char **pNames )
{
int pCount = 0;
if (!SDL_Vulkan_GetInstanceExtensions(host.hWnd, (unsigned int*)&pCount, NULL))
if (!SDL_Vulkan_GetInstanceExtensions(host.hWnd, &count, pNames))
{
Con_Reportf( S_ERROR "Couldn't get Vulkan extensions: %s\n", SDL_GetError());
return -1;
}
*pNames = Mem_Malloc(host.mempool, pCount * sizeof(const char*));
if (!SDL_Vulkan_GetInstanceExtensions(host.hWnd, (unsigned int*)&pCount, *pNames))
{
Con_Reportf( S_ERROR "Couldn't get Vulkan extensions: %s\n", SDL_GetError());
return -1;
}
return pCount;
return (int)count;
}
void *VK_GetVkGetInstanceProcAddr( void )

View File

@ -442,7 +442,7 @@ typedef struct ref_api_s
render_interface_t *drawFuncs;
// Vulkan
int (*VK_GetInstanceExtensions)( const char ***pNames );
int (*VK_GetInstanceExtensions)( unsigned int count, const char **pNames );
void *(*VK_GetVkGetInstanceProcAddr)( void );
vulkan_non_dispatchable_handle_t (*VK_CreateSurface)( vulkan_handle_t vkInstance );
} ref_api_t;

View File

@ -7,6 +7,7 @@
#include "ref_api.h"
#include "crtlib.h"
#include "com_strings.h"
#include "eiface.h"
#define VK_NO_PROTOTYPES
#include <vulkan/vulkan.h>
@ -15,6 +16,9 @@ typedef struct vulkan_core_s {
PFN_vkGetInstanceProcAddr get_proc_addr;
uint32_t vulkan_version;
VkInstance instance;
VkDebugUtilsMessengerEXT debug_messenger;
byte *pool;
} vulkan_core_t;
vulkan_core_t vk_core = {0};
@ -27,10 +31,143 @@ vulkan_core_t vk_core = {0};
#define XVK_INSTANCE_FUNC(f) \
((PFN_ ##f)vk_core.get_proc_addr(vk_core.instance, #f))
static PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion;
#define NULLINST_FUNCS(X) \
X(vkEnumerateInstanceVersion) \
X(vkCreateInstance) \
#define INSTANCE_FUNCS(X) \
X(vkDestroyInstance) \
X(vkEnumeratePhysicalDevices) \
X(vkGetPhysicalDeviceProperties2) \
X(vkGetPhysicalDeviceFeatures2) \
X(vkGetPhysicalDeviceQueueFamilyProperties) \
X(vkGetPhysicalDeviceSurfaceSupportKHR) \
X(vkGetPhysicalDeviceMemoryProperties) \
X(vkCreateDevice) \
#define INSTANCE_DEBUG_FUNCS(X) \
X(vkCreateDebugUtilsMessengerEXT) \
X(vkDestroyDebugUtilsMessengerEXT) \
#define X(f) PFN_##f f = NULL;
NULLINST_FUNCS(X)
INSTANCE_FUNCS(X)
INSTANCE_DEBUG_FUNCS(X)
#undef X
static dllfunc_t nullinst_funcs[] = {
#define X(f) {#f, (void**)&f},
NULLINST_FUNCS(X)
#undef X
};
static dllfunc_t instance_funcs[] = {
#define X(f) {#f, (void**)&f},
INSTANCE_FUNCS(X)
#undef X
};
static dllfunc_t instance_debug_funcs[] = {
#define X(f) {#f, (void**)&f},
INSTANCE_DEBUG_FUNCS(X)
#undef X
};
static const char *resultName(VkResult result) {
switch (result) {
case VK_SUCCESS: return "VK_SUCCESS";
case VK_NOT_READY: return "VK_NOT_READY";
case VK_TIMEOUT: return "VK_TIMEOUT";
case VK_EVENT_SET: return "VK_EVENT_SET";
case VK_EVENT_RESET: return "VK_EVENT_RESET";
case VK_INCOMPLETE: return "VK_INCOMPLETE";
case VK_ERROR_OUT_OF_HOST_MEMORY: return "VK_ERROR_OUT_OF_HOST_MEMORY";
case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "VK_ERROR_OUT_OF_DEVICE_MEMORY";
case VK_ERROR_INITIALIZATION_FAILED: return "VK_ERROR_INITIALIZATION_FAILED";
case VK_ERROR_DEVICE_LOST: return "VK_ERROR_DEVICE_LOST";
case VK_ERROR_MEMORY_MAP_FAILED: return "VK_ERROR_MEMORY_MAP_FAILED";
case VK_ERROR_LAYER_NOT_PRESENT: return "VK_ERROR_LAYER_NOT_PRESENT";
case VK_ERROR_EXTENSION_NOT_PRESENT: return "VK_ERROR_EXTENSION_NOT_PRESENT";
case VK_ERROR_FEATURE_NOT_PRESENT: return "VK_ERROR_FEATURE_NOT_PRESENT";
case VK_ERROR_INCOMPATIBLE_DRIVER: return "VK_ERROR_INCOMPATIBLE_DRIVER";
case VK_ERROR_TOO_MANY_OBJECTS: return "VK_ERROR_TOO_MANY_OBJECTS";
case VK_ERROR_FORMAT_NOT_SUPPORTED: return "VK_ERROR_FORMAT_NOT_SUPPORTED";
case VK_ERROR_FRAGMENTED_POOL: return "VK_ERROR_FRAGMENTED_POOL";
case VK_ERROR_UNKNOWN: return "VK_ERROR_UNKNOWN";
case VK_ERROR_OUT_OF_POOL_MEMORY: return "VK_ERROR_OUT_OF_POOL_MEMORY";
case VK_ERROR_INVALID_EXTERNAL_HANDLE: return "VK_ERROR_INVALID_EXTERNAL_HANDLE";
case VK_ERROR_FRAGMENTATION: return "VK_ERROR_FRAGMENTATION";
case VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS: return "VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS";
case VK_ERROR_SURFACE_LOST_KHR: return "VK_ERROR_SURFACE_LOST_KHR";
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR";
case VK_SUBOPTIMAL_KHR: return "VK_SUBOPTIMAL_KHR";
case VK_ERROR_OUT_OF_DATE_KHR: return "VK_ERROR_OUT_OF_DATE_KHR";
case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR";
case VK_ERROR_VALIDATION_FAILED_EXT: return "VK_ERROR_VALIDATION_FAILED_EXT";
case VK_ERROR_INVALID_SHADER_NV: return "VK_ERROR_INVALID_SHADER_NV";
case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT:
return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT";
case VK_ERROR_NOT_PERMITTED_EXT: return "VK_ERROR_NOT_PERMITTED_EXT";
case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT: return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT";
case VK_THREAD_IDLE_KHR: return "VK_THREAD_IDLE_KHR";
case VK_THREAD_DONE_KHR: return "VK_THREAD_DONE_KHR";
case VK_OPERATION_DEFERRED_KHR: return "VK_OPERATION_DEFERRED_KHR";
case VK_OPERATION_NOT_DEFERRED_KHR: return "VK_OPERATION_NOT_DEFERRED_KHR";
case VK_PIPELINE_COMPILE_REQUIRED_EXT: return "VK_PIPELINE_COMPILE_REQUIRED_EXT";
default: return "UNKNOWN";
}
}
#define XVK_CHECK(f) do { \
const VkResult result = f; \
if (result != VK_SUCCESS) { \
gEngine.Host_Error( S_ERROR "%s:%d " #f " failed (%d): %s\n", \
__FILE__, __LINE__, result, resultName(result)); \
} \
} while(0)
static const char *validation_layers[] = {
"VK_LAYER_KHRONOS_validation",
};
static void loadInstanceFunctions(dllfunc_t *funcs, int count)
{
for (int i = 0; i < count; ++i)
{
*funcs[i].func = vk_core.get_proc_addr(vk_core.instance, funcs[i].name);
if (!*funcs[i].func)
{
gEngine.Con_Printf( S_WARN "Function %s was not loaded\n", funcs[i].name);
}
}
}
VkBool32 debugCallback(
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageTypes,
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
void *pUserData) {
(void)(pUserData);
(void)(messageTypes);
(void)(messageSeverity);
// TODO better messages, not only errors, what are other arguments for, ...
if (messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
gEngine.Con_Printf(S_ERROR "Validation: %s\n", pCallbackData->pMessage);
#ifdef DEBUG
#ifdef _MSC_VER
__debugbreak();
#else
__builtin_trap();
#endif
#endif
}
return VK_FALSE;
}
qboolean R_VkInit( void )
{
const qboolean debug = !!(gEngine.Sys_CheckParm("-vkdebug") || gEngine.Sys_CheckParm("-gldebug"));
if( !gEngine.R_Init_Video( REF_VULKAN )) // request Vulkan surface
{
@ -38,15 +175,17 @@ qboolean R_VkInit( void )
return false;
}
// TODO VkInstance create ...
vk_core.get_proc_addr = gEngine.VK_GetVkGetInstanceProcAddr();
if (!vk_core.get_proc_addr)
{
gEngine.Con_Printf( S_ERROR "Cannot get vkGetInstanceProcAddr address" );
return false;
gEngine.Con_Printf( S_ERROR "Cannot get vkGetInstanceProcAddr address" );
return false;
}
vkEnumerateInstanceVersion = XVK_INSTANCE_FUNC(vkEnumerateInstanceVersion);
vk_core.pool = Mem_AllocPool("Vulkan pool");
loadInstanceFunctions(nullinst_funcs, ARRAYSIZE(nullinst_funcs));
if (vkEnumerateInstanceVersion)
{
vkEnumerateInstanceVersion(&vk_core.vulkan_version);
@ -59,21 +198,86 @@ qboolean R_VkInit( void )
gEngine.Con_Printf( "Vulkan version %u.%u.%u\n", XVK_PARSE_VERSION(vk_core.vulkan_version));
{
const char **instance_exts = NULL;
const int num_instance_exts = gEngine.VK_GetInstanceExtensions(&instance_exts);
if (num_instance_exts < 0)
const char **instance_extensions = NULL;
unsigned int num_instance_extensions = debug ? 1 : 0;
VkApplicationInfo app_info = {
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.apiVersion = VK_API_VERSION_1_0,
.applicationVersion = VK_MAKE_VERSION(0, 0, 0), // TODO
.engineVersion = VK_MAKE_VERSION(0, 0, 0),
.pApplicationName = "",
.pEngineName = "xash3d-fwgs",
};
VkInstanceCreateInfo create_info = {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pApplicationInfo = &app_info,
};
int vid_extensions = gEngine.VK_GetInstanceExtensions(0, NULL);
if (vid_extensions < 0)
{
gEngine.Con_Printf( S_ERROR "Cannot get Vulkan instance extensions" );
gEngine.Con_Printf( S_ERROR "Cannot get Vulkan instance extensions\n" );
return false;
}
gEngine.Con_Reportf("Vulkan instance extensions: %d\n", num_instance_exts);
for (int i = 0; i < num_instance_exts; ++i)
num_instance_extensions += vid_extensions;
instance_extensions = Mem_Malloc(vk_core.pool, sizeof(const char*) * num_instance_extensions);
vid_extensions = gEngine.VK_GetInstanceExtensions(vid_extensions, instance_extensions);
if (vid_extensions < 0)
{
gEngine.Con_Reportf("\t%d: %s\n", i, instance_exts[i]);
gEngine.Con_Printf( S_ERROR "Cannot get Vulkan instance extensions\n" );
Mem_Free(instance_extensions);
return false;
}
Mem_Free(instance_exts);
if (debug)
{
instance_extensions[vid_extensions] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
}
gEngine.Con_Reportf("Requesting instance extensions: %d\n", num_instance_extensions);
for (int i = 0; i < num_instance_extensions; ++i)
{
gEngine.Con_Reportf("\t%d: %s\n", i, instance_extensions[i]);
}
create_info.enabledExtensionCount = num_instance_extensions;
create_info.ppEnabledExtensionNames = instance_extensions;
if (debug)
{
create_info.enabledLayerCount = ARRAYSIZE(validation_layers);
create_info.ppEnabledLayerNames = validation_layers;
gEngine.Con_Printf(S_WARN "Using Vulkan validation layers, expect severely degraded performance\n");
}
// TODO handle errors gracefully -- let it try next renderer
XVK_CHECK(vkCreateInstance(&create_info, NULL, &vk_core.instance));
loadInstanceFunctions(instance_funcs, ARRAYSIZE(instance_funcs));
if (debug)
{
loadInstanceFunctions(instance_debug_funcs, ARRAYSIZE(instance_debug_funcs));
if (vkCreateDebugUtilsMessengerEXT)
{
VkDebugUtilsMessengerCreateInfoEXT debug_create_info = {
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
.messageSeverity = 0x1111, //:vovka: VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
.messageType = 0x07,
.pfnUserCallback = debugCallback,
};
XVK_CHECK(vkCreateDebugUtilsMessengerEXT(vk_core.instance, &debug_create_info, NULL, &vk_core.debug_messenger));
} else
{
gEngine.Con_Printf(S_WARN "Vulkan debug utils messenger is not available\n");
}
}
Mem_Free(instance_extensions);
}
initTextures();
@ -83,9 +287,11 @@ qboolean R_VkInit( void )
void R_VkShutdown( void )
{
gEngine.Con_Printf("VK FIXME: %s\n", __FUNCTION__);
if (vk_core.debug_messenger)
{
vkDestroyDebugUtilsMessengerEXT(vk_core.instance, vk_core.debug_messenger, NULL);
}
// TODO destroy everything
//vkDestroyInstance(vk_core.instance, NULL);
vkDestroyInstance(vk_core.instance, NULL);
}