【问题标题】:When to use multiple MTLRenderCommandEncoders to perform my Metal rendering?何时使用多个 MTLRenderCommandEncoder 来执行我的 Metal 渲染?
【发布时间】:2020-02-02 23:00:11
【问题描述】:

我正在学习 Metal,我试图解决一个概念性问题:我的代码究竟应该在什么级别处理需要不同管道状态的连续绘图操作?据我了解(来自这样的答案:https://stackoverflow.com/a/43827775/2752221),我可以使用单个MTLRenderCommandEncoder 并在调用drawPrimitives: 和编码器状态之间更改其管道状态、它正在使用的顶点缓冲区等每次调用 drawPrimitives: 时的当前状态将被保留。那太好了。但似乎 Metal 的设计是这样的:可以创建多个 MTLRenderCommandEncoder 实例,并使用它们将一批命令顺序地扔到 MTLCommandBuffer 中。鉴于前者有效——使用MTLRenderCommandEncoder 并改变其状态——为什么要使用后者呢?什么情况下做前者是正确的,什么情况下需要做后者?后者是必要/适当的情况的示例是什么?

如果重要的话,我正在使用 Objective-C 开发 macOS 应用程序。谢谢。

【问题讨论】:

    标签: objective-c metal


    【解决方案1】:

    忽略有点高级的多线程编码情况,您希望在一帧期间创建多个渲染命令编码器的主要原因是因为您需要更改要渲染到的纹理。

    您会注意到在创建渲染命令编码器时需要提供渲染通道描述符。出于这个原因,我们经常说属于特定编码器的命令序列构成渲染通道。该描述符的附件是指将由编码器编码的命令写入的纹理。

    许多不同的技术,包括阴影贴图和像绽放这样的后处理效果,都需要多次通过才能产生。由于您无法在传递过程中更改附件,因此创建新的编码器是对帧中的多个传递进行编码的唯一方法。

    相应地,您通常应该每帧使用一个命令缓冲区。但是,您有时可以通过将传递拆分到多个命令缓冲区来减少帧时间,但这在很大程度上取决于工作负载的形状,并且只能与分析一起完成,因为它并不总是一种优化。

    【讨论】:

    • 非常有趣。我越来越清楚我还有多少东西要学。有没有一本书你会特别推荐给我?虽然我目前的工作不需要它,但我想了解“阴影贴图”和“绽放”之类的东西。我想要更广泛地了解 GPU 渲染的工作原理以及可以用它做什么。理想情况下,特别提到金属,但也许那本书还不存在......?
    • 市场上有几本 Metal 书籍,但最新的(并且恰好包括对阴影贴图的讨论)是 this one
    • 别忘了this one。 ;)
    • @warrenm:是否可能需要单独的渲染命令编码器来同步缓冲区写入/读取?我对此有疑问并在此处发布了一个问题:Using multiple render pipelines in a single MTLRenderCommandEncoder: How to Synchronize MTLBuffer?
    【解决方案2】:

    除了 Warren 的回答之外,查看问题的另一种方法是检查 API。许多金属对象是从描述符创建的。从它创建对象时描述符的属性控制该对象的生命周期。这些是对象在创建后无法更改的方面。

    相比之下,对象将有各种 setter 方法在其生命周期内修改其他属性。

    对于渲染命令编码器,在其生命周期内固定的属性是由用于创建它的MTLRenderPassDescriptor 指定的属性。如果您想为这些属性中的任何一个使用不同的值进行渲染,唯一的方法是从不同的描述符创建一个新的编码器。另一方面,如果您可以使用编码器的 setter 方法完成您需要/想做的所有事情,那么您就不需要新的编码器了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-14
      • 2018-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多