2023年12月22日发(作者:)

DIRECTDRAW7的性能研究

一 发展史

在说起DirectDraw7前,先对DirectX本身作个了解, DirectX是一种图形应用程序接口(API),简单的说它是一个辅助软件,一个提高系统性能的加速软件,由微软创建开发的,微软将定义它为“硬件设备无关性”。从字面上看来,它的意思不难理解,Direct是直接的意思,X是很多东西,加在一起就是一组具有共性的东西,从内部原理探讨,也简单说来DirectX 就是一系列的 DLL (动态连接库),通过这些 DLL,开发者可以在无视于设备差异的情况下访问底层的硬件,DirectX 封装了一些 COM(Component Object Model)对象,这些 COM 对象为访问系统硬件提供了一个主要的接口。从技术侧面方面来分析,我们可以将它分为如下几个部分:

DirectDraw:为程序直接访问显存提供接口,同时和其它的Windows应用程序保持兼容,这是Directx中非常重要的部分,它担任图形处理的关键。DirectDraw就是来帮助windows程序也能直接进行硬件操作,更进一步还能加速显卡的速度,使游戏更为流畅。另外DirectDraw还支持mmx、3dnow、agp等技术,还能处理多屏幕显示,让窗口环境的游戏更加多姿多采。

Direct3D:为访问3D加速设备提供接口。

DirectInput:为各种输入设备提供接口,这用来处理游戏的一些外围装置,例如游戏摇杆、gamepad、方向盘、vr手套、力反馈的各种设备等。以往要在Dos下用方向盘来玩赛车游戏,就要先调整好irq、dma等各种设置。而现在DirectInput则使这些设备与游戏配合良好,不需要做特别配置。

DirectPlay:为游戏提供网络功能接口,比如支持通过 TCP/I、IPX 等协议进行游戏中的数据传输,这是为了满足近来流行的网络游戏而开发的api,支持多通信协议,让玩家可以用各种连网方式来进行对战,此外也提供网络对话功能及保密措施。

DirectSound:为访问声卡提供接口,支持WAV、MIDI 等文件的直接播放,这是用来处理声音的api,除了播放声音和处理混音之外,还加强了3d音效,并提供了录音功能。前面所举的声卡兼容的例子,就是利用了DirectSound来解决的。

DirectSound3D:通过此接口,可以模拟出某一个声音在三维空间中任何一个位置的播放所产生的效果,从而达到逼真的环绕立体声。

DirectMusic:此接口主要是生成一系列的原始声音采样反馈给相应的用户事件。

在DOS时代,用户玩游戏的时候,都必须确定所用声卡的品牌,然后再设置它的IRQ、I/O、DMA等,如果其中有一项设置不对游戏就发不出声。这些设置对用户来说不是件容易的事情,当时的用户计算机知识不多,当然这对游戏厂商来说,也不是件好事情,为了今后用户今后有声音的设置,那么它需要事先把市面上所有声卡硬件数据都收集过来,然后根据不同的API来写不同的驱动程序。而DirectX的出现,就是为了解决这些问题,它作为动态链接库,里面包含了众多的链接程序文件,如果是符合DirectX标准的游戏软件,这些访问最底层系统硬件的任务就由DirectX自动完成,如今玩家在玩Windows游戏的时候,并不需再对硬件作这些设置了,因为Directx提供了一个共同的应用程序界面,只要游戏是依照Directx这个标准来开发的,不管用户使用什么品牌的显卡、声卡,什么型号,这些相关的配置都交由Windows及DirectX配合完成,当然,这也是有条件的,用户使用的显卡、声卡的驱动程序也必须支持Directx。从这里看出,如今多媒体电脑发展的这么如火如荼,DirectX的贡献不小,它是由微软开发,由众多游戏和硬件制造厂商共同更新升级的的标准,只要所有软件硬件支持DirectX,那么它们就能进行低端的会话,

这里先回顾一下过去DirectX的发展,可以肯定地说,没有Windows操作系统前,根本就无DirectX这个概念,自从Windows3.1的GUI图形介面登场以后,越來越多的人开始使用Window。不过,Windows3.1的声音处理一次只能播放一个音,图形处理的能力也很弱,但是它的简单易操作性及越来越多的用户,加上微软的大力推广,Windows家族壮大起来了。

日益壮大的Windows家族,吸引了更多游戏商家的注意,开始开发基于Windows界面的游戏,微软也注意到这点,于是给众多的软硬件商家提供一个共同开发的标准平台(就是DirectX),大家都遵循这个标准,这样做对谁来说都是有意义的,硬件制造商按照此标准研发制造更好的产品,游戏程序员根据这套标准开发游戏。也就是说,无论硬件是否支持某特殊效果,只要DirectX标准中有,写游戏的程序员就可以把它写到游戏中,当这个游戏在硬件上运行,如果此硬件根据DirectX标准把这个效果做到了此硬件驱动程序中,驱动程序驾驭其硬件算出此效果,用户就可以欣赏到此效果。

在DirectX诞生之初,业界已经有众多标准,其中有两个重要的标准:OpenGL和Glide,特别是非常成熟的OpenGL,它被用于图形、影像服务器,制作电影、科教片等等,随着技术逐渐成熟,越来越普及,如当时大名鼎鼎的QuakeIII游戏就是基于这个标准的,而DirectX,很多硬件、主流游戏都不支持它,没有游戏、没有硬件,即使再有好的标准也是没有意义的,DirectX的魅力一直没有的到表现,但是它有微软的支持推广,它就有希望。

表一DirectX的发展

DirectX1.0:为游戏而生

DirectX出现是在Windows发布后,Windows3.1的声音处理一次只能播放一个音,图形处理的能力也很弱,加之整个Windows3.1的操作系统还很脆弱,这个时候它更不用不上,加上DirectX标准刚刚推出,很多硬件不支持,很多主流游戏也不支持,没有游戏、没有硬件,即使再有好的标准也是没有意义的,DirectX的魅力一直没有的到表现。但是随着Windows95的发布,稳定的窗口操作系统,出现了划时代的变化,DirectX的命运也由此改变。

Direct X 2.0:2D崛起3D雏形

终于DirectX升级到了2.0,这个时候标志性的产物诞生了,2.0最大的改善是在Direct Draw,而且这个时代的经典游戏也出现了,很有代表意义的《红色警戒(RedAlert)》和《Diable(恐惧)》,红警的Windows版本和Diable都是在DirectX的标准上开发的。可惜的是,当时很多老显卡由于不能完全支持DirectX2.0,而不能玩Diable。除了2D以外,DirectX2.0的D3D部分的雏形基本完成,由于当时3D游戏较少,很多都是基于DOS开发的。世嘉公司的VR战士的PC版本就是基于DirectX2.0开发完成的,虽然效果粗糙了一些,但Direct 3D魅力还是可以感受到的。

Direct X3.0:D3D发展壮大

1997年微软发布了最后一个版本的Windows95,同年发布了DirectX 3.0,这时候DirectX的魅力被众多软硬件厂商看好,让D3D有了与OpenGL与Glide

格斗的勇气。从这个版本开始,很多玩家知道了DirectX存在,也是这个时候开始出现了3D加速卡,如3DFX的Voodoo,Nvidia的Riva128,Intel的I740。这个时候3D游戏越来越多,但是当时的应用程序接口标准却有几个,主要的三个分别是专业的OpenGL接口,微软的D3D接口和3DFX的Glide接口。其中影响力最大的是3DFX的Glide,3DFX如日中天,Glide当然是大树底下好乘凉,游戏程序员使用它可以轻松容易的编出复杂、生动的3D效果,看好3DFX当然看好Glide。可是3DFX的自我封闭,不开放政策,导致它后来的破产被Nvidia收购,没有了3DFX支持Glide的影响力也从此走向衰弱,这是后话了。

DirectX 5.0:D3D日益强大

微软似乎没有发布4.0版本的DirectX,DirectX3.0发布后没多久发布了DirectX5.0。尽管5.0与3.0时间间隔不长,但它的意义可不简单。DirectX5.0的D3D效果可以与当时的OpenGL平分秋色。首次引入了雾化的支持,让3D游戏更有空间真实感,更能让玩家体验到真实的三维三维游戏环境;除此以外在游戏系统的兼容性方面作了很大改善。

DirectX 6:D3D权威出现

在DirectX5.0发布不久第二代3D加速卡问世了,这一代3D加速卡借助DirectX6.0的技术争得不可开交。主要代表显卡是Nvidia的Riva TNT,并连的VooDoo2,VooDoo3。到了这个时代,市场格局已经很清晰,是NVidia与3DFX的斗争。DirectX 6的3D效果更多了,而且借助硬件的强大性能,可以渲染出高分辨率下的32位色的3D效果,这一点采用PCI总线技术的VOODOO系列败下阵来,它只能支持800x600下的16位色渲染,而Nvidia一开始就使用先进的AGP总线结构,高规格,新技术,每次发布新品都给用户更高性能的享受,每次成功都为他奠定显卡老大的基础。

DirectX 7:D3D权威确立

DirectX7的发布又一次把显卡市场进行重新整合,DirectX7最大的特色就是支持T&L,中文名称是“坐标转换和光源”。3D游戏中的任何一个物体都有一个坐标,当此物体运动时,它的坐标发生变化,这指的就是坐标转换;3D游戏中除了场景+物体还需要灯光,没有灯光就没有3D物体的表现,无论是实时3D游戏还是3D影像渲染,加上灯光的3D渲染是最消耗资源的。在T&L问世之前,位置转换和灯光都需要CPU来计算,CPU速度越快,游戏表现越流畅。使用了T&L功能后,这两种效果的计算用显示卡的GPU(可以理解为显示卡的CPU)来计算,这样就可以把CPU从繁忙的劳动中解脱出来,让CPU做他该作的事情,比如逻辑运算、数据计算等等。换句话说,拥有T&L显示卡,使用DirectX7,即使没有高速的CPU,同样能能流畅的跑3D游戏。T&L成为当时人们关注的焦点。这时候第一块个支持T&L功能的显示卡是Nvidia的Geforce 256, 随后发布的Geforce

2基本上可以说是Geforce 256的一个提速版本,除了速度快了很多以外,其他没有技术上的提升,同时ATI发布的Radeon7500,一度成为支持T&L功能的效果最好的显示卡。DirectX7的发布却成了VOODOO系列显卡的噩耗,这时候3DFX

也走到了尽头,被Nvidia收购,成为了显示卡中的历史,带给后人的是遗憾和叹息。

DirectX8.0:D3D的疯狂

2001年微软发布了DirectX8,一场显卡革命开始,它首次引入了“像素渲染”概念,同时具备像素渲染引擎(Pixel Shader)与顶点渲染引擎(Vertex

Shader),反映在特效上就是动态光影效果。它发布没多久,Madonion(就是今天的Futuremark)发布了基于DirectX8的3Dmark2001显卡测试软件,它支持DirectX8的全部特效。可是当时华丽的场景,只有极少数显卡才能体验到,绝大部分显卡都不能完成此软件的全部测试,其中的4个场景跑不出来。原因是,DirectX8集成了两大特技――VS (Vertex Shader)和PS(Pixel Shader)。通过vs和ps的渲染,可以很容易的宁造出真实的水面动态波纹光影效果。主要代表显卡是NVIDIA的Geforce 3,后期ATI的Radeon8500。DirectX8的发布成了真正的第4代3D加速卡时代来临的标志。

DirectX9.0 :让人耳目一新

2002年底,微软发布DirectX9.0,如果从参数上看,DirectX9相比DirectX8仅是提高了PS和VS的版本,目前版本都是2.0版本,似乎没有质的变化,其实不然,下面分别对Pixel Shader和Vertex Shader比较。

