Problem:
In certain graphics cards, the current queue selection process will pick the same queueFamilyIndex more than once if there are not enough individual queueFamilyIndex's for each (graphics, transfer and present) queue. This triggers a validation error within vulkan that goes as follows:
Output:
Validation Error: [ VUID-VkDeviceCreateInfo-queueFamilyIndex-02802 ] Object 0: handle = 0x1088d50, type = VK_OBJECT_TYPE_PHYSICAL_DEVICE; | MessageID = 0x29498778 | CreateDevice(): pCreateInfo->pQueueCreateInfos[2].queueFamilyIndex (=1) is not unique and was also used in pCreateInfo->pQueueCreateInfos[1]. The Vulkan spec states: The queueFamilyIndex member of each element of pQueueCreateInfos must be unique within pQueueCreateInfos, except that two members can share the same queueFamilyIndex if one describes protected-capable queues and one describes queues that are not protected-capable (https://vulkan.lunarg.com/doc/view/1.3.224.0/linux/1.3-extensions/vkspec.html#VUID-VkDeviceCreateInfo-queueFamilyIndex-02802)
neofetch --stdout
shadoww@xddz
------------
OS: Debian GNU/Linux 11 (bullseye) x86_64
Host: Aspire A315-21G V1.12
Kernel: 5.10.0-18-amd64
Uptime: 1 day, 13 hours, 37 mins
Packages: 2926 (dpkg)
Shell: zsh 5.8
Resolution: 1366x768
WM: bspwm
Theme: Adwaita-One-Dark [GTK2/3]
Icons: hicolor [GTK2/3]
Terminal: alacritty
Terminal Font: Iosevka
CPU: AMD A9-9420 RADEON R5 2C+3G (2) @ 3.000GHz
GPU: AMD ATI Radeon R5 M230 / R7 M260DX / Radeon 520 Mobile
GPU: AMD ATI Radeon R2/R3/R4/R5 Graphics
Memory: 5397MiB / 7410MiB
VkQueueFamilyProperties (vulkaninfo
):
VkQueueFamilyProperties:
========================
queueProperties[0]:
-------------------
minImageTransferGranularity = (1,1,1)
queueCount = 1
queueFlags = QUEUE_GRAPHICS | QUEUE_COMPUTE | QUEUE_TRANSFER | QUEUE_SPARSE_BINDING
timestampValidBits = 64
present support = true
queueProperties[1]:
-------------------
minImageTransferGranularity = (1,1,1)
queueCount = 4
queueFlags = QUEUE_COMPUTE | QUEUE_TRANSFER | QUEUE_SPARSE_BINDING
timestampValidBits = 64
present support = true
./engine/src/renderer/vulkan/vulkan_device.c
/* avoid creating additional queues for shared indices */
b8 present_shares_graphics_queue = (context->device.graphics_queue_index == context->device.present_queue_index);
b8 transfer_shares_graphics_queue = (context->device.graphics_queue_index == context->device.transfer_queue_index);
u32 index_count = 1;
if (!present_shares_graphics_queue) {
index_count++;
}
if (!transfer_shares_graphics_queue) {
index_count++;
}
u32 indices[index_count];
u8 index = 0;
indices[index++] = context->device.graphics_queue_index;
if (!present_shares_graphics_queue) {
indices[index++] = context->device.present_queue_index;
}
if (!transfer_shares_graphics_queue) {
indices[index++] = context->device.transfer_queue_index;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * */
VkDeviceQueueCreateInfo queue_create_infos[index_count];
for (u32 i = 0; i < index_count; ++i) {
queue_create_infos[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue_create_infos[i].queueFamilyIndex = indices[i];
queue_create_infos[i].queueCount = 1;
/* TODO: Enable this for a future enhancement. */
/* if (indices[i] == context->device.graphics_queue_index) { */
/* queue_create_infos[i].queueCount = 2; */
/* } */
queue_create_infos[i].flags = 0;
queue_create_infos[i].pNext = 0;
f32 queue_priority = 1.0f;
queue_create_infos[i].pQueuePriorities = &queue_priority;
}
/* request device features */
/* TODO: configuration driven */
VkPhysicalDeviceFeatures device_features = {0};
device_features.samplerAnisotropy = VK_TRUE; /* request anisotropy */
/* * * * * * * * * * * * * */
/* create device */
VkDeviceCreateInfo device_create_info = {VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO};
device_create_info.queueCreateInfoCount = index_count;
device_create_info.pQueueCreateInfos = queue_create_infos;
device_create_info.pEnabledFeatures = &device_features;
device_create_info.enabledExtensionCount = 1;
const char * extension_names = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
device_create_info.ppEnabledExtensionNames = &extension_names;
/* deprecated and ignored */
device_create_info.enabledLayerCount = 0;
device_create_info.ppEnabledLayerNames = 0;
/* * * * * * * * * * * * * */
/* failure */
VK_CHECK(vkCreateDevice(context->device.physical_device,
&device_create_info,
context->allocator,
&context->device.logical_device));
M_INFO("Successfully created logical device.");
/* * * * * * * * */
As you can see above, I've only got 2 "queue families", yet, the current code requires at least one queue family for each mode (graphics, present, transfer).
How can I possibly fix this?