create vulkan device
This commit is contained in:
parent
0dcedece06
commit
0170f3e408
260
ref_vk/vk_core.c
260
ref_vk/vk_core.c
|
@ -12,25 +12,11 @@
|
|||
#define VK_NO_PROTOTYPES
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
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};
|
||||
|
||||
#define XVK_PARSE_VERSION(v) \
|
||||
VK_VERSION_MAJOR(v), \
|
||||
VK_VERSION_MINOR(v), \
|
||||
VK_VERSION_PATCH(v)
|
||||
|
||||
#define XVK_INSTANCE_FUNC(f) \
|
||||
((PFN_ ##f)vk_core.get_proc_addr(vk_core.instance, #f))
|
||||
|
||||
#define NULLINST_FUNCS(X) \
|
||||
X(vkEnumerateInstanceVersion) \
|
||||
X(vkCreateInstance) \
|
||||
|
@ -44,15 +30,23 @@ vulkan_core_t vk_core = {0};
|
|||
X(vkGetPhysicalDeviceSurfaceSupportKHR) \
|
||||
X(vkGetPhysicalDeviceMemoryProperties) \
|
||||
X(vkCreateDevice) \
|
||||
X(vkGetDeviceProcAddr) \
|
||||
X(vkGetPhysicalDeviceProperties) \
|
||||
|
||||
#define INSTANCE_DEBUG_FUNCS(X) \
|
||||
X(vkCreateDebugUtilsMessengerEXT) \
|
||||
X(vkDestroyDebugUtilsMessengerEXT) \
|
||||
|
||||
#define DEVICE_FUNCS(X) \
|
||||
X(vkGetDeviceQueue) \
|
||||
|
||||
static PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
|
||||
|
||||
#define X(f) PFN_##f f = NULL;
|
||||
NULLINST_FUNCS(X)
|
||||
INSTANCE_FUNCS(X)
|
||||
INSTANCE_DEBUG_FUNCS(X)
|
||||
DEVICE_FUNCS(X)
|
||||
#undef X
|
||||
|
||||
static dllfunc_t nullinst_funcs[] = {
|
||||
|
@ -73,6 +67,12 @@ static dllfunc_t instance_debug_funcs[] = {
|
|||
#undef X
|
||||
};
|
||||
|
||||
static dllfunc_t device_funcs[] = {
|
||||
#define X(f) {#f, (void**)&f},
|
||||
DEVICE_FUNCS(X)
|
||||
#undef X
|
||||
};
|
||||
|
||||
static const char *resultName(VkResult result) {
|
||||
switch (result) {
|
||||
case VK_SUCCESS: return "VK_SUCCESS";
|
||||
|
@ -130,18 +130,6 @@ 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,
|
||||
|
@ -165,41 +153,58 @@ VkBool32 debugCallback(
|
|||
return VK_FALSE;
|
||||
}
|
||||
|
||||
qboolean R_VkInit( void )
|
||||
{
|
||||
const qboolean debug = !!(gEngine.Sys_CheckParm("-vkdebug") || gEngine.Sys_CheckParm("-gldebug"));
|
||||
typedef struct physical_device_s {
|
||||
VkPhysicalDevice device;
|
||||
VkPhysicalDeviceMemoryProperties memory_properties;
|
||||
VkPhysicalDeviceProperties properties;
|
||||
} physical_device_t;
|
||||
|
||||
if( !gEngine.R_Init_Video( REF_VULKAN )) // request Vulkan surface
|
||||
typedef struct vulkan_core_s {
|
||||
uint32_t vulkan_version;
|
||||
VkInstance instance;
|
||||
VkDebugUtilsMessengerEXT debug_messenger;
|
||||
|
||||
byte *pool;
|
||||
|
||||
qboolean debug;
|
||||
|
||||
VkSurfaceKHR surface;
|
||||
|
||||
physical_device_t physical_device;
|
||||
VkDevice device;
|
||||
VkQueue queue;
|
||||
} vulkan_core_t;
|
||||
|
||||
vulkan_core_t vk_core = {0};
|
||||
|
||||
static void loadInstanceFunctions(dllfunc_t *funcs, int count)
|
||||
{
|
||||
gEngine.Con_Printf( S_ERROR "Cannot initialize Vulkan video" );
|
||||
return false;
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
*funcs[i].func = vkGetInstanceProcAddr(vk_core.instance, funcs[i].name);
|
||||
if (!*funcs[i].func)
|
||||
{
|
||||
gEngine.Con_Printf( S_WARN "Function %s was not loaded\n", funcs[i].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vk_core.get_proc_addr = gEngine.VK_GetVkGetInstanceProcAddr();
|
||||
if (!vk_core.get_proc_addr)
|
||||
static void loadDeviceFunctions(dllfunc_t *funcs, int count)
|
||||
{
|
||||
gEngine.Con_Printf( S_ERROR "Cannot get vkGetInstanceProcAddr address" );
|
||||
return false;
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
*funcs[i].func = vkGetDeviceProcAddr(vk_core.device, funcs[i].name);
|
||||
if (!*funcs[i].func)
|
||||
{
|
||||
gEngine.Con_Printf( S_WARN "Function %s was not loaded\n", funcs[i].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vk_core.pool = Mem_AllocPool("Vulkan pool");
|
||||
|
||||
loadInstanceFunctions(nullinst_funcs, ARRAYSIZE(nullinst_funcs));
|
||||
|
||||
if (vkEnumerateInstanceVersion)
|
||||
{
|
||||
vkEnumerateInstanceVersion(&vk_core.vulkan_version);
|
||||
}
|
||||
else
|
||||
{
|
||||
vk_core.vulkan_version = VK_MAKE_VERSION(1, 0, 0);
|
||||
}
|
||||
|
||||
gEngine.Con_Printf( "Vulkan version %u.%u.%u\n", XVK_PARSE_VERSION(vk_core.vulkan_version));
|
||||
|
||||
static qboolean createInstance( void )
|
||||
{
|
||||
const char **instance_extensions = NULL;
|
||||
unsigned int num_instance_extensions = debug ? 1 : 0;
|
||||
unsigned int num_instance_extensions = vk_core.debug ? 1 : 0;
|
||||
VkApplicationInfo app_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||
.apiVersion = VK_API_VERSION_1_0,
|
||||
|
@ -231,7 +236,7 @@ qboolean R_VkInit( void )
|
|||
return false;
|
||||
}
|
||||
|
||||
if (debug)
|
||||
if (vk_core.debug)
|
||||
{
|
||||
instance_extensions[vid_extensions] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
|
||||
}
|
||||
|
@ -245,7 +250,7 @@ qboolean R_VkInit( void )
|
|||
create_info.enabledExtensionCount = num_instance_extensions;
|
||||
create_info.ppEnabledExtensionNames = instance_extensions;
|
||||
|
||||
if (debug)
|
||||
if (vk_core.debug)
|
||||
{
|
||||
create_info.enabledLayerCount = ARRAYSIZE(validation_layers);
|
||||
create_info.ppEnabledLayerNames = validation_layers;
|
||||
|
@ -258,7 +263,7 @@ qboolean R_VkInit( void )
|
|||
|
||||
loadInstanceFunctions(instance_funcs, ARRAYSIZE(instance_funcs));
|
||||
|
||||
if (debug)
|
||||
if (vk_core.debug)
|
||||
{
|
||||
loadInstanceFunctions(instance_debug_funcs, ARRAYSIZE(instance_debug_funcs));
|
||||
|
||||
|
@ -278,8 +283,151 @@ qboolean R_VkInit( void )
|
|||
}
|
||||
|
||||
Mem_Free(instance_extensions);
|
||||
return true;
|
||||
}
|
||||
|
||||
qboolean createDevice( void )
|
||||
{
|
||||
VkPhysicalDevice *physical_devices = NULL;
|
||||
uint32_t num_physical_devices = 0;
|
||||
uint32_t best_device_index = UINT32_MAX;
|
||||
uint32_t queue_index = UINT32_MAX;
|
||||
|
||||
XVK_CHECK(vkEnumeratePhysicalDevices(vk_core.instance, &num_physical_devices, physical_devices));
|
||||
|
||||
physical_devices = Mem_Malloc(vk_core.pool, sizeof(VkPhysicalDevice) * num_physical_devices);
|
||||
XVK_CHECK(vkEnumeratePhysicalDevices(vk_core.instance, &num_physical_devices, physical_devices));
|
||||
|
||||
gEngine.Con_Reportf("Have %u devices:\n", num_physical_devices);
|
||||
for (uint32_t i = 0; i < num_physical_devices; ++i)
|
||||
{
|
||||
VkQueueFamilyProperties *queue_family_props = NULL;
|
||||
uint32_t num_queue_family_properties = 0;
|
||||
VkPhysicalDeviceProperties props;
|
||||
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &num_queue_family_properties, queue_family_props);
|
||||
queue_family_props = Mem_Malloc(vk_core.pool, sizeof(VkQueueFamilyProperties) * num_queue_family_properties);
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &num_queue_family_properties, queue_family_props);
|
||||
|
||||
vkGetPhysicalDeviceProperties(physical_devices[i], &props);
|
||||
gEngine.Con_Reportf("\t%u: %04x:%04x %d %s %u.%u.%u %u.%u.%u\n",
|
||||
i, props.vendorID, props.deviceID, props.deviceType, props.deviceName,
|
||||
XVK_PARSE_VERSION(props.driverVersion), XVK_PARSE_VERSION(props.apiVersion));
|
||||
|
||||
for (uint32_t j = 0; j < num_queue_family_properties; ++j)
|
||||
{
|
||||
VkBool32 present = 0;
|
||||
if (!(queue_family_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT))
|
||||
continue;
|
||||
|
||||
vkGetPhysicalDeviceSurfaceSupportKHR(physical_devices[i], j, vk_core.surface, &present);
|
||||
|
||||
if (!present)
|
||||
continue;
|
||||
|
||||
queue_index = i;
|
||||
break;
|
||||
}
|
||||
|
||||
Mem_Free(queue_family_props);
|
||||
|
||||
// TODO pick the best device
|
||||
// For now we'll pick the first one that has graphics and can present to the surface
|
||||
if (queue_index < num_queue_family_properties)
|
||||
{
|
||||
best_device_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (best_device_index < num_physical_devices)
|
||||
{
|
||||
float prio = 1.f;
|
||||
VkDeviceQueueCreateInfo queue_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
||||
.flags = 0,
|
||||
.queueFamilyIndex = queue_index,
|
||||
.queueCount = 1,
|
||||
.pQueuePriorities = &prio,
|
||||
};
|
||||
const char *device_extensions[] = {
|
||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
||||
};
|
||||
VkDeviceCreateInfo create_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
.flags = 0,
|
||||
.queueCreateInfoCount = 1,
|
||||
.pQueueCreateInfos = &queue_info,
|
||||
.enabledExtensionCount = ARRAYSIZE(device_extensions),
|
||||
.ppEnabledExtensionNames = device_extensions,
|
||||
};
|
||||
|
||||
vk_core.physical_device.device = physical_devices[best_device_index];
|
||||
vkGetPhysicalDeviceMemoryProperties(vk_core.physical_device.device, &vk_core.physical_device.memory_properties);
|
||||
|
||||
vkGetPhysicalDeviceProperties(vk_core.physical_device.device, &vk_core.physical_device.properties);
|
||||
gEngine.Con_Printf("Picked device #%u: %04x:%04x %d %s %u.%u.%u %u.%u.%u\n",
|
||||
best_device_index, vk_core.physical_device.properties.vendorID, vk_core.physical_device.properties.deviceID, vk_core.physical_device.properties.deviceType, vk_core.physical_device.properties.deviceName,
|
||||
XVK_PARSE_VERSION(vk_core.physical_device.properties.driverVersion), XVK_PARSE_VERSION(vk_core.physical_device.properties.apiVersion));
|
||||
|
||||
// TODO allow it to fail gracefully
|
||||
XVK_CHECK(vkCreateDevice(vk_core.physical_device.device, &create_info, NULL, &vk_core.device));
|
||||
|
||||
loadDeviceFunctions(device_funcs, ARRAYSIZE(device_funcs));
|
||||
|
||||
vkGetDeviceQueue(vk_core.device, 0, 0, &vk_core.queue);
|
||||
}
|
||||
|
||||
Mem_Free(physical_devices);
|
||||
return true;
|
||||
}
|
||||
|
||||
qboolean R_VkInit( void )
|
||||
{
|
||||
vk_core.debug = !!(gEngine.Sys_CheckParm("-vkdebug") || gEngine.Sys_CheckParm("-gldebug"));
|
||||
|
||||
if( !gEngine.R_Init_Video( REF_VULKAN )) // request Vulkan surface
|
||||
{
|
||||
gEngine.Con_Printf( S_ERROR "Cannot initialize Vulkan video\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
vkGetInstanceProcAddr = gEngine.VK_GetVkGetInstanceProcAddr();
|
||||
if (!vkGetInstanceProcAddr)
|
||||
{
|
||||
gEngine.Con_Printf( S_ERROR "Cannot get vkGetInstanceProcAddr address\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
vk_core.pool = Mem_AllocPool("Vulkan pool");
|
||||
|
||||
loadInstanceFunctions(nullinst_funcs, ARRAYSIZE(nullinst_funcs));
|
||||
|
||||
if (vkEnumerateInstanceVersion)
|
||||
{
|
||||
vkEnumerateInstanceVersion(&vk_core.vulkan_version);
|
||||
}
|
||||
else
|
||||
{
|
||||
vk_core.vulkan_version = VK_MAKE_VERSION(1, 0, 0);
|
||||
}
|
||||
|
||||
gEngine.Con_Printf( "Vulkan version %u.%u.%u\n", XVK_PARSE_VERSION(vk_core.vulkan_version));
|
||||
|
||||
if (!createInstance())
|
||||
return false;
|
||||
|
||||
vk_core.surface = gEngine.VK_CreateSurface(vk_core.instance);
|
||||
if (!vk_core.surface)
|
||||
{
|
||||
gEngine.Con_Printf( S_ERROR "Cannot create Vulkan surface\n" );
|
||||
// FIXME destroy surface
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!createDevice())
|
||||
return false;
|
||||
|
||||
initTextures();
|
||||
|
||||
return true;
|
||||
|
@ -293,5 +441,7 @@ void R_VkShutdown( void )
|
|||
}
|
||||
|
||||
vkDestroyInstance(vk_core.instance, NULL);
|
||||
|
||||
Mem_FreePool(&vk_core.pool);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue