Vulkan 同步:避免写后写危险,为什么这是正确的?

问题描述 投票:0回答:1

在问题中:“第一个渲染通道写入深度附件。第二个渲染通道重新使用相同的深度附件。”

我看到官方维基(vulkan wiki)说:

这是一个 WAW(写后写)冒险的例子,它总是需要内存依赖。即使 render-pass 不读取前一个 pass 的输出(事实上,在这个例子中,之前的图像内容由于从 UNDEFINED 转换的性质而明确不被保留)我们仍然需要一个内存依赖来确保对图像的写入是没有重新订购。

它提供了一个例子,使用 subpass 依赖:

.srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,  // Store op is always performed in late tests, after subpass access
.dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, // Load op is always performed in early tests, before subpass access
.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT

虽然 vulkan 教程(vulkan 教程深度缓冲区章节)为该问题提供了一个看似不同的解决方案:

.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
.srcAccessMask = 0
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;

在这种情况下,如果我们忽略颜色附加阶段和访问位,那么这个解决方案似乎只提供了执行依赖性,但没有深度附加操作的内存依赖性。

我不确定我是否理解正确(关于深度附件的两种情况是相同的,第二种解决方案只为操作提供关于深度附件的执行依赖性) 因此,如果有人可以澄清为什么第二种解决方案是正确的(或者它们本质上是相同的),我将不胜感激。

如果我的理解是正确的,那么 vulkan 教程中的解决方案无法在跨不同子通道的多个内存写入之间提供内存屏障,那么为什么它是一个可接受的解决方案?

synchronization gpu vulkan memory-barriers
1个回答
0
投票

同步情况是这样的:

现在,Vulkan 规范非常明确:

  • 深度附件的加载操作发生在
    VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
    中,如果是
    VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
    ,则为
    VK_ATTACHMENT_LOAD_OP_LOAD
    ,如果是
    *_WRITE
    CLEAR
    ,则为
    DONT_CARE
  • Store Op 的深度连接发生在
    VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
    VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
  • Layout Transition 总是发生在
    srcStageMask
    dstStageMask
    之间。

Wiki 示例中的情况是他们进行布局转换,然后

CLEAR
加载操作,然后没有最终布局转换。处理同步的依赖项在第二个渲染过程中。原来如此:

VkSubpassDependency dependency = {
  .srcSubpass = VK_SUBPASS_EXTERNAL, // previous render passes
  .dstSubpass = 0, // this render pass
  .srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,  // Store op of previous render pass
  // layout transition happens here 
  .dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, // Load op of this render pass
  .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // Store Op access of previous render pass
  // the Clear Load Op (`READ` flag is redundant as per https://github.com/KhronosGroup/Vulkan-Docs/issues/2055)
  .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT 
  .dependencyFlags = 0
};

令人满意地解释教程中的选择是教程制作者的责任(特别是如果它与官方材料不同)。如果学习材料中有任何不明确的地方,请联系他们的作者(而不是一般社区),以便可以在不明确的地方对其进行澄清,而不是在其他地方散布混乱。

乍一看,

srcStageMask
似乎不正确。应该是
LATE
,匹配Store Op阶段

srcAccessMask
应该(保守地)包括在内(因为
WRITE
匹配
DONT_CARE
存储操作访问),尽管有 some talk 在写后写的情况下消除访问标志。

© www.soinside.com 2019 - 2024. All rights reserved.