D3D设备是D3D的粉刷组件;它封装并存储粉刷的状态,另外,D3D设备执行转换和光操作,并光栅化一个图像到一个面上。
本节主要包括内容:
1. 设备类型
2. 创建设备
3. 选择设备
4. 不为人知的设备
5. 决定硬件支持
6. 处理顶点数据
7. 设备支持的初基类型
按照架构来说,D3D设备包含一个转换模块、一个光模块、一个光栅化模块;如下图所示:
D3D当前支持两种主要类型的D3D设备:带硬件加速的光栅化以及硬件和软件顶点处理的阴影HAL设备、一个引用设备。
你可以将这些设备看作两个独立的驱动。软件和引用设备通过软件驱动来表示,HAL设备通过硬件驱动来表示。最通常的利用这些设备的方式是在shipping程序中使用HAL设备作,在特性测试的时候引用驱动。第三方提供枚举特殊的设备----例如,开发的硬件没有发布。
程序创建的D3D设备必须于程序正在运行的设备性能相匹配,通过访问安装在计算机上的硬件来访问或者枚举软件中3D硬件能力来访问。因此,D3D为硬件访问和软件枚举提供设备。
硬件加速设备比软件设备有更好的性能,HAL设备类型在所有支持D3D图像卡上可用。在大多数情况下,程序将有硬件加速的计算机作为目标并依赖软件来适应低端计算机。
由于引用设备的异常,软件设备并不总是能提供和硬件设备相同的特性。程序可以查询来决定设备支持那些特性。
因为DirectX9提供的引用设备和软件的行为等同于HAL设备,基于HAL设备上的程序编码在软件或引用设备无须修改。注意,提供的软件或引用设备行为与HAL设备相同的时候,设备性能变化,特殊软件设备可能实现较小部分的能力。
行为
D3D让你可以指定设备行为,例如设备类型,IDirect3D9::CreateDevice方法来促使一个或多个行为多哥标志的联合来控制D3D设备的全局行为。这些行为指定什么需要或不需要在D3D运行时维护,使用所有设备类型和所有设备行为是可能的。例如,在设备创建的时候使用D3DCREATE_PUREDEVICE来指定D3DDEVTYPE_SW是有效的。
1.1.1. 设备类型
Ø HAL设备
最基本的设备类型是HAL设备,它支持硬件加速光栅化,且支持硬件和软件顶点处理。如果你的正在运行程序的计算机配备了支持微软Direct3D功能,你应该使用显示卡来支持3D操作。Direct3D HAL设备以硬件的形式实现了全部或部分转换、光和光栅化模块。
程序不需要直接访问3D卡,它们调用Direct3D函数和方法,Direct3D通过HAL来访问硬件。如果你的程序正在运行的那台计算机上支持HAL,那么它通过使用HAL设备将获得最好的性能。
在C++创建一个HAL设备,需要调用IDirect3D9::CreateDevice方法,并传递D3DDEVTYPE_HAL常量作为设备类。
备注:硬件设备不能粉刷8位粉刷目标表面。
Ø 引用设备
D3D另外支持引用设备类型或者叫引用光栅,与软件设备不同的是,引用设备支持每个D3D特性,因为这些功能为了实现精确,而不是速度,并且以软件实现,所以结果不是很快。无论什么时候,引用设备都利用特定的CPU指令,但它并不是为了某些程序使用的,使用引用设备仅仅是为了功能测试或演示的目的。
为了在C++创建一个引用设备,调用IDirect3D9::CreateDevice方法,并传递D3DDEVTYPE_REF常量作为设备类型。
1.1.2. 创建一个设备
备注:所有通过给定的微软D3D对象创建的粉刷设备都共享相同的物理资源。虽然你的程序能从一个单个D3D对象创建多个粉刷设备,由于他们使用同一个设备,所以你必须付出极端性能的惩罚。
为了在C++程序中创建D3D设备,你的程序应该首先创建一个D3D对象,这个将在D3D对象中解释。
首先,初始化D3DPRESENT_PARAMETERS结构,它在创建D3D设备的时候用到,下面的代码例子详细说明一个窗口程序后台缓冲区弹出到前台缓冲区。
LPDIRECT3DDEVICE9 pDevice = NULL;
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory (&d3dpp, sizeof (d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
下面,创建D3D设备,下面的IDirect3D9::CreateDevice调用指定默认的适配器,一个硬件抽象层设备和软件顶点处理。
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&d3dpp,&d3dDevice)))
return E_FAIL;
注意,创建、释放、复位设备的调用应该在和焦点窗口的窗口程序在同一个线程中。
在创建设备之后,设置它的状态。
1.1.3. 选择一个设备
程序能够查询硬件来检查支持D3D设备的类型。本节包含在枚举显示适配器和选择D3D设备的基本任务。
程序必须执行一系列的任务来选择一个适当的D3D设备。注意,下面的步骤目的是一个满屏幕的程序,在多数情况下,一个窗口程序不能下面步骤的大部分。
1. 初始化;
程序必须枚举系统上的显示卡;一个卡就是一个物理硬件块。注意,可能不止一块图形卡,例如双重显示的情况。与多监视器无关的程序可以忽略这步,并在第二步中传递D3DADAPTER_DEFAULT来调用IDirect3D9::EnumAdapterModes方法。
2. 对于每块卡,程序调用IDirect3D9::EnumAdapterModes来枚举支持的显示模式。
3. 如果必要的话,程序需要调用IDirect3D9::CheckDeviceType来检查每种枚举模式中的硬件加速情况,如下面代码所示。注意,这是唯一可能使用IDirect3D9::CheckDeviceType的地方,详细见:判断硬件支持。
D3DPRESENT_PARAMETERS Params;
// Initialize values for D3DPRESENT_PARAMETERS members.
Params.BackBufferFormat = D3DFMT_X1R5G5B5;
if(FAILED(m_pD3D->CheckDeviceType(Device.m_uAdapter, Device.m_DevType,Params.BackBufferFormat, Params.BackBufferFormat, FALSE)))
return E_FAIL;
4. 程序检查调用IDirectD39::GetDeviceCaps方法来检查该卡上期望的设备功能级别。该方法过滤那些不支持需要功能的设备,IDirect3D9::GetDeviceCaps返回的设备能力对于一个通过所有IDirect3D9::CheckDeviceType检查的设备来说是一个常量。
5. 设备总是能够粉刷设备支持一个枚举显示模式格式的面。如果要求粉刷一个不同格式的面,它调用IDirect3D9::CheckDeviceFormat,如果设备能粉刷这个格式,就可以保证所有IDirect3D9::GetDeviceCaps返回的能力都适用。
6. 最后,程序可以决定是否采用多采样技术,例如:使用IDirect3D9::CheckDeviceMultiSampleType方法来支持一个全场景 antialiasing作为粉刷格式。
在完成上面的步骤之后,程序应该有一个它可以操作的显示模式列表,最后一步就是核实有足够可用的设备可访问的内存来满足缓冲区和antialiasing的需要。这个测试是必要的,因为模式和多采样合并的内存消耗在核实之前并不可预知,另外,有些显卡结构并不是有一个固定的设备访问内存;这意味着程序或许会在“满屏模式”的时候报“显存溢出”的错误。典型地,程序应该从它提供给用户的模式列表中删除满屏模式,或者应该试着通过减少后台内存的数量来消耗较少的内存,或者使用不是怎么复杂的多采样技术。
窗口程序执行同样的一系列任务。
1. 判断被窗口客户区覆盖的桌面矩形
2. 枚举显卡,查询显卡看哪个监视器覆盖了客户区,如果客户区被多个卡拥有,那么程序能选择独立地驱动每块卡,或者驱动单个卡且有D3D从一个设备到另一个设备传递像素。程序也可以不管上面的两步而使用D3DADAPTER_DEFAULT卡。注意,这可能导致将窗口放置到一个次要的监视器较慢。
3. 程序应该调用IDirect3D9::CheckDeviceType来决定在桌面模式下设备是否能支持指定格式的后台缓冲区的粉刷。IDirect3D9::GetAdapterDisaplayMode可用来判断桌面显示格式,如下面代码:
D3DPRESENT_PARAMETERS Params;
// Initialize values for D3DPRESENT_PARAMETERS members.
// Use the current display mode.
D3DDISPLAYMODE mode;
if(FAILED(m_pD3D->GetAdapterDisplayMode(Device.m_uAdapter, &mode)))
return E_FAIL;
Params.BackBufferFormat = mode.Format;
if(FAILED(m_pD3D->CheckDeviceType(Device.m_uAdapter,Device.m_DevType,Params.BackBufferFormat, Params.BackBufferFormat, FALSE)))
return E_FAIL;
1.1.4. 放弃一个设备
微软的D3D设备可以处在操作状态或放弃状态;操作状态是设备的正常的状态,设备按照预期来运行和表现所有的粉刷。当一个事件发生时,设备会转换到放弃状态,例如在满屏模式下丢失键盘焦点,导致粉刷变成不可能。丢失状态是所有粉刷操作平静失败的表现,这意味着粉刷操作不能返回成功代码,即使是在粉刷操作失败的情况下(The lost state is characterized by the silent failure of all rendering operations, which means that the rendering methods can return success codes even though the rendering operations fail);在这种情况下,IDirect3DDevice9::Presenter将返回错误代码D3DERR_DEVICELOST。
根据设计,能导致设备变成丢失状态的全套场景是不确定的,某些典型的例子包括焦点丢失,例如当用户按下ALT+TAB或一个系统对话框被初始化时,设备也可以由于电源管理事件而丢失,或者当另外一个程序采用满屏操作时;另外任何来自IDirect3DDevice9::Reset的失败都将导致设备进入丢失状态。
所有继承自IUnknow的方法都可保证在设备丢失之后正常工作。在设备都是之后,每个函数通常有三个选择:
1. 失败并返回D3DERR_DEVICELOST;这意味着程序需要认识丢失的设备,以便于程序能标识那些不能按照预期发生的事情。
2. 安静地失败,返回S_OK或者其他的返回值-如果一个函数安静地失败,程序通常不能区分是成功的结果还是安静地失败
3. 函数返回一个返回值。
1.1.4.1. 对丢失设备的响应
一个丢失的设备在它已经被复位以后必须重创建资源(包括显存资源)。如果一个设备丢失了,程序查询设备来看是否能够恢复到操作状态;如果不能,程序等待,直到设备可以被恢复。
如果设备可以被恢复,程序通过销毁所有的显存资源和任何交换链来准备设备,然后,程序调用IDirect3DDeivice9::Reset方法;方法Reset是设备丢失之后唯一有效的方法,也是程序唯一用来改变丢失设备到操作状态的方法。IDirect3DDevice9::Reset只有在程序释放了所有以D3DPOOL_DEFAULT方式分配的资源时才会失败,这些资源包括由IDirect3DDevice9::CreateRenderTarget和IDirect3DDevice9::CreateDepthStencilSurface方法创建的资源。
大部分情况,频繁的调用D3D并不会返回设备已经丢失的信息。程序能继续调用粉刷方法,例如:IDirect3DDevice9::DrawPrimitive,如果没有接收到设备丢失的通知;而在内部,这些操作被抛弃直到设备被复位为可操作状态。
程序可以通过查询IDirect3DDevice9::TestCooperativeLevel方法来决定遇到丢失设备的时候如何做。
1.1.4.2. 锁定操作
在D3D内部,其做了充分的工作保证设备丢失之后锁定操作能成功;然而,它不保证在锁定操作过程中显存资源数据是准确的。它确保不返回错误代码,这允许程序在锁定操作过程中是可写的如果不关心设备丢失。
1.1.4.3. 资源
资源能消耗显存,因为一个丢失设备从显卡拥有的显存断开,在设备丢失时不可能担保分配显存。结果所有资源创建方法都被实现为成功返回D3D_OK,但实际上仅仅分配虚拟系统内存;因为任何显存资源必须在设备调整大小的之前被销毁,没有过量分配显存的问题。这些虚拟的表面允许锁定和复制操作看起来运行的很正常,直到程序调用IDirect3DDevice9::Present和发现设备已经丢失了。
所有显存必须在设备从丢失状态被复位为操作状态之前释放;这意味着程序应该释放任何通过IDirect3DDevice9::CreateAdditionalSwapChain创建的交换链和任何放在D3DPOOL_DEFAULT内存类中的资源,其他状态数据会在转换到操作状态时自动被销毁。
开发一个单响应设备丢失编码途径是值得鼓励的;如果不同,这个编码途径很可能与设备启动时初始化的编码途径相似。
1.1.4.4. 重新得到数据
D3D允许程序允许程序验证纹理并粉刷状态,而不是通过IDirect3DDevice::ValidateDevice硬件来单向粉刷。这个方法通常在程序初始化的时候调用,如果设备丢失将返回D3DERR_DEVICELOST。
D3D也允许程序从显存资源复制产生的和以前写的图像到永久系统内存资源,因为源图像可能在任何时候丢失,D3D允许在设备都是的时候复制操作失败。
关于异步查询,如果FLUSH标志被设置,IDirect3DQuery9::GetData返回D3DERR_DEVICELOST,为了指示IDirect3DQuery9::GetData永远不会返回S_OK。
复制操作,IDirect3DDevice9::GetFontBufferData失败并返回D3DERR_DEVICELOST,由于在设备丢失的时候没有基本的表面。IDirect3DDevice9::CreateAdditionalSwapChain在设备的丢失的时候不能创建BACK缓冲区而失败并返回D3DERR_DEVICELOST。这些情况是除IDirect3DDevice9::Present 、IDirect3DDevice9::TestCooperativeLevel和IDirect3DDevice9::Reset方法之外返回D3DERR_DEVICELOST的唯一情况。
1.1.4.5. 可编程阴影
在微软D3D 9.0中,Vertex Shader1_1和Pixel_Shader_1_X并不需要在复位之后重新创建,他们会被记住。在以前的DirectX版本中,丢失设备要求阴影也需要重新创建。
1.1.5. 判断硬件支持
微软D3D提供了下面的函数来判断硬件的支持情况。
1. IDirect3D9::CheckDeviceFormat
用来判断一个表面格式是是否可以用作纹理,一个格式是否能用作纹理和粉刷对象或者一个表面格式是否可以用作深度模板缓冲区。另外,这个方法被用来验证深度缓冲区格式支持和深度模板缓冲区格式支持。
2. IDirect3D9::CheckDeviceType
用来验证设备执行硬件加速的能力,一个设备能力来为表现构造交换链,或者一个粉刷当前显示格式的设备能力。
3. IDirect3D9::CheckDpthStencilMatch
用来验证一个深度模板缓冲区格式是否和一个粉刷目标格式相兼容。注意,在调用该方法之前,程序应该调用在深度模板和粉刷目标格式上都调用过IDirect3D9::CheckDeviceFormat方法。
1.1.6. 处理顶点数据
IDirect3DDevice9接口支持以软件和硬件的方式的顶点处理。通常对于软件和硬件顶点处理的设备能力是不同的;硬件能力是可边的,依赖于显示卡和驱动,而软件呢能是固定的。
下面的标志用来控制HAL和引用设备的顶点处理行为。
l D3DCREATE_SOFTWARE_VERTEXPROCESSING
l D3DCREATE_HARDWARE_VERTEXPROCESSING
l D3DCREATE_MIXED_VERTEXPROCESSING
在调用IDirect3D9::CreateDevice时指定顶点处理行为标志之一,也可以指定混合模式,用来表示可以指定硬件和软件顶点处理模式。在任何时候仅仅可以为一个设备设置一种顶点处理标志。注意,D3DCREATE_HARDWARE_VERTEXPROCESSING标志在创建虚设备(D3DCREATE_PUREDEVICE)的时候要求被设置。
为了避免在单个设备上的多重顶点处理,仅仅硬件顶点处理能力可以在运行时查询,软件顶点处理能力是固定的,在运行时不能查询。
你能和D3DCAPS9的VerterProcessingCaps成员商讨来决定设备的硬件处理能力,对于软件顶点处理支持下面的能力:
l D3DVTXPCAPS的D3DVTXPCAPS_DIRECTIONALLLIGHTS成员
l D3DVTXPCAPS的D3DVTXPCAPS_LOCALVIEWER成员
l D3DVTXPCAPS的D3DVTXPCAPS_POSITIONALLIGHTS成员
l D3DVTXPCAPS的D3DVTXPCAPS_TEXGEN成员
l D3DVTXPCAPS的D3DVTXPCAPS_TWEENING成员
另外,下表列出了软件顶点出来模式时D3DCAPS9成员的设置值:
成员 |
软件顶点处理能力 |
MaxActiveLights |
无限制 |
MaxUserClipPlanes |
6 |
MaxVertexBlendMatrices |
4 |
MaxStreams |
16 |
MaxVertexIndex |
0xFFFFFFFF |
软件顶点处理提供一系列顶点处理能力,包括一些极大数量的光和可编程顶点阴影完全支持。你能够在使用HAL设备的任何时候在软件和硬件顶点处理之间切换,唯一同时支持硬件和软件顶点处理的设备类型。唯一要求是用做软件顶点处理的顶点缓冲区必须被分配在系统内存中。