Direct3D

     這一章我們首先將描述direct3D的通用的架構,並且討論Direct3D與windows GDI的聯繫,然後再引入Direct3D的一些抽象概念:devices, swap chains , surfaces和resources。 接下來,我們將描述IDirect3D接口,這個接口揭露了系統裏面的圖形devices。   

    當一個圖形應用程序初始化的時候,它首先probe系統裏面的圖形設備,然後再選擇一個合適的設備來滿足應用程序的display需求。這個過程稱作“device enumeration”。IDirect3D使枚舉設備過程非常容易,能夠讓我們檢查出現在系統裏面的設備是否符合我們的需要。

    每一個monitor都是由一個adapter驅動的,它能夠支持很多種顯示模式和刷新率。每個adapterd都擁有運行在windowed 和exclusive模式下的的硬件和軟件設備對象。應用程序列舉出每個adapter上的可用的設備,檢查他們的capability和支持的顯示模式,找到一個合適的設備。當這個設備找到之後,應用程序需要檢查這個設備是否支持render target 格式,resource格式以及multisampling。

   Direct3D能夠枚舉默認adapter上的所有設備或者所有adapters上的所有設備。 多個monitor的系統開始很通用,應用程序能充分利用多個monitor的附加的顯示空間。

 

Direct3D Architecture

     Direct3D是windows系統裏面與GDI相同層級的組件。Direct3D 設備驅動直接與圖形硬件打交到,並且可以直接與顯卡驅動程序通信。Direct3D的抽象概念包括devices, swap chains和resources。 設備封裝了硬件渲染操作方法,設備屬性控制渲染行爲並且提供渲染信息,設備方法用於執行渲染。設備至少包括一個swap chain和多個用於渲染的資源。資源存放在設備硬件裏或者其附近,用於提供圖形渲染所需要的特定數據。Direct3D提供的資源包括場景幾何體(頂點和索引)以及外觀數據(圖片,紋理和volumes)。

     surface也是一種資源,它包含一個矩形集合的像素數據,如color, alpha, depth/stencil以及紋理信息。一個swap chain 包含了一個和多個back buffer surface。設備的render target也是back buffer surface,並且還可能攜帶一個depth/stencil  surface。

     所有的back buffer都是合理的render target,但是並不是所有render target都是back buffer。我們也可以讓一個紋理surface作爲render target,來實現動態的渲染效果。

     爲了獲得設備對象,Direct3D提供了設備枚舉和創建的方法。所有的其他對象就可以由設備來創建。應用程序首先獲取runtime的接口,選擇和創建一個設備。接着使用設備創建其他的資源對象。

 

Windowed and Exclusive mode

 

     Direct3D 設備兩種不同的操作模式:windowed 和exclusive。在windowed下,圖形渲染在桌面窗口的客戶端區域進行。Direct3D 將跟GDI一起工作,使用::stretchBlt方法在windows的客戶端區域present一個back buffer。在Exclusive模式下,Direct3D直接調用顯卡驅動,而並不通過GDI。當一個exclusive模式的應用程序運行的時候,其他應用程序都不可以再訪問顯卡了。

 

Devices Type

 

     每個adapter支持幾種類型的設備。Direct3D支持的三種類型:包括HAL 設備,reference設備以及可插拔的軟件設備。D3DDEVTYPE定義了設備類型。

typedef enum _D3DDEVTYPE

{

      D3DDEVTYPE_HAL = 1,

      D3DDEVTYPE_NULLREF = 4,

      D3DDEVTYPE_REF = 2,

      D3DDEVTYPE_SW = 3
} D3DDEVTYPE;

     HAL(hardware abstraction layer)設備使用了圖形渲染的硬件加速,所以是速度最快的設備類型。reference設備只有在SDK的安裝版本里面纔有,它包括了對整個圖形的pipeline進行軟件實現。這個設備雖然速度很慢,但是它易於圖形應用程序的調試。null referece 設備將什麼都不做,所有的渲染只是一個黑屏。當系統沒有裝SDK,但是應用程序請求一個reference設備的時候,它就返回一個null reference。可插拔的軟件設備通過RegisterDevice設備方法提供,Direct3D 9.0c還沒有可插拔的軟件設備。

 

Resources

 

     每種資源都有Type,Pool, Format和Usage屬性。這些屬性都是在資源創建的時候一次性指定。Type屬性指定了資源的類型,定義在D3DRESOURCETYPE枚舉類型裏面。

typedef enum _D3DRESOURCETYPE

{

      D3DRTYPE_SURFACE = 1,

      D3DRTYPE_VOLUME = 2,

      D3DRTYPE_TEXTURE = 3,

      D3DRTYPE_VOLUMETEXTURE = 4,

      D3DRTYPE_CUBETEXTURE = 5,

      D3DRTYPE_VERTEXBUFFER= 6,

      D3DRTYPE_INDEXBUFFER = 7   

}

 

Pool屬性描述了Direct3D怎麼管理它,定義在D3DPOOL枚舉類型裏面。資源默認是在設備內存裏面的。managed 池裏面資源是在系統內存裏面,當需要使用他的時候它將copy到設備內存裏面。系統內存池的資源只存在於系統內存裏面。scratch池裏面的資源只存在與系統內存裏面,並且它不受設備格式限制。當一個設備lost的時候,它的默認池裏面的資源都會lost。

typedef enum _D3DPOOL

{

D3DPOOL_DEFAULT = 0,

D3DPOOL_MANAGED = 1,

D3DPOOL_SYSTEMMEM=2,

D3DPOOL_SCRATCH = 3

}D3DPOOL;

格式屬性描述了資源在內存裏面的layout,它定義在D3DFORMAT枚舉類型裏面。所有的資源都有一種格式,但是大部分格式枚舉都是像素數據的格式。

typedef enum _D3DFORMAT

{

D3DFMT_UNKNOWN = 0,

D3DFMT_INDEX16 = 101,

D3DFMT_INDEX32 = 102,

D3DFMT_VERTEXDATA = 100,

D3DFMT_A4L4 = 52,

D3DFMT_A8 = 28,

D3DFMT_L8 = 50,

D3DFMT_P8=41,

D3DFMT_R3G3B2 = 27,

D3DFMT_A1R5G5B5 = 25

D3DFMT_A4R4G4B4= 26,

D3DFMT_A8L8 = 51,

D3DFMT_A8P8 = 40,

D3DFMT_A8R3G3B2 = 29,

D3DFMT_L16 = 81,

D3DFMT_L6V5U5= 61,

D3DFMT_R16F = 111,

D3DFMT_R5G6B5 = 23,

D3DFMT_V8U8= 60,

D3DFMT_X1R5G5B5 = 24,

D3DFMT_X4R4G4B4 = 30,

 

D3DFMT_R8G8B8 = 20,

D3DFMT_A2R10G10B10= 35,

D3DFMT_A2W10V10U10= 31,

D3DFMT_A2W10V10U10 = 67,

D3DFMT_A8B8G8R8 = 32,

D3DFMT_A8R8G8B8 = 21,

D3DFMT_CxV8U8 = 117,

D3DFMT_G16R16 = 34,

D3DFMT_Q8W8V8U8 = 63,

D3DFMT_R32F = 114,

D3DFMT_V16U16 = 64,

D3DFMT_W11V11U10 = 65,

D3DFMT_X8L8V8U8 = 62,

D3DFMT_X8B8G8R8 = 33,

D3DFMT_X8R8G8B8=22,

 

D3DFMT_A16B16G16R16= 36,

D3DFMT_A16B16G16R16F = 113,

D3DFMT_G32R32F = 115,

D3DFMT_Q16W16V16U16 = 110,

 

D3DFMT_A32B32G32R32F = 116,

 

D3DFMT_DXT1 = MAKEFOURCC('D','X','T','1');

D3DFMT_DXT2 = MAKEFOURCC('D','X','T','2');

D3DFMT_DXT3 = MAKEFOURCC('D','X','T','3');

D3DFMT_DXT4 = MAKEFOURCC('D','X','T','4');

D3DFMT_DXT5 = MAKEFOURCC('D','X','T','5');

D3DFMT_G8R8_G8B8 = MAKEFOURCC('G','R','G','B');

D3DFMT_R8G8_B8G8 = MAKEFOURCC('R','G','B','G');

D3DFMT_UYVY = MAKEFOURCC('U','Y','V','Y');

D3DFMT_YUY2 =MAKEFOURCC('Y','U','Y','2');

D3DFMT_MULT2_ARGB8 = MAKEFOURCC('M','E','T','1');

D3DFMT_D15S1 = 73,

D3DFMT_D16 = 80,

D3DFMT_D16_LOCKABLE = 70,

D3DFMT_D32F_LOCKABLE = 82,

D3DFMT_D24S8  = 75,

D3DFMT_D24FS8 = 83,

D3DFMT_D24X4S4 = 79,

D3DFMT_D24X8 = 77,

D3DFMT_D32 = 71

}D3DFORMAT;

 

    An,Ln,Bn,Pn,Rn,Gn和Bn都是無符號的,Un,Vn,Wn,Qn是有符號的。Dn和Sn設備指定的depth/stencil surface數據。

   MAKEFOURCC宏用來生成一個四字符碼。附加的vendor指定的格式可以通過MAKEFOURCC定義。DXTn格式是壓縮紋理格式。D3DCOLOR的像素格式是D3DFMT_A8R8G8B8,然而PALETTEENTRY和COLORREF 卻讓R和G互換。

   Usage 包括D3DUSAGE_AUTOGENMIPMAP,D3DUSAGE_DEPTHSTENCIL,D3DUSAGE_DMAP,D3DUSAGE_DONOTCLIP,D3DUSAGE_DYNAMIC,D3DUSAGE_NPATCHES,D3DUSAGE_POINTS,D3DUSAGE_RENDERTARGET,D3DUSAGE_RTPATCHES,D3DUSAGE_SOFTWAREPROCESSING,D3DUSAGE_WRITEONLY。

 

