vulkan 管道屏障是如何在 GPU 或其驱动程序方面实现的?

问题描述

我认为管道障碍是内核模式驱动程序中命令的重新排序,但似乎并非如此。此外,我认为它可能类似于驱动程序端 GPU 调度程序的提示,但它似乎仍然不是真的。它只是构建 KMD 主命令缓冲区的提示,还是代表 GPU 命令处理器的某种指令的管道屏障?

编辑:如何实现管道障碍?

解决方法

正如 Nicol 所说,细节将取决于具体实施和障碍。但一般原则是相似的。

GPU 是流水线处理器,这意味着每个命令都要经过多个执行阶段。阶段在绘制调用内部和之间并发运行。例如,绘制命令 N 的片段处理可能与绘制命令 N+1 的顶点处理同时执行。屏障命令可防止后续命令的工作在 dstStageMask 中的先前命令完成执行 srcStageMask 中的所有阶段之前开始执行 srcStageMask 中的任何阶段。除了这个执行屏障,管道屏障还可以包括一个内存屏障,它确保前面命令完成的内存访问与后面的命令。

所以这一切都与重新排序无关,它只与新命令在前一个命令完成之前开始的事实有关,有时您需要防止这种情况发生。最明显的例子是渲染到纹理:您希望在对纹理的任何读取发生之前完成对纹理的所有写入。没有管道屏障,没有什么可以阻止它们重叠。

通常,GPU 会有一个(内部)命令,在之前的命令都通过命令执行点后“发出信号”一些标记,另一个命令“等待”某个标记发出信号,然后再允许任何后续工作继续。标记可能只是一个内存位置(信号:写入特定值,等待:旋转直到该位置包含特定值)。或者它可能是某种特殊用途的片上资源。屏障将只是一个信号命令,然后是一个等待命令。这会在部分 GPU 闲置的管道中产生“气泡”。为了最大限度地减少这种情况,一些 GPU 将能够在管道中的多个点发出信号并等待。能够在颜色写入完成后发出信号并在光栅化之前等待是很常见的,例如,允许绘制 N+1 的顶点工作发生,而绘制 N 的片段工作正在发生,但停止 N+1 片段工作。 dstStageMaskself.view.window?isOpaque = true tableView.enclosingScrollView.setDrawsBackground = true tableView.backgroundColor = .black scrollView.backgroundColor = .black 允许实现准确地知道依赖项是什么,但大多数实际上无法利用这种精细的粒度,并且会创建一个更粗糙的保守气泡。

内存屏障对应于缓存清理(将脏行写入内存)和缓存无效(删除缓存数据)操作。 “可见性”意味着清理本地缓存,将数据写回内存,以便以后从内存中读取的任何内容都能看到新值。 “可用性”意味着使本地缓存无效,因此任何新读取都将在缓存中丢失(而不是看到旧数据)并从内存中获取。 GPU 通常具有针对不同本地缓存(例如纹理缓存、深度/模板缓存等)的特定操作的特殊命令。

因此,在渲染到纹理的情况下,您需要在纹理渲染命令和从纹理读取的任何命令之间插入一个管道屏障。驱动程序将生成一个 GPU 一个(或多个)命令,等待先前的命令完成混合阶段的执行,然后清理颜色附件缓存,然后发出一些标记。然后它将生成 GPU 命令以等待标记发出信号并使纹理缓存无效,然后再允许任何未来的绘制调用开始片段着色。

正如我之前所说,GPU 提供的实际命令可能比这粗得多,例如它可能是“等待所有先前的绘制命令完全完成,然后清除所有不具有自动一致性的缓存并使之无效,然后允许后续绘制命令开始顶点获取和顶点着色。”