懷遠做網(wǎng)站電話溫州seo招聘
在Visutal Studio 2022中完成DirectX設(shè)備初始化
- 1 DirectX12
- 1.1 DirectX 簡介
- 1.2 DirectX SDK安裝
- 2 D3D12初始化
- 2.1 創(chuàng)建Windwos桌面項目
- 2.2 修改符合模式
- 2.3 下載d3dx12.h文件
- 2.4 創(chuàng)建一個異常類D3DException,定義拋出異常實例的宏ThrowIfFailed
- 3 D3D12的初始化步驟
- 3.1 初始化前的準備
- 3.1.1 增加頭文件的引用:
- 3.1.2 引用Direct3D庫文件、IDXGI庫文件
- 3.1.5 增加InitDirect3D函數(shù)
- 3.1.6 啟用D3D12的調(diào)試層
- 3.2 創(chuàng)建Direct3D設(shè)備
- 3.2.1 增加IDXGIFactory和ID3D12Device兩個全局的COM對象智能指針
- 3.2.2 創(chuàng)建一個D3D12設(shè)備
- 3.2.3 如果創(chuàng)建主顯示適配器失敗,使用WARP軟件適配器
- 3.3 創(chuàng)建圍欄
- 3.3.1 增加全局圍欄和描述符變量
- 3.3.2 創(chuàng)建D3D12圍欄
- 3.3.3 我們來了解下資源與描述符
- 3.4 檢測對4X MSAA 質(zhì)量級別的支持
- 3.4.1 增加全局資源數(shù)據(jù)格式和4X MASS質(zhì)量級別變量
- 3.5 檢測支持的D3D最高版本
- 3.6 創(chuàng)建命令隊列和列表
- 3.6.1 增加全局變量
- 3.6.2 創(chuàng)建命令隊列和命令列表
- 3.7 描述并創(chuàng)建交換鏈
- 3.7.1 創(chuàng)建全局變量
- 3.7.2 描述并創(chuàng)建交換鏈
- 3.7.3 處理CPU和GPU的同步
- 3.8 創(chuàng)建描述符堆
- 3.8.1 增加全局變量
- 3.8.2 創(chuàng)建描述符堆
- 3.9 創(chuàng)建渲染目標視圖
- 3.9.1 增加全局變量
- 3.9.2 調(diào)整后臺緩沖區(qū)的大小,并為它創(chuàng)建渲染目標視圖 / 描述符
- 3.9 創(chuàng)建深度/模板緩沖區(qū)及其視圖
- 3.10 設(shè)置視口和裁剪矩形
- 4 完整代碼
- 錯誤:“&”要求左值
- 錯誤:D3D12GetDebugInterface: This method requires the D3D12 SDK Layers for Windows 10, but they are not present on the system.。
1 DirectX12
1.1 DirectX 簡介
DirectX 是 Windows 中的一組組件,允許游戲、軟件直接與視頻和音頻硬件結(jié)合使用。 使用 DirectX的游戲可以更有效地使用內(nèi)置于硬件的多媒體加速器功能,從而改善整體的多媒體體驗。
1.2 DirectX SDK安裝
- 方法1,通過Windows 10 SDK安裝,官網(wǎng)下載最新版本:Windows SDK
- 方法2,通過VS安裝,做為一個開發(fā)人員,我更喜歡這種方式
安裝完成后,我們可以了解下DirectX SDK頭文件目錄和庫文件目錄。
頭文件目錄:
C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\shared
C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\um
庫文件目錄 :
C:\Program Files (x86)\Windows Kits\10\Lib\10.0.19041.0\um\x64
(注意:10.0.19041.0是我電腦上面的版本,大家的可能不一樣)
2 D3D12初始化
有了開發(fā)環(huán)境,我們來完成D3D12初始化。
2.1 創(chuàng)建Windwos桌面項目
我們創(chuàng)建一個Windwos桌面項目,從頭開始學習D3D11的初始化過程。
打開Visutal Studio 2022,選擇菜單:文件->新建->項目,創(chuàng)建新項目。選擇C++類型,輸入 Windows桌面向?qū)?進行篩選,在結(jié)果中選擇“Windows桌面向?qū)А?,點擊下一步。
配置項目名稱和地址,點擊創(chuàng)建
在彈出來的對話框中選擇“桌面應(yīng)用程序(.exe)”,勾選 “空項目”,點擊確定建建一個空的Windwos桌面項目。
我這里沒有勾選“空項目”,主要是偷懶不想寫注冊窗口和消息處理。
2.2 修改符合模式
創(chuàng)建項目后在項目屬性找c/c++,找到語言,找到符合模式選否。不改碰到錯誤時再改也行。
2.3 下載d3dx12.h文件
打開官方github上面的d3dx12.h文件,把里面的代碼拷貝下來。在工程解決方案里創(chuàng)建一個叫DXUtils的文件夾,在這個文件夾下新建一個d3dx12.h文件,把內(nèi)容放在里面。
這個文件里面是官方寫好的一些輔助結(jié)構(gòu)體,不屬于DirectX 12 SDK的核心部分,但是可以通過微軟官方網(wǎng)站下載獲得,方便我們后面開發(fā)。
以CD3DX12作為前綴的結(jié)構(gòu)體全都定義在d3dx12.h頭文件當中。
2.4 創(chuàng)建一個異常類D3DException,定義拋出異常實例的宏ThrowIfFailed
#pragma once#include <windows.h> // Windows 頭文件
#include<string> // 提供wsring類,在Windows平臺上應(yīng)該使用wstring和wchar_t// 定義異常類
class D3DException
{
public:D3DException() = default;// 顯示:異常函數(shù)的返回值、函數(shù)名、代碼所處文件名,所處代碼行數(shù)D3DException(HRESULT hr, const std::wstring& functionName, const std::wstring& filename, int lineNumber){ErrorCode = hr;FunctionName = functionName;Filename = filename;LineNumber = lineNumber;}std::wstring ToString()const;HRESULT ErrorCode = S_OK;std::wstring FunctionName;std::wstring Filename;int LineNumber = -1;
};// AnsiToWString函數(shù)(將字符串映射到 UTF-16 (寬字符) 字符串)
inline std::wstring AnsiToWString(const std::string& str)
{WCHAR buffer[512];MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, buffer, 512);return std::wstring(buffer);
}// 如果發(fā)生異常,拋出一個異常實例
#ifndef ThrowIfFailed
#define ThrowIfFailed(x) \
{ \HRESULT hr__ = (x); \std::wstring wfn = AnsiToWString(__FILE__); \if(FAILED(hr__)) { throw D3DException(hr__, L#x, wfn, __LINE__); } \
}
#endif
3 D3D12的初始化步驟
準備工作做發(fā)了,下面我們就來完成D3D12的初始化
要初始化D3D12,首先需要創(chuàng)建D3D12設(shè)備(ID3D12Device)。我們可以通過該ID3D12Device與硬件進行交互,命令硬件完成一些工作(比如:在顯存中分配資源、清空后臺緩沖區(qū)、將資源綁定到各種管線階段、繪制幾何體)。具體而言:
接口 | 說明 |
---|---|
ID3D12Device | 代表著一個顯示適配器,顯示適配器一般指3D圖形硬件即顯卡。顯示適配器也可以用軟件通過模擬硬件顯卡的計算處理過程來代替,軟件也可以作為適配器(如WARP適配器)。 |
- Direct3D設(shè)備既可以檢測系統(tǒng)環(huán)境對功能的支持情況,又能創(chuàng)建所有其他的Direct3D接口對象(如資源、視圖和命令列表)。
- 創(chuàng)建Direct3D設(shè)備使用函數(shù)D3D12CreateDevice。
現(xiàn)在我們開始在MyD3DApp.cpp中來增加設(shè)備的初始化。
3.1 初始化前的準備
3.1.1 增加頭文件的引用:
#include<wrl.h> // 提供了ComPtr類,它是COM對象的智能指針,使我們無需手動Release
#include<d3d12.h> // Direct3D12頭文件,ID3D12開頭類型始于此
#include<dxgi1_4.h> // DirectX圖形基礎(chǔ)設(shè)施頭文件,IDXGI開頭類型始于此
#include<string> // 提供wsring類,在Windows平臺上應(yīng)該使用wstring和wchar_t
#include<assert.h>
#include "DXUtils/d3dx12.h"
3.1.2 引用Direct3D庫文件、IDXGI庫文件
// 引用Direct3D庫文件
#pragma comment (lib, "d3d12.lib")
// 引用IDXGI庫文件
#pragma comment (lib, "dxgi.lib")
增加使用Windows運行時庫(Windows Runtime Library,WRL)為COM對象提供的COM對象的智能指針Microsoft::WRL::ComPtr類的命名空間。
using namespace Microsoft::WRL; // 方便使用Microsoft::WRL::ComPtr類
3.1.5 增加InitDirect3D函數(shù)
// 初始化Direct3D
bool InitDirect3D()
{
}
除了全局變量,后面的代碼都在InitDirect3D中增加
3.1.6 啟用D3D12的調(diào)試層
#if defined(DEBUG) || defined(_DEBUG) // 如果在Debug模式,啟用D3D12的調(diào)試層,// 啟用調(diào)試后,D3D會在錯誤發(fā)生時向VC++的輸出窗口發(fā)送調(diào)試信息{ComPtr<ID3D12Debug> debugController;ThrowIfFailed(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)));debugController->EnableDebugLayer();}
#endif
3.2 創(chuàng)建Direct3D設(shè)備
3.2.1 增加IDXGIFactory和ID3D12Device兩個全局的COM對象智能指針
// IDXGIFactory: DXGI中最關(guān)鍵的接口之一,可以枚舉顯示適配器
ComPtr<IDXGIFactory4> mdxgiFactory;// ID3D12Device: 代表一個顯示適配器(顯卡)
ComPtr<ID3D12Device> md3dDevice;
- D3D12Device 就是Direct3D中用于提供顯卡控制接口的對象,它代表著當前系統(tǒng)中的顯示適配器。一般來說,它是一個3D圖形硬件(如顯卡), 但是,操作系統(tǒng)在沒有顯卡的時候也能正常的顯示圖像,這時候使用的就是軟件顯示適配器,如(WARP適配器)
- 獲取顯示適配器
顯示適配器是真正實現(xiàn)了圖形處理能力的對象,上面的D3D12Device是對顯示適配器的進一步封裝。
這是我系統(tǒng)中的顯示適配器
那么在程序中我們怎么才能知道使用的是哪個適配器呢,畢竟游戲的使用性能較高的適配較好。 - 我們了解下DXGI的概念。
DXGI是一種與Direct3D配合使用的API,設(shè)計DXGI的基本理念是使得多種圖形API中的底層任務(wù)能夠使用通用的API,比如3D和2D的圖形API在底層都可以使用相同的,比如Direct3D和Direct2D內(nèi)部實現(xiàn)交換鏈時可以使用同一套接口。
我們在獲取系統(tǒng)的可用顯示適配器時,會使用到 IDXGIFactory,主要用于創(chuàng)建SwapChain以及枚舉顯示適配器
后面的代碼會使用IDXGIFactory4來枚舉系統(tǒng)中的顯示適配器
3.2.2 創(chuàng)建一個D3D12設(shè)備
// 創(chuàng)建可用于生成其他 DXGI 對象的 DXGI 1.0 FactoryThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(&mdxgiFactory)));// 創(chuàng)建一個D3D硬件適配器// D3D12CreateDevice參數(shù)為:(適配器指針,應(yīng)用程序所需最低功能級別,所建ID3D12Device接口的COM ID)// 返回所創(chuàng)建的D3D12設(shè)備HRESULT hardwareResult = D3D12CreateDevice(nullptr, // 適配器指針,創(chuàng)建設(shè)備時用的顯示適配器,適配器指針傳入nullptr表示使用主顯示適配器D3D_FEATURE_LEVEL_12_0, // 應(yīng)用程序需要硬件支持的最低功能級別IID_PPV_ARGS(&md3dDevice));// IID_PPV_ARGS是Direct3D為我們提供的一個工具宏,它為我們生成了接口中的后兩個參數(shù)
IID_PPV_ARGS宏會展開為兩項,第一項根據(jù)__uuidof獲取了COM對象的ID(全局唯一標識符,GUID),IID_PPV_ARGS輔助函數(shù)本質(zhì)是把指針強制轉(zhuǎn)換為void類型
3.2.3 如果創(chuàng)建主顯示適配器失敗,使用WARP軟件適配器
// 創(chuàng)建主顯示適配器失敗,使用WARP軟件適配器if (FAILED(hardwareResult)){ComPtr<IDXGIAdapter> pWarpAdapter;ThrowIfFailed(mdxgiFactory->EnumWarpAdapter(IID_PPV_ARGS(&pWarpAdapter)));// 不同windows版本的WARP最高支持的功能級別也不同// 再次創(chuàng)建D3D設(shè)備時,僅適配器指針參數(shù)不同,傳入WARP適配器指針ThrowIfFailed(D3D12CreateDevice(pWarpAdapter.Get(),D3D_FEATURE_LEVEL_12_0,IID_PPV_ARGS(&md3dDevice)));}
3.3 創(chuàng)建圍欄
CPU和GPU的同步需要使用到圍欄,第一步中我們創(chuàng)建好設(shè)備,第二步就可以創(chuàng)建圍欄了。
另外,如果使用描述符進行工作,需要獲取描述符的大小。描述符在不同GPU平臺上的大小不同,因此我們需要將獲取的描述符大小信息緩存起來,方便需要時直接引用。
3.3.1 增加全局圍欄和描述符變量
// ID3D12Fence: 表示圍欄
ComPtr<ID3D12Fence> mFence;// RTV描述符大小,RTV描述符: 渲染目標視圖資源
UINT mRtvDescriptorSize = 0;
// DSV描述符大小,DSV描述符: 深度/模板視圖資源
UINT mDsvDescriptorSize = 0;
// CbvSrvUav描述符大小,CBV描述符: 常量緩沖區(qū)視圖資源...
UINT mCbvSrvUavDescriptorSize = 0;
3.3.2 創(chuàng)建D3D12圍欄
bool CreateD3DFence()
{// 創(chuàng)建圍欄ThrowIfFailed(md3dDevice->CreateFence(0,D3D12_FENCE_FLAG_NONE,IID_PPV_ARGS(&mFence)));// 獲取描述符大小mRtvDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);mDsvDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);mCbvSrvUavDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}
可以看到新出現(xiàn)的四個變量都是通過 md3dDevice 對象獲取到的,這說明:
?1. Direct3D12 設(shè)備對象能創(chuàng)建所有其他的Direct3D接口對象。
?2. COM對象需要使用特定方法或通過其他COM對象的方法獲取。
3.3.3 我們來了解下資源與描述符
- 在渲染過程中,GPU需要對資源進行讀和寫。但是GPU和資源并不是直接綁定的,而是通過一個中間角色 “描述符”來進行綁定的。
- 描述符是一種對送往GPU的資源進行描述的輕量級結(jié)構(gòu),它是一個中間層。當GPU需要對資源進行讀或?qū)憰r,GPU就會問描述符:資源在哪里,我應(yīng)該按照哪種數(shù)據(jù)格式進行讀寫。
- 描述符的作用有兩點:
?1. 指定資源數(shù)據(jù)。
?2. 為GPU解釋資源信息。 - 創(chuàng)建資源時可用無類型格式,如DXGI_FORMAT_R8G8B8A8_TYPELESS類型,它是4個分量組成,每個分量占8個位。如果某個資源在創(chuàng)建時采用了無類型格式,那么在為它創(chuàng)建描述符時必須指明其具體類型。
- 注意:視圖和描述符的含義是等價的。
- 每個描述符都有一種具體類型,用來明確資源的具體作用,常用的描述符如下:
描述符 | 說明 |
---|---|
CBV | 常量緩沖區(qū)視圖 |
SRV | 著色器資源視圖 |
UAV | 無序訪問視圖 |
sampler | 采樣器資源描述符 |
RTV | 渲染目標視圖資源 |
DSV | 深度/模板視圖資源 |
- 描述符堆中存有一系列描述符,本質(zhì)上是存放用戶程序中某特定類型描述符的一塊內(nèi)存。我們需要為每一種類型的描述符創(chuàng)建出單獨的描述符,當然同一種描述符也可以創(chuàng)建多個描述符堆。
- 我們可以用不同的描述符來描述同一個資源,達到以不同的數(shù)據(jù)格式或內(nèi)容部分去讀寫資源的目的。
- 由于創(chuàng)建描述符的過程中需要執(zhí)行一些類型的檢測和驗證工作,最好不要在運行時才創(chuàng)建描述符,創(chuàng)建描述符的最佳時機為初始化期間。
- 當然有時確實需要使用無類型資源所帶來的靈活性,此時在一定限度內(nèi),可以考慮在運行時創(chuàng)建描述符。
3.4 檢測對4X MSAA 質(zhì)量級別的支持
我們要使用4X MSAA,之所以選擇4X,是因為借助此采樣數(shù)量就可以獲取開銷不高但性能非凡的效果。而使用4X MSAA之前,我們要先檢查設(shè)備是否支持4X MSAA 質(zhì)量級別的圖像。
3.4.1 增加全局資源數(shù)據(jù)格式和4X MASS質(zhì)量級別變量
void Check4XMSAA()
{// DXGI_FORMAT: 資源數(shù)據(jù)的格式,一種枚舉類型 DXGI_FORMAT mBackBufferFormat = DXGI_FORMAT_R8G8B8A8_UNORM;// 檢測對4X MASS質(zhì)量級別的支持D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msQualityLevels;msQualityLevels.Format = mBackBufferFormat; // 紋理格式msQualityLevels.SampleCount = 4; // 采樣次數(shù)msQualityLevels.Flags = D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE; // 默認選項msQualityLevels.NumQualityLevels = 0; // 質(zhì)量級別// 使用ID3D12Device::CheckFeatureSupport函數(shù),查詢我們設(shè)置的這種圖像質(zhì)量的級別ThrowIfFailed(md3dDevice->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS