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
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 toSHADER_READ_LAYOUT
), and S3 (render passVK_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
was0
anddstStage
was probablyBOTTOM_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 aVkMemoryBarrier
.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 specifiedSTAGE_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
anddstPipe = BOTTOM_OF_PIPE
, so basically can be anywhere. It can be as late as inBOTTOM_OF_PIPE
(to be precise, happens-beforeBOTTOM_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 inSTAGE_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:
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 explicitVK_EXTERNAL
dependency is described in the spec too bellow Valid Usage sections of VkSubpassDependency (basically all memory that is available beforeTOP_OF_PIPE
is made visible to the whole first subpass for attachment use).