Direct3D基礎概念和模型整理

damenhanter發表於2016-07-03

 參考整理自文章:

http://zh.wikipedia.org/zh/Direct3D

http://blog.csdn.net/weili_2007/article/details/1907066

 http://msdn.microsoft.com/en-us/library/windows/desktop/bb219679(v=vs.85).aspx#Direct3D_System_Integration

概念主要包括IDirect3D, Adapter, Device, swap chain(surface後臺快取、前臺快取、深度和模板快取),資源(資源型別_D3DRESOURCETYPE、格式_D3DFORMAT、資源存放的記憶體區域Pool、資源的使用標識Usage)。模型就是這些概念形成的Direct3D物件介面模型。

一、圖形模型基礎

1)顯示卡物理組成:

(1)顯示卡的BIOS用於驅動顯示卡.

(2)GPU,

(3)視訊記憶體RAM,

(4)RAMDAC數模轉換器

(5)介面PCI/AGP/TV輸出。

2)圖形資料傳輸模型:

      顯示卡BIOS初始化,資料從磁碟讀取或來自程式內部(CPU&RAM) ->(1)主機板PCI/AGP高階圖形埠輸入->(2)DeviceGPU複雜的數學和幾何運算的圖形渲染管道->(3)視訊記憶體RAM存放GPU運算需要的資料和完成後的資訊(畫素+位置)視訊記憶體低端1GB/2GB高階4GB/6GB->(4)VGA(CRT)/PCIe/ViVo等埠輸出Monitor監視器

Direct3D圖形管道渲染過程:


Direct3D 10 API定義了vertices(頂點), textures(紋理), buffers(緩衝區),以及state群組轉換到螢幕上的流程。這樣的流程被描述成rendering pipeline(渲染流水線),其中有著許多不同的階段. Direct3D 10 渲染流水線的各階段包括:

  1. 輸入組裝(Input Assembler):程式從美術磁碟檔案CPU/系統RAM取得頂點,並將程式提供的資料裝進流水線。
  2. 頂點著色引擎Vertex Shader): 每次處理一個頂點,比如變換、貼圖、光照。
  3. 幾何著色器(Geometry Shader): Shader Model 4.0引進了幾何著色器,使用Shader資源來處理點、線、面的幾何座標變換,一次最多處理六個點,快速地將模型類似的頂點結合起來進行運算。此一過程無需CPU參與。
  4. 流輸出(Stream Output):將Vertex Shader和Pixel Shader處理完成的資料輸出給使用者。
  5. 光柵化(Rasterizer): 把算完的頂點轉成畫素,再將畫素(pixels)輸出給pixel shader. 這裡亦可執行其他工作,像是切割非視錐區域的畫素,或者對頂點進行插值以得到畫素資料。
  6. 畫素著色引擎Pixel Shader):決定最後要往渲染目標(render targe)寫入的畫素顏色,同時也可以計算一個準備寫到深度緩衝區的深度值。
  7. 輸出混合(Output Merger):接收來自於pixel shader的slice,進行傳統的Stencil測試和Depth測試,整合各種不同的輸出資料(顏色和位置),用以建立最後之結果。

    CPU和GPU,記憶體和視訊記憶體的分工,進而提高計算和記憶體使用效率,優化程式的效能:    

    在固定渲染管道中,程式設計的圖形檔案讀取,硬體裝置效能的檢測,由顯示卡介面卡執行型別和後臺快取表面引數等指定的裝置的生成,裝置建立的各種資源貼圖動畫光照,裝置狀態的設定,裝置的轉換操作設定等,會在CPU程式碼中進行非渲染中的計算和對Dircet3D/OPENGL的渲染狀態設定。

    實際在CPU提交渲染後,還需要GPU真正對裁剪,背面消隱,變換,光照等進行計算,紋理畫素深度測試,模板測試,畫素融合,光柵化;視訊記憶體進行儲存,並由顯示卡進行渲染出來。

    所以CPU層面的資源量,運算量也要控制好;GPU各種計算的開啟控制,儘量讓視訊記憶體的命中率高不需要頻繁請求CPU, 這樣才能有比較好的程式圖形計算效能和記憶體開銷。

注:Shader程式設計把更多的計算交付給的GPU處理,可以處理計算量比較大的效果實現,且程式也獲得比較好的效能。


3)渲染管道中的座標轉換:

