Syncronization in single command buffer

342 Views Asked by At

In my Vulkan app I'm using a single command buffer and I'm prerecording everything in it, right now I have a bug and one of the places that I'm suspicious about it, is where I copying a region of data from a staging buffer to GPU(device local) buffer, and then I do my operations on that buffer.

The Question is, should I do synchronization even when I'm using a single command buffer?

My question is not specific to only copy buffer it is a general question, Is there any case that even in a single command buffer app you should do synchronization?

2

There are 2 best solutions below

3
On BEST ANSWER

In Vulkan, you have to almost synchronize everything.

It is not because you are using only one command buffer that commands can not be run asynchronously.

Let's say for example that you are copying a buffer, and after you want to read this buffer as a Vertex Buffer.

You must issue a memory barrier from the TRANSFER_STAGE to the VERTEX_INPUT_STAGE and with a srcAccess TRANSFER_WRITE and a dstAccess VERTEX_ATTRIBUTE_READ.

Going that way, the barrier ensure the transfer is finished AND that the memory is both available and visible.

It could be red like that : When the second command reach the VERTEX_INPUT_STAGE, please wait for the prior command finish the TRANSFER_STAGE (It is the execution barrier). And flush the TRANSFER_WRITE cache for the TRANSFER_STAGE and invalidate the VERTEX_ATTRIBUTE_READ cache for the VERTEX_INPUT_STAGE (it is the memory barrier). I used the word flush / invalidate for a specific stage here because some stages TOP and BOTTOM does not access memory, so it is useless to try to perform a memory barrier on them.

However, I read that you are using a staging buffer, when you WRITE into your staging buffer, the memoryBarrier from the HOST are made by the submission of the command buffer. However, if you do not use COHERENT memory, you must use vkFlushMappedMemoryRanges.

A good idea could be to use the barrier JUST before you will use the datas :

TRANSFER
WORK that do not use the value transferred
BARRIER
USE DATAS

You could have more informations here

0
On

Should I do synchronization even when I'm using a single command buffer?

I am tempted to make a single word Answer: "yes".

Even with a single buffer (or generally a queue) you need to synchronize, because commands in the command buffer are allowed to overlap in execution. You need to synchronize their accesses to resources (VkImages, VkBuffers and their memory). You usually do that with pipeline barriers, which add a execution dependency and memory dependency between some suboperations of the commands in the queue.

Chances are you are using a swapchain in your app. There is no "presentation pipeline" to synchronize with pipeline barriers, so semaphores must be used for synchronization.

And finally you still need to synchronize with host (CPU). You are not allowed to destroy handles that are still in use (and you do need to destroy/clenup eventually). You must make sure they are not in use by using fences or fence-like vkDeviceWaitIdle() synchronization.

And let's not forget that (as always) you need to synchronize your CPU threads too. To be specific in Vulkan you still need to synchronize/mutex around the arguments you pass to commands.

There are only a few rare exceptions where you do not have to do some kind of explicit synchronization. For exemple you do not need to synchronize host (CPU) writes that are coherent (or flushed) as long as that happened before calling vkQueueSubmit.