新建Windows窗口工程
使用VS2019工程创建一个默认的窗口工程。
创建一个win32应用
创建交换链和设备及上下文
添加头文件和依赖库如下:
#include <d3d11.h>
#pragma comment(lib, "d3d11.lib")
我们要做的第一件事是填写交换链的描述。交换链是图形将被绘制到的前后缓冲区。通常,您使用单个后台缓冲区,对其进行所有绘图,然后将其交换到前台缓冲区,然后将其显示在用户屏幕上。这就是为什么它被称为交换链。
交换链描述DXGI_SWAP_CHAIN_DESC
D3D11CreateDeviceAndSwapChain创建
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
: 指向用来创建设备的显示适配器的指针。NULL表示使用默认的适配器
DriverType
: 指定驱动类型,常用的有D3D_DRIVER_TYPE_HARDWARE
,使用硬件驱动
Software
: 实现软件光栅器的DLL的句柄。如果DriverType
是D3D_DRIVER_TYPE_SOFTWARE
,Software不能为NULL
Flags
: 运行时层标记
pFeatureLevels
:指向D3D特性等级数组的指针,如果为NULL,则使用默认的特性等级数组,默认数组如下:
{
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
中的元素个数。
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
: 描述多重采样参数
BufferUsage
: 描述表面的用法和CPU访问后缓冲的操作。后缓冲用于着色器输入或渲染对象输出
BufferCount
: 缓冲区个数,包括前缓冲
OutputWindow
: 输出窗口句柄,不能为NULL
Windowed
: true表示窗口模式,false表示全屏模式
SwapEffect
: 枚举类型。描述了提交表面后处理缓冲区内容的可选方法
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
: 枚举类型。描述缩放模式
示例代码
创建交换链及设备的代码如下:
DXGI_SWAP_CHAIN_DESC swapChainDesc;
ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));
// 设置为单个后台缓冲区。
swapChainDesc.BufferCount = 1;
// 设置后台缓冲区的宽度和高度。
swapChainDesc.BufferDesc.Width = width;
swapChainDesc.BufferDesc.Height = height;
// 为后台缓冲区设置常规的32位表面。
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
// 设置刷新率,设置让系统尽快刷新
swapChainDesc.BufferDesc.RefreshRate.Numerator = 0;
swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
// 设置后台缓冲区的使用目的
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;
// 呈现后丢弃后台缓冲区内容。
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
// 不要设置高级标志。
swapChainDesc.Flags = 0;
// 特征级别设置为 11.0,即 DirectX 11
D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_0;
// 创建交换链、设备及上下文
D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, &featureLevel, 1,
D3D11_SDK_VERSION, &swapChainDesc, &m_swapChain, &m_device, NULL, &m_deviceContext);
创建渲染目标
使用交换链后台缓存创建渲染目标。
ID3D11Texture2D* backBufferPtr;
HRESULT hr = m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&backBufferPtr);
hr = m_device->CreateRenderTargetView(backBufferPtr, NULL, &m_renderTargetView);
backBufferPtr->Release();
渲染
在消息循环中渲染,其中消息循环中取系统消息队列中的消息需要改用PeekMessage
,如果没有消息时进行渲染操作。
在每次渲染前可以使用CreateRenderTargetView
,将渲染目标使用指定的颜色清除其后台缓冲。
PeekMessage、GetMessage区别
-
GetMessage
的主要功能是从消息队列中“取出”消息,消息被取出以后,就从消息队列中将其删除;而PeekMessage
的主要功能是“窥视”消息,如果有消息,就返回true
,否则返回false
。也可以使用PeekMessage
从消息队列中取出消息,这要用到它的一个参数(UINT wRemoveMsg)
,如果设置为PM_REMOVE
,消息则被取出并从消息队列中删除;如果设置为PM_NOREMOVE
,消息就不会从消息队列中取出。 - 如果
GetMessage
从消息队列中取不到消息,则线程就会被操作系统挂起,等到OS重新调度该线程,GetMessage
每次都会等待消息,直到取到消息才返回;而PeekMessage
只是查询消息队列,没有消息就立即返回,从返回值判断是否取到了消息。
效果
image.png完整代码见:使用git log可以查看初始化过程
网友评论