4

The vulkan docs mention that moving image layouts in render passes (see VkAttachmentDescription structure) is preferred compared to moving them using barriers (i.e. vkCmdPipelineBarrier). I can understand that since the latter introduce sync points which constrain parallel execution.

Now consider a typical example: A transition from VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL. In this case the resource is going to be read in the shader, but in order to do that safely it is necessary to synchronize the writing of the color attachment with the reading in the shader. In other words we need to use a barrier anyway and moving the layout in the render pass doesn't seem to give any advantage at all.

Can somehow explain how all this works in detail? In which situations does one have a real advantage of moving layouts in render passes? Are there (practical) layout changes which do not require further synchronization?

Tim Diekmann
  • 7,755
  • 11
  • 41
  • 69
S. Jordan
  • 115
  • 5
  • It is called "transitioning" not "moving". – krOoze Jul 18 '18 at 12:27
  • 1
    May I have the quote where the recommendation is in the spec. I can't seem to find it. – krOoze Jul 18 '18 at 13:10
  • I see, it's indeed not in the specs. I got this from the Vulkan Programming Guide. That book is also using 'moving' instead of 'transitioning'. – S. Jordan Jul 18 '18 at 14:13
  • Instead of a pipeline barrier, You can (and even should) synchronize operations inside and after a render pass using render pass dependencies. They are designed exactly for this purpose. – Ekzuzy Jul 19 '18 at 13:51

1 Answers1

4

Firstly, you are not given a choice. The API forces you to provide finalLayout, and intermediate VkAttachmentReference::layouts. You can use vkCmdPipelineBarrier inside the render pass conditionally (aka subpass self-dependency), but one of the rules is you are not allowed to change the layout of an attached image:

If a VkImageMemoryBarrier is used, the image and image subresource range specified in the barrier must be a subset of one of the image views used by the framebuffer in the current subpass. Additionally, oldLayout must be equal to newLayout, and both the srcQueueFamilyIndex and dstQueueFamilyIndex must be VK_QUEUE_FAMILY_IGNORED.

So during a render pass, you can only change layout using the render pass mechanism, or you must be outside the render pass. That leaves only the "outside render pass" case to discuss:

Good way to think of a render pass is that it (potentially, based on platform) copies the resource (using loadOp) to specialized memory, and when done copies it back (using storeOp) back to general-purpose memory.

That being said, it is reasonable to assume you may get the layout transition to finalLayout for free as part of the storeOp. (And similarly the transition from initialLayout to first VkAttachmentReference::layout as part of the loadOp.) So, it makes sense to have the layout transition as part of the renderpass, if possible\convenient enough.

krOoze
  • 12,301
  • 1
  • 20
  • 34
  • Thanks for your response! I understand that finalLayout is not optional. Yet I guess it is possible to set the finalLayout to 'VK_IMAGE_LAYOUT_GENERAL' in case the right layout isn't known yet at that point. Later on one could then use a barrier to transition to the correct layout. I understand now with your answer that this approach is likely to be less efficient. – S. Jordan Jul 18 '18 at 14:11
  • @S.Jordan `GENERAL` almost never makes sense — you always need to synchronize anyway. Synch. cmds always offer layout transition as part of them, so you might as well provide the specific layout needed (GPUs which do not need it will safely ignore it, others will benefit greatly). – krOoze Jul 18 '18 at 14:22
  • @S.Jordan Though, you can provide `finalLayout` that is already the layout of the image. It might be useful if you have some advanced needs (doing complicated engine), where convenience\flexibility\maintainability beats performance. But most of the time (esp. at the tutorial stage) it is better to stick with the default (what the API is coaxing you to do) — providing proper `finalLayout` means the driver can optimize as described above, and also the driver knows the synchronization+transition requirements of the app bit sooner (which may also help). – krOoze Jul 18 '18 at 14:27
  • I was thinking of the general layout as a placeholder to use until the proper layout is set using the barrier. Now, with your comment, I see that I can simply set finalLayout=initialLayout in the render pass when the layout isn't known yet, and this may be slightly more efficient. I should have mentioned that I indeed work with a large engine which currently doesn't track resources to allow me to know the final layout at the beginning of the render pass. – S. Jordan Jul 19 '18 at 07:11
  • Can I change the layout of an image during a render pass using a barrier if the image is not bound as an output attachment, only as input sampler during the next draw call? – Desperado17 Jun 10 '21 at 23:24