我们在HLSL中有一个像素着色器,它在一些地方用于稍微不同的东西,因此有几个条件块意味着在某些情况下省略了复杂的功能。同样,这意味着我们将纹理作为采样器参数传递,这些参数可能并不总是被使用。
我不知道这两件事增加了多少性能,但特别是因为我们在集成图形芯片上支持SM2.0,效率低下是个问题。那么,传递纹理而不使用它意味着任何额外的开销吗?并且使用if
只是简单地添加一些指令,还是会因为停顿等问题而大幅影响事情,就像进行CPU优化一样?
答案 0 :(得分:20)
在GPU上设置纹理需要一些CPU时间,但与实际batch成本相比,它相当小。更重要的是,它应该对实际的着色器执行没有任何影响,如果着色器从不引用它。
现在,有三种方法可以处理分支:
首先,如果分支条件总是相同的(如果它只依赖于编译时常量),那么分支的一侧可以完全内联。在许多情况下,如果可以通过这种方式消除重要分支,则可以优先编译着色器的多个版本。
第二种技术是着色器可以评估分支的两侧,然后根据条件选择正确的结果,所有这些都没有实际分支(它是算术的)。当分支中的代码很小时,这是最好的。
最后,它实际上可以使用分支指令。首先,分支指令具有适度的指令计数成本。然后是管道。 x86有一个很长的串行管道,你可以很容易地停止。 GPU有一个完全不同的并行管道。
GPU并行评估片段组(像素),一次为多个片段执行一次片段程序。如果组中的所有片段采用相同的分支,那么您只有该分支的执行成本。如果它们采用两个(或更多)分支,则必须对该组碎片执行多次着色器以覆盖所有分支。
因为片段组具有屏幕上的位置,所以如果您的分支具有类似的屏幕上位置,则会有所帮助。见下图:
http://http.developer.nvidia.com/GPUGems2/elementLinks/34_flow_control_01.jpg
现在,着色器编译器通常可以很好地选择最后两种方法中的哪一种使用(对于第一种方法,编译器将为您内联,但您必须自己制作多个着色器版本)。但是,如果您正在优化性能,那么查看编译器的实际输出会很有用。为此,在DirectX SDK Utilities中使用fxc.exe
和/Fc <file>
选项,以获取已编译着色器的反汇编视图。
(因为这是性能建议:记住要始终测量你的性能,找出你遇到的限制,然后担心优化它。如果你的纹理获取限制,优化你的着色器分支没有意义,因为例子。)