** 选择正确的 ** ** Device
**
** 翻译:clayman
** The number of possible permutations when cretion a device is quite staggering. 如今,市场里有大量不同类型的显示卡,记住每种显卡所支持的特性几乎时不可能的。你应该询问 device ,让它告诉你它所支持的特性。我们接下来将讨论:
枚举系统里所有的适配器( adapter )
枚举每一个 device 所支持的格式
确定所列举的设备功能
** 枚举系统里的适配器 ** ** **
** ** 如今的大多数系统都支持多显示器。虽然这还不是主流配置,但多显示器确实很有用,并且变的越来越流行。在过去,这是高端图形卡专有的功能。但现在 ATI , nVidia 以及 Matrox 都支持让多台显示器共享一块显卡的多头显示技术。
Direct3D 的 device 必须指定给每一个适配器。在这里,你可以把“适配器”理解为一块链接了特定显示器的显卡。比如 ATI Radeon 9700 的显卡只是一块物理适配器,但它有两个显示器接口( DVI 和 VGA ),因此,在 Direct3D 里,它有两个适配器。也许你不知道选哪一个,甚至不确定有多少 device 在运行游戏的系统里,那么怎样来检测它们并且选择正确的一个呢?
在 Direct3D 里,一个叫做 Manager 的静态类可以简单的完成以上任务:枚举适配器和 device 的信息;获得系统里 device 所支持特性的信息。
Manager 类最重要的属性就是适配器的列表。在许多地方都会用到这个属性。它有一个“ count ”成员储存了系统里适配器的数量。因此,可以直接用索引访问适配器( e.g. Manager.Adapters[0] ) , 也可以枚举出系统里所有适配器。
用一个简单的程序测试一下这个功能,它将以树状结构显示出系统里的适配器,以及他们所支持的显示模式:
1. 创建新的 C# Windows Form 工程;
2. 添加 DirectX 组件;
3. 创建一个 TreeView 控件,并且占满整个窗口:把 Dock 属性设置为 fill
好了,现在该加入扫描每一个适配器,显示所支持的每一种显示模式的函数了:
** Public void LoadGRaphics() **
** { **
** foreach(AdapterInformation ai in Manager.Adapters) **
** { **
** treeNode root = new TreeNOde(ai.Information.Description); **
** treeNode driverInfo = new TreeNode(string.Format(“Driver information:{0} – {1}”, ai.Information.DriverName, ai.Information.DriverVersion) ); **
** root.Node.Add(driverInfo); **
** treeNode displayMode – new TreeNodeJ(string.Format(“Vurrent Display Mode:{0} ** ** × ** ** {1} ** ** × ** ** {2}”, ai.CurrentDisplayMode.Width, ai.CurrentDisplayMOde.Height, ai.CurrentDisplayuMode.Format) ); **
** foreach(DisplayMode dm in ai.SupportedDisplayModes) **
** { **
** treeNode supportedNode = new TreeNode(string.Format(“Supported:{0} ** ** × ** ** {1} ** ** × ** ** {2}”, dm.Width, dm.Height, dm.Format) ); **
** displayMode.Nodes.Add(supportedNode); **
** } **
** root.Nodes.Add(displayMode); **
** treeView1.Node.Add(root); **
** } **
** } **
虽然代码看起来有一点点多,但它所做的事情实际上是非常简单的。你可以先分开来看看我们都作了些什么。首先,我们枚举系统里的适配器。 C# 的 Foreach 迭代器使这个过程异常的简单。对每一个适配器来说,这个循环都只执行一次,并且用给定的适配器填充 AdapterInformation 结构。观察一下 AdapterInformation 结构,有以下几个成员
** Public struct AdapterInformation **
** { **
** int adapter; **
** DisplayMode CurrentDisplayMode; **
** AdapterDetails Information; **
** AdapterDetails GetWhqlInformation(); **
** DisplayModeEnumerator SupportedDisplayModes; **
** } **
这里 adapter 成员指创建 device 时的适配器序数。序数是一个基于 0 的索引,并且序数的个数等于系统里适配器的个数。两个返回 AdapterDetails 结构的成员都使用同一个方法返回同样的结果。对 Information 成员来说, Windows Hardware Quality Labs ( WHQL )并不返回细节,而 GetWhqlInformation 却可以。获得这些信息要花费一些代价及事件,所以我们把它分成了两部分。
AdapterDetails 结构保存了适配器的大量信息,包括对适配器自身的描述以及驱动信息。虽然这不是一定会用到的,但应用程序却能依次作出对硬件类型的判断。
剩下的两个成员返回 DisplayMode 结构。这些结构包含了大量的显示模式,包括显示的高度和宽度,刷新率以及使用的格式。 CurrentDisplayMode 返回当前的显示模式, SupportedDisplayModes 返回适配器所支持的模式的列表。
So ,我们用从 Information 属性获得的对 device 的描述作为 tree view 的根节点。然后加入了一个表示驱动程序名字以及版本号的子节点。同样也加入了一个显示当前显示模式的子节点,并且在这个子节点下列出了所有支持的显示模式。
运行程序,可以看到包含了所有支持模式的列表。填充 present parameter 结构时,这些模式都能当作正确的后备缓冲格式。每一个枚举出来的模式后面都有一个以固定模式显示的字符串( e.g X8R 8G 8B8 ) , 字母和数字交替出现。字母表示了数据的类型,数字表示这种类型的数据所占的位数。下边是常见的字母:
A ―― alpha B ―― blue X---unused L----luminance R----red P----palette G---green
(虽然有很多种格式,但只有几种能正确的用于后备缓冲以及显示模式。可用于后备缓冲的模式包括: A2R 10G 10B10, A1R 5G 5B5, A8R 8G 8B8, X1R 5G 5B5, X8R 8G 8B8, R 5G 5B5; Display formats can be the same as the back buffer formats, with the exception of those that contain an alpha component . The only format that can be used for a display weith alpha is A2R 10G 10B10 , and even then that’s only in full-screen mode. )
每种类型所占的位数加起来,就是这种格式的总大小。比如 X8R 8G 8B8 ,就是 32 位的格式,红、绿、蓝各 8 位,还有 8 位没有使用。
至今为止,我们获得了要创建的适配器序数,要支持的后备缓冲格式,那么关于 device 构造函数的其他参数呢?很幸运, Manager 类有我们所需的一切。
** 判断哪一个设备是可用的 ** ** **
manager 类有许多方法可以用来检测你的适配器是否支持一个特定的功能。比如,你需要检测适配器是否支持一种特殊的格式,但又不想枚举所有可能的适配器以及格式,那你就可以用 manager 类来解决这个问题。使用如下的方法:
pubic static System.Boolean CheckDeviceType(int adapter, DeviceType checkType, Format DisplayFormat, Format backBufferFormat, bool windowed, int result)
这个方法可以快速的检测出 device 是否支持你将要使用的格式。第一个参数是你要检测的适配器序数;第二个是要检测的 device 类型,但这个值大多数情况下都被设置为 DeviceType.Fardware 。接着指定将使用的后备缓冲类型和显示格式,以及是否需要全屏显示。最后一个参数是可选的,如果使用的话他将返回关于这个方法的一个整数(即 COM 中的 HRESULT )。如果这是一个有效的设备,则方法返回 true ,否则为 false 。当你预先知道要使用的格式使,这个方法是很有用的。
(应该注意到,在窗口模式,后备缓冲的格式不一定要匹配于显示格式,只要你的硬件支持适当的颜色转换就可以了。不论你的硬件是否支持这种功能, CheckDeviceType 方法都会返回适当的结果,应该使用 manager 类的 CheckDeviceFormatConversion 方法来判断是否支持这种转换。也可以在窗口模式下使用 Format.Unknown 。全屏模式下不需要这种转换。)
** 检测 ** ** Device ** ** 的功能( ** ** capabilities ** ** ) ** ** **
我们把每一个 device 能完全用硬件实现的功能都叫做“ capability ”,或简称做“ Cap ”。 Direct3D 有一个 Caps 结构可以列出 device 所支持的每一种可能的 capabilities 。创建了 device 之后,就可以使用 device 的 Caps 属性来检测他所支持的特性,但如果在创建设备之你就想知道 device 所支持的特性该怎么办呢?自然, Manager 类也有一个方法能完成这个任务。
现在,先前的程序里加一点点代码来获得系统里每一种适配器的 capabilities 。我们将不再使用 tree view 来显示这些 capabilities ,应为这可能包含了数百种 capabilities 。最好的方法是使用一个 text box 。回到 windows form 的设计模式,把 tree view 的 Dock 属性改为“ <SPAN lang=EN-US style="FONT-SIZE: