渲染优化
当我们谈优化时,我们谈些什么 - 知乎 (zhihu.com)
命令方向基于材质/RenderState的排序
减少drawcallRenderState是一个比较笼统的称呼,对于OpenGL这类基于状态机的Graphics API,像是buffer/texture绑定,framebuffer切换,shader切换,depth/stencil/culling mode/blend mode等都属于状态切换,并且有性能开销。状态切换中涉及的开销包括driver端的命令验证及生成;GPU内部硬件状态机的重新配置;显存的读写;CPU/GPU之间的同步等。这里有一张图[25]大致量化了各类状态切换的开销:Attribute方向几何数据优化减少顶点数量
减少顶点意味对于Mobile GPU,还意味着更快的Bining Pass(主要是带宽压力)。(buffer)更少的顶点从System Memory/DRAM里读取到Shader Core(带宽压力)更少的 VS 执行(计算压力)减少顶点的三种方法模型的减面LODnormal map去代替高模体现细节。各种剔除 Culling (视椎体剔除,背面剔除、遮挡剔除)视椎体剔除(算出物体的中心到面的最小距离(带正负方向的)与包围球的半径做比较,如果小于半径,就表示在外面。)背面剔除遮挡剔除(虽然 gpu 有深度测试,会将有遮挡的物体进行剔除,但是我们仍然希望在提交 GPU 之前对遮挡关系进行判断,提前剔除掉一些东西,减少渲染压力。)对于有early-z机制的GPU(IMR/TBR)是有效的,对TBDR无效。减少每个顶点数据量数据量更少意味着VAF阶段和Binning Pass阶段更少的读写开销。我们可以在VS里使用一些快速的顶点数据压缩/解码方案[21][22](少量的计算开销换取更少的带宽开销)。避免小三角形
小三角形最直观的缺点就是:在屏幕上占用的像素非常少,是一种视觉上的浪费。由于硬件管线中,针对三角形有图元装配的环节(Triangle Setup),还有三角形的剔除(Vertex Culling/Triangle Clipping),因此主要是“构造一个三角形的固定开销”。文章[19]中还提到了一定要避免小于32像素的Triangle,我猜是因为小于32像素的三角形在PS阶段,组的Warp可能是不足32pixel的(有待考证)。近几年提出的GPU Driven Pipeline里面,已经有用Compute Shader去剔除小三角形的优化方法[23]。优化索引缓冲
点被访问越多次,memory cache的命中率越高,相应地,带宽开销就越小。可以通过重排index buffer,让一段indices patch内同一顶点被引用的次数尽可能地多[24]。Interleaving Attributes vs. Seperate Attributes
自定义Attributes: 如果一堆属性在VS中始终是会被一起使用(比如skinned weight和skinned indices;Normal/Tangent),我们应该把它们放在一起以减少Graphics API bind的次数,如果一堆属性在不同VS中使用频率相差很大(比如position非常频繁,但vertex color很少使用),那么我们应该存储在不同buffer。这个原理和AoS/SoA的区别一样,也是尽量提高缓存的利用率(缓存加载的时候的最小单位是Cache Line,通常64/128Bytes,所以要保证每次memory access能load