在 Vulkan 中具有透明性的多个绘制调用之间是否需要同步?
Is synchronization needed between multiple draw calls with transparency in Vulkan?
我正在学习 Vulkan,我刚刚使用原始 ImGui 存储库中的 Vulkan-GLFW 示例将 ImGui 集成到我的代码中,并且工作正常。
现在我想同时在屏幕上渲染 GUI 和我的 3D 模型,并且由于 GUI 和模型肯定需要不同的着色器,所以我需要使用多个管道并提交多个命令。 GUI 是部分透明的,所以我希望它在模型之后呈现。 Vulkan 规范指出命令的执行顺序不太可能是我记录命令的顺序,因此我需要某种同步。在this Reddit post中提出了几种完全实现我的目标的方法,我曾经认为我必须使用多个子通道(连同子通道依赖)或屏障或其他类似的同步方法来解决这个问题。
然后我看了一下SaschaWillems' Vulkan examples,虽然在ImGui的例子中,我看到两个绘图调用之间没有同步,它只记录了先绘制模型的命令,然后是绘制命令图形用户界面。
我很困惑。在这种情况下真的需要同步吗,还是我对命令重新排序或混合有误解?谢谢
想一想你在做什么。为什么您认为两组命令之间需要同步?因为第二组命令需要与第一组中的数据混合,对吧?因此,它需要做一个 read/modify/write (RMW),它必须能够读取前一组命令写入的数据。正在读取的数据必须已经写入,这通常需要同步。
但请多想想这意味着什么。混合必须从帧缓冲区中读取才能完成它的工作。但是......深度测试也是如此,对吧?它必须读取现有样本的深度值,将其与传入的片段进行比较,然后根据深度测试丢弃或不丢弃该片段。所以基本上 每个使用深度测试的绘制调用 都包含一个帧缓冲区 read/modify/wright.
然而...您的深度测试有效。它们不仅在没有显式同步的绘制调用之间工作,而且还在 绘制调用中工作。如果绘图调用中的两个三角形重叠,您可以通过顶部的三角形看到底部的三角形,对吧?您不必进行三角形间同步来确保前面三角形的写入在读取之前完成。
所以不知何故,深度测试的 RMW 在没有任何显式同步的情况下工作。那么...为什么您认为混合阶段的 RMW 不正确?
Vulkan 规范指出命令和命令中的阶段将以基本上无序的方式执行,但有几个例外。最明显的是显式执行的存在 barriers/dependencies。但它也表示,固定功能的每个样本测试和混合阶段将始终(好像)按提交顺序(在子通道内)执行。不仅如此,它还要求在命令中生成的三角形也以特定的、明确定义的顺序执行这些阶段(好像)。
这就是为什么你的深度测试不需要同步; Vulkan 要求对此进行处理。这也是为什么您的 混合 不需要同步(在子通道内)。
所以你有很多选择(按从快到慢的顺序):
- 在与非 UI 相同的子通道中渲染您的 UI。只需根据需要更改管道即可。
- 在子通道中渲染您的 UI,并明确依赖于非 UI 子通道的帧缓冲区图像。虽然这在技术上比较慢,但如果有的话,它可能不会慢很多。此外,这对于延迟渲染很有用,因为你的 UI 需要在你的光照通道之后发生,这无疑将是它自己的子通道。
- 在不同的渲染过程中渲染您的 UI。只有在您需要进行一些全屏工作 (SSAO) 的情况下才真正需要这样做,这会强制您的非 UI 渲染过程终止。
我正在学习 Vulkan,我刚刚使用原始 ImGui 存储库中的 Vulkan-GLFW 示例将 ImGui 集成到我的代码中,并且工作正常。
现在我想同时在屏幕上渲染 GUI 和我的 3D 模型,并且由于 GUI 和模型肯定需要不同的着色器,所以我需要使用多个管道并提交多个命令。 GUI 是部分透明的,所以我希望它在模型之后呈现。 Vulkan 规范指出命令的执行顺序不太可能是我记录命令的顺序,因此我需要某种同步。在this Reddit post中提出了几种完全实现我的目标的方法,我曾经认为我必须使用多个子通道(连同子通道依赖)或屏障或其他类似的同步方法来解决这个问题。
然后我看了一下SaschaWillems' Vulkan examples,虽然在ImGui的例子中,我看到两个绘图调用之间没有同步,它只记录了先绘制模型的命令,然后是绘制命令图形用户界面。
我很困惑。在这种情况下真的需要同步吗,还是我对命令重新排序或混合有误解?谢谢
想一想你在做什么。为什么您认为两组命令之间需要同步?因为第二组命令需要与第一组中的数据混合,对吧?因此,它需要做一个 read/modify/write (RMW),它必须能够读取前一组命令写入的数据。正在读取的数据必须已经写入,这通常需要同步。
但请多想想这意味着什么。混合必须从帧缓冲区中读取才能完成它的工作。但是......深度测试也是如此,对吧?它必须读取现有样本的深度值,将其与传入的片段进行比较,然后根据深度测试丢弃或不丢弃该片段。所以基本上 每个使用深度测试的绘制调用 都包含一个帧缓冲区 read/modify/wright.
然而...您的深度测试有效。它们不仅在没有显式同步的绘制调用之间工作,而且还在 绘制调用中工作。如果绘图调用中的两个三角形重叠,您可以通过顶部的三角形看到底部的三角形,对吧?您不必进行三角形间同步来确保前面三角形的写入在读取之前完成。
所以不知何故,深度测试的 RMW 在没有任何显式同步的情况下工作。那么...为什么您认为混合阶段的 RMW 不正确?
Vulkan 规范指出命令和命令中的阶段将以基本上无序的方式执行,但有几个例外。最明显的是显式执行的存在 barriers/dependencies。但它也表示,固定功能的每个样本测试和混合阶段将始终(好像)按提交顺序(在子通道内)执行。不仅如此,它还要求在命令中生成的三角形也以特定的、明确定义的顺序执行这些阶段(好像)。
这就是为什么你的深度测试不需要同步; Vulkan 要求对此进行处理。这也是为什么您的 混合 不需要同步(在子通道内)。
所以你有很多选择(按从快到慢的顺序):
- 在与非 UI 相同的子通道中渲染您的 UI。只需根据需要更改管道即可。
- 在子通道中渲染您的 UI,并明确依赖于非 UI 子通道的帧缓冲区图像。虽然这在技术上比较慢,但如果有的话,它可能不会慢很多。此外,这对于延迟渲染很有用,因为你的 UI 需要在你的光照通道之后发生,这无疑将是它自己的子通道。
- 在不同的渲染过程中渲染您的 UI。只有在您需要进行一些全屏工作 (SSAO) 的情况下才真正需要这样做,这会强制您的非 UI 渲染过程终止。