nikitablack
nikitablack

Reputation: 4663

How to synchronize uniform buffer updates?

I have a number of uniform buffers - one for every framebuffer. I guarantee with the help of fences that the update on cpu is safe, i.e. when I'm memcpy I'm sure buffer is not in use. After an update, I'm flushing the memory.

Now, if I understand correctly, I need to make the new data available for the gpu - for this, I need to use barriers. This is how I'm doing it right now:

VkBufferMemoryBarrier barrier{};
barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
barrier.pNext = nullptr;
barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_UNIFORM_READ_BIT;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.buffer = buffer;
barrier.offset = offset;
barrier.size = size;

vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT, 0, 0, nullptr, 1, &barrier, 0, nullptr);

Well, actually in my case everything works without the barrier. Do I need it at all?

If I change barrier.dstAccessMask and dstStageMask to VK_ACCESS_TRANSFER_READ_BIT and VK_PIPELINE_STAGE_TRANSFER_BIT respectively, everything again works fine, layers are not complaining. What is the better choice and why?

If I try to set a barrier after vkCmdBeginRenderPass, the layer complains. So I moved all my barriers between vkBeginCommandBuffer and vkCmdBeginRenderPass. How correct is this?

Upvotes: 3

Views: 1373

Answers (1)

Nicol Bolas
Nicol Bolas

Reputation: 474336

Well, actually in my case everything works without the barrier.

Does the specification say you need it? Then you need it.

When dealing with Vulkan, you should not take "everything appears to work" as a sign that you've done everything right.

What is the better choice and why?

The "better choice" is the correct one. The GPU is not doing a transfer operation on this memory; it's reading it as uniform data. Therefore, the operation you specify in the barrier must match this.

Layers aren't complaining because it's more or less impossible for validation layers to know when you've written to a piece of memory. Therefore, they can't tell if you correctly built a barrier to make such writes available to the GPU.

If I try to set a barrier after vkCmdBeginRenderPass, the layer complains.

Barriers inside render passes have to be inside subpasses with self-dependencies. And the barrier itself has to match the subpass self-dependency.

Basically, barriers of the kind you're talking about have to happen before the render pass.


That being said, merely calling vkQueueSubmit automatically creates a memory barrier between (properly flushed) host writes issued before vkQueueSubmit and any usage of those writes from the command buffers in the submit command (and of course, commands in later submit operations).

So you shouldn't need such a barrier, so long as you can ensure that you've finished your writes (and any needed flushing) before the vkQueueSubmit that reads from them. And if you can't guarantee that, you probably should have been using a vkCmdWaitEvents barrier to prevent trying to read until you had finished writing (and flushing).

Upvotes: 3

Related Questions