Reputation: 4663
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
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