Create a logical device with a single queue

A single graphics-capable queue should be enough for now. However, I'm
not sure I'm happy with a lot of the code: it's a bit difficult to write
flexibly configured code for Vulkan (or seems to be at this stage),
especially in C.
This commit is contained in:
Bill Currie 2019-07-07 01:28:05 +09:00
parent 2bc78e7f0a
commit ab08e4f207
4 changed files with 138 additions and 7 deletions

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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();
}