Opengl 条件语句会减慢着色器的速度吗?

Opengl 条件语句会减慢着色器的速度吗?,opengl,glsl,shader,direct3d,hlsl,Opengl,Glsl,Shader,Direct3d,Hlsl,我想知道着色器(顶点/片段/像素…)中的“如果语句”是否真的会降低着色器的性能。例如: 使用此选项是否更好: vec3 output; output = input*enable + input2*(1-enable); 而不是使用这个: vec3 output; if(enable == 1) { output = input; } else { output = input2; } 在另一个论坛上,有人谈到了这一点(2013年): 这里的家伙说,如果语句真的对着色器的性能

我想知道着色器(顶点/片段/像素…)中的“如果语句”是否真的会降低着色器的性能。例如:

使用此选项是否更好:

vec3 output;
output = input*enable + input2*(1-enable);
而不是使用这个:

vec3 output;
if(enable == 1)
{
    output = input;
}
else
{
    output = input2;
}
在另一个论坛上,有人谈到了这一点(2013年): 这里的家伙说,如果语句真的对着色器的性能有害

此外,他们还讨论了if/else语句(2012)中的内容:

也许硬件或shadercompiler现在更好了,他们以某种方式解决了这个(可能不存在)性能问题

编辑:

在这种情况下,让我们假设enable是一个统一变量,它始终设置为0:

if(enable == 1) //never happens
{
    output = vec4(0,0,0,0);
}
else  //always happens
{
    output = calcPhong(normal, lightDir);
}
我想这里我们在着色器中有一个分支,它会减慢着色器的速度。对吗


制作两个不同的着色器是否更有意义,比如一个用于else,另一个用于if部件?

它高度依赖于硬件和条件

如果您的条件是一致的:不用麻烦,让编译器来处理它。 如果您的条件是动态的(比如从属性计算的值或从纹理或其他东西获取的值),那么它就更复杂

对于后一种情况,您几乎必须进行测试和基准测试,因为这取决于每个分支中代码的复杂性以及分支决策的“一致性”

例如,如果其中一个分支占用了99%的大小写并丢弃了片段,那么您很可能希望保留条件。但是在上面的简单示例中,如果
enable
是某种动态条件,那么算术选择可能会更好


除非您有上述明确的案例,或者您正在为一个固定的已知体系结构进行优化,否则您最好让编译器为您弄清楚这一点。

它高度依赖于硬件和条件

如果您的条件是一致的:不用麻烦,让编译器来处理它。 如果您的条件是动态的(比如从属性计算的值或从纹理或其他东西获取的值),那么它就更复杂

对于后一种情况,您几乎必须进行测试和基准测试,因为这取决于每个分支中代码的复杂性以及分支决策的“一致性”

例如,如果其中一个分支占用了99%的大小写并丢弃了片段,那么您很可能希望保留条件。但是在上面的简单示例中,如果
enable
是某种动态条件,那么算术选择可能会更好


除非您有上述明确的案例,或者除非您正在为一个固定的已知体系结构进行优化,否则编译器可能会更好地为您解决这个问题。

着色器的哪些方面甚至可能导致
if
语句出现性能问题?这与着色器如何执行以及GPU从何处获得其海量计算性能有关

单独的着色器调用通常并行执行,同时执行相同的指令。它们只是在不同的输入值集上执行它们;他们共用制服,但内部登记册不同。所有执行相同操作序列的一组着色器的一个术语是“波前”

任何形式的条件分支的潜在问题是,它都可能把这一切搞砸。它导致波前内的不同调用必须执行不同的代码序列。这是一个非常昂贵的过程,因此必须创建一个新的波前,将数据复制到其中,等等

除非。。。没有

例如,如果条件是波阵面中每次调用所采用的条件,则不需要运行时发散。因此,
if
的成本只是检查条件的成本

假设有一个条件分支,假设波阵面中的所有调用都采用相同的分支。该条件下表达式的性质有三种可能:

  • 编译时静态。条件表达式完全基于编译时常量。因此,您可以通过查看代码了解将采用哪些分支。几乎所有编译器都将此作为基本优化的一部分来处理
  • 静态均匀分支。该条件基于一些表达式,这些表达式涉及在编译时已知为常量的内容(特别是常量和
    uniform
    值)。但是表达式的值在编译时是未知的。因此,编译器可以静态地确定波前永远不会被这个
    if
    破坏,但编译器无法知道将采用哪个分支
  • 动态分支。条件表达式包含常量和一致性以外的术语。在这里,编译器无法先验地判断波前是否会被破坏。是否需要这样做取决于条件表达式的运行时计算
不同的硬件可以处理不同的分支类型,而不会产生分歧

此外,即使不同的波前采用了一个条件,编译器也可以重新构造代码,使其不需要实际的分支。您给出了一个很好的示例:
output=input*enable+input2*(1-enable)
在功能上等同于
if
语句。编译器可以检测到一个
,如果
被用来设置一个变量,那么就可以同时执行这两个方面。这通常适用于分支体较小的动态条件

几乎所有的硬件都能处理
var=bool?val1:val2
无需发散。早在2002年,这是可能的

由于这是非常依赖硬件的,它。。。取决于硬件。然而,可以看到硬件的某些时代: