Antoine Morrier
Antoine Morrier

Reputation: 4076

RenderPass Dependency and (transition) memory barrier

I am facing a comprehensive issue.

Let's say I have an image in a TRANSFER_LAYOUT layout. Going that way, the memory is already made available (not visible).

Let's say I update a uniform buffer (via vkCmdCopyBuffer).

Now let's say I have a renderPass (with an "empty frameBuffer", so there is no colorAttachment to make thing simpler) that use the prior image in SHADER_READ_OPTIMAL layout and the uniform buffer we just update. The image and the buffer are both used inside the fragment shader.

Is it correct to do the following?

Transition the image to SHADER_READ_LAYOUT

srcAccess = 0; // layers will say error : it must be TRANSFER_READ
dstAccess = 0; // The visibility will be made in the renderpass dependency (hower layers tells that it should be SHADER_READ I think)
srcPipe = TOP_OF_PIPE;
dstPipe = BOTTOM_OF_PIPE;

It is, in my understanding, meaningless to use different access than 0 here because TOP_OF_PIPE and BOTTOM_OF_PIPE does not access memory.

In the renderpass dependency from VK_EXTERNAL_SUBPASS :

srcAccess = TRANSFER_WRITE; // for the uniformBuffer
dstAccess = SHADER_READ; // for the uniform and the image
srcPipeline = TRANSFER; // For the uniformBuffer
dstPipeline = FRAGMENT_SHADER; // They are used here

Going that way, we are sure that the uniform buffer will not have any problems : The data are both made available and visible thanks to the renderPass. The memory should also be made visible for the image (also thanks to the dependency). However, the transition is write here to happened "not before" the bottom stage. Since I am using the image in FRAGMENT_STAGE, is it a mistake? Or is the "end of the renderPass dependency" behave like a bottom stage?

This code works on NVIDIA, and on AMD, but I am not sure it is really correct

Upvotes: 1

Views: 720

Answers (1)

krOoze
krOoze

Reputation: 13306

To understand synchronization perfectly, one must simply read the specification; especially the Execution and Memory Dependencies theory chapter. Lets analyze your situation in terms of what is written in the specification.

You have (only) three synchronization commands: S1 (image transition to TRANSFER_LAYOUT and availability operation), S2 (image transition to SHADER_READ_LAYOUT), and S3 (render pass VK_EXTERNAL dependency).

Your command buffer is an ordered list like: [Cmds0, S1, Cmds1, S2, Cmds2, S3, Cmds3].

For S1 let's assume you did the first part of a dependency (i.e. src part) correctly. You only said you made the image available from.

You also said you did not made it visible to, so let's assume dstAccess was 0 and dstStage was probably BOTTOM_OF_PIPE.

S2 has no execution dependency and it has not memory dependency. Only layout transition. There is an layout transition synchronization exception in the spec saying that layout transitions are performed in full in submission order (i.e. implicit execution dependency is automagically added). I personally would not be comfortable relying on it (and I would not trust drivers to implement it correctly on the first try). But lets assume it is valid, and assume the image will be correctly transitioned and made available from (and not visible to) at some point after the S1.

The S3 is an external subpass dependency on non-attachment resource, but the spec reassures us it is no different than vkCmdPipelineBarrier with a VkMemoryBarrier.

The second part of the dependency (i.e. dst) in S3 seems correct for your needs.


TL;DR, so far so good.


The first part of the dependency (i.e. dst) in S3 would indeed be the problematic one.

There is no automatic layout transitions for non-attachment resources, so we cannot rely on that crutch as above.

Set of commands A3 are all the commands before the renderpass.

Synchronization scope A3S are only those kinds of operations that are on the srcStage pipline stage or any logically earlier stage (i.e. TOP_OF_PIPE up to the specified STAGE_TRANSFER).

The execution dependency is made between A3' and B3'. Above we agreed the B3' half of the dependency is correct. The A3' half is intersection of A3 and A3S.

The layout transition in S2 is made between srcPipe = TOP_OF_PIPE and dstPipe = BOTTOM_OF_PIPE, so basically can be anywhere. It can be as late as in BOTTOM_OF_PIPE (to be precise, happens-before BOTTOM_OF_PIPE of commands recorded after S2 is executed). So the layout transition is part of A3, but there is no guarantee it is part of A3S; so there would not be guarantee the transition is part of the intersection A3'.

That means there is no guarantee the layout transition to SHADER_READ_LAYOUT happens-before the image reading in the first subpass in STAGE_FRAGMENT_SHADER.

There is no correct memory dependency either because that is defined in terms of A3' too.

EDIT: Somehow missed this, which is probably the problem:

Or is the "end of the renderPass dependency" behave like a bottom stage?

Beginning and end of a render pass does not behave like anything. It only affects submission order. In the presence of VK_EXTERNAL dependency only that applies (and of course any other previous explicit synchronization commands). What happens without explicit VK_EXTERNAL dependency is described in the spec too bellow Valid Usage sections of VkSubpassDependency (basically all memory that is available before TOP_OF_PIPE is made visible to the whole first subpass for attachment use).

Upvotes: 2

Related Questions