總結
- 第 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 市集遊戲所需支援的最低層級。 (如果您的遊戲的 Arm 套件不支援 9_1,則認證將會失敗。)如果您的遊戲也包含支援著色器模型 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,並自動取得全螢幕值。
注意 務必將 SDKVersion 參數設定為 D3D11_SDK_VERSION,適用於 UWP 應用程式。
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 部分:渲染。