初始化 Direct3D 11
总结
- 第 1 部分:初始化 Direct3D 11
- 第 2 部分:转换呈现框架
- 第 3 部分:移植游戏循环
介绍如何将 Direct3D 9 初始化代码转换为 Direct3D 11,包括如何获取 Direct3D 设备和设备上下文的句柄以及如何使用 DXGI 设置交换链。 将简单的 Direct3D 9 应用移植到 DirectX 11 和 通用 Windows 平台 (UWP) 演练的第 1 部分。
初始化 Direct3D 设备
在 Direct3D 9 中,我们通过调用 IDirect3D9::CreateDevice 创建了 Direct3D 设备的句柄。 我们从获取指向 IDirect3D9 接口 的指针开始,并指定了多个参数来控制 Direct3D 设备和交换链的配置。 在执行此操作之前,我们调用 GetDeviceCaps ,以确保我们没有要求设备执行它无法执行的操作。
Direct3D 9
UINT32 AdapterOrdinal = 0;
D3DDEVTYPE DeviceType = D3DDEVTYPE_HAL;
D3DCAPS9 caps;
m_pD3D->GetDeviceCaps(AdapterOrdinal, DeviceType, &caps); // caps bits
D3DPRESENT_PARAMETERS params;
ZeroMemory(¶ms, sizeof(D3DPRESENT_PARAMETERS));
// Swap chain parameters:
params.hDeviceWindow = m_hWnd;
params.AutoDepthStencilFormat = D3DFMT_D24X8;
params.BackBufferFormat = D3DFMT_X8R8G8B8;
params.MultiSampleQuality = D3DMULTISAMPLE_NONE;
params.MultiSampleType = D3DMULTISAMPLE_NONE;
params.SwapEffect = D3DSWAPEFFECT_DISCARD;
params.Windowed = true;
params.PresentationInterval = 0;
params.BackBufferCount = 2;
params.BackBufferWidth = 0;
params.BackBufferHeight = 0;
params.EnableAutoDepthStencil = true;
params.Flags = 2;
m_pD3D->CreateDevice(
0,
D3DDEVTYPE_HAL,
m_hWnd,
64,
¶ms,
&m_pd3dDevice
);
在 Direct3D 11 中,设备上下文和图形基础结构被视为独立于设备本身。 初始化分为多个步骤。
首先创建设备。 我们获取设备支持的功能级别列表 - 这告知我们需要了解的 GPU 的大部分内容。 此外,我们不需要创建接口即可访问 Direct3D。 而是使用 D3D11CreateDevice 核心 API。 这样,我们便能够处理设备和设备的即时上下文。 设备上下文用于设置管道状态并生成呈现命令。
创建 Direct3D 11 设备和上下文后,我们可以利用 COM 指针功能来获取最新版本的接口,其中包括其他功能,并且始终推荐使用。
注意 D3D_FEATURE_LEVEL_9_1(对应于着色器模型 2.0)是 Microsoft Store 游戏需要支持的最低级别。 (如果你不支持 9_1,游戏的 Arm 包将失败认证。如果你的游戏还包括着色器模型 3 功能的呈现路径,则应在数组中包含D3D_FEATURE_LEVEL_9_3。
Direct3D 11
// This flag adds support for surfaces with a different color channel
// ordering than the API default. It is required for compatibility with
// Direct2D.
UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
#if defined(_DEBUG)
// If the project is in a debug build, enable debugging via SDK Layers.
creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
// This example only uses feature level 9.1.
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_9_1
};
// Create the Direct3D 11 API device object and a corresponding context.
ComPtr<ID3D11Device> device;
ComPtr<ID3D11DeviceContext> context;
D3D11CreateDevice(
nullptr, // Specify nullptr to use the default adapter.
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
creationFlags,
featureLevels,
ARRAYSIZE(featureLevels),
D3D11_SDK_VERSION, // UWP apps must set this to D3D11_SDK_VERSION.
&device, // Returns the Direct3D device created.
nullptr,
&context // Returns the device immediate context.
);
// Store pointers to the Direct3D 11.2 API device and immediate context.
device.As(&m_d3dDevice);
context.As(&m_d3dContext);
创建交换链
Direct3D 11 包括名为 DirectX 图形基础结构(DXGI)的设备 API。 DXGI 接口允许我们(例如)控制交换链的配置和设置共享设备的方式。 在初始化 Direct3D 的此步骤中,我们将使用 DXGI 创建交换链。 由于我们创建了设备,因此我们可以按照接口链返回到 DXGI 适配器。
Direct3D 设备实现 DXGI 的 COM 接口。 首先,我们需要获取该接口,并使用它来请求托管设备的 DXGI 适配器。 然后使用 DXGI 适配器创建 DXGI 工厂。
请注意 ,这些是 COM 接口,因此你的第一个响应可能是使用 QueryInterface。 应改用 Microsoft::WRL::ComPtr 智能指针。 然后,只需调用 As() 方法,即可提供正确接口类型的空 COM 指针。
Direct3D 11
ComPtr<IDXGIDevice2> dxgiDevice;
m_d3dDevice.As(&dxgiDevice);
// Then, the adapter hosting the device;
ComPtr<IDXGIAdapter> dxgiAdapter;
dxgiDevice->GetAdapter(&dxgiAdapter);
// Then, the factory that created the adapter interface:
ComPtr<IDXGIFactory2> dxgiFactory;
dxgiAdapter->GetParent(
__uuidof(IDXGIFactory2),
&dxgiFactory
);
有了 DXGI 工厂后,就可以使用它来创建交换链。 让我们定义交换链参数。 我们需要指定表面格式;我们将选择 DXGI_FORMAT_B8G8R8A8_UNORM,因为它与 Direct2D 兼容。 我们将关闭显示缩放、多重采样和立体声渲染,因为它们未在此示例中使用。 由于我们直接在 CoreWindow 中运行,因此可以将宽度和高度设置为 0 并自动获取全屏值。
注意 对于 UWP 应用,始终将 SDKVersion 参数设置为 D3D11_SDK_VERSION。
Direct3D 11
ComPtr<IDXGISwapChain1> swapChain;
dxgiFactory->CreateSwapChainForCoreWindow(
m_d3dDevice.Get(),
reinterpret_cast<IUnknown*>(window),
&swapChainDesc,
nullptr,
&swapChain
);
swapChain.As(&m_swapChain);
为确保我们的渲染频率不会超过屏幕实际显示的频率,我们将帧延迟设置为 1 并使用 DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL。 这可以节省电源,是存储认证要求;本演练的第 2 部分将详细介绍如何演示到屏幕。
请注意 ,当呈现线程被阻止时, 可以使用多线程(例如 ThreadPool 工作项)继续其他工作。
Direct3D 11
dxgiDevice->SetMaximumFrameLatency(1);
现在,我们可以设置用于呈现的后台缓冲区。
将后台缓冲区配置为呈现目标
首先,我们必须获取后台缓冲区的句柄。 (请注意,后端缓冲区由 DXGI 交换链拥有,而在 DirectX 9 中,它由 Direct3D 设备拥有。然后,我们告知 Direct3D 设备使用它作为呈现目标,方法是使用后台缓冲区创建呈现目标 视图 。
Direct3D 11
ComPtr<ID3D11Texture2D> backBuffer;
m_swapChain->GetBuffer(
0,
__uuidof(ID3D11Texture2D),
&backBuffer
);
// Create a render target view on the back buffer.
m_d3dDevice->CreateRenderTargetView(
backBuffer.Get(),
nullptr,
&m_renderTargetView
);
现在设备上下文将发挥作用。 我们告知 Direct3D 使用设备上下文接口使用新创建的呈现目标视图。 我们将检索后退缓冲区的宽度和高度,以便我们可以将整个窗口作为视区的目标。 请注意,后台缓冲区附加到交换链,因此,如果窗口大小发生更改(例如,用户将游戏窗口拖动到另一个监视器),则需要调整后退缓冲区的大小,并且需要重做某些设置。
Direct3D 11
D3D11_TEXTURE2D_DESC backBufferDesc = {0};
backBuffer->GetDesc(&backBufferDesc);
CD3D11_VIEWPORT viewport(
0.0f,
0.0f,
static_cast<float>(backBufferDesc.Width),
static_cast<float>(backBufferDesc.Height)
);
m_d3dContext->RSSetViewports(1, &viewport);
现在,我们有一个设备句柄和一个全屏呈现目标,现在可以加载和绘制几何图形。 继续执行 第 2 部分:呈现。