Vulkan --- vkAcquireNextImageKHR throws std::out_of_range when certain queue families are used

510 views Asked by At

TL;DR

vkAcquireNextImageKHR throws std::out_of_range when certain queue families are used. Is this expected behavior? How to debug?

Detailed description

The Vulkan program I use is based on vulkan-tutorial.com. I discovered that my VkPhysicalDevice has three queue families, each flagged with VK_QUEUE_GRAPHICS_BIT and present support:

uint32_t queueFamilyCount;
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());

std::vector<uint32_t> graphicsQueueFamilyIndices;
std::vector<uint32_t> presentQueueFamilyIndices;
int i = 0;
for (const auto& queueFamily : queueFamilies)
{
  if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT)
  {
    graphicsQueueFamilyIndices.push_back(i);
  }

  VkBool32 presentSupport = false;           
  vkGetPhysicalDeviceSurfaceSupportKHR(         
      device,
      i,          
      surface,
      &presentSupport
    );
  if (presentSupport)
  {
    presentQueueFamilyIndices.push_back(i);
  }

  ++i;
}

// graphicsQueueFamilyIndices = {0, 1, 2}
// presentQueueFamilyIndices = {0, 1, 2}

These are later used when creating the logical device, the swapchain (the queue families all have present capability) and the command pool. Later the program calls

vkAcquireNextImageKHR(device, swapchain, UINT64_MAX, semaphore, VK_NULL_HANDLE, &imageIndex);

But using any other than 0 causes this API call to throw an uncaught std::out_of_range (output is that of lldb): But using any combination of present and graphics queue indices of the following causes this API call to throw an uncaught std::out_of_range: (1, 1), (1, 2), (2, 1), (2, 2).

lldb output is as follows:

2019-12-01 11:36:35.599882+0100 main[22130:167876] flock failed to lock maps file: errno = 35
2019-12-01 11:36:35.600165+0100 main[22130:167876] flock failed to lock maps file: errno = 35
libc++abi.dylib: terminating with uncaught exception of type std::out_of_range: Index out of range
Process 22130 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
    frame #0: 0x00007fff675c949a libsystem_kernel.dylib`__pthread_kill + 10
libsystem_kernel.dylib`__pthread_kill:
->  0x7fff675c949a <+10>: jae    0x7fff675c94a4            ; <+20>
    0x7fff675c949c <+12>: movq   %rax, %rdi
    0x7fff675c949f <+15>: jmp    0x7fff675c33b7            ; cerror_nocancel
    0x7fff675c94a4 <+20>: retq
Target 0: (main) stopped.

The same error is caused when using an indices that doesn't even refer to a queue, like 123. I'm using the VK_LAYER_KHRONOS_validation layer, which doesn't utter any complaint.

Questions

(1) Is this the expected behavior for passing the wrong queue family index to Vk?

(2) Are there validation layers that are capable of catching this error and making it more verbose?

(3) Why do these choices of queue families cause this error?

Details

Using queue family indices (1, 1) for graphics and present queue families during logical device creation while using index 0 for everything else already causes vkAcquireNextImage to raise the error. Of course, VK_LAYER_KHRONOS_validation raises the following warning upon command pool creation:

Validation layer: vkCreateCommandPool: pCreateInfo->queueFamilyIndex (= 0) is not one of the queue families given via VkDeviceQueueCreateInfo structures when the device was created. The Vulkan spec states: pCreateInfo::queueFamilyIndex must be the index of a queue family available in the logical device device. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkCreateCommandPool-queueFamilyIndex-01937)

I'm using MoltenVK (from the Vulkan SDK, version 1.1.126.0) on macOS Catalina 10.15.1.

Workarounds

  • Using version 1.1.121.1 of the SDK prevents the throw from occurring.

  • Creating a device queue family with index 0 alongside any other device queues one might require prevents the throw from occurring.

Issue on GitHub

This has now been raised as issue on GitHub [here].

1

There are 1 answers

3
krOoze On BEST ANSWER

That seems to be a bug in MoltenVK. Inspection of the MoltenVK source indicates that it always implicitly uses queue 0 of queue family 0 for vkAcquireNextImage. The fact that you have no problems if you create that queue explicitly, or if you use just a Fence tells me MoltenVk probably forgets to initialize that implicit queue properly for itself.

The GitHub Issue is filed at KhronosGroup/MoltenVK#791.