zoukankan      html  css  js  c++  java
  • shader程序员需要注意的优化Tips

    在写shader的时候,其实一些写法对于其执行影响非常大,而且由于gpu和cpu在架构上的不同,代码的优化思想也不一样,最近一直在写几个shader,为了性能问题,查阅了很多资料,把一些tips总结下来。

    首先要树立几个思想:

    1.gpu是SIMD的架构,即单指令多数据流架构,即在gpu上同时执行n个数据和执行1个数据的效率是一样的,我们要

    尽量的把并行的计算搬到gpu上

    2.gpu是以向量计算为基础设计的,也就是说在gpu上执行一个向量乘法和执行一个float的乘法的效率是一样的,

    并不向cpu那样要多执行几次

    3、通常,需要渲染的像素比顶点数多,而顶点数又比物体数多很多。所以如果可以,尽量将运算从PS移到VS,或直接通过script来设置某些固定值;

    所以

    1.尽量把一些计算合并成向量计算,记住一个向量计算和一个float计算那样快!

    比如 

    float x,y;

    x = x * a;

    y = y * b;

    不如写成 float2 v = float2(x,y);

    v = v*float2(a,b);

    因为前一种写法是两次乘法计算,而后一种只要1次

    2.不要在gpu里面用分支或者条件判断这种语句,尽管大多数gpu 的shader支持这种语法,但是多数gpu里面的

    这种控制语句涉及到一些同步等消耗的操作,其实大多数这种语句都可以用数值的方式替代。

    比如 你想写 

    1. float4 a;  
    2. if(b > 1)  
    3. {  
    4.  a.a=1;  
    5. }  
    6. else  
    7. {  
    8.  a.a =0.5;  
    9. }  

    可以改写成 

    1. float4 a;  
    2. float tmp = step(b,1);  
    3. a = tmp * 0.5 + (1-tmp);  


    if else可以被step出来的0 或1的乘法代替又比如

    1. float4 a;  
    2. if(b && c || d && e)  
    3. {  
    4.  a.a = 1;  
    5. }  
    6. else  
    7. {  
    8.  a.a = 0.5;  
    9. }  

    可以写成

    1. float4 a;  
    2. float tmp = step(1, (float)b*(float)c + float(d)*float(e));  
    3. a = tmp + (1-tmp) * 0.5;  

    && 我们用转换到float后的乘法代替,||可以被判断加法step 1代替

    而这种操作,尤其是shader内置的函数比条件判断和分支的效率要高很多,别忘了,GPU纯粹是为了计算的,而不是做判断

    3.尽量使用shader为我们提供的内置函数,这些内置的函数比我们想象的要快很多,往往应用了某些gpu的特殊特性。

    比如要比较a和b谁大用max(a,b),还有例如上面反复用的step,虽然你可以写用(float)(a>=1)来替换step(1,a),

    但是这还是没有内置函数更快的,包括常用的saturate()把一个数归到0-1,总之一句话,如果能用一个内置函数替换

    你的某些代码,就尽量替换。而且这些内置函数基本上都是支持对向量操作的,所以如果用step(a,fixed3(1,2,3))其

    实只是一条指令,但是却可以同时返回用a同1 2 3分别比较的结果。

     

    4.使用swizzle是非常快的,例float4 a = float4(1,1,1,1),用a.wz = float2(2,3)要比 a.w=3; a.z=2要高效很多

    5.浮点数精度相关:
      float:最高精度,通常32位
      half:中等精度,通常16位,-60000到60000,
      fixed:最低精度,通常11位,-2.0到2.0,1/256的精度。
      尽量使用低精度。对于color和unit length vectors,使用fixed,其他情况,根据取值范围尽量使用half,实在不够则使用float。
      在移动平台,关键是在fragment shader中尽可能多的使用低精度数据。另外,对于多数移动GPU,在低精度和高精度之间转换是非常耗的,在fixed上做swizzle操作也是很费事的。

    6.Alpha Test
      Alpha test和clip()函数,在不同平台有不同的性能开销。
      通常使用它来cull那些完全透明的像素。
      但是,在ios和一些android上使用的PowerVR GPUs上面,alpha test非常的昂贵。

    7、Color Mask
      在移动设备上,Color Mask也是非常昂贵的,所以尽量别使用它,除非真的是需要。

    8、在使用Surface Shader时,可以通过一些指令让shader优化很多。
      通常情况下,Surface shader的很多默认选项都是开启的,以适应大多数情况,但是很多时候,你可以关闭其中的一些选项,从而让你的shader运行的更快:
      (1) approxview 对于使用了view direction的shader,该选项会让view dir的normalize操作per-vertex进行,而不是per-pixel。这个优化通常效果明显。
      (2) halfasview 可以让Specular shader变得快一些,使用一个介于光照方向和观察方向之间的half vector来代替真正的观察方向viewDir来计算光照函数。
      (3) noforwardadd Forward Render时,完全只支持一盏方向光的per-pixel渲染,其余的光照全部按照per-vertex或SH渲染。这样可以确保shader在一个pass里渲染完成。
      (4) noambient 禁掉ambient lighting和SH lighting,可以让shader快一点儿。

  • 相关阅读:
    能力与知识、技能三者之间的区别与联系(技能与知识最大的差别是,技能是以熟练不熟练为判断的,才干是自动自发的能力,仅有知识而缺乏技能所谓“高分低能”)
    薪酬是由其商业价值与企业需求的匹配程度决定(别人的难题,就是你的价值)
    SpringMVC类型转换、数据绑定
    jQuery easyuI datagrid
    流程控制
    微信接口后台开发与配置
    WCF的简单
    .Net集成PayPal的Demo
    WCF服务最近经常死掉
    扩展方法、链式编程
  • 原文地址:https://www.cnblogs.com/hellohuan/p/8118084.html
Copyright © 2011-2022 走看看