首页 > 解决方案 > 关于子通道依赖性的 Vulkan 规范说明

问题描述

我需要对 Vulkan Spec 中的某些内容有所了解。第 8.1 节说:

渲染通道必须包括在同一附件或别名附件上操作的任何两个子通道之间的子通道依赖关系(直接或通过子通道依赖链),并且这些子通道依赖关系必须包括执行和内存依赖关系,以分离别名的使用,如果至少一个这些子通道写入其中一个别名。如果别名是在内存中重叠的不同图像子资源的视图,则这些依赖项不得包括 VK_DEPENDENCY_BY_REGION_BIT。

这是否意味着如果子通道 S0 写入附件 X(作为颜色、深度或解析)并且后续子通道 S1 使用该附件 X(作为颜色、输入、深度或解析),那么必须存在来自S0->S1(直接或通过链)?

编辑 1:经过进一步思考,这种情况不仅仅是 S0 写入和 S1 读取。如果 S0 读取和 S1 写入,那也需要从 S0->S1 同步。

编辑 2:我应该说,我之前特别不确定的是由 2 个不同的子通道编写的颜色附件。假设子通道没有逻辑依赖关系,除了它们使用相同颜色的附件之外,如果它们使用不同的附件,它们可以并行运行。在阅读本段之前,我的印象是,如果子通道 B 需要来自子通道 A 的一些实际数据,则仅在 2 个子通道之间需要依赖关系,因此需要等到这些数据可用。那几段谈到了一般的记忆危害。

如果逻辑上不需要以某种方式对 2 个子通道进行排序,则 GPU 可以决定先运行哪个更好。但是,如果开发人员总是必须在 2 个子通道接触同一个附件时声明依赖关系,那么这就是只有 gpu 才能解决的潜在速度损失。GPU 应该不难发现,虽然 2 个子通道之间没有开发人员声明的依赖关系,但它们确实读/写同一个附件,所以它不应该只是盲目地在同时来自两个子通道。是的,我的意思是 GPU 会为基本情况做一些简单的同步,以免自己被斩首。

标签: vulkan

解决方案


如果渲染通道具有两个子通道 A 和 B,并且都使用相同的附件,并且 A 写入共享附件,那么从逻辑上讲,A 和 B之间存在排序要求。必须有。

如果两个操作之间没有排序要求,那么这两个操作在逻辑上是可以交错的。也就是说,部分运行一个,然后部分运行另一个,然后完成第一个。它们可以在任何程度上交错。

你不能交错 A 和 B,因为你得到的结果是不连贯的。对于 A 和 B 之间的任何共享附件,如果 B 写入该附件中的像素,A 是否应该读取该数据?如果 B 向它写入两次怎么办?A应该读取预先写入的值,第一次写入后的值,还是第二次写入后的值?如果 A 也写入该像素,B 的写入应该发生在它之前还是之后?或者 A 的写入应该在 B 的两次写入之间?如果是这样,哪些?

将 A 和 B 交错是没有意义的。它们之间必须有一个逻辑顺序。因此,您假设的场景“没有逻辑需要以某种方式对 2 个子通道进行排序”是没有意义的。

您希望 B 完成的任何读/写操作在 A 完成的写操作之前发生,或者您希望它们发生在之后。没有一个选择比另一个更好或更正确;它们都是同样有效的使用模式。

Vulkan 是一个显式的低级渲染 API。弄清楚您要做什么不是 Vulkan 的工作。告诉Vulkan 你想让它做什么是你的工作。而且由于任何一种可能性都是完全有效的,因此您必须告诉 Vulkan 您想要做什么。


A & B 都需要 5 个颜色的附件,但除了内存之外,它们互不关心。为什么 GPU 不能在子通道之间智能地共享 5 种颜色的附件,在它认为合适的时候交错?

那怎么可能呢?

如果 A 的前半部分将一些数据写入附件,而 A 的后半部分操作将读取该数据,则 B 无法进入其中并覆盖该数据。因为这样数据将被不正确的值覆盖,而 A 的后半部分将无法访问前半部分写入的数据。

vkCmdClearAttachments如果 A 和 B 都从清除缓冲区开始(仅供参考:至少应该认为调用可能是可疑的),则不可能进行交错。因为他们要做的第一件事就是完全覆盖附件。这些子通道中的渲染命令期望附件具有已知数据,并且有人来捣乱它会破坏这些假设并产生不正确的结果。

因此,无论这些子通道在做什么,它们都必须在另一个之前完整地执行。您可能不关心它们执行的顺序,但它们必须完全按照某种顺序执行,它们之间没有重叠。

Vulkan 只是让您拼出该命令是什么。


推荐阅读