memory-model synchronization vulkan

synchronization - 在Vulk中的Acquire-Present场景中,使用信号量“同步”渲染过程布局过渡

发布于 2020-05-11 09:19:42

因此,有一个官方示例https://github.com/KhronosGroup/Vulkan-Docs/wiki/Synchronization-Examples#combined-graphicspresent-queue

/* 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};

有人可以为我提供规范中的相关部分,以确保在不通知队列的等待信号(获取图像)之前,结合保证(构成推理链)不会发生这种依赖关系布局转换吗?

特别是我找不到如何解释这种“从同一阶段到其自身的依赖性”。

要清楚。我发现了很多与这里相关的地方。我正在阅读文档已有一个多月的时间,但是我一直在努力寻找文档的一致性。

例如,何时(根据规范)发生可用性操作?何时提交了相关的内存依赖操作(按照提交顺序)?如果是,则是否提交子通道依赖项?还是在源作用域指令和目标作用域指令之间(在中If srcSubpass is equal to VK_SUBPASS_EXTERNAL, the first synchronization scope includes commands that occur earlier in submission order than the vkCmdBeginRenderPass)。如果是srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,则上述示例中的指的是什么指令

在krOoze的答案之后进行编辑

我以为我会在这里写。一是因为评论太长,二是因为我认为它可能对其他人有用。

我承认,我误解了规范中有关执行依赖关系链的部分。

总结一下。为了根据规范定义所讨论的机制,我们具有以下内容:

  1. 信号量操作等待发生在子传递依赖项操作之前(这里实际上有一些麻烦):

    6.4.2。信号量等待*
    信号量等待操作发生在执行依赖关系中的第一组操作之后,发生在执行依赖关系中的第二组操作之前。

    但是如何确保我们的子传递依赖项操作在第二组中?它在同一批中,没有针对子传递依赖项定义提交顺序(至少我看不到),并且信号量第二个同步作用域的定义没有帮助,因为我们的子传递依赖项没有发生在VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT流水线阶段(这是第二个同步范围的限制,在vkQueueSubmit的情况下)。更重要的是,同步作用域并没有定义第二组操作。这是一个不同的术语。但是我发现了另一条可能在这里有用的语句(嗯,如果我们同意子传递依赖关系是工作项的一部分):

    4.3.5。队列提交
    每个批次包括三个不同的部分:

    1. 执行零个或多个信号量,然后再执行其余的批处理。
    2. 零个或多个要执行的工作项。
    3. 零个或多个信号量表示工作项完成。

    并且我们需要确保此顺序可以构造执行依赖关系链:

  2. 等待信号量和子传递依赖关系根据以下内容构成执行依赖关系链:

    6.1。执行和内存依赖关系
    执行依赖关系链是一系列执行依赖关系,这些序列形成第一个依赖关系A'与最终依赖关系B'之间的先发生关系。对于每连续的执行依赖对,如果第一个依赖关系中的B S与第二个依赖关系中的A S的交集不是空集,则存在一条链

    (有关详细信息,请参见krOoze的答案)

    由此我们知道,子传递依赖项的目标范围将发出信号量之后发生(信号操作在信号量等待操作的源范围中)。
    现在我们应该可以使用布局转换规则:

  3. 布局转换发生在子传递依赖项的可用性操作之后:

    7.1。创建渲染通道创建
    自动布局转换,使其从initialLayout 发生转变-在所有依赖项的可用性操作之后, srcSubpass等于VK_SUBPASS_EXTERNAL,其中dstSubpass使用将转换的附件。

    老实说,我仍然缺少规范中发信号量和可用性操作部分之间的顺序,但我认为可以假定。
    (以上方法之所以可行,是因为可用性操作是内存依赖项操作的一部分:

    执行内存依赖项的操作将生成:
    •在依赖项的第一个访问范围和设备域的目标范围内具有所有写入的源作用域的可用性操作。

    好,我们的第一个访问范围是空的,但它仍然是可用性操作,对吗?

还有以下语句:

但是,对于附件,子通道依赖项的工作方式类似于类似于上述VkMemoryBarrier定义的VkImageMemoryBarrier,队列族索引设置为VK_QUEUE_FAMILY_IGNORED,布局如下:
•相当于oldLayout的是根据srcSubpass的子通道描述的附件布局。
•相当于newLayout是根据dstSubpass的子通道描述的附件布局。

...这带来了另一个分析范围,但我的头已经痛了。当我对上述想法进行了一些回顾时,我将非常乐于编辑更多内容。

*所有规范引自“Vulkan®1.2.132-规范(带有所有已注册的Vulkan扩展名)”

查看更多

提问者
listerreg
被浏览
23
krOoze 2020-02-22 02:02

我在krOoze / Hello_Triangle / doc上略过了这一点在这种情况下应该发生的是:

在此处输入图片说明

特别是我找不到如何解释这种“从同一阶段到其自身的依赖性”。

现在,让我们首先解决这个问题。这就是我所说的同步系统的事前直觉

You do not "synchronize stages" or something like that. That is intuition that will only cause you confusion. You synchronize scopes.

People also confuse a pipeline with a flow-chart. There is a huge intuition difference. In flow-chart, you start at a start, then you go over all the stages in order, then you are finished and forever done. That is not what pipeline is. It never starts, and never finishes. Pipeline just is. It is like a desktop game board. You stuff commands through the pipeline, and they go through the stages like pegs on the board.

A synchronization command is something that introduces a dependency between two things: between the source synchronization scope and destination synchronization scope. It guarantees the src scope happens-before the dst scope.

A scope is some subset of queue operations, and at what stage they currently their execution can be at.

So, with this better intuition,

    .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
    .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,

is a perfectly normal thing to do. It means the commands in the source scope (for a barrier, the commands recorded earlier, or more formally those "earlier in submission order") reached COLOR_ATTACHMENT stage, before any commands in the destination scope reached COLOR_ATTACHMENT stage. (In contrast, without the dependendency it would mean that any command can be at any stage in its execution at any given time).

For example when (according to the specification) an availability operation does happen.

These are somewhat inserted in the dependency the barrier defines. Assuming you included a memory dependency in your barrier.

The availability operation (if any) happens-after the source synchronization scope. Then happens the layout transition (if any). Then happens the visibility op (if any). And only after then can the source synchronization scope execute.

Could someone please provide me with relevant sections in the specification that combined guarantee (constitute a chain of reasoning)

I just want to pat you on the head right now for wanting the authoritative information... :D

So, you need to know the formalism and the nomenclature. It is the thing all the synchronization primitives are described with. It is only one-page but relatively hard read. I tried explain the important parts above. I am not gonna quote it here, it is the 6.1. Execution and Memory Dependencies chapter.

现在,信号量等待有其自己的章节。重要的是要注意,其他命令的行为与其他命令的行为略有不同vkQueueSubmit(这很烦人)。无论如何(6.4.2。信号量等待):

第二个同步范围包括同一批中提交的每个命令。在的情况下vkQueueSubmit,第二个同步范围仅限于对流水线级的操作,该流水线级由的相应元素指定目标级掩码确定pWaitDstStageMask同样,在的情况下vkQueueSubmit,第二个同步作用域还包括以后按提交顺序出现的所有命令

第二访问范围包括设备执行的所有内存访问。

批处理(for vkQueueSubmit)是单个VkSubmitInfo提交命令也有自己的章节;基本上,它的意思是“提交数组中稍后的所有其他批处理,以及vkQueueSubmit同一队列中的任何将来的批处理”。

因此,这意味着:“如果等待信号量,VkSubmitInfopWaitDstStageMask只有在信号量发出信号后,程序中的所有命令才能到达阶段”。

现在,重要的是要了解渲染通行证的功能。除了记录的命令外,它还具有其他“可同步化”功能:自动布局转换,加载操作和存储操作。

自动布局转换:

自动布局从initialLayout发生的转变过渡到srcSubpass等于的所有依赖项可用性操作之后VK_SUBPASS_EXTERNAL,其中dstSubpass使用将要转变的附件

在子流程中所有依赖项可见性操作之前,都会自动将布局转换为子流程中使用的布局dstSubpass

因此,简单来说,布局转换会潜入VkSubpassDependency您所定义的依赖项内部它发生在.srcStageMaskwith之后.srcAccessMask它之前发生.dstSubpass,并.dstStageMask.dstAccessMask

负载op:

对附件中每个样本的加载操作发生在使用该附件的第一个子通道中访问该样本的任何记录命令之前。[...]具有颜色格式的附件的加载操作在VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT管道阶段执行

VK_ATTACHMENT_LOAD_OP_LOAD[...]对于彩色格式的附件,使用访问类型VK_ACCESS_COLOR_ATTACHMENT_READ_BIT

VK_ATTACHMENT_LOAD_OP_CLEAR(或VK_ATTACHMENT_LOAD_OP_DONT_CARE)对于彩色格式的附件,使用访问类型VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT

加载操作是使用附件(您的.dstSubpass的第一个子通道的一部分以上明确确定了您.dstStageMask.dstAccessMask

现在,我们来选择pWaitDstStageMaskand .srcStageMask.srcAccessMask你列出它pWaitDstStageMask = COLOR_ATTACHMENT_OUTPUT.srcStageMask = COLOR_ATTACHMENT_OUTPUT.srcAccessMask = 0

信号量等待操作必须在VkSubpassDependency填充之前进行这被指定为依赖链

执行依赖关系链是一系列执行依赖关系,这些序列在第一个依赖关系A'与最终依赖关系B'之间形成先于关系对于每对连续的执行依赖对,如果第一个依赖关系中B S与第二个依赖关系中的A S的交集不是空集,则存在一条链

即,两个后续的同步原语也彼此同步并形成过渡属性。我们的A“这里是旗语信号,我们的B”这里的夏令范围VkSubpassDependency我们的小号这里是一个信号DST范围,即pWaitDstStageMask而我们的一个小号是我们的src范围VkSubpassDependency

所以我们的pWaitDstStageMask交点.srcStageMask仍然是COLOR_ATTACHMENT_OUTPUT因此,形成了一个依赖链,该依赖链可确保信号量信号发生在渲染通道子通道COLOR_ATTACHMENT_OUTPUT中的命令之前0

现在,将它们放在一起:来自的信号量信号vkAcquireNextImage使表示演示引擎读取的交换链图像可用信号量等待vkQueueSubmit使交换链映像对于批处理中的所有命令可见(限制为)COLOR_ATTACHMENT_OUTPUTVkSubpassDependency那个信号量锁链正在等待。该图像仍然可见,因此不需要其他内存依赖项,因此.srcAccessMask是这样0布局转换将写入图像,并使其(隐式地)布局转换中可用,并且对于.dst*提供给的任何内容都是可见VkSubpassDependency