HLSL分支回避(HLSL branch avoidance)

2019-07-31 16:12发布

我有一个着色器,我想移动一半的顶点的顶点着色器。 我试图决定从性能的角度做到这一点的最好办法,因为我们正在处理超过10万名绿党,所以速度是至关重要的。 我已经看了3种不同的方法:(伪代码,但足以给你的想法。 <complex formula>我可以不给了,但我可以说,它涉及sin()函数,以及一个函数调用(只返回一个数字,但仍然是一个函数调用),以及对浮点数一堆基本算术)。

if (y < 0.5)
{
    x += <complex formula>;
}

这具有的优点<complex formula>只执行一半的时间,但不足之处是,它肯定会导致一个分支,它实际上可能比式慢。 这是最可读的,但我们更关心的速度比在这方面的可读性。

x += step(y, 0.5) * <complex formula>;

使用HLSL的步骤()函数(如果第一个参数是更大和1,如果小于它返回0),就可以消除分支,但现在的<complex formula>正在被呼叫的每个时间,并且其结果被乘以0(因此无用功)的时间的一半。

x += (y < 0.5) ? <complex formula> : 0;

这个我不知道。 请问?:导致一个分支? 如果不是,是在等式的两边评估或只有一个是相关的?

最后一种可能性是, <complex formula>可以被卸载回CPU而不是GPU,但我担心,这将是在计算罪()和其它操作,这可能会导致净损失慢。 此外,就意味着多了一个号码将被传递给着色器,以及其他可能导致开销为好。 任何人有任何见解,以这将是最好的行动过程?


附录:

据http://msdn.microsoft.com/en-us/library/windows/desktop/bb509665%28v=vs.85%29.aspx

step()函数使用?:在内部,因此它可能是因为没有比我的第三个更好的解决方案,并有可能更糟<complex formula>是绝对称得上每一次,而这可能只是称为半采用了直板的时间?: (没有人回答问题的那部分呢。)虽然避免两者并用:

x += (1.0 - y) * <complex formula>;

可能比任何人都好,因为没有被任何位置进行比较。 (而且y总是0或1)静止执行<complex formula>不必要一半的时间,但可能是值得的,以避免完全分支。

Answer 1:

也许看看这个答案 。

我的猜测 (这是一个性能问题:衡量 )是你是最断保持的if声明。

原因一:着色器编译器,理论上(如果正确地调用),应该足够聪明,使类似的东西分支指令之间的最佳选择, step功能,当它编译你的if语句。 以改善它的唯一办法是[1]个人资料。 请注意,它可能是依赖于硬件的,在这个级别的粒度。

[1]或者,如果您对您的数据是如何布局的具体知识,阅读...

原因排名第二的是这样的着色单元工作:如果在单位,甚至一个片段或顶点需要一个不同的分支到别人,那么着色器单元必须采取两个分支。 但是,如果他们都以相同的分支 - 另一个分支被忽略。 因此,尽管它是每单位,而不是每个顶点 - 它仍然是有可能被跳过昂贵的分支。

对于片段中,着色单元具有屏幕上的地方-这意味着你与附近的像素组都采取同样的分支(见我的插图最佳性能挂钩的答案 )。 说实话,我不知道顶点如何分为单位 - 但是如果你的数据被适当地组合 - 你应该得到所需的性能优势。

最后:这是值得指出的是,你的<complex formula> -如果你说你能吊起它从你的HLSL手动的-它可能会得到提升到一个基于CPU的预着色器反正(在PC上至少,从内存的Xbox 360并不支持这一点,没有关于PS3的想法)。 您可以通过反编译着色器检查。 如果它是东西,你只需要计算一次,每个抽奖(而不是每个顶点/片段),它可能最好的性能做它的CPU上。



Answer 2:

我厌倦了我的条件句被忽略,所以我只是做了另一个内核,并没有在C执行覆盖。 如果你需要的是准确的所有时间,我建议此修复程序。



文章来源: HLSL branch avoidance