Vulkan的执行模型和同步
Vulkan's execution model and sycnhronization
我想澄清我对 Vulkan 执行模型的困惑,我想验证我的理解并获得我仍然不清楚的问题的答案。
所以我的理解如下:
主机和设备彼此完全异步执行。我必须使用 VkFence
在它们之间进行同步,即当我想知道某个特定提交已在设备上完成执行时,我必须在主机上等待适当的 VkFence
发出信号。
不同的命令队列相互异步执行。 Vulkan 规范不对向这些队列的提交开始或完成执行的顺序提供任何保证。因此,队列 A 上的 vkQueueSubmit
完全独立于队列 B 上的 vkQueueSubmit
执行,我必须使用 VkSemaphore
以确保例如提交到队列 B 后开始执行提交到队列A完了
但是提交到同一个命令队列的不同命令尊重它们的提交顺序,这意味着后提交的命令不会开始执行,除非先提交的命令已经开始执行,但另一方面这并不意味着这些后面的命令不能在前面的命令之前完成执行。
状态设置命令(例如vkCmdBindPipeline
、vkCmdBindVertexBuffers
...)不是异步的并且延迟到以后(例如vkCmdDraw
)。实际上它们在主机上(而不是在设备上)立即执行并修改 VkCommandBuffer
的状态,这个累积修改的状态用于记录后面的动作命令。
从同步的角度来看VkRenderPass
可以认为只是管道屏障的一个更简单的接口。它可以被认为是在渲染通道实例的开头有一个管道屏障(代替 vkCmdBeginRenderPass
),一个在渲染通道实例的结尾(代替 vkCmdEndRenderPass
)和一个管道屏障在每个子通道之后(代替 vkCmdNextSubpass
)。
在我的脑海中,命令如何在单个命令队列上执行的心智模型是一个巨大的命令流(按照它们被记录到命令缓冲区的顺序以及这些命令的顺序缓冲区被提交到队列)被管道屏障分割。每个管道屏障将流分成两部分,屏障之前的命令(A 部分)和屏障之后的命令(B 部分)。只有在 A 部分中的所有命令都已执行完流水线阶段 X 之后,才允许 B 部分中的命令开始(或者更确切地说继续执行流水线阶段 Y)。
问题:
Vulkan 规范(第 2.2.1 节。队列操作)指出:
Command buffer submissions to a single queue respect submission order
and other implicit ordering guarantees, but otherwise may overlap or
execute out of order. Other types of batches and queue submissions
against a single queue (e.g. sparse memory binding) have no implicit
ordering constraints with any other queue submission or batch.
假设在我的程序中我只有一个通用队列,它可以发出各种命令(图形、计算、传输、演示...),那么上面的语句是否意味着以下内容?
vkQueueSubmit #3
仅在 vkQueueSubmit #2
已经开始执行后才开始执行,它仅在 vkQueueSubmit #1
已经开始执行后才开始执行,...但是 vkQueueBindSparse
或 vkQueuePresentKHR
可以开始于任何时候,无论它们何时由主持人发出...换句话说,我总是必须使用 VkSemaphore
来确保演示文稿 (vkQueuePresentKHR
) 在正确的时间开始(只有在我所有的图形工作之后已提交并执行,因此可以展示了)。
我对命令缓冲区本身的提交顺序定义有点困惑。规范状态(第 6.2 节。隐式同步保证):
1)
For commands recorded outside a render pass, this includes all other
commands recorded outside a render pass, including
vkCmdBeginRenderPass and vkCmdEndRenderPass commands; it does not
directly include commands inside a render pass.
2)
For commands recorded inside a render pass, this includes all other
commands recorded inside the same subpass, including the
vkCmdBeginRenderPass and vkCmdEndRenderPass commands that delimit the
same render pass instance; it does not include commands recorded to
other subpasses.
第一个要点似乎很清楚。提交顺序是命令被记录到命令缓冲区的顺序,而 vkCmdBeginRenderPass
和 vkCmdEndRenderPass
块中的任何内容都被视为一个命令,用于本要点的目的。不过,第二个要点对我来说有点不清楚。这里的提交顺序是如何定义的?很明显,特定子通道中的任何命令都不会开始执行,除非先前的命令已经开始执行或除非执行了 vkCmdBeginRenderPass
。但是不同的子通道呢?这是否意味着子通道 1 可以在子通道 0 开始执行之前开始执行?这对我来说没有意义。有意义的是,如果后面的子通道只允许在前面的子通道完成后开始。
Vulkan 规范(第 6.1.2 节。流水线阶段)指出:
Execution of operations across pipeline stages must adhere to implicit
ordering guarantees, particularly including pipeline stage order.
这是否意味着例如绘图调用 2 的顶点着色器阶段不允许开始执行,除非绘图调用 1 的顶点着色器阶段已经开始执行?
我对 Vulkan 命令队列执行的心理模型(我理解的第 6 个)引发了一个问题,提交到命令缓冲区 (B) 开头的管道屏障是否会影响更早的命令缓冲区(一种)。我的意思是它会让命令缓冲区 B 中的命令等到命令缓冲区 A 中的命令完成后再开始执行吗?我在某处读到不同命令缓冲区之间的同步是事件的工作,但根据我的理解,这也应该有障碍。
此外,如果我使用 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT
作为源阶段,使用 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
作为管道屏障的目标阶段,基本上应该禁用屏障前后命令之间的任何重叠,对吗?
据我所知,Vulkan 中有几种不同的并行性:
- 在 CPU 和 GPU 之间,这些与
VkFence
同步
- 在 GPU 上的不同命令队列之间,这些队列与
VkSemaphore
同步
- 在同一队列的不同提交之间,异常似乎是
vkQueueSubmit
的提交。这些也与 VkSemaphore
. 同步
在不同的绘制调用之间。这些与管道屏障同步。
这个是我最困惑的。因此,如果我有一个 drawcall 以某种方式使用任何先前 drawcall 的结果或写入相同的渲染目标(帧缓冲区),那么据我所知,我需要确保后面的 drawcall 看到所有的内存效果以前的绘图调用。但是,当我渲染一个有一堆游戏角色、树木和建筑物的场景时呢?假设每个这样的对象都是一个绘图调用,并且所有这些绘图调用都写入同一个帧缓冲区。我是否需要在每次 drawcall 后发出内存屏障?直觉上这感觉是多余的,我检查过的演示在这种情况下没有发出任何障碍,但是是否有任何保证逻辑上紧随其后的绘制调用将看到逻辑上在它们之前的绘制调用的记忆效应?问题是,我什么时候需要在不同的绘制调用之间进行同步?
在单个绘图调用中。使用着色器原子指令可以实现此级别的同步。
然而,就我而言,我没有做任何不寻常的事情,比如从多个着色器实例写入相同的内存地址,或者从我刚刚写入的相同内存中读取(例如,在片段着色器中实现自定义混合),我应该没事。换句话说,如果每个片段着色器只读取和写入其对应的像素或顶点数据,我就不需要担心同一个 drawcall 中的同步问题。
The host and the device execute completely asynchronously with respect to each other.
是的。
除非使用显式同步(即VkFence
、vk*WaitIdle
、VkEvent
)。或者是一种罕见的隐式同步(主机写入对于任何后续 vkQueueSubmit
的设备访问都是可见的)。
请注意还必须有一个 "memory domain operation"。 IE。在 CPU 上读取 GPU 输出时必须使用 VK_PIPELINE_STAGE_HOST_BIT
。 (VkFence
单独进行执行和内存依赖是不够的)。
Different command queues execute asynchronously with respect to each other.
正确。换句话说,来自任何两个队列的命令可能 运行 串行,彼此相邻(并行),甚至是 pre-empted 和 time-shared,或以上的某种组合。什么都可以。除非使用显式同步(VkSemaphore
或 VkFence
)。
However different commands submitted to the same command queue respect their submission order
是的。但只是规范形式主义,没有 real-world 效果。它只是被指定,所以我们有正式的语言框架来描述规范中的其他内容(例如,它指定了描述管道障碍行为所必需的术语)。
State setting commands (e.g. vkCmdBindPipeline
, vkCmdBindVertexBuffers
...) are not asynchronous and delayed for later (like e.g. vkCmdDraw
).
不,我不会这么描述它。
他们不是"delayed"。它们只是在命令缓冲区中记录的位置执行。
这也许是我们需要 "submission order" 形式主义的地方之一。 state 命令之后提交顺序中的所有命令都会看到新状态。 (即只有状态命令之后记录的命令才能看到新状态)。
From the perspective of synchronization VkRenderPass
can be thought of as just a simpler interface to pipeline barriers.
我不这么认为。它实际上可能更复杂一些。
它所做的是更有效的同步,尽管它可能在功能上定义了与管道屏障相同的同步。它的不同之处在于(除其他事项外)它将此同步定义为一个整体(即您预先告诉驱动程序您将使用哪些资源,然后概述您稍后要对它们执行的所有操作)。
Render Pass 是移动平铺架构 GPU 所需的工具。在桌面上,如果他们从移动 GPU 中获得一些架构灵感,或者只是作为驱动程序优化的 oracle,它也很有用。
so does the above statement mean the following ? vkQueueSubmit #3 starts execution only after vkQueueSubmit #2 has already started execution, which starts only after vkQueueSubmit #1 has already started
是的,也不是。阅读上面关于提交顺序的形式主义。
从技术上讲,是的,命令保证按顺序执行其 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
。 但是那个阶段什么都没做。
AIS,它只是用于其他事物的规范形式。它本身并没有说明什么。
I am a little bit confused with the definition of submission order within command buffers themselves.
是的,语言有点棘手。绊倒你的部分是子通道。请注意,根据定义,子通道也是异步的。因此我们不能使用引用“1)”中的简单规则。
如果我对其进行解码,规范引用的含义是:
a) Render Pass Instance 之前(即 vkCmdBeginRenderPass
之前)记录的任何命令在提交顺序上比 vkCmdBeginRenderPass
早 ,并且早于子通道中的任何和所有命令。 (反之亦然,子通道中的任何内容都按提交顺序排列。)
b) 同样,在 Render Pass Instance 之后(即 vkCmdEndRenderPass
之后)记录的任何命令在提交顺序上都比 vkCmdEndRenderPass
晚 ,并且更晚比子通道中的任何和所有命令都要多。
c) 单个子通道中的命令的提交顺序与它们在 (vkCmd*
) 中记录的顺序相同。
d) 任何两个子通道中的命令 没有 彼此有提交顺序。
记住提交顺序只是一种形式主义。 "d)" 实际上意味着你不能在子通道 1
中执行 vkCmdPipelineBarrier
并期望该障碍覆盖子通道 0
中的任何内容。 (你必须做的是使用 VkSubpassDependency
而不是 vkCmdPipelineBarrier
来实现子通道 0
和 1
之间的依赖关系。)
Execution of operations across pipeline stages must adhere to implicit ordering guarantees, particularly including pipeline stage order.
这只是链接到规范中其他一些内容的介绍性声明。它本身并没有说明什么。
"implicit ordering guarantees" 指向我们介绍的提交顺序的链接。
"pipeline stage order" 只是链接到流水线阶段排序。这只是在管道阶段之间指定 "logical order"(例如,顶点着色器在片段着色器之前)。这意味着每当您在任何 srcStage
参数中使用阶段标志位时,Vulkan 都会隐含地假设您也指的是任何逻辑上较早的阶段标志位。 (对于 dstStage
也是如此)。
My mental model of Vulkan's command queue execution (number 6 of my understanding) provokes the question, whether a pipeline barrier submitted to the beginning of a command buffer (B) would affect an earlier command buffer (A)
是的,这是总体思路。
可以这样想:vkQueueSubmit
将命令缓冲区中的命令连接到队列的末尾。它被称为 "queue" 是有原因的。因此,管道屏障会影响先前提交的命令缓冲区。 (顺便说一句,这就是为什么它被称为 submission order)
Also if I used VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT
as source stage and VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
as destination stage of a pipeline barrier that should basically disable any overlap between the commands before and after the barrier, right ?
是的,但那是代码腐烂。
在这种情况下,请改用 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT
。任何阅读此类代码的人都更容易理解。
So as I see it, there are several different parallelisms in Vulkan:
异步。
不保证并行性。 IE。允许驱动程序序列化工作负载,或 time-share 它。
但是例如凭借一些常识,您可以猜测 CPU 和 GPU 之间会有(显着的)并行性,如果它是专用 GPU。
The question is, when do I need to synchronize between different drawcalls ?
是的,我认为绘制命令之间没有帧缓冲区同步是 exceptions\simplifications Vulkan 所具有的功能之一。
我相信人们支持Primitive Order and Rasterization Order的规范。
即在 单个 子通道中,您不应该需要两个 vkCmdDraw*
之间的管道屏障来同步颜色和深度缓冲区。 (我认为)您仍然需要显式同步子通道中的绘制与其他子通道以及渲染通道实例之外的绘制。
However as far as I am not doing anything unusual, like writing to the same memory address from multiple shader instances or reading from the same memory that I have just written to (e.g. implementation of custom blending in fragment shader), I should be fine.
是的。流水线以及固定和可编程阶段的工作方式应与 OpenGL 中的类似。在大多数情况下,您应该能够使用 OpenGL 的着色器,只需很少修改或无需修改即可实现相同的行为。
我想澄清我对 Vulkan 执行模型的困惑,我想验证我的理解并获得我仍然不清楚的问题的答案。
所以我的理解如下:
主机和设备彼此完全异步执行。我必须使用
VkFence
在它们之间进行同步,即当我想知道某个特定提交已在设备上完成执行时,我必须在主机上等待适当的VkFence
发出信号。不同的命令队列相互异步执行。 Vulkan 规范不对向这些队列的提交开始或完成执行的顺序提供任何保证。因此,队列 A 上的
vkQueueSubmit
完全独立于队列 B 上的vkQueueSubmit
执行,我必须使用VkSemaphore
以确保例如提交到队列 B 后开始执行提交到队列A完了但是提交到同一个命令队列的不同命令尊重它们的提交顺序,这意味着后提交的命令不会开始执行,除非先提交的命令已经开始执行,但另一方面这并不意味着这些后面的命令不能在前面的命令之前完成执行。
状态设置命令(例如
vkCmdBindPipeline
、vkCmdBindVertexBuffers
...)不是异步的并且延迟到以后(例如vkCmdDraw
)。实际上它们在主机上(而不是在设备上)立即执行并修改VkCommandBuffer
的状态,这个累积修改的状态用于记录后面的动作命令。从同步的角度来看
VkRenderPass
可以认为只是管道屏障的一个更简单的接口。它可以被认为是在渲染通道实例的开头有一个管道屏障(代替vkCmdBeginRenderPass
),一个在渲染通道实例的结尾(代替vkCmdEndRenderPass
)和一个管道屏障在每个子通道之后(代替vkCmdNextSubpass
)。在我的脑海中,命令如何在单个命令队列上执行的心智模型是一个巨大的命令流(按照它们被记录到命令缓冲区的顺序以及这些命令的顺序缓冲区被提交到队列)被管道屏障分割。每个管道屏障将流分成两部分,屏障之前的命令(A 部分)和屏障之后的命令(B 部分)。只有在 A 部分中的所有命令都已执行完流水线阶段 X 之后,才允许 B 部分中的命令开始(或者更确切地说继续执行流水线阶段 Y)。
问题:
Vulkan 规范(第 2.2.1 节。队列操作)指出:
Command buffer submissions to a single queue respect submission order and other implicit ordering guarantees, but otherwise may overlap or execute out of order. Other types of batches and queue submissions against a single queue (e.g. sparse memory binding) have no implicit ordering constraints with any other queue submission or batch.
假设在我的程序中我只有一个通用队列,它可以发出各种命令(图形、计算、传输、演示...),那么上面的语句是否意味着以下内容?
vkQueueSubmit #3
仅在vkQueueSubmit #2
已经开始执行后才开始执行,它仅在vkQueueSubmit #1
已经开始执行后才开始执行,...但是vkQueueBindSparse
或vkQueuePresentKHR
可以开始于任何时候,无论它们何时由主持人发出...换句话说,我总是必须使用VkSemaphore
来确保演示文稿 (vkQueuePresentKHR
) 在正确的时间开始(只有在我所有的图形工作之后已提交并执行,因此可以展示了)。我对命令缓冲区本身的提交顺序定义有点困惑。规范状态(第 6.2 节。隐式同步保证):
1)
For commands recorded outside a render pass, this includes all other commands recorded outside a render pass, including vkCmdBeginRenderPass and vkCmdEndRenderPass commands; it does not directly include commands inside a render pass.
2)
For commands recorded inside a render pass, this includes all other commands recorded inside the same subpass, including the vkCmdBeginRenderPass and vkCmdEndRenderPass commands that delimit the same render pass instance; it does not include commands recorded to other subpasses.
第一个要点似乎很清楚。提交顺序是命令被记录到命令缓冲区的顺序,而
vkCmdBeginRenderPass
和vkCmdEndRenderPass
块中的任何内容都被视为一个命令,用于本要点的目的。不过,第二个要点对我来说有点不清楚。这里的提交顺序是如何定义的?很明显,特定子通道中的任何命令都不会开始执行,除非先前的命令已经开始执行或除非执行了vkCmdBeginRenderPass
。但是不同的子通道呢?这是否意味着子通道 1 可以在子通道 0 开始执行之前开始执行?这对我来说没有意义。有意义的是,如果后面的子通道只允许在前面的子通道完成后开始。Vulkan 规范(第 6.1.2 节。流水线阶段)指出:
Execution of operations across pipeline stages must adhere to implicit ordering guarantees, particularly including pipeline stage order.
这是否意味着例如绘图调用 2 的顶点着色器阶段不允许开始执行,除非绘图调用 1 的顶点着色器阶段已经开始执行?
我对 Vulkan 命令队列执行的心理模型(我理解的第 6 个)引发了一个问题,提交到命令缓冲区 (B) 开头的管道屏障是否会影响更早的命令缓冲区(一种)。我的意思是它会让命令缓冲区 B 中的命令等到命令缓冲区 A 中的命令完成后再开始执行吗?我在某处读到不同命令缓冲区之间的同步是事件的工作,但根据我的理解,这也应该有障碍。
此外,如果我使用
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT
作为源阶段,使用VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
作为管道屏障的目标阶段,基本上应该禁用屏障前后命令之间的任何重叠,对吗?据我所知,Vulkan 中有几种不同的并行性:
- 在 CPU 和 GPU 之间,这些与
VkFence
同步
- 在 GPU 上的不同命令队列之间,这些队列与
VkSemaphore
同步
- 在同一队列的不同提交之间,异常似乎是
vkQueueSubmit
的提交。这些也与VkSemaphore
. 同步
在不同的绘制调用之间。这些与管道屏障同步。
这个是我最困惑的。因此,如果我有一个 drawcall 以某种方式使用任何先前 drawcall 的结果或写入相同的渲染目标(帧缓冲区),那么据我所知,我需要确保后面的 drawcall 看到所有的内存效果以前的绘图调用。但是,当我渲染一个有一堆游戏角色、树木和建筑物的场景时呢?假设每个这样的对象都是一个绘图调用,并且所有这些绘图调用都写入同一个帧缓冲区。我是否需要在每次 drawcall 后发出内存屏障?直觉上这感觉是多余的,我检查过的演示在这种情况下没有发出任何障碍,但是是否有任何保证逻辑上紧随其后的绘制调用将看到逻辑上在它们之前的绘制调用的记忆效应?问题是,我什么时候需要在不同的绘制调用之间进行同步?
在单个绘图调用中。使用着色器原子指令可以实现此级别的同步。
然而,就我而言,我没有做任何不寻常的事情,比如从多个着色器实例写入相同的内存地址,或者从我刚刚写入的相同内存中读取(例如,在片段着色器中实现自定义混合),我应该没事。换句话说,如果每个片段着色器只读取和写入其对应的像素或顶点数据,我就不需要担心同一个 drawcall 中的同步问题。
- 在 CPU 和 GPU 之间,这些与
The host and the device execute completely asynchronously with respect to each other.
是的。
除非使用显式同步(即VkFence
、vk*WaitIdle
、VkEvent
)。或者是一种罕见的隐式同步(主机写入对于任何后续 vkQueueSubmit
的设备访问都是可见的)。
请注意还必须有一个 "memory domain operation"。 IE。在 CPU 上读取 GPU 输出时必须使用 VK_PIPELINE_STAGE_HOST_BIT
。 (VkFence
单独进行执行和内存依赖是不够的)。
Different command queues execute asynchronously with respect to each other.
正确。换句话说,来自任何两个队列的命令可能 运行 串行,彼此相邻(并行),甚至是 pre-empted 和 time-shared,或以上的某种组合。什么都可以。除非使用显式同步(VkSemaphore
或 VkFence
)。
However different commands submitted to the same command queue respect their submission order
是的。但只是规范形式主义,没有 real-world 效果。它只是被指定,所以我们有正式的语言框架来描述规范中的其他内容(例如,它指定了描述管道障碍行为所必需的术语)。
State setting commands (e.g.
vkCmdBindPipeline
,vkCmdBindVertexBuffers
...) are not asynchronous and delayed for later (like e.g.vkCmdDraw
).
不,我不会这么描述它。 他们不是"delayed"。它们只是在命令缓冲区中记录的位置执行。
这也许是我们需要 "submission order" 形式主义的地方之一。 state 命令之后提交顺序中的所有命令都会看到新状态。 (即只有状态命令之后记录的命令才能看到新状态)。
From the perspective of synchronization
VkRenderPass
can be thought of as just a simpler interface to pipeline barriers.
我不这么认为。它实际上可能更复杂一些。
它所做的是更有效的同步,尽管它可能在功能上定义了与管道屏障相同的同步。它的不同之处在于(除其他事项外)它将此同步定义为一个整体(即您预先告诉驱动程序您将使用哪些资源,然后概述您稍后要对它们执行的所有操作)。
Render Pass 是移动平铺架构 GPU 所需的工具。在桌面上,如果他们从移动 GPU 中获得一些架构灵感,或者只是作为驱动程序优化的 oracle,它也很有用。
so does the above statement mean the following ? vkQueueSubmit #3 starts execution only after vkQueueSubmit #2 has already started execution, which starts only after vkQueueSubmit #1 has already started
是的,也不是。阅读上面关于提交顺序的形式主义。
从技术上讲,是的,命令保证按顺序执行其 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
。 但是那个阶段什么都没做。
AIS,它只是用于其他事物的规范形式。它本身并没有说明什么。
I am a little bit confused with the definition of submission order within command buffers themselves.
是的,语言有点棘手。绊倒你的部分是子通道。请注意,根据定义,子通道也是异步的。因此我们不能使用引用“1)”中的简单规则。
如果我对其进行解码,规范引用的含义是:
a) Render Pass Instance 之前(即 vkCmdBeginRenderPass
之前)记录的任何命令在提交顺序上比 vkCmdBeginRenderPass
早 ,并且早于子通道中的任何和所有命令。 (反之亦然,子通道中的任何内容都按提交顺序排列。)
b) 同样,在 Render Pass Instance 之后(即 vkCmdEndRenderPass
之后)记录的任何命令在提交顺序上都比 vkCmdEndRenderPass
晚 ,并且更晚比子通道中的任何和所有命令都要多。
c) 单个子通道中的命令的提交顺序与它们在 (vkCmd*
) 中记录的顺序相同。
d) 任何两个子通道中的命令 没有 彼此有提交顺序。
记住提交顺序只是一种形式主义。 "d)" 实际上意味着你不能在子通道 1
中执行 vkCmdPipelineBarrier
并期望该障碍覆盖子通道 0
中的任何内容。 (你必须做的是使用 VkSubpassDependency
而不是 vkCmdPipelineBarrier
来实现子通道 0
和 1
之间的依赖关系。)
Execution of operations across pipeline stages must adhere to implicit ordering guarantees, particularly including pipeline stage order.
这只是链接到规范中其他一些内容的介绍性声明。它本身并没有说明什么。
"implicit ordering guarantees" 指向我们介绍的提交顺序的链接。
"pipeline stage order" 只是链接到流水线阶段排序。这只是在管道阶段之间指定 "logical order"(例如,顶点着色器在片段着色器之前)。这意味着每当您在任何 srcStage
参数中使用阶段标志位时,Vulkan 都会隐含地假设您也指的是任何逻辑上较早的阶段标志位。 (对于 dstStage
也是如此)。
My mental model of Vulkan's command queue execution (number 6 of my understanding) provokes the question, whether a pipeline barrier submitted to the beginning of a command buffer (B) would affect an earlier command buffer (A)
是的,这是总体思路。
可以这样想:vkQueueSubmit
将命令缓冲区中的命令连接到队列的末尾。它被称为 "queue" 是有原因的。因此,管道屏障会影响先前提交的命令缓冲区。 (顺便说一句,这就是为什么它被称为 submission order)
Also if I used
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT
as source stage andVK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
as destination stage of a pipeline barrier that should basically disable any overlap between the commands before and after the barrier, right ?
是的,但那是代码腐烂。
在这种情况下,请改用 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT
。任何阅读此类代码的人都更容易理解。
So as I see it, there are several different parallelisms in Vulkan:
异步。
不保证并行性。 IE。允许驱动程序序列化工作负载,或 time-share 它。
但是例如凭借一些常识,您可以猜测 CPU 和 GPU 之间会有(显着的)并行性,如果它是专用 GPU。
The question is, when do I need to synchronize between different drawcalls ?
是的,我认为绘制命令之间没有帧缓冲区同步是 exceptions\simplifications Vulkan 所具有的功能之一。
我相信人们支持Primitive Order and Rasterization Order的规范。
即在 单个 子通道中,您不应该需要两个 vkCmdDraw*
之间的管道屏障来同步颜色和深度缓冲区。 (我认为)您仍然需要显式同步子通道中的绘制与其他子通道以及渲染通道实例之外的绘制。
However as far as I am not doing anything unusual, like writing to the same memory address from multiple shader instances or reading from the same memory that I have just written to (e.g. implementation of custom blending in fragment shader), I should be fine.
是的。流水线以及固定和可编程阶段的工作方式应与 OpenGL 中的类似。在大多数情况下,您应该能够使用 OpenGL 的着色器,只需很少修改或无需修改即可实现相同的行为。