最近发现我们的《天下贰》在Nvidia的SLI系统上不仅没有提高性能,反而降低了不少,使我疑惑不解,经过查询资料总算找到了满意的答案。

先说说什么是SLI吧,SLI(“可扩展连接接口”的缩写)允许多个图形芯片同时工作以获得更高的性能。基于SLI技术的主板称之为“PCI Express”主板,它带有两个x16物理信道,每个插槽可配置一个“PCI Express”图形显卡。当两个图形显卡通过一个外置的桥式连接器连通后,驱动程序能自动识别该配置并进入“SLI Multi-GPU”模式。在“SLI Multi-GPU”模式下,驱动程序将两个显卡配置为一个独立的设备:也就是说,所有的图形处理程序将这两个图形芯片视为一个独立的逻辑设备。 由于驱动程序将渲染工作分割给两个物理图形芯片进行处理,使得这个独立的逻辑设备的运行速度最高可达到单个图形芯片的 1.9 倍。但是需要注意的是,SLI模式运行时并不具有双倍的视频内存,比如,插入两个256M内存的图形显卡仍然最多只有256MB的视频内存。

这是因为般情况下会在两个图形芯片复制所有的视频内存,也就是说,在任何情况下,图形芯片0和图形芯片1中的内存数据都是完全一样的。

在SLI系统中运行应用程序时,由驱动程序决定运行何种模式:兼容模式、轮流帧渲染器模式(AFR)、或分割帧渲染器模式(SFR)。 兼容模式仅仅用在单个图形芯片进行渲染时(也就是说,第二个图形芯片一直处于闲置状态)。在这种模式下,不会有任何性能提高,但是能够确保应用程序可以在SLI模式运行。 在AFR模式下,驱动程序在图形芯片0(GPU 0)上渲染n帧,在图形芯片1(GPU 1)上渲染n+1帧,在GPU 0上渲染n+2帧,依此类推。只要每个都是独立帧(即每帧图像没有相同数据),AFR这时效率最高,这是因为包括逐顶点,光栅化和逐像素在内的所有渲染都要在图形芯片之间平均分割,如果在帧之间包含有共同数据(例如,重新使用先前渲染至纹理的数据),这些数据就必须在图形芯片间传输,而这种数据传输导致了部分通讯损耗,所以无法真正达到2倍的增速。 对于SFR,驱动程序将每帧图像的顶部部分分配给GPU 0,而将底部分部分配给GPU 1,并且在每帧的顶部和底部部分间寻求平衡量:如果由于顶部渲染量少于底部渲染量时,GPU 0这时没有被充分利用,那么驱动程序就把顶部部分分割得比底部大一些,从而使两个图形芯片都充分发挥作用。

由于GPU 0和GPU 1可以分别处理场景的顶部和底部图像,故而可以避免在两个图形芯片上处理所有定点图像。
SFR模式也需要数据共享,例如,渲染至纹理操作就是这样。这是因为AFR在一般情况下通讯损耗比较少,而且在顶点负载分配的平衡性方面比SFR更为理想。所以AFR模式是优先选用的模式。然而,时候却不能使用AFR模式。比如,如果应用程序将帧缓存的最大数量限制为小于两个时,就不能使用AFR模式。

为了最大限度发挥SLI的威力,我们不得不在编写程序时注意一些问题,而这些问题主要来自如下方面:

1)使用了垂直同步,不能最大发挥SLI的并行渲染威力,解决方法就是关闭垂直同步;

2)不当使用RT(Render Target),这也是我们《天下贰》需要解决的主要问题,下面我大概说明下。

上面已经提到,在SLI环境下,不会double显存,而是每种D3D资源都会在每个gpu上创建一个备份,这就带来一个问题,在afr工作模式下,2个gpu是交替渲染不同的帧,如果gpu0更新了rt,并期望rt能在以后若干帧得到利用(典型用法是:比如渲染光照贴图等不需要每帧更新的rt),那么gpu0就需要通知gpu1更新rt,这样才能保证gpu1使用rt时能得到正确的渲染结果,而gpu0通知gpu1更新的过程是非常耗时的,据我所知,d3d目前不能做到显存到显存的读写,而是显存到内存再到显存,可想而知这个速度是多么的慢,据说ogl可以实现显存到显存的读写(未验证),这也是我们《天下贰》以及大部分没有针对SLI优化的游戏需要解决的问题,如果解决不好,就会导致性能下降的问题,如果是这样关闭SLI可能比开启SLI效率还要高。

知道了问题,解决起来也不是那么轻松,第一尽量不要使用隔帧渲染(这帧需要利用上一帧的渲染结果),并用Clear函数清除rt,这相当于告诉其他gpu,不需要同步rt;如果不能避免隔帧渲染(毕竟很多东西实时渲染效率更低,或者效果要求),就为每个sli gpu创建一份单独的rt,比如,如果2快显卡集成的sli系统就需要创建2份rt,奇数帧渲染0号rt,偶数帧渲染1号rt,这样就保证了每个gpu只使用自己渲染的rt,而且不需要额外调用Clear函数,不会带来同步问题。之说以说解决起来不轻松,是因为,为每个rt单独创建对应rt,是非常浪费显存的,显存没有double,而对象double了,而且还要考虑帧数的奇偶性,有点头疼。

 

关于sli的开发问题还有一些,比如frame buffer的使用,不过个人感觉这不是关键,如果有兴趣可以参考

 原文:http://http.download.nvidia.com/developer/SDK/Individual_Samples/DEMOS/Direct3D9/src/slibestpract/docs/slibestpract.pdf