首先,PS 2.0具备完全可编程的架构,能对纹理效果即时演算、动态纹理贴图,还不占用显存,理论上对材质贴图的分辨率的精度提高无限多;另外PS1.4只能支持28个硬件指令,同时操作6个材质,而PS2.0却可以支持160个硬件指令,同时操作16个材质数量,新的高精度浮点数据规格可以使用多重纹理贴图,可操作的指令数可以任意长,电影级别的显示效果轻而易举的实现。

其次,VS 2.0通过增加Vertex程序的灵活性,显著的提高了老版本(DirectX8)的VS性能,新的控制指令,可以用通用的程序代替以前专用的单独着色程序,效率提高许多倍;增加循环操作指令,减少工作时间,提高处理效率;扩展着色指令个数,从128个提升到256个。

另外,增加对浮点数据的处理功能,以前只能对整数进行处理,这样提高渲染精度,使最终处理的色彩格式达到电影级别。突破了以前限制PC图形图象质量在数学上的精度障碍,它的每条渲染流水线都升级为128位浮点颜色,让游戏程序设计师们更容易更轻松的创造出更漂亮的效果,让程序员编程更容易。

我们从上面的介绍应该都知道了,DirectX对整个多媒体系统的各个方面都有影响,声音、显示等,而且DirectX版本都是兼容的,新的版本兼容以前老的版本。

二 Directdraw7在使用方面与Directdraw的异同

1、DirectDraw7编程基本步骤:

步骤一:初始化一个DirectDraw7对象,和显卡对应。

步骤二:设置屏幕的显示方式和模式。

步骤三:创建主表面和其他表面。

步骤四:把子表面的数据处理后放到主表面上。

2、在使用方面与directdraw的异同:

(1)声明变量

原来是:

LPDIRECTDRAW lpDD; //DirectDraw对象

LPDIRECTDRAWSURFACE lpDDSPrimary ; //DirectDraw主表面

LPDIRECTDRAWSURFACE lpDDSBack ; //后台缓冲表面

DDSURFACEDESC ddsd ; //表面描述

DDSCAPS ddscaps ;

现在是:

LPDIRECTDRAW7 lpDD; //DirectDraw对象

LPDIRECTDRAWSURFACE7 lpDDSPrimary ; //DirectDraw主表面

LPDIRECTDRAWSURFACE7 lpDDSBack ; //后台缓冲表面

DDSURFACEDESC2 ddsd ; //表面描述

DDSCAPS2 ddscaps ;

而且声明完表面描述后应立即用

ZeroMemory( &ddsd, sizeof( ddsd ) );

ZeroMemory( &ddscaps, sizeof( ddscaps ) );

这两个语句使ddsd和ddscaps中的变量都为零,如果不这样做下面的CreateSurface会不成功。

(2)创建idirectdraw对象

原来是:

HRESULT WINAPI DirectDrawCreate(

GUID FAR *lpGUID,

LPDIRECTDRAW FAR *lplpDD,

IUnknown FAR *pUnkOuter

);

现在是:

HRESULT WINAPI DirectDrawCreateEx(

GUID FAR *lpGUID,

LPVOID

*lplpDD,

REFIID

iid,

IUnknown FAR *pUnkOuter

);

其中iid参数必须设置为IID_IDirectDraw7。

如: 创建lpDD的指针时要用

DirectDrawCreateEx(NULL, (void**)&lpDD,IID_IDirectDraw7, NULL);

(注意)IID_IDirectDraw7是IdirectDraw7的GUID接口名称,所以必须在link时有库。而原来只要有即可。

(3)设置显示模式:

不同是在SetDisplayMode函数原来有三个参数,现在有五个,后两个是:

dwRefreshRate

Refresh rate of the new mode. Set this value to 0 to request the default refresh rate for the driver.

大意是:用于设置显示时的刷新频率,(就是65MHZ、75MHZ、85MHZ),如果设为0使用当前默认设置。

