diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index 1ab96300c..d0cc47a6f 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -24,13 +24,13 @@ GLOBAL_LEVEL_VULKAN_FUNCTION (vkCreateInstance) INSTANCE_LEVEL_VULKAN_FUNCTION (vkEnumeratePhysicalDevices) INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceProperties) INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceFeatures) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceQueueFamilyProperties) INSTANCE_LEVEL_VULKAN_FUNCTION (vkCreateDevice) INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetDeviceProcAddr) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkDestroyInstance) INSTANCE_LEVEL_VULKAN_FUNCTION (vkEnumerateDeviceLayerProperties) INSTANCE_LEVEL_VULKAN_FUNCTION (vkEnumerateDeviceExtensionProperties) INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceMemoryProperties) -INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceQueueFamilyProperties) -INSTANCE_LEVEL_VULKAN_FUNCTION (vkDestroyInstance) #undef INSTANCE_LEVEL_VULKAN_FUNCTION @@ -46,6 +46,8 @@ INSTANCE_LEVEL_VULKAN_FUNCTION_EXTENSION (vkCreateDebugUtilsMessengerEXT) #define DEVICE_LEVEL_VULKAN_FUNCTION(function) #endif +DEVICE_LEVEL_VULKAN_FUNCTION (vkGetDeviceQueue) + #undef DEVICE_LEVEL_VULKAN_FUNCTION #ifndef DEVICE_LEVEL_VULKAN_FUNCTION_EXTENSION diff --git a/include/QF/Vulkan/init.h b/include/QF/Vulkan/init.h index b12dcd42e..4a97b82f8 100644 --- a/include/QF/Vulkan/init.h +++ b/include/QF/Vulkan/init.h @@ -31,14 +31,23 @@ #include "QF/qtypes.h" #include "QF/Vulkan/funcs.h" +typedef struct { + VkDevice device; + VkQueue queue; + + #define DEVICE_LEVEL_VULKAN_FUNCTION(name) PFN_##name name; + #define DEVICE_LEVEL_VULKAN_FUNCTION_EXTENSION(name) 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; - VkPhysicalDeviceFeatures features; VkPhysicalDeviceMemoryProperties memory; uint32_t numQueueFamilies; VkQueueFamilyProperties *queueFamilies; @@ -61,5 +70,8 @@ VulkanInstance_t *Vulkan_CreateInstance (const char *appName, const char **layers, const char **extensions); void Vulkan_DestroyInstance (VulkanInstance_t *instance); +int Vulkan_ExtensionsSupported (const VkExtensionProperties *extensions, + int numExtensions, + const char * const *requested); #endif // __QF_Vulkan_init_h diff --git a/libs/video/renderer/vulkan/init.c b/libs/video/renderer/vulkan/init.c index 4967c8125..2c4fb7ca1 100644 --- a/libs/video/renderer/vulkan/init.c +++ b/libs/video/renderer/vulkan/init.c @@ -388,3 +388,23 @@ Vulkan_DestroyInstance (VulkanInstance_t *instance) instance->vkDestroyInstance (instance->instance, 0); free (instance); } + +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; + } + } + return !*requested; +} diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 099135be7..43921df30 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -59,6 +59,7 @@ static void *vulkan_library; static VulkanInstance_t *vulkan_instance; +static VulkanDevice_t *vulkan_device; static void load_vulkan_library (void) @@ -102,21 +103,117 @@ Vulkan_Init_Cvars () "restart)."); } -const char *extensions[] = { - "foo", +static const char *instance_extensions[] = { 0, }; +static const char *device_extensions[] = { + 0, +}; + +static int +count_bits (uint32_t val) +{ + int bits = 0; + while (val) { + bits += val & 1; + val >>= 1; + } + return bits; +} + +static int +find_queue_family (VulkanPhysDevice_t *dev, uint32_t flags) +{ + int best_diff = 32; + uint32_t family = -1; + + for (uint32_t i = 0; i < dev->numQueueFamilies; i++) { + VkQueueFamilyProperties *queue = &dev->queueFamilies[i]; + + if ((queue->queueFlags & flags) == flags) { + int diff = count_bits (queue->queueFlags & ~flags); + if (diff < best_diff) { + best_diff = diff; + family = i; + } + } + } + return family; +} + +static void +load_device_funcs (VulkanInstance_t *inst, VulkanDevice_t *dev) +{ +#define DEVICE_LEVEL_VULKAN_FUNCTION(name) \ + dev->name = (PFN_##name) inst->vkGetDeviceProcAddr (dev->device, #name); \ + if (!dev->name) { \ + Sys_Error ("Couldn't find device level function %s", #name); \ + } + +#define DEVICE_LEVEL_VULKAN_FUNCTION_EXTENSION(name) \ + 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" +} + +static VulkanDevice_t * +create_suitable_device (VulkanInstance_t *instance) +{ + for (uint32_t i = 0; i < instance->numDevices; i++) { + VulkanPhysDevice_t *phys = &instance->devices[i]; + if (!Vulkan_ExtensionsSupported (phys->extensions, phys->numExtensions, + device_extensions)) { + return 0; + } + int family = find_queue_family (phys, VK_QUEUE_GRAPHICS_BIT); + if (family < 0) { + return 0; + } + 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, + 0, 0, + 0, device_extensions, + &features + }; + memset (&features, 0, sizeof (features)); + VulkanDevice_t *device = calloc (1, sizeof (VulkanDevice_t)); + if (instance->vkCreateDevice (phys->device, &dCreateInfo, 0, + &device->device) == VK_SUCCESS) { + load_device_funcs (instance, device); + device->vkGetDeviceQueue (device->device, family, + 0, &device->queue); + return device; + } + } + return 0; +} + void Vulkan_Init_Common (void) { + Sys_Printf ("Vulkan_Init_Common\n"); Vulkan_Init_Cvars (); load_vulkan_library (); - vulkan_instance = Vulkan_CreateInstance (PACKAGE_STRING, 0x000702ff, 0, extensions);//FIXME version - Sys_Printf ("Vulkan_Init_Common\n"); + vulkan_instance = Vulkan_CreateInstance (PACKAGE_STRING, 0x000702ff, 0, instance_extensions);//FIXME version + vulkan_device = create_suitable_device (vulkan_instance); + if (!vulkan_device) { + Sys_Error ("no suitable vulkan device found"); + } if (developer->int_val & SYS_VID) { + Sys_Printf ("%p %p\n", vulkan_device->device, vulkan_device->queue); Vulkan_DestroyInstance (vulkan_instance); Sys_Quit(); }