direct3d---direct11 rendering pipeline

zhulinzhulinlin發表於2020-10-31

Direct3d pre

在寫direct3d程式碼之前,首先需要明白direct3d的特性,首先了解direct3d是基於COM的,其次其渲染管線清楚,再其次對於COM_Ptr要非常熟悉。

COM(Component Object Model)

這是一個比較複雜的概念,簡單來說就是做到binary compatibility,com給我們一個建立介面的標準,並可以在binary level層面進行重用程式碼。
舉個例子,一般的程式碼重用層面是發生在原始檔的,通過設計類等進行重用程式碼,而不同的編譯器編譯出來的二進位制目標結果如dll等是無法重用的,因為不同編譯器的編譯方式可能不同,如某種編譯器把指向虛擬函式標的指標放在儲存物件記憶體的開始,而另一種編譯器則放在最後,則不同編譯器的理解方式不一樣,重用會導致失敗,即我想在當前編譯平臺使用另一個平臺編譯出來的dll會失敗,而COM支援不同編譯器重用dll,具體說到direct3d中來說,就是directX就是一系列的COM物件。
需要知道以下幾件事:
1.com obejct是通過介面進行管理的,而介面可以看作是一系列的函式,如下device是COM obejct,而createrendertargetview函式進行管理它。其實介面本來就是定義了類必須實現的一系列函式規範。

device->CreateRenderTargetView()

如果我們想要使用COM obejct,首先我們向COM factory提出建立COM object的請求,然後其會返回其介面指標,如下指標p,
而p又指向了函式表,所以是呼叫createrendertarget函式
在這裡插入圖片描述
以上圖片連結https://devblogs.microsoft.com/oldnewthing/20040205-00/?p=40733
2.每一個COM物件都有一個ID,一般通過函式__uuid(com object)進行呼叫

COM Ptr

由於上面我們獲得是介面指標,但我們一般是通過create函式返回該介面指標,所有很多地方會用到指標的指標的概念,同時為了更好的維護記憶體,我們會採用智慧指標。即在direct3d中一般用COM ptr的方式來建立指標。
comptr和C++ smart pointer作用類似,都是儲存引用計數來防止記憶體洩漏。有幾個重要的方法如下:
ComPtr::Get() 該方法返回真正的COM物件的介面指標
Comptr::GetAddressOf(),該方法返回COM物件介面指標的指標
ComPtr::Release():該方法將comptr置為NULL
運算子過載 &=Comptr::ReleaseAndGetAddressOf()

Overview of the Graphics Pipeline

圖形的渲染管線是一系列在硬體上執行的階段,我們把資料放入渲染管線開始階段,其最終結果會得到2d影像,同時我們也可從圖形渲染管線的輸出流階段中流出處理過的幾何圖形
在這裡插入圖片描述
有些階段是可以程式設計 ,被稱為著色器,用HLSL語言編寫
圖形渲染管線著色器有,vertex shader,hull shader,domain shader,geometry shader,pixel shader,

Input Assembler (IA) stage

我們需要給IA提供Input layout,則該階段可以知道如何正確讀取頂點資料,然後把資料組成圖元,在把頂點資料組合成圖元的同時,該階段還會把系統生成的值以字串的形式附加到圖元上,比如圖元ID,例項ID,頂點ID,這些值稱為Semantic.在HLSL中必須要指定輸入輸出的語義
下面指定了包含位置資訊的layout

D3D12_INPUT_ELEMENT_DESC layout[] =
{
    { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_PER_VERTEX_DATA, 0 },  
};

Vertex Shader(VS)stage

頂點著色器,每個頂點都會執行一次頂點著色器,通常頂點著色器會進行矩陣變換,光照計算等操作
下面輸入引數後的POSITION表示即為我們指定的layout中的位置資訊,這也是HLSL語義的用法

float4 main(float4 pos : POSITION) : SV_POSITION
{
    return pos;
}

Hull Shader(HS)Stage

可選階段,Tessellation stage包含Hull Shader,Tessellator,Domian stage,它們共同實現了細分,對於之前已經裝配好的圖元進行細分,在GPU上產生新圖元,並不儲存到記憶體中,Hull Stage考慮如何以及在哪裡給圖元增加新頂點
輸入的細節少的圖元被稱作Patches,HS接受input patch,並輸出output patch,關於這些後設資料的patch可以在HS中計算出來

Tessellator (TS) stage

這是個固定階段,接受來自Hull Stage的資料,產生規範化域中的合適型別,比如(四邊形和三角形),傳送資料給Domain Shader

Domain Shader(DS)stage

針對某一規範化的域計算生成真正的頂點座標

Geometry Shader(GS) stage

對已產生的圖元進行操作,刪除或者變成其他圖元型別

Stream output(SO) stage

這個階段是為了從圖形管線中獲取資料,從幾何著色器獲取,如果沒有幾何著色器則從頂點著色器中獲取,獲取的頂點資料會被髮送到若干個vertex buffer,頂點資料會以列表的形式進行傳送,不完整的圖元會被拋棄不會被髮送

Rasterizer Stage(RS)

在執行光柵化之前,會進行視口變換
光柵化階段會確定圖元所覆蓋的片段,並通過插值的方式產生片段的屬性資訊,同時該階段還會執行裁剪操作,

Pixel Shader(PS) stage

對每個片段執行一次,決定螢幕畫素的最終顏色,進行光照或者陰影計算。

Output Merger(OM)stage

這個階段通過接受片段顏色值,depth/stencil buffers,並決定最終那個畫素會被寫入render target中,同時還會進行透明混合,render target是一個二維紋理資源可以被繫結到OM階段的,一旦一個場景被繪製到render target上,我們可以呼叫swap chain的present call來進行顯示結果。

swap chain

這裡的swap chain是一個COM物件
其實簡單來說,swap chain就是控制雙緩衝如何進行交換的,一般來說我們是繪製到back buffer,然後繪製完畢後,和front buffer進行交換,然後顯示到螢幕中,交換的方式可以選擇為交換指標(flip)
這裡首先顯示卡adapter會從front buffer(frame buffer)一行一行掃描以如HDMI形式傳送給LCD顯示,而LCD也是一行一行進行寫入,直到最後一行結尾才進行照亮顯示。一般flip傳送的時間節點在LCD完成當前幀的寫入,即到了最後一行末尾,而轉向第一行開始的時間間隔內

相關文章