dwFlags

Flags describing additional options. Currently, the only valid

flag is DDSDM_STANDARDVGAMODE, which causes the method to set Mode 13 instead of Mode X 320x200x8 mode. If you are setting another resolution, bit depth, or a Mode X mode, do not use this flag and set the parameter to 0.

如:

if ( lpDD->SetDisplayMode(640,480,8,0,0)!=DD_OK)

return FALSE ;

idirectdraw7的不同主要有上面几点,其他的API函数和idirectdraw一样调用,虽然idirectdraw7在显示上比idirectdraw快些,但主要还是看显卡支不支持idirectdraw7,就目前的主流显卡是支持的。

下面是idirectdraw7的简单创建:

#include

#include

#include

//全局变量

LPDIRECTDRAW7 lpDD; //DirectDraw对象

LPDIRECTDRAWSURFACE7 lpDDSPrimary ; //DirectDraw主表面

LPDIRECTDRAWSURFACE7 lpDDSBack ; //后台缓冲表面

HDC hdc ;

char szMsg1[]="DirectDraw程序" ;

char szMsg2[]="退出 请按ESC" ;

BOOL bActive = TRUE ;

HWND hwnd ;

//函数声明

LRESULT CALLBACK WinProc ( HWND hWnd, UINT message, WPARAM wParam, LPARAM

lParam ) ;

BOOL InitWindow ( HINSTANCE hInstance, int nCmdShow ) ;

BOOL InitDDraw ( void ) ; //初始化DirectX

void FreeDDraw ( void ) ; //释放DirectX对象

void MainLoop ( void ) ; //游戏主循环

//-------------------------------------------------------

//函数:WinMain()

//功能:Win32应用程序入口函数.进行初始化工作,处理消息循环

//-------------------------------------------------------

int WINAPI WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPSTR lpCmdLine, int nCmdShow )

{

MSG msg ;

//初始化主窗口

if ( !InitWindow(hInstance,nCmdShow) )

return FALSE ;

//初始化DirectDraw环境,并实现DirectDraw功能

if ( !InitDDraw() ){

MessageBox ( GetActiveWindow(), "初始化DirectDraw过程中出错!",

"Error", MB_OK ) ;

FreeDDraw () ;

DestroyWindow ( GetActiveWindow() ) ;

return FALSE ;

}

while(1){

if ( PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) ){ //如果有消息就处理消息

if ( !GetMessage(&msg, NULL, 0, 0 ) )

return ;

TranslateMessage ( &msg );

DispatchMessage ( &msg );

}

else if(bActive){ //如果程序处于激活状态,进入游戏主循环

MainLoop();

}

//等待消息

else WaitMessage();

}

return ;

}

//--------------------------------------

//函数:InitWindow()

//功能:创建主窗口

//--------------------------------------

static BOOL InitWindow ( HINSTANCE hInstance, int nCmdShow )

{

// HWND hwnd ; //窗口句柄

WNDCLASS wc ; //窗口类结构

//填充窗口类结构

= 0 ;

dProc = WinProc ;

xtra = 0 ;

xtra = 0 ;

nce = hInstance ;

= LoadIcon ( hInstance, IDI_APPLICATION ) ;

r = LoadCursor ( NULL, IDC_ARROW ) ;

kground = (HBRUSH)GetStockObject(BLACK_BRUSH) ;

nuName = NULL ;

assName = "dxHello" ;

//注册窗口类

RegisterClass ( &wc ) ;

//创建主窗口

hwnd = CreateWindowEx ( 0, "dxHello", "", WS_POPUP,

0, 0, GetSystemMetrics(SM_CXSCREEN),

GetSystemMetrics(SM_CYSCREEN),

NULL, NULL, hInstance, NULL ) ;

if ( !hwnd )

return FALSE ;

ShowWindow ( hwnd, nCmdShow ) ;

UpdateWindow ( hwnd ) ;

return TRUE ;

}

