丢弃对OpenGL中的程序性能有害吗?

时间:2011-12-14 17:36:42

标签: android opengl-es opengl-es-2.0 shader

我正在阅读this文章,作者写道:

  

以下是通过两个简单步骤在每个平台上编写高性能应用程序的方法:   [...]
  遵循最佳做法。在Android和OpenGL的情况下,这包括“批量绘制调用”,“不在片段着色器中使用丢弃”等内容。

我以前从未听说丢弃会对性能等产生不良影响,并且在没有必要使用详细的alpha时一直使用它来避免混合。

有人可以解释为什么以及何时使用丢弃可能被视为不良做法,以及discard + depthtest与alpha + blend相比如何?

编辑:在收到关于这个问题的答案后,我做了一些测试,通过渲染背景渐变,其上面有纹理四边形。

  • 使用GL_DEPTH_TEST和以“if( gl_FragColor.a < 0.5 ){ discard; }”行结尾的片段着色器提供了 32 fps
  • 从片段着色器中删除if / discard语句增加了 渲染速度约为 44 fps
  • 将GL_BLEND与混合函数一起使用“(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)“而不是GL_DEPTH_TEST也导致 44 fps

5 个答案:

答案 0 :(得分:20)

“discard”对每种主流图形加速技术都有害 - IMR,TBR,TBDR。这是因为片段的可见性(以及因此深度)只能在片段处理之后确定,而不能在Early-Z或PowerVR的HSR(隐藏表面移除)等期间确定。图形管道在移除之前得到的东西往往表明它对性能;在这种情况下,更多的碎片处理+破坏其他多边形的深度处理=不良影响

如果必须使用discard,请确保仅使用包含它的着色器渲染需要它的tris,并且为了最小化其对整体渲染性能的影响,按顺序渲染对象:不透明,丢弃,混合。

顺便提一下,只有PowerVR硬件才能确定延迟步骤中的可见性(因此它是唯一被称为“TBDR”的GPU)。其他解决方案可能是基于区块的(TBR),但仍然使用依赖于提交顺序的Early Z技术,如IMR所做的那样。 TBR和TBDR在片上进行混合(比去主存储器更快,耗电更少),因此混合应该有利于透明度。正确渲染混合多边形的常用过程是禁用深度写入(但不测试)并以后向前深度顺序渲染tris(除非混合操作与顺序无关)。通常近似排序足够好。几何形状应该避免大面积的完全透明的碎片。通过这种方式,每个像素仍然可以处理多个片段,但硬件深度优化不会像丢弃的片段那样中断。

答案 1 :(得分:18)

它依赖于硬件。对于PowerVR硬件和使用基于图块的渲染的其他GPU,使用discard意味着TBR不再假设绘制的每个片段都将成为像素。这个假设很重要,因为它允许TBR首先评估的所有深度,然后仅评估最顶层片段的片段着色器。一种延迟渲染方法,硬件除外。

请注意,启用alpha测试会遇到同样的问题。

答案 2 :(得分:3)

此外,在片段着色器中只有一个“if”语句会导致某些硬件出现大幅减速。 (具体而言,严重流水线化的GPU或执行单指令/多数据的GPU将会对分支语句产生很大的性能损失。)因此,您的测试结果可能是“if”语句与其他人提到的效果的组合。

(对于它的价值,当我切换到深度排序我的半透明物体并将它们渲染回前面时,测试我的Galaxy Nexus显示了巨大的加速,而不是以随机顺序渲染并丢弃着色器中的碎片。)< / p>

答案 3 :(得分:1)

对象A位于对象B的前面。对象A具有使用“discard”的着色器。因此,我无法正确地执行'Early-Z',因为我需要知道对象A的哪些部分将通过对象A可见。这意味着对象A必须一直通过处理管道直到最后在我确定对象B是否实际可见之前,(直到执行片段处理)为止。

这对于HSR和'Early-Z'来说是不好的,因为可能被遮挡的对象必须坐下并等待深度信息在被处理之前被更新。如上所述,它对每个人都不利,或者,以更友好的方式“朋友不要让朋友使用丢弃”。

答案 4 :(得分:-1)

在您的测试中,您的 if 语句是按像素级别的性能

if ( gl_FragColor.a < 0.5 ){ discard; }

将被渲染的每个像素处理一次(很确定是每个像素而不是每个纹素)

如果您的 if 语句正在测试 Uniform 或 Constant,您最有可能得到不同的结果,因为 Constants 仅在编译时处理一次,或者 Uniforms 每次更新处理一次。