问题
I think I do understand how Vulkan synchronization works, but I do have a problem of understanding the synchronization with the WSI.
The the Synchronization Examples, we can find this code
/* Only need a dependency coming in to ensure that the first
layout transition happens at the right time.
Second external dependency is implied by having a different
finalLayout and subpass layout. */
VkSubpassDependency dependency = {
.srcSubpass = VK_SUBPASS_EXTERNAL,
.dstSubpass = 0,
// .srcStageMask needs to be a part of pWaitDstStageMask in the WSI semaphore.
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
.srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
.dependencyFlags = 0};
According to me, it should be something like that :
VkSubpassDependency dependency = {
.srcSubpass = VK_SUBPASS_EXTERNAL,
.dstSubpass = 0,
// .srcStageMask needs to be a part of pWaitDstStageMask in the WSI semaphore.
.srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE,
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
.srcAccessMask = 0,
.dstAccessMask = 0,
.dependencyFlags = 0};
Indeed, since we are going to WRITE into the attachment, there is no need to use a WRITE_BIT
(meaning make writes available) in the dstAccessMask
.
But the true issue is in the srcStageMask
.
I understand why the dstStageMask
is COLOR_ATTACHMENT_OUTPUT_BIT
. It is because it is okay to have the prior stages working since we don't touch the attachment.
However, for the srcStageMask
, I did not see anything about the link between WSI and the COLOR_ATTACHMENT_OUTPUT_BIT
. To me, the layout transition must appear at the end of the presentation, and just before the beginning of the COLOR_ATTACHMENT_OUTPUT
stage.
And the end of presentation, for me, should be represented by BOTTOM_OF_PIPE
and not COLOR_ATTACHMENT_OUTPUT
Where am I mistaken?
回答1:
Indeed, since we are going to
WRITE
into the attachment, there is no need to use aWRITE_BIT
(meaning make writes available) in the dstAccessMask.
I am not exactly sure of your logic here. It should be WRITE
exactly because we are going to write to the attachment.
It would perhaps help describe what is happening here (from krOoze/Hello_Triangle/doc):
The VkSubpassDependency
chains of the the semaphore (via pWaitDstStageMask
). Then it performs its layout transition. Then it syncs with the Load Op. (Then Load Op happens in the subpass. And subpass vkDraw
s some stuff into the swapchain image.)
Now assumably (as is typical for first use of the swapchain image) our Load Op is VK_ATTACHMENT_LOAD_OP_CLEAR
. That means VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
+ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
access.
So:
Presentation is gonna read the swapchain image, and submit a semaphore signal.
We chain our
VkSubpassDependency
to the signal (viapWaitDstStageMask
). Semaphore signal already covers all memory accesses, therefore oursrcAccessMask = 0
.The Dependency performs its implicit dependency to the Layout Transition (takes your
src
, and invents some internaldst
), then Layout Transition happens, which reads the image and writes it back, then the dependency performs another implicit Dependency (invents somesrc
that covers the layout transition, and uses yourdst
).The Load Op happens in the subpass, and you have to make sure explicitly it happens-after everything above. So your
dst
in your Dependency must beVK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
+VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
to cover the Load Op.
Now, there are three types of memory hazards: read→write, write→write, and write→read (and read→read is a non-hazard). In WWH something writes a resource, while some other write also writes it. It is not clear which write happens last, so the memory contents becomes garbage. In RWH and WRH read and write may happen at the same time. It is not clear if the read sees the unmodified memory, or the written one (i.e. it reads garbage).
Without an explicit dependency, the Layout Transition and the subsequent Load Op form a write→write hazard. Therefore dstAccessMask
must not be 0
to resolve the hazard and make sure one write happens-before the second one.
(It is perhaps worth noting we introduce the VkSubpassDependency
solely for the sake of the layout transition. Otherwise the semaphore wait would already be all that is needed. The default is srcStageMask = TOP_OF_PIPE
, which means without explicit Dependency the layout transition could happen before the semaphore wait, i.e. before presentation finishes reading it; that would be a read→write hazard).
To me, the layout transition must appear at the end of the presentation, and just before the beginning of the
COLOR_ATTACHMENT_OUTPUT
stage. And the end of presentation, for me, should be represented byBOTTOM_OF_PIPE
and notCOLOR_ATTACHMENT_OUTPUT
We have little bit of choice here: pWaitDstStageMask = dependency.srcStageMask = ?
Now our situation is this:
vkBeginCommandBuffer();
[possibly vkCmdDispatch()?]
vkBeginRenderPass();
vkCmdDraw(); // does vertex shading + fragment shading, then color writes
vkEndRenderPass();
vkEndCommandBuffer();
vkQueueSubmit(.pwaitDstStageMask = ?);
If we use VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
, then the semaphore wait does not block starting the hypothetical vkCmdDispatch()
(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
). And the Subpass Dependency src
does not force it to finish neither. Great!
The Stage used should not be any earlier stage than VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
. E.g. with VK_PIPELINE_STAGE_ALL_COMMANDS
the semaphore wait would unnecesserily block the vkCmdDispatch()
as well as vertex and fragment shader of the vkCmdDraw
. Meanwhile we need the swapchain image only when we actually need to write it at the Load Op (which you can imagine happens when the vkCmdDraw()
gets to the point it needs to perform color writes).
Now, we could choose VK_PIPELINE_STAGE_BOTTOM_OF_PIPE
. The semaphore blocks nothing (dstStage\pWaitDstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE
means the same as "nothing"). Great! But the Subpass Dependency now blocks everything (srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE
means the same as VK_PIPELINE_STAGE_ALL_COMMANDS
). That means our vkCmdDispatch
has to finish, before our subpass starts. Not so great...
So, the best practice is to use pWaitDstStageMask = dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
.
来源:https://stackoverflow.com/questions/61319050/wsi-synchronization-subpass-dependency-and-link-to-color-attachment-output