3

I have read almost everything that google gave me to this topic and haven't been able to reach a satisfactory conclusion. It's essentially a follow up question to this one:

Moving image layouts with barrier or renderpasses

Assume I have a color attachment which is written to in one render pass and sampled from in a second one. Let there be only one subpass in both render passes. One way to handle the layout transition and dependencies is to add a barrier between the two render passes, which changes the layout from VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL.

But Vulkan also offers implicit layout transitions (vkAttachmentDescription, initialLayout and finalLayout). I guess that there is a performance advantage of using them, so let's simply try to get rid of our barrier. We set the initialLayout and finalLayout field in the vkAttachmentDescription structure and remove the barrier. The problem is, we lost the synchronisation provided by the barrier, so we need to get the synchronisation back by other means. And this is the point where the confusion starts, leading to my questions:

1) What's the recommended way to synchronize the attachment between the two render passes? Obviously I could simply re-add the barrier and not change the layout, but wouldn't that defeat the purpose of the whole exercise, which was to get better performance by using implicit layout transitions and getting rid of the barrier? Or should I add a subpass dependency from the single sub pass of render pass 1 to VK_SUBPASS_EXTERNAL? Are there any caveats of using VK_SUBPASS_EXTERNAL performance-wise?

2) What about synchronizing the attachment backwards? It is the application's responsibility to transition the attachment to the correct initial layout, which can be done with a barrier, obviously. Can this barrier be replaced to get a performance advantage? The only way I can think of would be to do the dependency part with a sub pass dependency from VK_SUBPASS_EXTERNAL to the single sub pass of render pass 1 and to use a 'fast' barrier (one that doesn't sync) which only does the layout change. Does this make sense? How would that barrier look like? Or is the 'full' barrier unavoidable in this case?

The short version of my questions is simply: how do other people do attachment synchronisation in conjunction with implicit layout transitions?

S. Jordan
  • 115
  • 5

2 Answers2

4

Generally speaking, when Vulkan or similar low-level APIs offers you multiple tools that can achieve what you want, you should give preference to the most specific tool that can solve your problem (without having to radically re-architect your code or fundamentally impact your design).

In your case, you have 2 options: barriers or render pass mechanisms (subpass dependencies and layout transitions). Barriers work with anything; they don't care where the image comes from, was used for, or where it is going. Render pass mechanisms only work for stuff that happens in a render pass and primarily deal with images attached to render passes (implicit layout transitions only work on attachments).

Render pass mechanisms are more specific, so you should prefer to use those tools if they meet your needs.

This is also why, if you have two "separate" rendering operations that could be in the same render pass (if you're reading from an attachment in a way that can live within the limitations of input attachments), you should prefer to put them in the same render pass.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
1

The short version of my questions is simply: how do other people do attachment synchronisation in conjunction with implicit layout transitions?

Render pass dependencies is what You are looking for. In case of two render passes You need to use the mentioned VK_SUBPASS_EXTERNAL value.

It is the application's responsibility to transition the attachment to the correct initial layout, which can be done with a barrier, obviously. Can this barrier be replaced to get a performance advantage?

However You perform layout transition, it doesn't matter. It is Your responsibility to transfer image's layout to the one specified as the initial layout. But I think the best way would be to once again use implicit layout transitions provided by render passes. If You are using them already, it should be possible to setup them in such a way so the first render pass transitions image to a layout which is the same as the initial layout of the second render pass, and the final layout of the second render pass is the same as the initial layout of the first render pass.

Ekzuzy
  • 3,193
  • 1
  • 16
  • 14
  • Thanks, this almost fully answers my questions. What is the answer to 2) if the attachment wasn't used as attachment in the previous render pass? – S. Jordan Jan 15 '19 at 07:46
  • This doesn't change the situation too much. You still need to transition the image to an appropriate layout (the same as initial layout of the second render pass). If You are not using it as attachment inside a render pass, You cannot utilize implicit layout transitions, so You need to use a barrier. – Ekzuzy Jan 15 '19 at 09:21
  • Almost there: assume I want to transition an image from shader-read in render pass 1 to attachment-write in render pass 2. There are two ways of achieving the transition AND the synchronisation: A) full barrier between the two render passes B) synchronize with a subpass dependency in render pass 2 (from VK_SUBPASS_EXTERNAL to subpass) and transition the layout with a sync-less barrier (TOP_OF_PIPE -> BOTTOM_OF_PIPE) between both render passes. A) is always correct, and I was asking whether B) is correct as well and whether it is potentially beneficial from a performance perspective. – S. Jordan Jan 16 '19 at 08:08
  • @S.Jordan I think it is recommended to do everything, as Nicol Bolas stated, using only the mechanisms render passes provide. So I think it would be C) synchronize with a subpass dependencies (I think appropriate dependencies should be defined in both render passes, but someone should confirm that) and transition the layout with implicit render pass layout transitions. If it is possible, I think explicit barriers should be avoided (for performance reasons). – Ekzuzy Jan 16 '19 at 09:14
  • In the scenario I described in the comment it's not possible to use an implicit transition, because the image is not used as attachment in the first render pass. So C) doesn't work there.Thus the question remains whether A) or B) is the way to go in this case. B) is basically C) with a sync-less barrier as replacement for the implicit transition. – S. Jordan Jan 16 '19 at 14:13
  • @S.Jordan Well... I'm not sure if there is something like "sync-less" barrier. How is the image used before the second render pass? Does it change layout? Because if the image is used only in one way before the second render pass, You may not need barriers at all and just use implicit layout transitions of the second render pass (with initial and final layouts being the same). In other cases You still need to use barriers to perform layout transitions. But, as far as I remember, render pass dependencies should also be defined (even with barriers just before the render pass). – Ekzuzy Jan 16 '19 at 21:35
  • As described earlier, the image is shader-read in render pass 1 and attachment-write in render pass 2. Therefore the layout MUST be transitioned between the two render passes. The implicit transition of render pass 2 is irrelevant here, because it transitions the image from attachment-write to some future layout used in a future render pass. Implicit transition in render pass 1 can't be used either, because the image is not an attachment there. That's why a barrier is required, but it wouldn't need to sync because the subpass dependency already does this. – S. Jordan Jan 17 '19 at 10:24
  • @S.Jordan OK, I simplified the situation and thought there is nothing going on after the second render pass. But it was my mistake, sorry. So You need to use image memory barrier(s) before the second render pass. And the question is whether it is better to use just the memory barrier or the memory barrier and subpass dependencies (I thought the focus was on other aspects). Here are some examples: https://github.com/KhronosGroup/Vulkan-Docs/wiki/Synchronization-Examples (look for "First draw samples a texture in the fragment shader. Second draw writes to that texture as a color attachment.") – Ekzuzy Jan 17 '19 at 11:07