//--------------------------------------------------

//函数:WinProc()

//功能:处理主窗口消息

//--------------------------------------------------

LRESULT CALLBACK WinProc ( HWND hWnd, UINT message, WPARAM wParam, LPARAM

lParam )

{

switch ( message ){

case WM_ACTIVATEAPP:

bActive = wParam;

break;

case WM_KEYDOWN: //击键消息

switch ( wParam ){

case VK_ESCAPE:

PostMessage ( hWnd, WM_CLOSE, 0, 0 ) ;

break ;

}

break ;

case WM_SETCURSOR:

SetCursor ( NULL ) ;

return TRUE ;

case WM_DESTROY: //退出消息

FreeDDraw () ;

PostQuitMessage ( 0 ) ;

break ;

}

//调用缺省消息处理过程

return DefWindowProc ( hWnd, message, wParam, lParam ) ;

}

//----------------------------------------------------------------

//函数: InitDDraw()

//功能: 初始化DirectDraw环境并实现其功能.包括:创建DirectDraw对象,

//设置显示模式,创建主表面

//----------------------------------------------------------------

BOOL InitDDraw (void)

{

DDSURFACEDESC2 ddsd ; //表面描述

DDSCAPS2 ddscaps ;

// HDC hdc ; //设备环境句柄

//创建DirectDraw对象

if ( DirectDrawCreateEx(NULL, (void**)&lpDD,IID_IDirectDraw7,

NULL)!=DD_OK )

return FALSE ;

//取得独占和全屏模式

if

( lpDD->SetCooperativeLevel(GetActiveWindow(),DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN)!=DD_OK )

return FALSE ;

//设置显示模式

if ( lpDD->SetDisplayMode(640,480,8,0,0)!=DD_OK)

return FALSE ;

//填充主表面信息

ZeroMemory( &ddsd, sizeof( ddsd ) );

ZeroMemory( &ddscaps, sizeof( ddscaps ) );

= sizeof(ddsd) ;

s = DDSD_CAPS|DDSD_BACKBUFFERCOUNT ;

=

DDSCAPS_PRIMARYSURFACE|DDSCAPS_FLIP|DDSCAPS_COMPLEX ;

BufferCount = 1 ;

//创建主表面对象

if ( lpDD->CreateSurface(&ddsd,&lpDDSPrimary,NULL)!=DD_OK )

return FALSE ;

//提取后台缓存表面指针

= DDSCAPS_BACKBUFFER ;

if ( lpDDSPrimary->GetAttachedSurface ( &ddscaps,

&lpDDSBack )!=DD_OK )

return FALSE ;

return TRUE ;

}

//-------------------------------------------------------

//函数:FreeDDraw()

//功能:释放所有的DirectDraw对象

//-------------------------------------------------------

void FreeDDraw(void)

{

if ( lpDD!=NULL ){

if ( lpDDSPrimary!=NULL ){

lpDDSPrimary->Release() ;

lpDDSPrimary = NULL ;

}

lpDD->Release() ;

lpDD = NULL ;

}

}

//-------------------------------------------------------

//函数:MainLoop()

//功能:游戏主循环

//-------------------------------------------------------

void MainLoop (void)

{

static int i = 0;

//后台缓冲表面上的操作

if ( lpDDSBack->GetDC(&hdc)==DD_OK ){

SetBkColor ( hdc, RGB(0+i,255-i,0+i) ) ;

SetTextColor ( hdc, RGB( 0+i,0+i,255-i) ) ;

TextOut ( hdc, 220, 200, szMsg1, lstrlen(szMsg1) ) ;

TextOut ( hdc, 280, 220, szMsg2, lstrlen(szMsg2) ) ;

lpDDSBack->ReleaseDC (hdc) ;

i+=10 ;

if ( i>255) i=0 ;

}

if (lpDDSPrimary->Flip(NULL,0)!=DD_OK){ //一经Flip,两个表面的指针互换!lpDDSPrimary指向后台表面,所以

FreeDDraw() ; //你就看到刚才在后台表面上写的字了,而lpDDSBack指向了原来的前台主表面

PostQuitMessage(0); //把它掉到后台进行操作

}

}

