新建Windows窗口工程
使用VS2019工程創(chuàng)建一個默認的窗口工程。
創(chuàng)建交換鏈和設備及上下文
添加頭文件和依賴庫如下:
#include <d3d11.h>
#pragma comment(lib, "d3d11.lib")
我們要做的第一件事是填寫交換鏈的描述代态。交換鏈是圖形將被繪制到的前后緩沖區(qū)途茫。通常祥楣,您使用單個后臺緩沖區(qū)症革,對其進行所有繪圖罗晕,然后將其交換到前臺緩沖區(qū),然后將其顯示在用戶屏幕上憔儿。這就是為什么它被稱為交換鏈忆植。
交換鏈描述DXGI_SWAP_CHAIN_DESC
D3D11CreateDeviceAndSwapChain創(chuàng)建
HRESULT D3D11CreateDeviceAndSwapChain(
[in, optional] IDXGIAdapter *pAdapter,
D3D_DRIVER_TYPE DriverType,
HMODULE Software,
UINT Flags,
[in, optional] const D3D_FEATURE_LEVEL *pFeatureLevels,
UINT FeatureLevels,
UINT SDKVersion,
[in, optional] const DXGI_SWAP_CHAIN_DESC *pSwapChainDesc,
[out, optional] IDXGISwapChain **ppSwapChain,
[out, optional] ID3D11Device **ppDevice,
[out, optional] D3D_FEATURE_LEVEL *pFeatureLevel,
[out, optional] ID3D11DeviceContext **ppImmediateContext
);
pAdapter
: 指向用來創(chuàng)建設備的顯示適配器的指針。NULL表示使用默認的適配器
DriverType
: 指定驅動類型谒臼,常用的有D3D_DRIVER_TYPE_HARDWARE
朝刊,使用硬件驅動
Software
: 實現(xiàn)軟件光柵器的DLL的句柄。如果DriverType
是D3D_DRIVER_TYPE_SOFTWARE
蜈缤,Software不能為NULL
Flags
: 運行時層標記
pFeatureLevels
:指向D3D特性等級數(shù)組的指針拾氓,如果為NULL,則使用默認的特性等級數(shù)組底哥,默認數(shù)組如下:
{
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_3,
D3D_FEATURE_LEVEL_9_2,
D3D_FEATURE_LEVEL_9_1,
}
FeatureLevel
: pFeatureLevels
中的元素個數(shù)痪枫。
SDKVersion
: SDK版本,使用D3D11_SDK_VERSION
叠艳。
pSwapChainDesc
: 指向交換鏈描述的指針DXGI_SWAP_CHAIN_DESC
交換鏈描述
typedef struct DXGI_SWAP_CHAIN_DESC {
DXGI_MODE_DESC BufferDesc;
DXGI_SAMPLE_DESC SampleDesc;
DXGI_USAGE BufferUsage;
UINT BufferCount;
HWND OutputWindow;
BOOL Windowed;
DXGI_SWAP_EFFECT SwapEffect;
UINT Flags;
} DXGI_SWAP_CHAIN_DESC;
BufferDesc
: 描述后緩沖的顯示模式
SampleDesc
: 描述多重采樣參數(shù)
BufferUsage
: 描述表面的用法和CPU訪問后緩沖的操作奶陈。后緩沖用于著色器輸入或渲染對象輸出
BufferCount
: 緩沖區(qū)個數(shù),包括前緩沖
OutputWindow
: 輸出窗口句柄附较,不能為NULL
Windowed
: true表示窗口模式吃粒,false表示全屏模式
SwapEffect
: 枚舉類型。描述了提交表面后處理緩沖區(qū)內容的可選方法
Flags
: 枚舉類型拒课。描述交換鏈的行為
顯示模式描述
typedef struct DXGI_MODE_DESC {
UINT Width;
UINT Height;
DXGI_RATIONAL RefreshRate;
DXGI_FORMAT Format;
DXGI_MODE_SCANLINE_ORDER ScanlineOrdering;
DXGI_MODE_SCALING Scaling;
} DXGI_MODE_DESC, *LPDXGI_MODE_DESC;
Width
: 分辨率寬
Height
: 分辨率高
RefreshRate
: 結構類型徐勃。描述刷新頻率
Format
: 結構類型。描述顯示模式
ScanlineOrdering
: 枚舉類型早像。描述掃描線繪制模式
Scaling
: 枚舉類型僻肖。描述縮放模式
示例代碼
創(chuàng)建交換鏈及設備的代碼如下:
DXGI_SWAP_CHAIN_DESC swapChainDesc;
ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));
// 設置為單個后臺緩沖區(qū)。
swapChainDesc.BufferCount = 1;
// 設置后臺緩沖區(qū)的寬度和高度卢鹦。
swapChainDesc.BufferDesc.Width = width;
swapChainDesc.BufferDesc.Height = height;
// 為后臺緩沖區(qū)設置常規(guī)的32位表面臀脏。
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
// 設置刷新率,設置讓系統(tǒng)盡快刷新
swapChainDesc.BufferDesc.RefreshRate.Numerator = 0;
swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
// 設置后臺緩沖區(qū)的使用目的
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
// 設置要渲染到的窗口句柄
swapChainDesc.OutputWindow = hwnd;
// 關閉多重采樣冀自。
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
// 設置為窗口模式
swapChainDesc.Windowed = true;
// 將掃描線排序和縮放設置為未指定揉稚。
swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
// 呈現(xiàn)后丟棄后臺緩沖區(qū)內容。
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
// 不要設置高級標志熬粗。
swapChainDesc.Flags = 0;
// 特征級別設置為 11.0搀玖,即 DirectX 11
D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_0;
// 創(chuàng)建交換鏈、設備及上下文
D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, &featureLevel, 1,
D3D11_SDK_VERSION, &swapChainDesc, &m_swapChain, &m_device, NULL, &m_deviceContext);
創(chuàng)建渲染目標
使用交換鏈后臺緩存創(chuàng)建渲染目標驻呐。
ID3D11Texture2D* backBufferPtr;
HRESULT hr = m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&backBufferPtr);
hr = m_device->CreateRenderTargetView(backBufferPtr, NULL, &m_renderTargetView);
backBufferPtr->Release();
渲染
在消息循環(huán)中渲染灌诅,其中消息循環(huán)中取系統(tǒng)消息隊列中的消息需要改用PeekMessage
芳来,如果沒有消息時進行渲染操作。
在每次渲染前可以使用CreateRenderTargetView
猜拾,將渲染目標使用指定的顏色清除其后臺緩沖即舌。
PeekMessage、GetMessage區(qū)別
-
GetMessage
的主要功能是從消息隊列中“取出”消息关带,消息被取出以后,就從消息隊列中將其刪除沼撕;而PeekMessage
的主要功能是“窺視”消息宋雏,如果有消息,就返回true
务豺,否則返回false
磨总。也可以使用PeekMessage
從消息隊列中取出消息,這要用到它的一個參數(shù)(UINT wRemoveMsg)
笼沥,如果設置為PM_REMOVE
蚪燕,消息則被取出并從消息隊列中刪除;如果設置為PM_NOREMOVE
奔浅,消息就不會從消息隊列中取出馆纳。 - 如果
GetMessage
從消息隊列中取不到消息,則線程就會被操作系統(tǒng)掛起汹桦,等到OS重新調度該線程鲁驶,GetMessage
每次都會等待消息,直到取到消息才返回舞骆;而PeekMessage
只是查詢消息隊列钥弯,沒有消息就立即返回,從返回值判斷是否取到了消息督禽。
效果
完整代碼見:使用git log可以查看初始化過程