DirectX 12 學習之路(二)

一、COM
COM 組件對象模型(Component Object Model) 微軟的一套軟件組件的二進制接口標準,使得跨編程語言的進程間通信、動態對象創建成爲可能。
https://zh.wikipedia.org/wiki/%E7%BB%84%E4%BB%B6%E5%AF%B9%E8%B1%A1%E6%A8%A1%E5%9E%8B

二、嚴格意義上DX12並不直接與本地窗口系統交互,DX12先渲染到DXGI交換鏈緩衝,然後DXGI再將交換鏈緩衝中的數據呈現到窗口顯示。從Direct3D10開始,由DXGI負責與本地窗口系統交互,Direct3D在DXGI的基礎上構建。

三、SIMD(Single Instruction Multiple Data)單指令多數據寄存器(寬SIMD可有128位),利用一條SIMD指令即可同時對4個32位浮點數或整數進行運算。SSE2(Streaming SIMD Extension 2)SIMD流指令擴展2,還有一個SSE。

四、用DirectXMath庫的XMVECTOR類型來描述向量,這樣就可以在代碼中利用SIMD技術進行高效運算。對於類中的數據成員,要使用XMFLOAT2、XMFLOAT3和XMFLOAT4這些類表示向量,並通過加載和存儲方法令數據在XMVECTOR類型與XMFLOATn類型之間相互轉化。另外,在使用常向量的初始化語法時,應採用XMVECTORF32類型。

五、爲了提高效率,當XMVECTOR類型的值被當作參數傳入函數時,可以直接存入SSE/SSE2寄存器中而不是棧上。要令代碼和平臺無關,我們將使用FXMVECTOR、GXMVECTOR、HXMVECTOR和CXMVECTOR類型來傳遞XMVECTOR參數。傳遞XMVECTOR參數的規則爲:前3個XMVECTOR參數應當用FXMVECTOR,第4個XMVECTOR參數用GXMVECTOR,第5個和第6個XMVECTOR參數使用HXMVECTOR類型,而其餘的XMVECTOR類型參數使用CXMVECTOR類型。

六、XMVECTOR類重載了一些運算符來實現向量的加法、減法和標量乘法。另外,DirectXMath庫還提供了一些實用函數,用於計算向量的模、模平方、兩個向量的點積、兩個向量的叉積及對向量進行規範化處理:
XMVECTOR XM_CALLCONV XMVector3Length(FXMVECTOR V);
XMVECTOR XM_CALLCONV XMVector3LengthSq(FXMVECTOR V);
XMVECTOR XM_CALLCONV XMVector3Dot(FXMVECTOR V1,FXMVECTOR V2);
XMVECTOR XM_CALLCONV XMVector3Cross(FXMVECTOR V1,FXMVECTOR V2);
XMVECTOR XM_CALLCONV XMVector3Normalize(FXMVECTOR V);

七、在比較浮點數時,一定要注意浮點數存在誤差。我們認爲相等的兩個浮點數可能會因此而有細微的差別。例如,已知在數學上規範化向量的長度爲1,但是在計算機程序中的表達上,向量的長度只能接近於1。此外,在數學中,對於任意實數p有1的p冪次方等於1,但是,只能在數值上逼近1時,隨着冪p的增加,所求近似值的誤差也在逐漸增大。數值誤差是可以積累的。

八、一個應用程序不一定要用到模板緩衝區,但一經使用,則深度緩衝區將總是與模板緩衝區如影隨行,共同進退。例如,32爲格式 DXGI_FORMAT_D24_UNORM_S8_UINT ,使用24位作爲深度緩衝區,其他8位作爲模板緩衝區。DXGI_FORMAT_D32_FLOAT_S8X24_UINT,該格式共64位,其中32位是浮點型深度緩衝區,8位(無符號整數)分配給模板緩衝區,剩餘的24位僅用於填充對齊,不作他用。

九、在渲染處理過程中,GPU可能會對資源進行讀(例如,從描述物體表面樣貌的紋理或者存有3D場景中幾何體位置信息的緩衝區中讀取數據)和寫(例如,向後臺緩衝區或深度/模板緩衝區寫入數據)兩種操作。在發出繪製命令之前,我們需要將與本次繪製調用(draw call)相關的資源綁定(bind 或稱 鏈接,link)到渲染流水線上。部分資源可能在每次繪製調用時都會有所變化,所以我們也就要每次按需更新綁定。但是GPU資源並非直接與渲染管線綁定,而是通過一種名爲描述符(descriptor)的對象對它間接引用,我們可以把描述符視爲一種對送往GPU的資源進行描述的輕量級結構。從本質上講,它實際上是一種中間層;若指定了資源描述符,GPU將既獲得實際的資源數據,也能瞭解到資源的必要信息。因此,我們需要把繪製調用需要引用的資源,通過指定描述符的方式綁定到渲染流水線。

十、視圖(view)和描述符(descriptor)是同義詞。例如,常量緩衝區視圖(constant buffer view)和常量緩衝區描述符(constant buffer descriptor)表達的是同一事物。“視圖”雖是Direct3D先前版本里的常用術語,但它仍沿用在Direct3D 12的部分API中。每個描述符都有一種具體類型,此類型指明瞭資源的具體作用。常用的描述符如下:
1.CBV/SRV/UAV描述符分別表示的是常量緩衝區視圖(Constant Buffer View)、着色器資源視圖(Shader Resource View)、無序訪問視圖(Unordered access view)這三種資源。
2.採樣器(Sampler)描述符,表示的是採樣器資源。
3.RTV描述符表示的是渲染目標視圖資源(Render Target View)。
4.DSV描述符表示的是深度/模板視圖資源(Depth/Stencil View)。

十一、超級採樣反走樣技術(Supersampling Anti-Aliasing, SSAA),使用4倍屏幕分辨率大小的後臺緩衝區和深度緩衝區。3D場景將以這種更大的分辨率渲染到後臺緩衝區中。當數據從後臺緩衝區調往屏幕顯示的時候,會將後臺緩衝區按4個像素一組進行解析(resolve,或稱爲降採樣,downsample。把放大的採樣點降低迴原採樣點數):每組用求平均值得方法得到一種相對平滑的像素顏色。因此,超級採樣是通過軟件的方式提升了畫面的分辨率,但是開銷昂貴,因爲它的每個像素的處理數量和佔用的內存大小都增大到了之前的4倍。

十二、多重採樣反走樣技術(Multisampling Anti-Aliasing,MSAA),通過跨子像素共享一些計算信息,從而使它比超級採樣的開銷更低。假設採樣4X多重採樣(即每個像素中都有4個子像素),並同樣使用4倍於屏幕分辨率的後臺緩衝區和深度緩衝區。值得注意的是,這種技術並不需要對每一個子像素都進行計算,而是僅計算一次像素中心處的顏色,再基於可視性(每個子像素經過深度/模板測試的結果)和覆蓋性(子像素的中心在多邊形裏面還是外面)將得到的顏色信息分享給其子像素。

十三、對於超級採樣來說,圖像的顏色要根據每一個子像素來計算,因此每個子像素都可能各具有不同的顏色,而以多重採樣的方式來求取圖像顏色時,每個像素只需計算一次,最後,將得到的顏色數據複製到多邊形覆蓋的所有可見子像素中。

十四、DirectX圖形基礎結構(DirectX Graphics Infrastructure, DXGI,也有譯爲DIrectX圖形基礎設施)是一種與Direct3D配合使用的API。設計DXGI的基本理念是使用多種圖形API中所共有的底層任務能借助一組通用API來進行處理。DXGI的一些常用功能有:交換鏈和頁翻轉功能、切換全屏模式、窗口模式、枚舉顯示適配器、枚舉顯示設備、枚舉所支持的顯示模式(分辨率、刷新率等)等這類圖形系統信息、。

十五、掃描式顯示設備的工作方式有兩種:逐行掃描與隔行掃描。將顯示設備的屏幕劃分爲多個行,稱之爲“場(field)”,奇數行稱爲奇數場(upper field),偶數行稱爲偶數場(lower field)。顧名思義,逐行掃描即在顯示每一幀畫面時都從上至下逐個場連續掃描,但根據人眼的視覺暫留效應,便可每幀僅掃描一種場,交替掃描。

十六、在Direct3D 12中,應用程序通過控制資源在顯存中的去留,主動管理資源的駐留情況(即residency。無論資源是否已位於顯存中,都可對其進行管理,在Direct3D 11中則由系統自動管理)。因爲顯存的空間有限,很可能不足以容下整個遊戲的所有資源,或用戶還有應用程序也在同時使用顯存。這裏給出一條與性能相關的提示:程序應當避免在短時間內於顯存中交換進出相同的資源,這會引起過高的開銷。最理想的情況是,所清除的資源在短時間內不會再次使用。

