在程序中掌控NVIDIA Optimus

转载请注明出处为KlayGE游戏引擎,本文的永久链接为http://www.klayge.org/?p=2052

NVIDIA的Optimus技术可以在笔记本上兼顾耗电量和性能,并能做到自动无缝切换。但问题就在于,不想让它自动的时候,该怎么办?在ThinkPad T420s上,NV的独立显卡是NVS 4200M,feature level支持到D3D 11.0;Intel的集成显卡是HD 3000,feature level支持到D3D 10.1。(对feature level还不熟悉的朋友可以看这篇

在BIOS中控制

支持Optimus的平台上,在BIOS中可以找到选项,可以选择使用NV、Intel或者自动切换。但这个是静态的,每次切换都得重启,肯定不是我们想要的。

在右键菜单中控制

在exe文件的图标上按右键,菜单里有一个“用图形处理器运行”的项,里面可以选择NV卡或者Intel卡。有趣的是,如果你在程序中枚举adapter,总会返回两块显卡。如果这里选的是NV卡,那么两块显卡都是NV卡。如果选的是Intel卡,那么第一显卡是Intel,第二是NV。

在驱动中控制

在NV的驱动中,可以通过全局profile,来控制所有程序是通过NV卡或者Intel卡来执行。另外还有个per-app的profile,可以让每个程序有不同的显卡配置。但这种方式仍然不够灵活,没法在程序中使用。

静态链接CUDA

Intel卡没法硬件支持CUDA,所以CUDA程序必然只能到NV的卡上执行。偶然发现NV GPU Computing SDK中的CUDA程序可以自动切换到NV的卡上执行,实验了一下各种组合,发现静态链接到cudart.lib,就可以切换到NV卡。动态载入nvcuda.dll的话则无效。这种方法需要引入一个用不着的库,不但不够简洁,在非NV平台上还会有麻烦。

枚举所有设备

前文提到,可以在程序中枚举adapter。如果强制选择了在NV卡上建立device的结果会如何呢?我试验的结果是,这么做确实能启动NV卡,但似乎系统会自动做个拷贝之类的事情,使得渲染的过程中有个固有开销。draw call越多越明显。虽然并非最佳,但仍不失为一个方案。

神奇的NvOptimusEnablement

NV开发者网站上,有个关于Optimus的新文档,里面提到了在R302以上的驱动里,引入了一个启动NV卡的新方法。通过从exe中导出一个名为NvOptimusEnablement的全局变量,它为1的时候驱动就能切换到NV的显卡:

extern "C"
{
_declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
}

通过这种方式,终于可以在程序中控制使用哪块显卡,并且没有上一种方法的性能下降问题。

另一个有趣的发现是,如果是在dll中建立设备,exe是通过lib链接到dll的话,那么一切正常:设备名为NVS 4200M、feature level支持D3D11。但如果exe是通过LoadLibrary去动态导入那个dll,就会出现设备名为Intel HD 3000而feature level支持D3D11的奇葩状况。但无论哪种方式,都是真的启用了NV卡,并且性能无损。

总结

前面列举了多种在Optimus平台上主动启用NV卡的办法。最后两种,尤其是最后一种,是实用的,但远非完美。希望某天NV能根据CreateDevice所在的module,而不是exe的module来决定是否切换NV卡,以及返回正确的设备名。

posted on 2012-09-25 12:30  龚敏敏  阅读(2047)  评论(0编辑  收藏  举报