0

我正在查看与 2017 年 WWDC 视频“Introducing Metal 2”相关的 Apple 演示项目,其中开发人员演示了参数缓冲区的使用。该项目在 Apple 开发者网站上标题为“使用参数缓冲区动态渲染地形”的页面上链接。在这里,它们与 CPU 同步资源写入以防止竞争条件,dispatch_semaphore_t当命令缓冲区在 GPU 上完成执行时发出信号,并在 CPU 比 GPU 提前几帧写入数据时等待它。这与之前的 2014 年 WWDC“使用金属:基础知识”中显示的内容一致。

我注意到它似乎APPLParticleRenderer正在发送要由 GPU 在计算通道中写入的数据,然后它才完成从前一个渲染通道的片段着色器的同一个缓冲区读取。缓冲区的资源存储方式为MTLResourceStorageModePrivate。我的问题:Metal 是否会自动同步对id<MTLBuffer>只能由 GPU 访问的私有 s 的访问?从 new 调用的渲染、计算和 blit 通道id<MTLCommandEncoder>是否只有在其他通道写入和读取缓冲区后才能访问缓冲区(独占访问)?我已经看到瓦片着色器中有保证的障碍,其中瓦片内存由内核专门访问,然后后续片段着色器访问内存。

最后,在 2016 WWDC “What's New in Metal, Part 2”中,第一位演讲者 Charles Brissart 在 16:44 提到,从同一个缓冲区读取和写入的片段和顶点函数必须放在两个渲染命令编码器中,但是对于计算内核,一个计算命令编码器就足够了。这与在粒子渲染器中看到的一致。

4

1 回答 1

1

有关此答案的简要版本,请参阅我对原始问题的评论。

事实证明,Metal 跟踪默认情况下调度到 GPU 的命令之间的依赖关系的MTLResource类型。根据 Metal 文档, a的hazardTrackingMode属性MTLResource默认为MTLHazardTrackingModeTrackedMTLHazardTrackingMode.tracked在 Swift 中)。这意味着 Metal 跟踪修改资源的命令之间的依赖关系,就像粒子内核的情况一样,并延迟执行,直到访问资源的先前命令完成。因此,由于_particleDataPool缓冲区有一个存储模式MTLResourceStorageModePrivatestorageModePrivate在 Swift 中),它只能由 GPU 写入;因此,此缓冲区的信号量不需要 CPU/GPU 同步,因此资源不需要多缓冲区系统。只有当 GPU 仍在读取资源时 CPU 可以写入资源时,我们才需要多个缓冲区,这样 CPU 就不会空闲。

请注意,a 的默认危险跟踪模式MTLHeapMTLHazardTrackingModeUntrackedMTLHazardTrackingMode.untracked在 Swift 中),在这种情况下,负责同步 GPU 的资源写入

编辑

在阅读了 Metal 中的资源同步之后,我想提出一些额外的观点,我想进一步澄清正在发生的事情。请注意,其余部分在 Swift 中。要了解更多详细信息,我建议在此处阅读 Metal 文档中的“同步”部分。

MTLF围栏

首先,aMTLFence用于在单个命令缓冲区的执行中同步对未跟踪资源的访问。栅栏可让您明确控制 GPU 何时访问资源,并且在您使用未跟踪的资源时是必需的。否则,Metal 将为您处理此同步

重要的是要注意,我在答案中提到的自动管理仅发生在编码传递之间的单个命令缓冲区内。但这并不意味着我们需要在同一命令队列中调度的命令缓冲区之间进行同步,因为命令缓冲区不会立即被调度执行。事实上,根据这里找到的协议addScheduledHandler(_:)方法的文档MTLCommandBuffer

设备对象在识别出与系统中其他命令缓冲区或其他 API 提交的工作任务的任何依赖关系后调度命令缓冲区。

此时访问这些相同的缓冲区是安全的。请注意,在单个渲染编码过程中,重要的是要提到,如果顶点着色器将同一通道中的片段着色器写入缓冲区,则这是未定义的。我在原始问题中提到了这一点,解决方案是使用两个渲染通道编码器。我还没有确定为什么这对于计算编码器来说不是必需的,但我想它与内核与顶点和片段着色器相比的执行方式有关

MTL事件

然而,在某些情况下,由同一队列创建的不同队列中的命令缓冲区需要访问相同的资源或以某种方式相互依赖。在这种情况下,同步是必要的,因为单独的队列在不知道另一个的情况下调度它们自己的命令缓冲区,这意味着两个命令缓冲区有可能同时执行。 MTLDevice

要解决此问题,您可以使用MTLEvent设备创建的实例,makeEvent()并在每个缓冲区的特定点对事件信号进行编码。

MTLSharedEvent

如果您有多个处理器(不同的 CPU 内核、CPU 和 GPU 或多 GPU)(没有双关语),则需要资源同步。在这里,您创建一个MTLSharedEvent代替 aMTLEvent可用于跨设备和进程同步。它本质上与 的 API 相同MTLEvent,但涉及不同设备上的命令队列。

于 2020-11-23T02:00:25.753 回答