第五节 Direct3D立即模式的要素

  Direct3D立即模式由一些相互联系的API成员组成,通过它们可以来创建对象,给对象填充数据,和将对象组织在一起。这些API是基于COM模型的。立即模式API是在Direct3D驱动器之上的一个很薄的层次。

这一部分给出了一些立即模式组成部分的技术资料。这些资料分一些几个部分来讨论:

 

一.DirectX 6.0中立即模式的一些变化

  DirectX 6.0对于先前的DirectX版本是兼容的,并且提供了一些新的特征,这些特征可以提高性能,增加易用性,开发新的硬件特性:

1. 性能增强:

2. 易用性改善:

3. 支持边缘切割硬件特性:

  DirectX 6.0使用与DirectX 5.0相同的对象模型,因此使用遗留下来的接口的程序,DirectX 6.0同样支持。

 

Direct3DDirectDraw

这一部分讨论Direct3DDirectDraw之间的联系,分以下几个部分:

1. DirectDraw, Direct3D, Direct3D接口

  Direct3D通过COM对象和接口来实现其功能。Direct3D接口是DirectDraw对象的接口。DirectDraw提供给程序员一个单独的、统一的对象,这个对象封装了DirectDrawDirect3D的各种状态。DirectDraw是程序要创建的第一个对象(调用DirectDrawCreate),也是最后一个释放的对象。通常DirectDraw对象表示显示设备,并且通过显示设备来执行Direct3D的大多数特性,这样就使得Direct3D的功能与DirecrDraw结合在一起。

  这一点也就意味着Direct3D驱动器状态的生存期(ligetime)与DirectDraw对象的生存期是相同的。释放Direct3D接口并不会破坏Direct3D驱动器的状态。只有当所有有关这一对象的引用(不论是Direct3D还是DirectDraw)都被释放之后,这一状态才会被销毁。因此,如果你释放了一个Direct3D接口,并同时保留了一个DirectDraw驱动器接口的引用,然后再一次查询这个Direc3D接口,那么这个Direct3D状态就会被保留下来。

  DirectDraw对象包括了三个Direct3D接口:IDirect3D, IDirect3D2, IDirect3D3IDirect3DIDirect3D2接口是老的接口。它们具有向后的兼容性。新程序应该使用IDirect3D3接口来创建其它的Direct3D对象,例如视口、灯光、纹理和材质等。详细内容见“Direct3D接口”。

2. Direct3D接口

  Direct3D对象的功能通过IDirect3D, IDirect3D2IDirect3D3接口来访问。这一部分我们来讨论这三个接口的有关内容。

2.1 IDirect3D接口

  IDirect3D支持执行缓冲的使用。它对现有的代码提供兼容。新编者的程序应该使用Direct3D3接口。

  如果你的程序使用了执行缓冲,那它必须通过DirectDraw对象的QueryInterface方法来得到一个指向IDirect3D接口的指针。

2.2 IDirect3D2接口

  IDirect3D2接口提供了Direct3D程序的一种更简单的结构。这种程序结构通过简单的调用来实现对图元的渲染,它不使用执行缓冲。设备支持两种方法来实现这种新的渲染方式, IDirect3DDevice2::DrawPrimitiveIDirect3DDevice2::DrawIndexedPrimitive方法;这两种方法在当前的设备接口IDirect3DDevice3中都提供支持。

  通过DirectDraw对象调用QueryInterface方法,程序能够得到一个指向IDirect3D2接口的指针。

  IDirect3D2接口是创建其它Direct3D立即模式接口的起点。使用它,你的程序可以找到和列举一个特殊的DirectDraw对象所支持的Direct3D设备的类型。它还包括了创建其它立即模式对象所需的一些方法。

  IDirect3D2IDirect3D之间一个最大的区别就是IDirect3D2实现了IDirect3D2::CreateDevice方法。这个方法用来创建一个支持DrawPrimitive方法的Direct3D设备。有关使用IDirect3D2::CreateDevice方法创建设备的详细内容见“Direct3D设备”。

  还要注意的是,我们无法使用IDirect3DDevice2提供的有关IDirect3Ddevice接口指针的一些新的特性。如果你的程序在一个DirectDraw表面上调用QueryInterface方法并得到了一个IDirect3Ddevice,那么他见不能访问后来的设备接口序所支持的一些特性。另外,它也不能调用以这种方式创建的设备对象的QueryInterface方法来得到一个IDirect3DDevice2接口。

2.3 IDirect3D3接口

  和IDirect3D2接口一样,IDirect3D3接口也支持DrawPrimitive方法。另外,IDirect3D3接口扩展了IDirect3DDevice3接口介绍的DrawPrimitive-结构程序的一些功能。新接口支持可塑(flexible)顶点格式、顶点缓冲和新的纹理处理能力。详细内容见“顶点格式”,“纹理”,“顶点缓冲”和“渲染”。

  通过一个DirectDraw对象使用QueryInterface方法,程序可以得到一个指向IDirect3D3接口的指针。详细内容见“得到一个IDirect3D3接口”。

3. 得到一个IDirect3D3接口

  一个Direct3D程序开始的时候,必须要得到一个指向IDirect3D3接口的指针,这样才能访问Direct3D的各种功能。用以下的步骤可以获得一个这样的指针:

  (1) 调用DirectDrawCreate创建一个DirectDraw设备。

  (2) 调用IUnknown::QueryInterface方法得到一个指向IDirect3D3接口的指针。

  下面的插图展示了这一步骤:

