0

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?

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
mango
  • 1
  • You trivially de-duplicate the list of queues before you pass it to the API? – krOoze Oct 10 '22 at 13:39
  • "*the current code requires at least one queue family for each mode (graphics, present, transfer).*" Vulkan does not require that implementations provide such things, so your "current code" needs to be changed to be in line with how implementations work. Basically, you wrote the code wrong, so fix that. – Nicol Bolas Oct 10 '22 at 13:43
  • Graphics queue virtually always has present (assuming there is any present at all). No driver will have separate present queue, because it currently does not make sense on API level. So might as well panic if that is not the case or polyfill it with `VK_SHARING_MODE_CONCURRENT`. All queues support some kind of transfer, so distinguishing that does not make much sense either, unless you are looking specifically for DMA queues. – krOoze Oct 10 '22 at 13:57

0 Answers0