金属:我需要多个RenderPipelines才能具有多个着色器吗?

J.D*_*Doe 3 graphics ios swift metal

我对金属非常陌生,因此在从丑陋的OpenGL状态机调用过渡到现代图形框架时,请多多包涵。我真的想确保我了解所有事情如何一起工作。

我已经阅读了大多数Apple文档,但是在描述各个组件的功能方面它们比它们如何组合起来做得更好。

我试图从本质上理解我是否应该有多个renderPipelines和renderEncoders在我的情况下。

要在更高层次上描述我的管道,是这样的:

  1. 从渲染到的屏幕外纹理中检索前一帧的内容,并在其上绘制一些新内容。
  2. 切换到屏幕上的渲染。从第1步将纹理绘制到屏幕上。
  3. 做一些后期处理(以本机分辨率)。
  4. 在四边形上绘制UI。(essentailly重复2)

因此,从本质上讲,将存在以下顶点/片段着色器对

  • 绘制实体(步骤1)
  • 在指定区域上绘制四边形(步骤2和4)
  • 后处理着色器1(步骤3)使用的输入与D不同,并且不能在同一着色器中完成
  • 后期处理着色器2(第3步)使用的输入与C不同,并且无法在同一着色器中完成

将有以下纹理组

  • 每个UI元素的纹理
  • 步骤1中完成的屏幕外绘图的纹理
  • 取决于金属性能,后期处理中可能会使用更多的屏幕外纹理

最终我的困惑是:

  • Q1。渲染管线仅采用一个顶点和一个片段函数,所以这意味着即使我的绘制过程只有3个唯一的步骤,我也需要4个渲染管线吗?
  • Q2。我应该如何在一个编码器中使用多个管道?每个成功的调用都不会.setRenderPipelineState覆盖前一个吗?
  • Q3。您是建议.setFragmentTexture在创建编码器后立即保留所有呼叫,还是只需要在需要时立即设置这些呼叫。
  • Q4。即使在管道状态之间切换时,保持depthState不变也有效吗?如何确保第1步中的实体具有深度渲染,但要确保帧之间的深度信息丢失,因此实体都位于先前内容的顶部?
  • Q5。在具有两个后处理步骤的渲染步骤3中,我该怎么办?那些必须是单独的管道吗?
  • Q6。知道步骤2和步骤4在输入不同的情况下基本上是相同的,我如何才能有效地构建管道?

我想如果有人带我逐步了解我需要什么以及为什么需要它,它将对我有帮助。理解某些psuedocode级别的renderCommandEncoder命令可能看起来是很有用的。

Ken*_*ses 8

Q1。渲染管线仅采用一个顶点和一个片段函数,所以这意味着即使我的绘制过程只有3个唯一的步骤,我也需要4个渲染管线吗?

如果着色器功能有4个唯一的组合,那么“我的绘制过程只有3个唯一的步骤”是不正确的。无论如何,是的,对于着色器函数的每种唯一组合(以及需要更改的渲染管线状态描述符的任何其他属性),您都需要一个单独的渲染管线状态对象。

Q2。我应该如何在一个编码器中使用多个管道?.setRenderPipelineState上的每个成功调用都不会覆盖前一个吗?

当您将绘制方法发送给渲染命令编码器时,该绘制命令将使用所有相关的当前状态进行编码并写入命令缓冲区。如果以后更改与编码器相关联的渲染管线状态,而该状态不影响先前编码的命令,则仅影响随后编码的命令。

Q3。您是建议在创建编码器后立即保留所有.setFragmentTexture调用,还是只需要在需要它们之前立即进行设置。

您只需要在对使用它们的绘制命令进行编码之前进行设置即可。除此之外,设置它们并不重要。我会尽一切努力来获得最清晰,最易读的代码。

Q4。即使在管道状态之间切换时,保持depthState不变也有效吗?

是的,否则将没有单独设置它们的单独方法。将有一种方法来设置两者。

如何确保第1步中的实体具有深度渲染,但要确保帧之间的深度信息丢失,因此实体都位于先前内容的顶部?

loadAction在渲染过程描述符中为深度附件配置,以使用适当的值(例如1.0)清除。当然,如果您使用多个渲染命令编码器,请仅对第一个执行此操作。同样,最后一个(或唯一)渲染命令编码器的渲染过程描述符可以/应该使用storeActionof .dontCare

Q5。在具有两个后处理步骤的渲染步骤3中,我该怎么办?那些必须是单独的管道吗?

好吧,您对方案的描述有点含糊。但是,如果要使用其他着色器函数,则可以,您需要使用其他渲染管线状态对象。

Q6。知道步骤2和步骤4在输入不同的情况下基本上是相同的,我如何才能有效地构建管道?

同样,您的描述太模糊了,以至于不知道如何回答。这些步骤在哪些方面相同?它们在哪些方面有所不同?您对不同的输入表示什么?

无论如何,只要采取看起来最简单,最直接的方法,即使它看起来效率不高。稍后担心优化。到那时,打开一个新问题,并显示您的实际工作代码,然后具体询问。