區域性座標系->世界座標系->觀察座標系

->背面消隱->光照->裁剪

->投影->視口座標系->光柵化。


二、IDirect3D統一介面

IDirect3D物件是支援Direct3D圖形裝置驅動的統一介面,可以用來得到系統的adapter(顯示卡)的硬體及軟體特性

IDirect3D提供了一個圖形硬體模型。在這個模型裡,一個Adapter(它被一個無符號整數所標識)可以建立一個或多個Device, 一個adapter連線一個或多個monitor。

注:一個Apdater並不完全與一張顯示卡等同,近些年,有些顯示卡上可以支援兩個apdater,稱作"dual head" display,IDirect3D9認為他們是不同的apdaters。

 

三、Adapter顯示卡介面卡標識號和列舉Adapter的功能:

Adapter用無符號整數的標識號表示,是顯示卡介面卡(AGP,PCI介面,GPU,視訊記憶體,Monitor)的軟體抽象物件,通過列舉adapter可以獲取指定型別的Device物件(一個adapter可以建立多個Device),及獲取Monitor的特徵

每一個monitor都是由一個adapter驅動的,它能夠支援很多種顯示模式和重新整理頻率,用Adapter ID(需要IDirct3D物件)獲取使用者的硬體特性支援情況的判斷,用於建立特定的Device, 例如:是否支援render target 格式,resource格式以及multisampling。

IDirect3D物件列舉Adapter的功能:

GetAdapterCount()
GetAdapterDisplayMode
GetAdapterIdentifier //得到介面卡描述
CheckDeviceType //判斷指定介面卡上的裝置是否支援硬體加速
GetDeviceCaps //指定裝置的效能,主要判斷是否支援硬體頂點處理(T&L)
GetAdapterModeCount //得到介面卡上指定緩衝格式所有可用的顯示模式
EnumAdapterModes //列舉所有顯示模式
CheckDeviceFormat
CheckDeviceMultiSampleType


建立裝置註意:

Direct3D 裝置兩種不同的操作模式:windowed 和exclusive。

在windowed下,圖形渲染在桌面視窗的客戶端區域進行。Direct3D 將跟GDI一起工作,使用::stretchBlt方法在windows的客戶端區域present一個back buffer。

在Exclusive模式下,Direct3D直接呼叫顯示卡驅動,而並不通過GDI。當一個exclusive模式的應用程式執行的時候,其他應用程式都不可以再訪問顯示卡了。

使用:

1)CheckDeviceFormat :

每個adapter有多種顯示模式。每個顯示模式包含screen dimension,refresh rate 和畫素格式,Direct3D使用結構體D3DDISPLAYMODE定義。

back buffer surface格式必須與顯示模式格式相容, 使用CheckDeviceFormat 發現相容的格式。一般情況下,back buffer格式與顯示格式有著相同的畫素深度和顏色layout。

一個XRGB顯示格式能與同樣深度的ARGB back buffer一起使用。

 

2)GetDeviceCaps:

 找到了合適的裝置,我們就可以通過GetDeviceCaps來檢查裝置的渲染功能。

 

3)CheckDeviceType: 

告訴我們顯示格式和back buffer格式對一個指定型別的裝置是否合理。

 

4)CheckDeviceFormat: 

接下來,我們可以使用CheckDeviceFormat更新所有的資源(back buffer surfaces, depth/stencilsurfaces,texture surfaces和volume texture 格式)。

再接下來,如果應用程式需要做深度可視性檢測,它應該使用CheckDepthStencilMatch發現一個深度buffer。

 

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

注意:CheckDeviceType 用於檢測Adapter允許的顏色Format與與它的某個裝置支援的backbuffer顏色格式是否相容。

CheckDeviceFormat用於檢測是否某個adapter的裝置支援某種資源格式。

 

5)GetAdapterIdentifier:

用於識別某個品牌的adapter。GetAdapterIdentifier返回一個D3DADAPTER_IDENTIFIER9的結構體。

 Driver和Description用於圖形介面對裝置的選擇。DriverVersion 指示了Direct3D的版本號碼。

VendorId, DeviceId,SubSysId,Revision 用來區分不同的硬體晶片。WHQLLEVEL就是這個驅動的WHQL(Windows hardware quality Laboratory) 資訊。

這個值如果是0表示它沒有過這個認證,如果是1表示過了,但是沒有日期資訊。決定WHQL LEVEL是一個很費時的操作,通常一般都是避免做這個操作。

將GetAdapterIdentifier的flag引數為0,就可以避免這個操作。

 

6)CreateDevice:

有些顯示卡可以在單張卡上提供多個視訊output。D3DCREATE_ADAPTERGROUP_DEVICE 允許應用程式通過單個裝置介面驅動兩個video output,允許資源在兩個output上共享。D3DCREATE_DISABLE_DRIVER_MANAGEMENT和D3DCREATE_DISABLE_DRIVER_MANAGEMENT_EXdisable裝置資源管理,強迫所有的資源管理髮生在執行時。使用ex 形式當建立資源記憶體不足的時候會返回錯誤,non-ex形式將不會返回錯誤。

 

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

 

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

 

   Presentation引數描述了裝置顯示在monitor上的渲染引數。presentation的每個成員描述了裝置的presentation的行為,所以在這個函式返回的時候有可能會修改裡面的值,所以presentation必須是可寫的。

 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。

 

7)GetAdapterMonitor:

 

對於多個monitor的系統來說,虛擬桌面由一個包含了所有參與到windows桌面的adapters的有邊界的矩形組成。

其他沒有參與進來的adapters也可以附著在這個系統上面。桌面上所有的adapters至少共享一個畫素邊界。

 

應用程式可能想要某個monitor的全屏的顯示,GetAdapterMonitor返回一個Adapter的HMonitor控制程式碼。

一旦你有這個控制程式碼,你就可以決定虛擬桌面的哪部分被這個moniter佔用。

 

8)NumberOfAdaptersInGroup:

 

多個adapter能從單張卡里面提供多個不同的video output。當使用D3DCREATE_ADAPTERGROUP_DEVICE建立裝置時,需要提供一組D3DPRESENT_PARAMETERS。

這個陣列的數目不能少於D3DCAPS的NumberOfAdaptersInGroup成員。只有一個D3DPRESENT_PARAMETERS 能使用focus視窗作為它的裝置視窗,

剩下的必須使用他們自己的top-level視窗作為裝置視窗。無論建立多少個swap chain,只有一個depth/stencil面被建立。

 

四、Device裝置物件

        Device是通過IDirct3D物件,Adapter的型別D3DDEVTYPE,表面特性D3DPRESENT_PARAMETERS指定的裝置物件(比Adapter具體),Adapter偏硬體,Device更加軟體具體化的"實際裝置物件"。Direct3D提供了裝置列舉和建立的方法。所有的其他物件就可以由裝置來建立。

       Device建立各種資源(CPU/RAM/AGP RAM/ 視訊記憶體),對資源的各種狀態設定和操作(變換\光照\光柵化),新版的D3D11中用Content負責資源的操作
DEVICE則是D3D的核心,它包裝了整個圖形流水管線,包括變換、光照和光柵化(著色),根據D3D版本不同,流水線也有區別,比如最新的D3D10就包含了新的GS幾何處理。因此Device建立和管理swap chains , surfaces和resources,執行轉換各種設定,且負責渲染資料。

Device至少包括一個swap chain和多個用於渲染的resources資源。

HAL(hardware abstraction layer)裝置使用了圖形渲染的硬體加速,所以是速度最快的裝置型別。

reference裝置只有在SDK的安裝版本里面才有,它包括了對整個圖形的pipeline進行軟體實現。這個裝置雖然速度很慢,但是它易於圖形應用程式的除錯。

null referece 裝置將什麼都不做,所有的渲染只是一個黑屏。當系統沒有裝SDK,但是應用程式請求一個reference裝置的時候,它就返回一個null reference。

可插拔的軟體裝置通過RegisterDevice裝置方法提供,Direct3D 9.0c還沒有可插拔的軟體裝置。


Architecturally, Direct3D devices contain a transformation module, a lighting module, and a rasterizing module, as the following diagram shows.



 

五、Swap chain交換鏈和各種surface表面快取

     swap chain和surface也是資源,會在PRESENT_PRAMETERS指定,在CreateDevice時候和Device一起被建立。也可以建立多個後臺快取,形成交換鏈,交換鏈會在Present時候按照佇列挪動的方式進行輪換
     一個swap chain 包含了一個和多個back buffer surface, surface也是一種資源,它包含一個矩形集合的畫素資料,如color, alpha, depth/stencil以及紋理資訊。

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

 