IDirect3D9

    可以通過Direct3D的全局核心函數來獲取IDirect3D9接口。

#define D3DSDK_VERSION 31

IDirect3D9 * WINAPI  ::Direct3DCreate9(UINT sdk_version);

    版本參數必須是D3D_SDK_VERSION。當direct3D頭文件改變時,這個數字將增加。如果傳了錯誤的版本號碼,這個函數將失敗,並且返回NULL。

   IDirect3D提供了一個圖形硬件模型。在這個模型裏,每個monitor都連接一個adapter(它被一個無符號整數所標識)。一個Apdater並不完全與一張顯卡等同,近些年,有些顯卡上可以支持兩個apdater,稱作"dual head" display,IDirect3D9認爲他們是不同的apdaters。

   接口提供了統一的方式檢查連接到系統的所有的適配器,並且選擇最適合的一個來完成渲染任務。

方法和屬性 描述
GetAdapterCount 系統裏面的adpater的數量
GetAdapterDisplayMode 一個adapter的當前video  display mode
GetAdapterIdentifier adapter的標識符
GetAdapterModeCount apdater可支持的video display mode 的數目
GetAdapterMonitor 一個adapter的HMONITOR
GetDeviceCaps 設備通常的capabilities
CheckDepthStencilMatch 檢查設備使用的depth/stencil surface與render target和adpater顯示格式是否匹配
CheckDeviceFormat 檢查設備支持的資源類型和格式
CheckDeviceFormatConversion  
CheckDeviceMultiSampleType 檢查設備是否支持multisample
CheckDeviceType  
EnumAdapterModes 在一個adpater上創建一個設備對象
RegisterSoftwareDevice 註冊一個direct3D的軟件設備

 

選擇一個設備

 

   一般情況下,應用程序列舉所有的設備,然後選擇一個最合適的設備。首先,調用GetAdapterCount 來獲取系統中的adapter的數目,每個adapter有多種顯示模式。每個顯示模式包含screen dimension,refresh rate 和像素格式,Direct3D使用結構體D3DDISPLAYMODE定義。

typedef struct _D3DDISPLAYMODE

{

UINT Width;

UINT   Height;

UINT   RefreshRate;

D3DFORMAT Format;

}D3DDISPLAYMODE;

Format 要麼是RGB格式,要麼是XRGB格式。 back buffer surface格式必須與顯示模式格式兼容。 使用CheckDeviceFormat 發現兼容的格式。一般情況下,back buffer格式與顯示格式有着相同的像素深度和顏色layout。一個XRGB顯示格式能與同樣深度的ARGB back buffer一起使用。GetAdapterModeCount返回apdator支持的顯示模式的數目。EnumAdapterModes返回顯示模式信息。adapter當前使用的顯示模式可以通過GetAdapterDisplayMode取得。 使用一些支持的顯示格式,我們可以查詢支持的設備類型。CheckDeviceType方法告訴我們顯示格式和back buffer格式對一個指定類型的設備是否合理。找到了合適的設備,我們就可以通過GetDeviceCaps來檢查設備的渲染功能。接下來,我們可以使用CheckDeviceFormat更新所有的資源(back buffer surfaces, depth/stencil surfaces,texture surfaces和volume texture 格式)。再接下來,如果應用程序需要做深度可視性檢測,它應該使用CheckDepthStencilMatch發現一個深度buffer。

