Search code examples
vulkan

Vulkan rendering to the same attachment set with multiple pipelines


Given that I have two different shaders, thus I've got two different VkPipelines. They'll work together to render on the same color attachment and depth attachment. (I'm using dynamic rendering so no render pass/subpass here). The second pipeline may rely on the first pipeline's output.

My current renderFrame records command buffer like this:

vkCmdBeginRendering (with attachments load op = clear, store op = ?)
vkCmdBindPipeline - bind the first pipeline
vkBindVertexBuffers
vkCmdDraw
vkCmdEndRendering

vkCmdBeginRendering (with same attachments, load op = ?, store op = store/don't care)
vkCmdBindPipeline - bind the second pipeline
vkBindVertexBuffers
vkCmdDraw
vkCmdEndRendering

And here are my questions:

  • Do I need some kind synchronization/barrier between the two pipelines? I've searched the web on myself and found this post, but two replies seem to be contradictory.
  • What storeOp should I use for the first vkCmdBeginRendering, and what loadOp should I use for the second vkCmdBeginRendering?

Till now I'm

  • not using any synchronization/barriers
  • color attachment storeOp = VK_ATTACHMENT_STORE_OP_STORE, depth attachment storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE for the first vkCmdBeginRendering
  • color attachment loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, depth attachment loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE for the second vkCmdBeginRendering

And that works on my platform (Windows 10/Linux + AMD GPU) without validation layers complaining about anything. But I want to be safe here, so posting this question.

My original project is a little big and the tech stack is a little bit weird, so I'm not posting real code here.


Edit 1: I've found that I don't actually need multiple vkCmdBeginRendering to use multiple pipelines:

vkCmdBeginRendering
vkCmdBindPipeline - bind the first pipeline
vkBindVertexBuffers
vkCmdDraw

vkCmdBindPipeline - bind the second pipeline
vkBindVertexBuffers
vkCmdDraw
vkCmdEndRendering

And the "synchronization" problem between multiple vkCmdDraw family commands has already been elaborated here and here. No synchronization is required.

However I still wonder the answer to the original question, since a pipeline can write to multiple attachments, and two pipelines may only share some output attachments (though I've not got a real-world example yet).


Solution

  • Do I need some kind synchronization/barrier between the two pipelines?

    As a general rule of thumb, even with dynamic rendering, you are required to manage the synchronization yourself. And when 2 render passes (dynamic or normal) write to same attachment, or one writes and one reads from same attachment, you need pipeline and memory barriers to synchronize the use. This is not needed for 2 simultaneous reads. In the Edit, you removed the vkCmdEndRendering and vkCmdBeginRendering at the end of 1st pass, so you won't need synchronization anymore. But, this means that you cannot read from the results of 1st pipeline from the 2nd pipeline. Because they are now the same pass.

    What storeOp should I use for the first vkCmdBeginRendering, and what loadOp should I use for the second vkCmdBeginRendering

    You mentioned that your 2nd pass may rely on first pipeline's output. So you may use storeOp Store in 1st pass, and loadOp load in 2nd pass.