擴充:

DX11:

1.device 作為 “實際物件”, 管理儲存各種資料(當然也負責與 hardwar的溝通), 和硬體互動, 用來建立資源,操作資源。

2.context 更多的是 “提供操作的介面”,device將很多資料操作委託給了context介面,通常用來操作各種快取資料,從而告知 device 進行如何繪圖 how to draw。

3.swapchain 實現了一個或多個的 surface 用來儲存 輸出到輸出裝置output device 之前的各種 “渲染資料”, 做得資料後臺加速,大部分 函式都是 與 buffer的狀態相關。


六、RUNTIME(Device)

Device內部由RUNTIME執行時管理排程Device的各種操作,有重要的命令結構Command Buffer(應該在系統RAM中),實現命名的分發。


七、Driver(GPU)

RUNTIME需要通過Adapter(GPU)的Driver來實現,Driver分為HAL Driver和REF Driver,Driver是硬體顯示卡或硬體顯示卡預定義的驅動和圖形操作指令
翻譯RUNTIME過來的各種Device的命令,進行物理的執行操作,當然Driver也有一個命令結構Driver Buffer(應該在視訊記憶體中)。

 

八、Resource各種資源

resources資源存放在裝置硬體裡或者其附近,用於提供圖形渲染所需要的特定資料

Direct3D提供的資源包括場景幾何體(頂點和索引)以及外觀資料(圖片,紋理和volumes)。

 

每種資源都有Type,Pool, Format和Usage屬性。這些屬性都是在資源建立的時候一次性指定。

1)Type:

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   

 

}

 

2)Pool:

Pool屬性描述了Direct3D怎麼管理它,定義在D3DPOOL列舉型別裡面。

當一個裝置lost的時候,它的預設池裡面的資源都會lost。

typedef enum _D3DPOOL

 

{

 

D3DPOOL_DEFAULT = 0,// 資源預設是在裝置記憶體裡面的。

 

D3DPOOL_MANAGED = 1,// managed 池裡面資源是在系統記憶體裡面,當需要使用他的時候它將copy到裝置記憶體裡面。

 

D3DPOOL_SYSTEMMEM=2,// 系統記憶體池的資源只存在於系統記憶體裡面,CPU RAM。

 

D3DPOOL_SCRATCH = 3 // scratch池裡面的資源只存在與系統記憶體裡面,並且它不受裝置格式限制。

 

}D3DPOOL;

 

注意:

應用程式可用的記憶體與當前使用的diplay mode 有關。如果裝置申請的video mode與桌面顯示的video mode不一致時,

建立一個exclusive模式的裝置可能引起不一致顯示模式的變化。為了避免在應用程式啟動時這種失常的效果,應用程式最好能在安裝的時候執行記憶體測試,然後儲存這個結果。

這個操作是安全的,因為在某種特殊的顯示模式可用記憶體量不會改變,除非硬體被更換。

 

3)Format:

格式屬性描述了資源在記憶體裡面的layout,它定義在D3DFORMAT列舉型別裡面。所有的資源都有一種格式,但是大部分格式列舉都是畫素資料的格式。

typedef enum _D3DFORMAT

 

{

 

D3DFMT_UNKNOWN = 0,

 

D3DFMT_INDEX16 = 101,

 

D3DFMT_INDEX32 = 102,

 

D3DFMT_VERTEXDATA = 100,

 

D3DFMT_A4L4 = 52,

 

D3DFMT_A8 = 28,

...

}

 

 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互換。

 

4)Usage:

標記怎麼樣去使用資源,挪動,壓縮,紋理方式,模板方式;怎麼樣使用會根據不同的資源型別,不同的記憶體存放,會有關聯,所以標記會僅限某種資源型別或某種記憶體型別下使用。

包括D3DUSAGE_AUTOGENMIPMAP,D3DUSAGE_DEPTHSTENCIL,

D3DUSAGE_DMAP,D3DUSAGE_DONOTCLIP,D3DUSAGE_DYNAMIC,D3DUSAGE_NPATCHES,

D3DUSAGE_POINTS,D3DUSAGE_RENDERTARGET,D3DUSAGE_RTPATCHES

,D3DUSAGE_SOFTWAREPROCESSING,D3DUSAGE_WRITEONLY。