前面说了对我这一年多的工做进行一个总结,因为工做比较紧,加上本人比较懒,一直没能抽出时间来写,最近稍微闲下来了。先写一篇GPU优化的,后续的文章但愿能慢慢补齐。这些基本都是我我的优化的实际经验,也参考了一些文章,我都放在后面引用 部分了,感兴趣的能够深刻研究。我的理解可能有问题,若有不正确的还请指正,下面进入正题。html
因为图形引擎的复杂性,瓶颈可能发生在CPU、GPU、,也可能发生在CPU与GPU的传输数据与交互之中。这里咱们只假设瓶颈在GPU上,讨论GPU的优化方法。算法
Premature optimization is the root of all evil. -- Donald Knuth 这告诉咱们过早优化程序是不可取的,我以为有两方面的意思,1、在没有找到高效的算法前就开始优化。2、在没有找到真正的瓶颈关就开始优化。正确的流程大概是这样的编程
一、使功能能工做,程序能跑起来。ide
二、功能正确的工做。函数
三、让整个程序能工做。工具
四、让整个程序能正确工做。oop
五、使用这个程序并找到性能瓶颈。性能
六、使用性能分析工具找到瓶颈所在。优化
七、使程序高效正确的运行。[1]ui
还有一个原则就是80~20原则,即只有百分之二十的代码是经常使用的,因此要集中优化这些代码,而不是一些不多执行的代码上花些时间。
既然直接谈GPU优化,那咱们就假设上面流程中的前五条已经知足,咱们假定GPU有瓶颈了,这时咱们能够借助一些工具如Perfhud、Intel GPA、NSight(替代Perfhud的工具)或其它方法来找到程序的瓶颈所在,而后根据这些分析结果来有目的的优化程序。
GPU可能存在的瓶颈主要在如下几个部分:
一、纹理传输带宽限制 (显存到高速缓冲区)
二、光栅操做完成后帧传输带宽限制(高速缓冲区到显存)
三、顶点着色处理能力限制(VS)
四、像素着色处理能力限制(PS)在新的硬件中使用统一着色处理单元时,能够动态调整VS PS使用的数量。
五、光栅化限制。
六、显卡显存太小。
七、算法自己不够高效。
八、Shader指令使用不合理。
具体查找瓶颈的方法以下:[2]
1、若是改变纹理尺寸,帧率有明显变化,则瓶颈可能在纹理传输带宽限制或纹理AGP传输能力限制。若改变纹理过滤方式帧率提升了,则多是纹理传输带宽限制。此时可经过减少纹理分辨率或纹理过滤方式来解决。
2、若改变窗口大小,帧率有明显变化,则多是因为光栅化或像素着色Shader限制,或者帧缓冲区带宽限制。此时减小PS指定数量,若FPS有明显变化,则说明是PS是瓶颈。不然此时改变后台缓冲区位宽,若帧率有明显变化则说明是帧缓冲区带宽限制,不然光栅化是瓶颈。
3、若改变颜色位宽帧率有明显变化,则说明瓶颈在帧缓冲区,此时能够经过改变帧缓冲区带宽来提升帧率,这在帧缓冲区带宽小的低端显卡止效果很明显。
4、减小VS指令数量,若是帧率有明显变化,则说明瓶颈在VS上,这种状况通常不会出现,若是在VS中访问纹理会比较慢,瓶颈可能会出现(Shader Model 3.0)。
5、若是减小顶点数量,帧率有明显提高,则说明瓶颈可能在顶点过多,或顶点AGP
传输限制,此时可能经过模型LOD来解决问题。
6、使用Perfhud等GPU分析工具来查找瓶颈,尤为是GPA能够实时修改查看效果,这样就能够比较高效的优化Shader。
7、若是自己算法有问题,则能够找更高效的方法来实现一样的效率,或者有时为了效率也是能够牺牲一些效果的,也能够作Shader的LOD,不一样配置下采用不一样的Shader,这样在低端和高端显卡上都会有一个不错的帧率。
优化方法:
一、纹理带宽限制。
(1)减小没必要要的大纹理。
(2)能够动态修改纹理分辨率,去掉纹理前面几级Mip map。
(3)尽可能使用DXT格式的纹理。
(4)避免使用非二次方的纹理。
(5)若是不须要写颜色,那就把颜色写关闭。(Pre-z 阴影贴图等。)
二、帧缓冲区带宽限制。
(1)减小颜色位宽,如使用16位颜色。
(2)减少后台缓冲区和Render Target大小。
(3)对于特效比较多的状况,能够先渲染到一张小的纹理上去而后再Up-Sampling到主Render Target上。
三、AGP传输瓶颈
(1)顶点尽可能使用索引条带或索引列表。
(2)对顶点进行排序,这样能够减小顶点重复计算的次数(对结果进行Cache),使用NVTriStrip这个工做。
(3)顶点大小应该是32(bit)的整数倍。
(4)使用模型LOD。
四、VS处理能力限制,通常不会成为瓶颈
(1)使用模型LOD,减小顶点数量。
(2)尽可能减小VS指令的数量。
(3)控制顶点纹理的使用。
(4)能在CPU计算的在CPU计算完成后再传给VS。
(5)方法3 中的优化也合适。
(6)尽可能使用低版本的Profile。
五、PS处理能力限制。
(1)尽可能减小指令的长度。
(2)尽可能使用低版本的Profile。(如PS_2_a)等。
(3)尽可能使用低精度half进行计算。
(4)利用硬件的特性来减小开销,好比若是要对纹理进行降采样,能够利用GPU的双线性来插值来实现,这样能够明显减小纹理访问的次数。
(5)能在CPU计算的在CPU计算完成后再传给PS。
(6)作Pre-Z。
(7)作Shader LOD,能够在不一样配置下切换。
六、算法自己不够高效
(1)尽可能寻找更高效的算法代替,这样比一条条指令压榨要提高太多效率。
7、Shader指令不合理,对GPU工做不是特别了解,致使写出低效的代码。[]
(1)使用代数化简指令来减小没必要要的计算。
(2)使用能工做的最小Profile版本。
(3)尽可能使用half。
(4)尽可能不要写太通用的函数,这样可能会产生一些无用的指令。
(5)不要乱用normalize,好比在PS中须要normalize,那么在VS中就没有必要使用。
(6)normalize过的向量不须要计算长度(就是1)。
(7)不要把向量放到多个Interpolator里面。
(8)能在CPU计算的就放到CPU计算。
(9)若是一个参数永远不变,则不必从CPU传进来。
(10)若是是结果是线性的,则这些计算能够放到VS计算,而不必在PS计算。
(11)使用下标小的interpolants。好比首先使用TEXCOORD0,再使用TEXCOORD1等。
(12)使用纹理查找来取代复杂的函数。(目前是至少是6条算数指令:1条取纹理的关系)
(13)Pre-z,尽可能避免Pre-Z失效。具体参见NVIDIA编程指南。
(14) 动态分支要谨慎使用,只有在大多数状况都走同一个分支时使用才有比较好的效果。
(15)产生阴影时可使用tex2DProj来利用硬件特性加速。
(16)了解GPU的汇编指令,写出正确的代码。
(17)纹理指令和算术指令交叉使用。
GPU的指令:[]
一、mad 是一条指令 (x + 1) * 0.5 = x * 0.5 + 0.5 前面是一条add+mul指定,后面是一条mad指令,编译器并不会为咱们优化。
二、括号不要乱加,好比 x + y * 0.5 + z * 0.2 是两条指令 mad-->mad而x + (y* 0.5 + z * 0.2)是mul-->mad-->add三条指令。
三、代数化简 (x + c) * (x-c) 三条指令 ---> x * x + (-c * c)两条指令
四、减小没必要要的mov指令。
1 float4 vPos = float4(0,0,0,0); 2 3 for (int i = 0; i < 4; ++i) 4 5 vPos += float4 (mul (vMat[i], vInputPos), 1.0); 6 7 ---> 8 9 float4 vPos = float4(0,0,0,1); 10 11 for (int i = 0; i < 4; ++i) 12 13 vPos .xyz+= mul (vMat[i], vInputPos);
这样减小了3条mov指令。
五、a/b 是用a * rcp(b)实现。D3D也可能使用div指定,但显式使用cp可能会产生更好的代码。(x + a) / x --> 1.0 + a * rcp(x)
六、正确使用[branch] [flatten] [loop] [unroll]。[branch]在分支友好的状况下效率才会比较高。[unroll]在指令限制未到使用可提升效率。
七、线性的运算放到VS里面去算,插值到PS便可。
八、更多优化方法请参考引用[4]。
总结:
游戏引擎是一个复杂的系统,瓶颈在不一样机器上出现可能不同,可能在CPU也可能在GPU,GPU上的瓶颈又可能出如今不一样的环节。工欲善其事,必先利其器!咱们要借助工具或上面提到的方法来找到程序的瓶颈,对症下药,不要盲目去优化,找到那20%的代码,首先是在算法上找优化的方法,若是肯定算法是好的了,那才要开始指令级别的优化,不然是徒劳的。而后根据上面的方法基本上能够解决大多数的性能问题,固然咱们还能够把多个效果结合到一块儿处理,由于可能有些中间结果是共用的,这样又能够省去一些额外的开销。尽最大限度的优化,作到在不一样配置机器上都能流畅运行,还要在高端机器上有次世代的画面效果。
引用:
[1] http://c2.com/cgi/wiki?PrematureOptimization
[2] http://www.cnblogs.com/lancidie/archive/2011/03/29/1998830.html
[3] NVIDIA GPU Programming Guide version 2.5.0
[4] Low-level thinking in high-level shading languages.