苹果公司表示,在他们的最佳实践为着色器avoid branching,并在着色器内的计算值特别分支。所以我用内置的clamp()
函数替换了一些if
语句。我的问题是,是clamp()
,min()
,和max()
可能是更有效的,或者是它们仅仅方便(即宏)功能,简单地扩展到if
块?为条件语句OpenGL ES的最佳做法,如果可能的话
我知道答案可能是执行相关的。无论如何,这些函数显然更清晰并且表达了意图,编译器可能会用做些事情。
苹果公司表示,在他们的最佳实践为着色器avoid branching,并在着色器内的计算值特别分支。所以我用内置的clamp()
函数替换了一些if
语句。我的问题是,是clamp()
,min()
,和max()
可能是更有效的,或者是它们仅仅方便(即宏)功能,简单地扩展到if
块?为条件语句OpenGL ES的最佳做法,如果可能的话
我知道答案可能是执行相关的。无论如何,这些函数显然更清晰并且表达了意图,编译器可能会用做些事情。
从历史上看,GPU支持每片段指令(如MIN
和MAX
)的时间长于支持任意条件分支的时间。在桌面OpenGL这样的一个例子是GL_ARB_fragment_program
扩展(现在GLSL取代),其中明确指出它不支持分支,但它确实提供了MIN
和MAX
指令以及其他一些条件指令。
我很肯定所有的GPU都会为这些操作提供专用硬件,因为常见的min()
,max()
和clamp()
都在着色器中。规范并不保证这一点,因为一个实现可以优化代码,但它看起来合适,但在现实世界中,您应该使用GLSL的内置函数而不是自己滚动。
如果正在使用您的条件,以避免大量的额外片段处理的唯一例外是。在某个时候,分支的成本将低于运行分支中所有代码的成本,但这里的平衡将非常依赖于硬件,您必须进行基准测试,以查看它是否对您的应用程序有帮助目标硬件。这里的那种东西我的意思是:
void main() {
vec3 N = ...;
vec3 L = ...;
float NDotL = dot(N, L);
if (NDotL > 0.0)
{
// Lots of very intensive code for an awesome shadowing algorithm that we
// want to avoid wasting time on if the fragment is facing away from the light
}
}
只是夹紧NDotL
到0-1,然后一直在处理每一个片段的阴影码只能由NDotL
通过最终的阴影项被乘以了很多无用功,如果NDotL
的本来是< = 0,理论上我们可以避免这个分支的开销。这种事情并不总是表现胜利的原因是它非常依赖硬件如何实现着色器分支。
优秀的评论。我应该已经意识到'MIN'和'MAX'早于一般的if块,我相信你对硬件支持是正确的。非常感谢! –
我认为应该提及的是,一些GPU不尊重标准,甚至根本不实施分支。我偶然发现的只有三星的Galaxy Tab系列。他们只是无声无息地死亡,没有任何消息。 –
我觉得你的最后一句话已经回答了它相当不错。除了看起来更精简以外,它们至少更有可能通过快速硬件指令来实现,而不是简单的“if”。除了这个一般的建议(尽管应该已经足够了),实际上它们很可能使用特殊的硬件指令或条件赋值,而不仅仅是包含“if”的函数。 –