[英]WSI synchronization subpass dependency and link to color attachment output
我想我确实了解 Vulkan 同步的工作原理,但在理解与 WSI 的同步方面确实存在问题。
同步示例,我们可以找到这段代码
/* 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};
在我看来,它应该是这样的:
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};
实际上,由于我们要写入附件,因此无需在dstAccessMask
中使用WRITE_BIT
(意思是使写入可用)。
但真正的问题在于srcStageMask
。
我明白为什么dstStageMask
是COLOR_ATTACHMENT_OUTPUT_BIT
。 这是因为我们不接触附件,所以可以让前面的阶段工作。
但是,对于srcStageMask
,我没有看到任何关于 WSI 和COLOR_ATTACHMENT_OUTPUT_BIT
之间链接的信息。 对我来说,布局转换必须出现在演示结束时,并且就在COLOR_ATTACHMENT_OUTPUT
阶段开始之前。 对我来说,演示结束应该由BOTTOM_OF_PIPE
而不是COLOR_ATTACHMENT_OUTPUT
我错在哪里?
实际上,由于我们要
WRITE
附件,因此无需在 dstAccessMask 中使用WRITE_BIT
(意思是使写入可用)。
我不太确定你的逻辑。 它应该是WRITE
,因为我们要写入附件。
它可能有助于描述这里发生的事情(来自krOoze/Hello_Triangle/doc ):
信号量的VkSubpassDependency
链(通过pWaitDstStageMask
)。 然后它执行布局转换。 然后它与加载操作同步。 (然后 Load Op 发生在子通道中。子通道vkDraw
一些东西放入交换链图像中。)
现在假设(这是第一次使用交换链图像的典型情况)我们的 Load Op 是VK_ATTACHMENT_LOAD_OP_CLEAR
。 这意味着VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
+ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
访问。
所以:
Presentation 将读取交换链图像,并提交信号量信号。
我们将VkSubpassDependency
到信号(通过pWaitDstStageMask
)。 信号量信号已经覆盖了所有 memory 访问,因此我们的srcAccessMask = 0
。
Dependency 执行其对 Layout Transition 的隐式依赖(获取您的src
,并发明一些内部dst
),然后发生 Layout Transition ,读取图像并将其写回,然后依赖执行另一个隐式依赖(发明一些src
覆盖布局过渡,并使用您的dst
)。
加载操作发生在子通道中,您必须明确确保它发生在上述所有操作之后。 因此,您的依赖项中的dst
必须是VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
+ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
才能覆盖加载操作。
现在,memory 危害分为三种类型:读→写、写→写和写→读(读→读是非危害)。 在 WWH 中,一些东西写入了资源,而其他一些东西也写入了它。 不清楚哪个写入最后发生,因此 memory 内容变成垃圾。 在 RWH 和 WRH 中读取和写入可能同时发生。 不清楚读取看到的是未修改的 memory,还是写入的(即读取垃圾)。
如果没有明确的依赖关系,布局转换和后续的加载操作会形成写→写风险。 因此dstAccessMask
不能为0
以解决危险并确保一次写入发生在第二次之前。
(可能值得注意的是,我们引入VkSubpassDependency
仅仅是为了布局转换。否则,信号量等待已经是所需要的。默认值为srcStageMask = TOP_OF_PIPE
,这意味着如果没有明确的依赖关系,布局转换可能发生在信号量等待,即在演示文稿完成读取之前;那将是读→写危险)。
对我来说,布局转换必须出现在演示结束时,并且就在
COLOR_ATTACHMENT_OUTPUT
阶段开始之前。 对我来说,演示结束应该由BOTTOM_OF_PIPE
而不是COLOR_ATTACHMENT_OUTPUT
我们在这里有一点选择: pWaitDstStageMask = dependency.srcStageMask =?
现在我们的情况是这样的:
vkBeginCommandBuffer();
[possibly vkCmdDispatch()?]
vkBeginRenderPass();
vkCmdDraw(); // does vertex shading + fragment shading, then color writes
vkEndRenderPass();
vkEndCommandBuffer();
vkQueueSubmit(.pwaitDstStageMask = ?);
如果我们使用VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
,那么信号量等待不会阻止启动假设的vkCmdDispatch()
( VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
)。 并且 Subpass Dependency src
不会强制它完成。 伟大的!
使用的阶段不应比VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
。 例如,使用VK_PIPELINE_STAGE_ALL_COMMANDS
信号量等待会不必要地阻塞vkCmdDispatch()
以及vkCmdDraw
的顶点和片段着色器。 同时,仅当我们实际需要在 Load Op 处写入交换链图像时才需要交换链图像(您可以想象当vkCmdDraw()
到达它需要执行颜色写入的点时会发生这种情况)。
现在,我们可以选择VK_PIPELINE_STAGE_BOTTOM_OF_PIPE
。 信号量不会阻塞任何东西( dstStage\pWaitDstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE
的意思与“无”相同)。 伟大的! 但是 Subpass Dependency 现在会阻止所有内容( srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE
的含义与VK_PIPELINE_STAGE_ALL_COMMANDS
相同)。 这意味着我们的vkCmdDispatch
必须在我们的子通道开始之前完成。 不太好...
因此,最佳实践是使用pWaitDstStageMask = dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.