初始化 Direct3D 11

总结

介绍如何将 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(&params, 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,
    &params,
    &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 部分:呈现