pic27.gif (2209 bytes)

  下面的代码说明了如何来查询一个IDirect3D3接口:

LPDIRECTDRAW lpDD; // IDirectDraw Interface
LPDIRECT3D3 lpD3D; // IDirect3D3 Interface
// Get an IDirectDraw interface.
// Use the current display driver.
hResult = DirectDrawCreate (NULL, &lpDD, NULL);

if (FAILED (hResult))
{
// Code to handle an error goes here.
}

// Get D3D interface
hResult = lpDD->QueryInterface (IID_IDirect3D3, (void **)&lpD3D);
if (FAILED (hResult))
{
// Code to handle the error goes here.
}

4. 使用IDirect3D3接口

  应用程序使用IDirect3D3接口来创建Direct3D设备、视口、灯光和材质。同时还要创建纹理。IDirect3D2接口下的纹理使用纹理句柄来进行操作。IDirect3D3接口对纹理处理能力进行了扩展。为了适应这些变化,IDirect3D3接口不再使用纹理句柄,取而代之的是纹理接口。详细内容见“纹理”部分。

  Direct3D通过调用IDirect3D3::CreateDevice方法来创建设备。详细内容见“Direct3D设备”部分。

  在创建视口时,使用IDirect3D3::CreateViewport方法。详细内容见“视口与裁剪”部分。

  灯光和材质的创建通过调用IDirect3D3::CreateLightIDirect3D3::CreateMaterial方法来实现。详细内容见“灯光与材质”。

5. DirectDraw合作级和FPU精度

  Direct3D使用单精度浮点运算来提高场景渲染的性能。缺省情况下,Direct3D检查FPU的精度(通常被设为双精度),并将它设置为单精度,完成必要的操作之后,再返回到应用程序调用之前将FPU改回到双精度。这一过程通过渲染循环不断的进行重复。

  在设置DirectDraw合作级时,可以通过包含DDSCL_FPUSETUP合作级标志来提高Direct3D的性能。这个标志主要是通知系统,程序不再依靠FPU设置来为双精度运算。当你使用DDSCL_FPUSETUP时,Direct3D就会将FPU设置为单精度,只有当Direct3D关闭时才将FPU恢复为双进度运算,这样就能减少每一个渲染循环对FPU的设置与恢复,从而提高了程序的性能。

  有一点很明显,那就是当我们使用了DDSCL_FPUSETUP,那么程序就被限制在只能使用单精度值。这样,就要求我们只能在程序接受单精度浮点值的情况下才能使用这个合作级的设置。如果需要一些双精度浮点运算,那么我们只能在需要的时候人工设置FPU的精度模式,但在使用Direct3D之前必须将FPU重新设置成单精度。如果没有将FPU恢复为单精度,那么程序的性能就会受到影响。

  浮点精度对于每一个线程都是特定的,因此在多线程的程序中,必须对每个线程的FPU设置进行仔细的检查。
  要点:在运行时间内加载一些动态连接库时,可能会使FPU被恢复设置为双精度模式。由一些编译器,例如Microsoft Visual C++,将DLL的入口点默认的设置为_DllMainCrtStartup,它是一个编译器提供的用于初始化C/C++的runtime成员的函数。这个函数同时将FPU设置为双精度模式。如果程序设置了DDSCL_FPUSETUP合作级,然后加载一个DLL,Direct3D将不会察觉FPU被重新设置了,这样程序的性能就会受到影响。
  如果程序在运行期间加载了DLLs,那么在LoadLibrary Win32it函数返回之后,以及调用任何Direct3D函数之前,程序就应立即检查和重新设置FPU精度模式。你可以明确的重新设置FPU,也可以重新调用IDirectDraw4::SetCooperativeLevel方法,使用DDSCL_FPUSETUP标志。使用SetCooperativeLevel来设置FPU精度模式有时可能会使DirectDraw表面丢失。
  (你可以明确的使用/ENTRY来设置DLLs的入口指针:linker switch,如果你这样做了,那么C/C++的运行时间将不会被自动初始化。)

  下面是一个控制台应用程序(console application)的源代码,它用来检查和设置FPU精度模式,它使用了内嵌的汇编语言:

#include <windows.h>
#include <math.h>
// This function evaluates whether the floating-point
// control word is set to single precision/round to nearest/
// exceptions disabled. If these conditions don't hold, the
// function changes the control word to set them and returns
// TRUE, putting the old control word value in the passback
// location pointed to by pwOldCW.

BOOL MungeFPCW( WORD *pwOldCW )
{
 BOOL ret = FALSE;
 WORD wTemp, wSave;
 __asm fstcw wSave
 if (wSave & 0x300 ||     // Not single mode
 0x3f != (wSave & 0x3f) ||   // Exceptions enabled
 wSave & 0xC00)       // Not round to nearest mode
 {
  __asm{
   mov ax, wSave
   and ax, not 300h    ;; single mode
   or ax, 3fh        ;; disable all exceptions
   and ax, not 0xC00    ;; round to nearest mode
   mov wTemp, ax
   fldcw wTemp
   }
  ret = TRUE;
 }
 *pwOldCW = wSave;
 return ret;
}

void RestoreFPCW(WORD wSave)
{
 __asm fldcw wSave
}

void __cdecl main()
{
 WORD wOldCW;
 BOOL bChangedFPCW = MungeFPCW( &wOldCW );
 // Do something with control word as set by MungeFPCW.
 if ( bChangedFPCW )
 
RestoreFPCW( wOldCW );
}

 

上一页 | 目录 | 下一页