1
votes

I am not quite sure if it is actually correct what I'm trying to do but there is not so much documentation about Vulkan so this is what I came up with. If I'm totally wrong in the way how I designed it, please correct me as well!

In my Vulkan application I have three different Queues

  • graphicsQueue: Used to submit graphics command buffers
  • presentQueue: Used to present finished images
  • transferQueue: Used to copy buffers, textures etc.

I am trying to implement async model loading, which means all vertices, textures etc are loaded in a separate thread. When the model is finished loading, the draw command buffers are updated by the main thread so the newly loaded object is rendered.

Everything is working as it should expect that I get a warning from the Vulkan Validation layers:

THREADING ERROR : object of type VkQueue is simultaneously used in thread ...

If I step through the the Debugger, I can see that the following lines are affected:

//main Loop
vkQueueSubmit(graphicsQueue, ...) //draw command buffer

and

//Background loading thread
vkQueueSubmit(transferQueue, ...)//copy vertex command buffer

I printed the address of graphicsQueue and transferQueue and found out that they are the same (same address), so it seems like my graphics Card only Supports a single Queue. So now I'm trying to synchronize the calls to vkQueueSubmit using a Semaphore:

submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = &queueSemaphore;

Unformtunately the error is still the same.

So my question: How do I properly synchronize calls to vkQueueSubmit?

1
double check your initialization to ensure that your assumption about the queues is correct - ratchet freak
As @NicolBolas noted, this is a problem with simultaneous access to a VkQueue object. Semaphores won't help You here - they are used to synchronize operations on the GPU. You need to use mutexes so the vkQueueSubmit() functions are not called from multiple threads at the same time. - Ekzuzy

1 Answers

7
votes

You're overthinking the problem.

You have a function which manipulates an object. And you want to be able to call that function from multiple threads on the same object. But manipulating that object through that function isn't thread-safe. So the onus is up to you to make it thread safe.

The solution is the same whether this is a Vulkan object or a regular C/C++ type: you use a mutex. If your two queues are the same queue, you have to lock a mutex around the site where each thread calls vkQueueSubmit.

Don't let Vulkan's complexities distract you from the simple solution ;)

All that being said however, if your graphics and transfer queues are the same, it would probably be better for you to find a way to restructure your code so that you're not trying to submit the different batches on different threads. That is, make your code more adaptive to the hardware.

If the GPU offers a distinct transfer queue, then your transfer thread generates the transfer CBs and submits them (along with passing the appropriate semaphore to the graphics submission thread so that it can wait at the correct time). If the GPU has no distinct transfer queue, then you can still generate the transfer CBs on a different thread. But instead of passing a semaphore to the graphics thread, you pass the command buffers. And those get submitted along with the next graphics batch; the graphics submission thread can also insert appropriate synchronization between the transfer and graphics operations.