【问题标题】:Subpass dependencies for a single subpass. How to?单个子通道的子通道依赖项。如何?
【发布时间】:2018-10-26 07:03:00
【问题描述】:

所以我有一个渲染通道,它带有一个直接绘制到帧缓冲区的子通道。规范并没有强制我使用依赖项——如果我省略它们,实现会隐式插入它们(尽管我不明白为什么它使用srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT 作为第一个子通道——这个阶段意味着一开始,即不要等什么)。

但是像往常一样使用 Vulkan - 最好是明确的。这就是混乱 - 多个来源以不同的方式使用子通道。

  1. Sdk 的多维数据集示例根本不使用它们。

  2. Vulkan-tutorial 只用了一个:

    dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
    dependency.dstSubpass = 0;
    dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    dependency.srcAccessMask = 0;
    dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
    

    为什么srcAccessMask 在这里为零?

  3. 没有秘密的 API 使用两个:

    dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
    dependency.dstSubpass = 0;
    dependency.srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
    dependency.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
    dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
    

    dependency.srcSubpass = 0;
    dependency.dstSubpass = VK_SUBPASS_EXTERNAL;
    dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    dependency.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
    dependency.dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
    dependency.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
    

    不清楚为什么srcStageMaskis VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT 在第一个子通道中 - 不是 这个阶段应该用于执行依赖,但这里我们 需要内存依赖?关于为什么dstStageMask的相同问题 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT 在第二个子通道中吗?

  4. Khronos 同步示例使用一个:

    dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
    dependency.dstSubpass = 0;
    dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    dependency.srcAccessMask = 0;
    dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
    

    为什么srcAccessMask 是 0?

  5. 这是我对两个依赖项的尝试:

        dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
        dependency.dstSubpass = 0;
        dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; // need to wait until
    presentation is finished reading the image
        dependency.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
        dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; // we are writing to
    the image in this stage
        dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
    
    and
    
        dependency.srcSubpass = 0;
        dependency.dstSubpass = VK_SUBPASS_EXTERNAL;
        dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; // we are writing to
    the image in this stage
        dependency.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
        dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; // presentation reads
    image in this stage (is it?)
        dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
    

所有这些都非常令人困惑。正如你所看到的,多个有能力的来源有不同的看法。使用哪一个?如何理解这些依赖关系?

【问题讨论】:

    标签: vulkan


    【解决方案1】:

    哦,天哪,这是一个大多数人都不太了解的话题。许多错误信息被假设和扩散。规范示例的正确位置是wikipage in the github repo

    有关交换链图像获取/呈现的相关部分可以找到here

    1. 这是在很多同步细节被正确确定之前的一个老例子。

    2. 其目的是将信号量用于等待 vkAcquireNextImage 的结果与渲染同步。这是一个先读后写的危险,信号量将包括内存可见性同步。所以不需要 srcAccessMask。

    3. 同样,屏障旨在与信号量同步。将命令缓冲区提交到队列时,您可以设置哪些阶段等待哪些信号量。在这种情况下,他们使用管道底部而不是VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT

    4. 答案与 2 相同,唯一的区别在于 dstAccessMask

    5. 我上面链接的 wiki 页面使用以下内容:

      /* 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};
      
      /* Normally, we would need an external dependency at the end as well since we are changing layout in finalLayout,
         but since we are signalling a semaphore, we can rely on Vulkan's default behavior,
         which injects an external dependency here with
         dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
         dstAccessMask = 0. */
      

      您混淆了第二道屏障的子通道索引。尽管如 cmets 中所述,在渲染通道的末尾已经有一个隐式屏障,它反过来与您用来与当前同步的信号量或栅栏同步。所以不需要显式依赖。

    【讨论】:

    • 棘轮怪胎,谢谢你的解释。示例 4 确实来自 Khronos github repo。以3(英特尔)为例,我仍然很困惑——第二个子通道目标阶段是VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,但提交信息的等待目标阶段是VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT——这不是错了吗?是的,我混合了第二个障碍的指标——复制粘贴错误,已修复。我现在不明白的是信号量是如何进入游戏的?它如何与子通道依赖项交互?我在哪里可以了解更多信息?
    • 3 中的第二个依赖项在命令缓冲区完成后将渲染通道的结尾同步到内容。命令缓冲区间同步的机制总是等待命令缓冲区完全完成。
    • @nikitablack 最好在规范 Semaphore SignalingSemaphore Waiting & Unsignaling 章节中。在章节Execution and Memory Dependencies 中了解什么是同步范围、访问范围和提交顺序,然后您就可以真正了解 Vulkan 同步的所有内容。
    猜你喜欢
    • 2020-08-24
    • 1970-01-01
    • 2019-07-14
    • 2014-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-10
    相关资源
    最近更新 更多