十七、在調用ID3D12CommandQueue::ExecuteCommandLists方法提交命令列表之前,一定要把命令列表關閉。
// 結束記錄命令
mCommandList->Close();

十八、在調用ID3D12CommandQueue::ExecuteCommandList©方法之後,我們就可以通過ID3D12GraphicsCommandList::Reset方法,安全地複用命令列表C佔用的相關底層內存來記錄新的命令集。Reset方法中的參數對應於ID3D12Device::CreateCommandList方法創建命令列表所用的參數。此方法把命令列表恢復爲剛創建時的初始狀態,我們可以藉此繼續複用其底層內存,也可以避免釋放舊列表再創建新列表這一系列的繁瑣操作。注意,重置命令列表不會影響命令列表中的命令,因爲相關的命令列表分配器仍在維護着其內存中被命令隊列引用的系列命令。

十九、向GPU提交了一整幀的渲染命令後,我們可能還要爲繪製下一幀而複用命令分配器中的內存,ID3D12CommandAllocator::Reset方法應用而生。注意,由於命令隊列可能引用命令分配器中的數據,所以在沒有確定GPU執行完命令分配器中的所有命令之前,千萬不要重置命令分配器。

二十、CPU和GPU間的同步。例子:CPU在t1時間點向命令隊列添加命令存儲物體P的位置信息,CPU在t2時間點向命令隊列添加命令繪製物體P,因爲向命令隊列添加命令不會阻塞CPU,所以CPU會繼續執行後續指令,CPU在t3時間點向命令隊列添加命令更新物體P的位置信息。如果GPU在繪製物體P之前,CPU就率先覆寫物體P的位置信息(t3),則這個行爲會產生錯誤。爲了解決這個問題:強制CPU等待,直到GPU完成所有命令的處理,達到某個指定的圍欄點(fence point)爲止。我們將這種方法稱爲刷新命令列表(flushing the command queue),可以通過圍欄(fence)來實現這一點。
在重置命令分配器之前,先通過刷新命令列表來確定GPU的命令已執行完畢。

二十一、資源轉換。當GPU得寫操作還沒完成或甚至還未開始,卻開始讀取資源,便會導致資源冒險(resource hazard)。爲此,Direct3D專門針對資源設計了一組相關狀態。資源在創建開始會處於默認狀態,該狀態將一直持續到應用程序通過Direct3D將其轉換(transition)爲另外一種狀態爲止。這就使GPU能夠針對資源狀態轉換與防止資源冒險作出適當額行爲。通過命令列表設置轉換資源屏障(transition resource barrier)數組,即可指定資源的轉換。

二十二、命令與多線程。注意問題:
1.每個線程通常都只使用各自的命令列表。
2.每個線程一般都僅使用屬於自己的命令分配器。
3.多線程可以訪問同一命令隊列,也能夠同時調用它的方法。特別是每個線程都能同時向命令隊列提交它們自己所生成的命令列表。
4.出於性能的原因,應用程序必須在初始化期間,指出用於並行記錄命令的命令列表最大數量。

二十三、IID_PPV_ARGS(ppType) 輔助函數的本質是將ppType強制轉換爲void**類型,獲取ppType的COM接口ID(globally unique identifier,全局唯一標識符,GUID)。

二十四、爲了輔助用戶管理COM對象的生命週期,Windows運行時庫(Windows Runtime Library,WRL)專門爲此提供了Microsoft::WRL::ComPtr類(#include <wrl.h>),我們可以把它當作是COM對象的智能指針。當一個ComPtr實例超出作用域範圍時,它會自動調用相應的COM對象的Release方法,省掉了我們手動調用的麻煩。

二十五、初始化Direct3D
1、用D3D12CreateDevice函數創建ID3D12Device接口實例。
2、創建一個ID3D12Fence對象,並查詢描述符的大小。
3、檢測用戶設備對4X MSAA質量級別的支持情況。
4、依次創建命令隊列、命令列表分配器和主命令列表。
5、描述並創建交換鏈。
6、創建應用程序所需的描述符堆。
7、調整後臺緩衝區的大小,併爲它創建渲染目標視圖。
8、創建深度/模板緩衝區及與之關聯的深度/模板視圖。
9、設置視口(viewport)。
10、設置裁剪區域(scissor rectangle)。

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