参考:Unity Shader: 优化GPU代码--用step()代替if else等条件语句
原文核心思路:
对于GPU来讲,各个顶点各个像素都在进行大量的并行运算,每个片段着色器都在同步运行,只有所有像素全部完成计算,才会进行下一次运算, 在片段着色器中,每个片段处理器每条指令操作上百个像素,如果有些片段(像素)采取一个分支而有些片段不采用另一个分支,则所有片段都会执行两个分支,但只在每个片段应该采取的分支上写入寄存器。不论何种策略,对追求高并行度的GPU来讲,分支是必须要同步的,那么最慢的case就会造成短板效应。另外,if/endif等流程控制操作对GPU来讲有较高的指令开销(4个时钟周期,Geforce6) 因此在GPU编程中,if else ,switch case和嵌套if语句等等是不推荐的会影响GPU的工作效率。相应的,可以用step()等函数进行替换,用阶梯函数的思维来构建条件语句。这样,所有的线程都执行完全一样的代码,加大了并行化计算的可能性,消除条件分支指令的性能损耗
归纳:
1.GPU高度并行,使用if逻辑判断,效率取决于最慢的分支情况
2.if语句需要用掉四个时钟周期(这个太费,特别在逐像素时)
3.通过数学函数将判断结果控制在0和1上,再通过与0和1的运算,实现if语句的效果
应用(部分代码说明):
if(passedTime<=maxTotalTime) { o.vertex = UnityObjectToClipPos((v.vertex + vertexOffset) + float4(v.tangent.zw, 0, 0) * scale) } else { o.vertex = fixed4(-2,0,0,1); }
上面的代码在顶点着色器中处理顶点动画效果,时间到达后隐藏
修改为:
float isPlaying = step(passedTime, maxTotalTime); o.vertex = UnityObjectToClipPos(((v.vertex + vertexOffset) + float4(v.tangent.zw, 0, 0) * scale) * isPlaying + fixed4(-2, 0, 0, 1) * (1 - isPlaying));
1、Step(a,x):如果x>=a返回1;如果x<a返回0
2、Clamp(x,a,b):如果x<a返回a;如果x>b返回b;如果在a和b之间就返回x
文章评论