user815129
user815129

Reputation: 2314

compute writes and transfer sync

I have a compute shader that writes into a storage buffer. As soon as the compute queue becomes idle, the storage buffer is transfered to an image. Pipeline barriers before and after the transfer take care of layout transitions.

The relevant code is as follows:

vkCmdDispatch(...);
...
vkQueueWaitIdle(...);
...

...

VkImageMemoryBarrier i = {};

i.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
i.srcAccessMask = 0;
i.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
i.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
i.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
...
i.image = texture;

i.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
i.subresourceRange....

vkCmdPipelineBarrier(
        commandbuffer,
        VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
        VK_PIPELINE_STAGE_TRANSFER_BIT,
        0,0,nullptr,0,nullptr,1,&i
);

...

vkCmdCopyBufferToImage(...);

...

i.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
i.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
i.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
i.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;

vkCmdPipelineBarrier(
        commandbuffer,
        VK_PIPELINE_STAGE_TRANSFER_BIT,
        VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
        0,0,nullptr,0,nullptr,1,&i
);

The image is then used in a subsequent renderpass, and everything works just fine.

However, I am a bit concerned that I might be experiencing an Undefined Behaviour, because even if waiting for the compute queue will ensure execution order between the buffer writes and the buffer transfer, there is no explicit barrier that ensures writes from the compute shader are actually available and visible to the buffer transfer.

Is there an implicit buffer or memory barrier (at least in this case) that I cannot find in the specs (1.1.123 as of today), or any other kind of mechanism, such that the above code is correct and the compute shader wites are always available to the buffer transfer?

If not, would I be right to assume there should be a VkBufferMemoryBarrier right before the first layout-transition pipeline barrier?

I am a bit confused, because reading the specs, I find:

"vkCmdPipelineBarrier is a synchronization command that inserts a dependency between commands submitted to the same queue, or between commands in the same subpass."

but here I would need to insert a memory dependency from two different queues and two distinct pipelines, so Im not really sure which pipeline would have to have a barrier.. if a barrier is even needed in the first place.

Upvotes: 0

Views: 318

Answers (1)

krOoze
krOoze

Reputation: 13276

You are thinking of a wrong synchronization tool. For synchronization between queues there is VkSemaphore.

There are additional complication in this case. The concept of queue family–resource ownership. In the case of VK_SHARING_MODE_EXCLUSIVE and differing queue families you must proceed as written in the Queue Family Ownership Transfer section of the specification. I.e. use special releasing and acquiring barrier + semaphore.

Otherwisely, only semaphore is needed as explained in Semaphore Signaling and Semaphore Waiting & Unsignaling sections:

The first access scope includes all memory access performed by the device.

The second access scope includes all memory access performed by the device.

Upvotes: 3

Related Questions