最後,需要使用multisampling應用程序需要通過CheckDeviceMultisampling來檢測。

注意:CheckDeviceType 用於檢測Adapter允許的顏色Format與與它的某個設備支持的backbuffer顏色格式是否兼容。CheckDeviceFormat用於檢測是否某個adapter的設備支持某種資源格式。

 

Determining Available Resource Memory

 

     當已經找到了一個能滿足應用程序需要的設備後,這個時候,我們要看看設備是否能提供足夠的內存資源滿足應用程序的需要。如果應用程序已經有了指定的內存需求,判斷備是否能夠滿足這個需求的唯一方式是初始化設備,並且嘗試創建必需的資源。

      應用程序可用的內存與當前使用的diplay mode 有關。如果設備申請的video mode與桌面顯示的video mode不一致時,創建一個exclusive模式的設備可能引起不一致顯示模式的變化。爲了避免在應用程序啓動時這種失常的效果,應用程序最好能在安裝的時候執行內存測試,然後保存這個結果。這個操作是安全的,因爲在某種特殊的顯示模式可用內存量不會改變,除非硬件被更換。

 

Device Capabilities

  

     圖形設備一般都有很多architectures ,harware capabilities和performance range。應用程序probe硬件的capablities,然後決定合適的渲染strategy。應用程序可以在某個指定的adapter上調用GetDeviceCaps來獲取它的capabilities。設備capabilities一般使用D3DCAPS9定義的。

 

Identifying a Particular Device

 

    在理想情況下,設備的支持情況和capabilities檢測以後,我們可能就不使用incapable的設備。 但是,現實環境去不這樣。GetAdapterIdentifier允許應用程序識別某個品牌的adapter。GetAdapterIdentifier返回一個D3DADAPTER_IDENTIFIER9的結構體。

    typedef struct _D3DADAPTER_IDENTIFIER9

   {

char  Driver[MAX_DEVICE_IDENTIFIER_STRING];

char  Description[MAX_DEVICE_IDENTIFIER_STRING];

char  DeviceName[32];

#ifdef _WIN32

     LARGE_INTEGER DriverVersion;

#else

     DWORD   DriverVersionLowPart;

     DWORD   DriverVersionHighPart;

#endif

  DWORD   VendorId;

  DWORD   DeviceId;

  DWORD   SubSysId;

  DWORD   Revision;

  GUID      DeviceIdentifier;

  DWORD  WHQLLevel;

  HMONITOR  hMonitor;

   } D3DADAPTER_IDENTIFIER9;

 

  Driver和Description用於圖形界面對設備的選擇。DriverVersion 指示了Direct3D的版本號碼。VendorId, DeviceId,SubSysId,Revision 用來區分不同的硬件芯片。WHQLLEVEL就是這個驅動的WHQL(Windows hardware quality Laboratory) 信息。這個值如果是0表示它沒有過這個認證,如果是1表示過了,但是沒有日期信息。決定WHQL LEVEL是一個很費時的操作,通常一般都是避免做這個操作。將GetAdapterIdentifier的flag參數爲0,就可以避免這個操作。

 

Creating the Device

 

    通過IDirect3D9::CreateDevice(UINT adapter, D3DDEVTYPE device_kind,HWND focus_window, DWORD behavior_flags, D3DPRESENT_PARAMETERS* presentation,IDirect3DDevice8 **result); focus_window 參數表示它將是設備的focus。 對於一個工作在exclusive mode 設備來說,窗口必須是一個top-level窗口。 應用程序不應該在響應WM_CREATE的消息處理函數裏創建設備。 當設備創建後並且在exclusive模式下,Direct3D 應用程序將接收focus 窗口的消息,Direct3D 將subclass這個focus的窗口。MFC 應用程序取得focus窗口句柄是通過函數::AfxGetSafeWindow。

   behavior_flags參數指定了創建設備的全局行爲,這些flag包括D3DCREATE_ADAPTERGROUP_DEVICE,D3DCREATE_DISABLE_DRIVER_MANAGEMENT,D3DCREATE_DISABLE_DRIVER_MANAGEMENT_EX, D3DCREATE_FPU_PRESERVE, D3DCREATE_HARDWARE_VERTEXPROCESSING, D3DCREATE_MIXED_VERTEXPROCESSING, D3DCREATE_MULTITHREADED, D3DCREATE_NOWINDOWCHANGES, D3DCREATE_PUREDEVICE,D3DCREATE_SOFTWARE_VERTEXPROCESSING。

    有些顯卡可以在單張卡上提供多個視頻output。D3DCREATE_ADAPTERGROUP_DEVICE 允許應用程序通過單個設備接口驅動兩個video output,允許資源在兩個output上共享。D3DCREATE_DISABLE_DRIVER_MANAGEMENT和D3DCREATE_DISABLE_DRIVER_MANAGEMENT_EX disable設備資源管理,強迫所有的資源管理髮生在運行時。使用ex 形式當創建資源內存不足的時候會返回錯誤,non-ex形式將不會返回錯誤。

     Direct3D使用單精度浮點計算。如果一個應用程序需要FPU更高的精度,有兩種選擇。或者應用程序保證FPU運行在單精度模式下,或者應用程序在執行浮點運算之前預先保存應用程序的FPU精度,當返回時再恢復FPU。

   pure device flag 讓是被使用最少的內部狀態跟蹤,可以提高應用程序的performance。

   Presentation參數描述了設備顯示在monitor上的渲染參數。presentation的每個成員描述了設備的presentation的行爲,所以在這個函數返回的時候有可能會修改裏面的值,所以presentation必須是可寫的。

   typedef  struct _D3DPRESENT_PARAMETERS_

{

UINT BackBufferWidth;

UINT   BackBufferHeight;

UINT  BackBufferFormat;

UINT  BackBufferCount;

D3DMULTISAMPLE_TYPE MultiSampleType;

DWORD MultiSampleQuality;

D3DSWAPEFFECT SwapEffect;

HWND     hDeviceWindow;

BOOL Windowed;

BOOL EnableAutoDepthStencil;

D3DFORMAT  AutoDepthStencilFormat;

DWORD Flags;

UINT  FullSCreen_RefreshRateInHz;

UINT  PresentationInterval;

}D3DPRESENT_PARAMETERS;

   Flags包含D3DPRESENTFLAG_DEVICECLIP, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, D3DPRESENTFLAG_VIDEO。

   D3DPRESENTFLAG_DEVICECLIP 限制了window模式下客戶端區域present操作的結構,它在WindowXP和Windows 2000下支持。D3DPRESENTFLG_VIDEO flag暗示了back buffer包含有video。D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL 在調用present後discard depth/stencil surface裏面的內容。這樣就使depth/stencil surface是一個可寫的surface。如果depth/stencil surface的格式是D3DFMT_D16_LOCKABLE 或者 D3DFMT_D32_LOCKABLE設置這個標記將會返回一個錯誤。

   在window模式下,hDeviceWindow指定了渲染窗口的句柄。如果hDeviceWindow爲null,則focus窗口將是被渲染的窗口。FullScreen_RefreshRateInHz必須是0。

   在exclusive模式下,hDeviceWindow指定了應用程序使用的top-level窗口。如果系統裏面有多個設備,只有一個設備能使用hDeviceWindow的focus_window。BackBufferWidth, BackBufferHeight, BackBufferFormat必須等於這個適配器的D3DDISPLAYMODE的相關成員。 FullScreen_PresentationInterval指定了presentation rate和屏幕refresh rate期望的關係。FullScreen_RefreshRateInHz是一個很裏的refresh rate 或者是D3DPRESENT_RATE_DEFUALT默認值。D3DPRESENT_RATE_DEFUALT 指示exclusive 模式下runtime選擇一個合適的refresh rate, window模式下使用當前的refresh rate。

 

Multiple Monitors

   

      對於多個monitor的系統來說,虛擬桌面由一個包含了所有參與到windows桌面的adapters的有邊界的矩形組成。其他沒有參與進來的adapters也可以附着在這個系統上面。桌面上所有的adapters至少共享一個像素邊界。

      應用程序可能想要某個monitor的全屏的顯示,GetAdapterMonitor返回一個Adapter的HMonitor句柄。一旦你有這個句柄,你就可以決定虛擬桌面的哪部分被這個moniter佔用。

 

Adapter Group Devices

    多個adapter能從單張卡里面提供多個不同的video output。當使用D3DCREATE_ADAPTERGROUP_DEVICE創建設備時,需要提供一組D3DPRESENT_PARAMETERS。這個數組的數目不能少於D3DCAPS的NumberOfAdaptersInGroup成員。只有一個D3DPRESENT_PARAMETERS 能使用focus窗口作爲它的設備窗口,剩下的必須使用他們自己的top-level窗口作爲設備窗口。無論創建多少個swap chain,只有一個depth/stencil面被創建。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章