java游戏优化,游戏性能优化杂谈(十四)

在思考渲染性能相关的问题的时候,往往可以从一个最为基本的问题出发:既然任何一帧最终呈现给玩家的只能是一屏的数据(比如2K分辨率的200万像素,或者4K分辨率的800万像素),那么所有的渲染计算就应该围绕这几百万像素展开:究极来说,任何对这几百万像素最终显示颜色没有贡献或者贡献不明显的计算,都可以被认为是冗余的,不必要的,可以被优化掉的。

比如,常见的CSM贴图(层叠式阴影贴图)的更新,通常我们会从光源的位置对场景进行Depth Only的渲染,所得到的深度缓冲区的结果就是一张阴影贴图。但是问题是,从光源可见的物体,往往并不一定从主相机所能见得到。也就是两者的可见范围并非完全重合。

所以,容易想到的是先用主相机的视锥对场景进行剔除,再在光源位置渲染剔除后的“主相机可见”场景对象生成CSM,期待是通过减少CSM需要渲染的对象数来提高性能。

不过主摄像机所能看见的阴影也有可能来自可见范围之外的对象。很多对象可能其自身并没有进入摄像机视锥,但是它的阴影进入了。所以我们不能简单地用视锥进行剔除,而是需要将视锥沿着光源方向进行延伸,然后剔除。

然而注意这种延伸本身会带来计算量。优化的特点是必须综合考虑各种因素,寻找平衡点。因此我们需要计算为了减少这种冗余所需作出的额外处理所造成的负荷,是否能被其产生的收益覆盖。否则就是负优化。

通常来说,渲染过程是一个计算量不断膨胀的过程:从可能只包括几个按键读数的用户输入,到几十个可互动对象,再到上百个可见模型,数十万上百万个三角形,最后是数百万个像素。输入输出的规模其实是固定不变的,所以需要优化的就是中间的过程。这里面往往容易出现的问题就是渲染了很多不必要的三角形。

关于被渲染三角形数量和像素数量的比例虽然不同的软硬件平台不尽相同,但是从性能角度考虑的话,通常来说无论是当代的CPU、GPU还是内存,都是采用的线性寻址的方式,所以2D或者3D的数据最终都是以1D的方式进行存储和处理的,那么就会涉及到一个编址的问题。目前采用比较多的是线性编址和莫顿编址。通常来说,CPU因为任务的多样性更加喜欢线性编址而GPU则为了高并行更加喜欢莫顿编址。

所以这里通常的选择是,需要CPU逐帧更新的顶点数据和顶点属性数据以线性buffer的形式存储,而只需要GPU读取的数据,如贴图等则以莫顿编址的方式展开在内存(显存)上,每个莫顿编址的“Z”字形块大小正好够塞满GPU高速缓存一条通道的大小。比如,当GPU高速缓存通道为64个字节的时候,假设每个像素对应一个32bit的数据,则每个块大小在2x2像素正好可以塞满一条GPU cache通道。

另外一方面,GPU当中通常使用SIMD(SIMT)来并行执行。现在比较常见到是SIMD32,也就是一个时钟周期可以同时处理32字节的数据。那么单个像素是32bit色深的时候,一个SIMD其实可以同时处理8个像素,就是两个2x2的像素块,需要对接两条GPU cache通道。

再进一步,如果我们把两个SIMD32作为一组,则可以同时处理4个2x2的像素块。如果我们把这4个2x2的像素块也进行莫顿Z字形编址,那么就相当于屏幕上一个4x4的像素块。

照此类推,我们可以使用8个SIMD处理一个8x8的像素块。

了解某种型号GPU当中的数据编址方式、SIMD的组织形式以及与高速缓存通道之间的关系,我们就可以知道对于该型号GPU最为高效的贴图和RT存储方式,以及理想的三角形面积。比如,当GPU一个核心拥有8个SIMD的时候,则表示一个三角形离散产生64个像素或以上是较为理想的。而远小于这个尺寸的三角形,则会带来性能问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值