实验室的系统需要绘制3D模型后用多块显卡来进行尽可能多的窗口输出。市面上有以Matrox为代表的多屏显卡,此类显卡输出功能极其强大,电视墙什么的毫无压力,但是——绘制能力捉急,不指望用它进行模型绘制渲染。绘制渲染方面还是普通的游戏卡比较猛,谁让人家就是玩这个的。
一开始我们是用的Geforce,用PCIE*4的主板,插上4块GTX660Ti,把所有的输出口,包括DVI、HDMI、DP,都用上,好不拉风。于是问题来了:画面确实开全了,却只有10fps不到,绘制能力咋跟不上呢?一查GPU-Z,其它三块显卡都在睡大觉,根本没工作,就第一块显卡在满负荷运转。再牛的卡也吃不消这么大面积的渲染啊……敢情其他几块显卡只负责抬抬手输出画面而已。
我们都知道Geforce显卡是支持一个叫SLI的技术的。但是此技术的坑爹之处在于开启之后所有的输出就到了第一块显卡上,其他的显卡固然是在工作,但是输出口就没有用了。咱要的不就是这些输出口么?不行。至于那个什么surround也用不成,固定分辨率的三个输出口可以用而已,比我们的需求差远了。
后来把渲染模型换成了把纹理贴在平面上显示图片。这回显卡负担应该不大了,即使是一块显卡工作,也应该游刃有余了。结果惊讶地发现,性能完全没有提高,仍然是10fps。这不得不让人怀疑不是绘制速度的问题了。
想了想,会不会是程序只开了一个大窗口包揽所有输出的原因。因为没法做到在每个显示输出做一个全屏窗口,因此画了一个大的无边框窗口覆盖所有显示区域。如果单独拆开来呢?于是把输出手动排了一下,多开几个窗口,每个窗口覆盖其对应的输出。结果……还是一样。一咬牙,只画了第一块显卡连接的窗口,意外发现,绘制图片速度飙到了800fps以上。
后来仔细分析,应该是显卡之间通信的问题。显卡之间除了诸如SLI或者crossfire这种技术由驱动内部调度之外,外部没有留接口给第三方程序直接通信。对于平时的应用,就只能是第一块显卡绘制的内容先从显存移到内存里,然后再由内存移到另一块显卡里,供另一块显卡输出。由于现在输出画面巨大,这样的速度该有多慢!所以要绘制速度提高,就要避免显卡之间大量数据通信。要做到这一点,就必须每块显卡各画各的,各输出各的,互不干预。
为了证实这一点猜想,开了一个正好覆盖第一块显卡输出大小的窗口,但是这回把窗口开偏一点点,让一小部分像素跨到第二块显卡的输出里,发现帧率从800+掉到了20+。把这个窗口全部移到第二块显卡的输出里,帧率依然是20+。看来果然是这个问题。而且,Geforce的卡死活不会让第二块卡工作。
可是明明已经将窗口分配给单块显卡了,其他几块显卡怎么就不工作呢?网上查阅了国内外各种论坛,讨论这个问题的人极少,但是也略微得到一些信息:Geforce在XP的时代,绘制逻辑确实是每块显卡单独管位于自己显示区域内的窗口的;可是进入win7之后,就换了逻辑,无论你插几块显卡开几个窗口,永远都是第一块显卡在工作。想要别的显卡工作怎么办?请买Quadro啦~nVidia不知道是在硬件还是驱动层面作了限制,有一个用于分配显卡绘制工作的参数WGL_NV_gpu_affinity,只能用于Quadro显卡,Geforce就别想啦~核弹厂真是做得一手好营销,就得去买死贵的Quadro,画模型还没Geforce快。而且这个参数还得详细写明哪部分工作交给哪块显卡,极大增加代码复杂性。当然,我们还有更为通用的解决方案:CUDA。但是计算机系的同学无不可怜地跟我说:那你得重写OpenGL的底层绘制代码。咳咳,天气真好。
所以我把目光放到了AMD上。某个论坛里有人提到了AMD的逻辑还是各个显卡管自己的窗口。而另一些网站或者论坛在强调nVidia的WGL_NV_gpu_ainity参数只能在Quadro上用,但是没说AMD的wgl_amd_gpu_association参数的限制。这是不是意味着AMD的卡有戏?
抱着试试看的态度搞来两张R9 290X,按照原来的方案,开了一个正好覆盖第一块显卡输出大小的窗口,fps接近1000;让一小部分像素跨到第二块显卡的输出里,fps掉到了20+;把这个窗口全部移到第二块显卡的输出里,fps回到几百了!从GPU-Z里看,负载确实转移到了第二块显卡上,第一块显卡空了下来,我大农企威武!
所以总结起来就是:在Windows 7系统下,nVidia的Geforce显卡逻辑是永远是接主屏的显卡在做绘制工作,而不管绘制的窗口开在了哪里;而AMD的显卡逻辑则是窗口的创建位置在哪块显卡上,就用哪块显卡来绘制。当然,如果窗口的大小超出了某块显卡的输出范围而跑到了别的显卡上,则数据交换依然无法避免,从而导致fps下降。