vulkan障碍和多线程

时间:2018-07-27 18:27:57

标签: multithreading 3d rendering vulkan

我想分享一下我如何在多线程渲染中保持内存屏障同步的想法。如果我对Vulkan内存屏障的想法是错误的,或者我当前的计划是否有意义,请告诉我。我没有任何人可以与您讨论,所以我会在这里寻求帮助。

对于Vulkan中的资源,当我在两次调用之间为它们设置内存壁垒时,我需要同时设置srcAccessMask和dst AccessMask。这对于单线程渲染很简单。但是对于多线程渲染,它变得很复杂。 dst AccessMask没问题,因为我们始终知道该资源将用于什么用途。但是对于srcAccessMask,当一个命令缓冲区尝试读取某些资源的当前访问掩码时,可能会有其他命令缓冲区将其更改为其他内容。因此,我目前解决该问题的想法是:

每个资源保持其自己的状态,我只会在将命令缓冲区提交到命令队列之前立即更新状态,我将在以后进行描述。每个命令缓冲区都维护有关其内部资源状态如何变化的跟踪记录。这样做,在同一个命令缓冲区中,每个资源的访问状态是明确的,唯一的问题是每个命令缓冲区的资源开始状态。

提交多个命令缓冲区以执行时,由于命令缓冲区的顺序现在已固定,因此我检查了所有命令缓冲区中每个资源的跟踪记录,根据每个命令缓冲区中资源的结束状态来更新资源状态,并使用它来更正每个命令缓冲区的跟踪记录中相同资源的开始状态。

然后我需要插入一个新的命令缓冲区以具有额外的内存屏障,以将资源转换为第一个命令缓冲区的正确状态,或者我需要为其余的命令缓冲区将内存屏障插入到先前的命令缓冲区中。我终于可以批量提交命令缓冲区了。

这些对您有意义吗?有更好的解决方案吗?还是我们甚至需要解决每种资源的访问状态“同步”问题?

谢谢您的时间

1 个答案:

答案 0 :(得分:2)

您所谈论的只是在一个这样的世界中才有意义:在这些世界中,任何渲染操作都没有丝毫了解其他地方正在发生的事情。图像的使用者不知道图像中的数据如何到达那里。这可能意味着它并不真正了解该图像在概念上的含义。

Vulkan是一个低级API。这个想法是您可以将渲染系统的高级概念直接连接到Vulkan。因此,从高层次上讲,您知道资源X的含义为Y,并且在此帧中将从操作Z生成其数据。这不是因为资源X中存储了某些东西,而是因为它。这就是X的资源。因此,生成它的操作和使用它的操作都知道发生了什么以及如何到达那里。

例如,如果您要进行延迟渲染和SSAO,则SSAO renderpass会知道包含深度缓冲区的纹理具有通过渲染生成的值。深度缓冲区不需要在其中存储一些东西;那仅仅是渲染的本质。这种方式很难编码。

您的大多数资源依赖关系就是(或应该如此)。

如果您正在通过帧缓冲区执行渲染到纹理的操作,那么使用者可能甚至不需要了解依赖项。您可以为renderpass和生成它的子通道设置适当的外部依赖关系。您可能知道为什么要执行“渲染到纹理”操作,并且可能知道操作的方向。如果您正在进行RTT反射,则知道目标将是某种着色器阶段纹理获取。而且,如果您不知道如何使用它,那么就可以放心设置所有目标阶段位。

如果您要处理流对象,其中正在以某种规律性将对象突然弹出内存和从内存中弹出的内容,那么您所说的是有一定意义的。即便如此,这实际上并不是每个资源的属性。

当加载流式块时,通过生成命令缓冲区并提交将其数据上载。这就是我们在实现方面存在分歧的地方。最好的性能选择是在专用于传输操作的队列上执行这些CB。但是由于Vulkan不能保证所有实现都具有这些实现,因此您需要能够将这些传输CB交付到主渲染队列中。

因此,当可以预期渲染线程开始使用资源时,您需要一种与渲染线程进行通信的方法。但这甚至不必基于每个资源。他们可以被告知“ X块中的东西可用”,然后他们就可以开始使用它了。

此外,实现差异变得很重要。看,如果是在另一个队列上完成的,则障碍不是正确的同步原语。现在,渲染CB必须让其提交的批处理等待 semaphore 。并且该信号量应处理内存的所有同步需求(即:目标位是所有内容)。因此,在将传输CB与呈现CB在同一队列上执行的实现中,您还可以节省一些麻烦,并在传输CB结束时发出一个障碍,使所有给定资源可用于所有阶段

因此,如前所述,这种自动化系统仅在您无法真正控制渲染的结构时才有用。如果您正在编写某种中间件,那么其中的上层代码定义了渲染的结构,这基本上是正确的。但是,如果是这种情况,Vulkan可能不是该工作的正确工具。

相关问题