三 DirectDraw7与DirecrDraw显示速度比较.

下面分别对这两个接口创建相应的主表面,通过对显存连续写20幅1024x768的位图(24位的)。发现DirectDraw7显示20幅大概需要70ms。而DirectDraw则大概需要190ms。而他们之间也是兼容的,也就是说新版本也是支持旧版本的,我们目前用的DirectDraw接口就是旧版本,所以在高版本Direct

x7.0,Direct x8.0/9.0他同样可以被创建并运行。但在性能方面却不如新版本DirectDraw7。下面是两者的分析数据:

(一) DirectDraw:每次显示20幅位图所需要的时间,一共10次。如下图1。

(

图1(DirectDraw)

(二)DirectDraw7:每次显示20幅位图所需要的时间,一共10次。如下图2。

图2(DirectDraw7)

(三)性能分析:

很显然,DirectDraw7的平均每显示20幅是70ms,而DirectDraw的是190ms,DirectDraw7 比DirectDraw大概快1.5倍。

四 从软件上研究显卡的性能对显示效率的影响

这里主要是研究了显存和系统内存的访问速度。当我们创建一个DirectDraw对象时,为了速度有更大的提高我们往往会创建双缓存表面,则带一个后存的主表面,在显示之前我们可以先把数据写到后存表面,等到要显示时通过Flip()或Blt() 等就可以实现,或者创建多个离屏的表面,预先把数据写上在通过Blt()/BltFast()函数拷贝到主表面上。这里就会涉及到两个问题:一,我们把后存表面或离屏表面创建在哪?显存呢?还是系统内存?二,如何把数据写到后存或离屏表面上更快些?下面就两方面分析:

(1)我们把后存表面或离屏表面创建在哪?显存呢?还是系统内存?

结论: 通过实验证实,创建在系统内存使得总的图象显示时间最少。

分析:一般来说,我们的图象数据是放在文件里,当我们解码后数据一般是放在系统内存里,这样一来,如果我们把表面放在系统内存里,那么显然路径短了写的时间就会少些,但此时主表面在显存,而后存在系统内存,他们之间的拷贝时间肯定会比两者都在显存的情况多,而把数据写到显存的路径会远些,时间也会增多,只有实验才知道这两者的快慢。看图3/图4。

图3 SetDisplayMode(1024,768,24);

图4 SetDisplayMode(1024,768,24);

可以看见,每张图片写到系统内存的时间比写到显存的时间少2-3ms,而系统表面到显存表面和显存间两表面的时间可以忽略不计。

(2)如何把数据写到后存或离屏表面上更快些

写数据到表面上,归根结底有两个方法:一个是使用Win32的函数如GetDC;

一个是直接写。因为directX最大的好处就是可以直接写数据到表面上,不用CPU的时间。而直接写有一个个字节写和数据块写,此篇只对一个个字节写做分析。

结论:直接写快。

分析:

使用Win32的函数如GetDC的情况:GetDC获取设备上下文DC(Device

Context),获得了设备上下文后,就可以写表面了。然而,Win32的图象函数是由GDI提供的。GDI是系统的一部分,它提供了抽象层,使得标准的Windows程序可以向表面写数据。

但GDI的缺点是它并不是为高性能的多媒体软件设计的,它主要用于商业软件如字处理和电子表格软件。GDI提供了对系统内存中的视频缓冲区的访问,但不提供对视频内存的访问。尽管GDI对于大多数的商业软件非常合适,但对于多媒体应用程序则显得太慢了。

直接写情况:利用directdraw提供的Lock()函数,可以得到系统分配给表面的内存起始地址,这样我们就可以直接对内存写数据。看图5/6/7/8/9。

图5

图6

图7

图8 利用Win32的函数GetDC

图9

图7是这两种写表面都用到的函数LoadImage();用以得到图象的数据,当然,如果我们的解码卡解码后得到的数据也可以直接写到系统内存的表面去,这样就不用LoadImage()函数了。

注意:如果想把表面创建在系统内存里,那么在表面属性设置时要置dwCaps

= DDSCAPS_SYSTEMMEMORY ; 创建在显存时置dwCaps = DDSCAPS_VIDEOMEMORY。

此外还用到Lock()、Unlock()、GetDC()、ReleaseDC()。

五 DIRECTDRAW接口的现状与前景

就我们开发中心板卡用到的DirectDraw接口,进行现状和前景的浅分析。

当前我们所用到的DirectDraw接口的版本是directx1.0,而DirectX是Microsoft公司为Windows 95及其以上版本平台所提供的一套支持多媒体运行的程序库与应用程序接口的总称。通俗一点说,DirectX就是一种让多媒体设备之间互动的应用编程接口。95年是1.0版本的发布年,随后又有directdraw4,directdraw7是在1999年发布directx7.0才出现的,综观它的发展历程,Microsoft公司在主要是在3D方面上进行开拓,对2D 在directx2.0时就已经得到了完善,这主要是从技术上的角度来说的,图象能不能显示是一个问题,图象显示的速度又是另一个问题。针对速度的问题,我分别用了directdraw和directdraw7做了图象显示速度的实验,具体见《DirectDraw7与DirecrDraw显示速度比较》。实验表明,DirectDraw7在速度显示方面比DirectDraw快将2倍,这说明随这directx版本的升级,硬件上的显卡性能也跟着升级。2002年,微软发布DirectX9.0,目前市场上卖的显卡都支持了directx9.0,面对这样的情况,我们板卡上的directdraw出现了这样的一个问题:显示的兼容性和速度发生了冲突。也就是说,我们的板卡可以在老的显卡上运行,但速度得不到理想的效果。而新显卡运行就的directdraw接口速度劣于directdraw,针对这个问题,我们可以从软件上解决。

先看看directdraw7对象的创建方法:

法一:

LPDIRECTDRAW7 lpdd7=NULL; //说明一个DirectDraw7.0对象。

if(DirectDrawCreateEx(NULL, (void **)&lpdd7, IID_IDirectDraw7,

NULL)!=DD_OK)

return 0;

法二:

LPDIRECTDRAW lpdd=NULL; //申明一个基本的DirectDraw变量。

LPDIRECTDRAW7 lpdd7=NULL; //申明一个DirectDraw7变量。

if(DirectDrawCreate(NULL, &lpdd, NULL)!=DD_OK) //注意,这里用旧的函数

return 0;

if(lpdd->QueryInterface(IID_IDirectDraw7, (void **)&lpdd7)!=DD_OK)

return 0;

else

{

lpdd->Release();

lpdd=NULL;

}

可以看到QueryInterface函数来创建了一个DirectDraw7对象。它同DirectDrawCreateEx函数的区别是,QueryInterface用来申请任何可能的DirectDraw对象,如果你愿意你可以去请求一个DirectDraw4对象。但

DirectDrawCreateEx函数确做不到,因为DirectDrawCreateEx是专门为DirectDraw7量身定做的只有在DirectX7.0中才有这个函数。用QueryInterface函数时,必须先创建一个基本的DirectDraw对象,然后再删除它。你也许会觉得很麻烦,但这么做的好处是一旦创建DirectDraw7失败,你仍然可以继续使用基本的DirectDraw对象。

因此,我们要用法二来创建directdraw7对象,因为对于2D的图象显示,directdraw技术上已经是完善的,对我们板卡的正常运行没什么影响,在可户端,主要你安装了directx7.0及以上,我们的程序就可以运行,对老显卡,如果它支持direct7.0及以上版本,那么图象的显示是通过硬件上实现的;如果它不支持,那么所安装的direct7.0及以上就可以通过软件模拟来实现,这种情况客户和编程人员都不用担心它。