我有一个着色器,我想在顶点着色器中移动一半的顶点。我试图从性能的角度来决定最好的方法,因为我们要处理超过 100,000 个顶点,所以速度至关重要。我看过 3 种不同的方法:(伪代码,但足以给你这个想法。<complex formula>
我不能给出,但我可以说它涉及一个sin()
函数,以及一个函数调用(只是返回一个数字,但仍然是一个函数调用),以及一堆关于浮点数的基本算术)。
if (y < 0.5)
{
x += <complex formula>;
}
这样做的好处<complex formula>
是只执行了一半的时间,但缺点是它肯定会导致一个分支,这实际上可能比公式慢。它是最易读的,但在这种情况下,我们更关心速度而不是可读性。
x += step(y, 0.5) * <complex formula>;
使用 HLSL 的 step() 函数(如果第一个参数大于则返回 0,如果小于则返回 1),您可以消除分支,但现在<complex formula>
每次都调用它,其结果乘以 0(因此浪费精力)一半的时间。
x += (y < 0.5) ? <complex formula> : 0;
这个我不知道。?:
原因是分支吗?如果没有,等式的两边是评估的还是只评估相关的?
最后一种可能性是<complex formula>
可以将其卸载回 CPU 而不是 GPU,但我担心它在计算 sin() 和其他操作时会变慢,这可能会导致净损失。此外,这意味着必须将另一个数字传递给着色器,这也可能导致开销。任何人都知道哪个是最好的行动方案?
附录:
根据http://msdn.microsoft.com/en-us/library/windows/desktop/bb509665%28v=vs.85%29.aspx
该step()
函数在?:
内部使用 a ,因此它可能不比我的第 3 个解决方案好,而且可能更糟,因为<complex formula>
每次肯定都会调用它,而它可能只在一半时间被直接调用?:
。(还没有人回答这部分问题。)虽然避免两者并使用:
x += (1.0 - y) * <complex formula>;
可能比他们中的任何一个都好,因为在任何地方都没有进行比较。(并且y
始终为 0 或 1。)仍然执行<complex formula>
不必要的一半时间,但完全避免分支可能是值得的。