共用方式為


初始化 Direct3D 11

摘要

說明如何將 Direct3D 9 初始化程式碼轉換為 Direct3D 11,包括如何取得 Direct3D 裝置和裝置內容的控制代碼,以及如何使用 DXGI 設定交換鏈結。 《將簡單的 Direct3D 9 應用程式移植到 DirectX 11 和通用 Windows 平台 (UWP)》逐步解說的第 1 部分。

初始化 Direct3D 裝置

在 Direct3D 9 中,我們呼叫 IDirect3D9::CreateDevice,以建立 Direct3D 裝置的控制代碼。 我們先取得 IDirect3D9 interface 的指標,然後指定一些參數,用以控制 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 指標功能取得最新版本的介面,其中包括額外功能,且我們建議一律採用。

注意Microsoft Store 遊戲須支援的最低層級為 D3D_FEATURE_LEVEL_9_1 (對應著色器模型 2.0)。 如果遊戲的 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,並自動取得全螢幕值。

注意如果是 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 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 部分:轉譯