~プログラミング~ DirectX 11の初期化をしよう その1

C++言語でDirectX 11を使ったアプリケーションを開発してみよう。

まずはDirectXを初期化するところから。

 

DirectX 9の時と比べると、ビデオカードがどの機能に対応しているかというのが「機能レベル」というもので明確にされている事で、細かい部分を気にせず初期化できるという点で楽になっているようです。

機能レベル

Dierect3D 9の時は GetDeviceCapsメソッドを使ってビデオカードの性能をチェックして実行できない機能を確認していました。

 

Direct3D 11では機能レベルという概念があり、このレベル毎にビデオカードがどのような機能を持つかが保証されるようになっています。

 

 

機能レベル毎の使用可能な機能一覧については下記を参照

https://msdn.microsoft.com/ja-jp/library/ee422086(v=vs.85).aspx 

D3D11CreateDeviceAndSwapChainで初期化

D3D11CreateDeviceAndSwapChainメソッドはデバイスの作成とスワップチェーンの作成を1度に行ってくれます。

HRESULT D3D11CreateDeviceAndSwapChain(
  IDXGIAdapter*               pAdapter,           //アダプターのポインタ。NULLだと規定のアダプタ
  D3D_DRIVER_TYPE             DriverType,         //ハードウェアを使うD3D_DRIVER_TYPE_HARDWAREを指定
  HMODULE                     Software,           //DeviceTypeがハードウェアの場合NULL
  UINT                        Flags,              //有効にするランタイムレイヤー
  CONST D3D_FEATURE_LEVEL*    pFeatureLevels,     //作成を試みる機能レベルの順序を指定する配列
  UINT                        FeatureLevels,      //作成を試みる機能レベルの順序を指定する配列の数
  UINT                        SDKVersion,         //D3D11_SDK_VERSIONを指定
  CONST DXGI_SWAP_CHAIN_DESC* pSwapChainDesc,     //スワップチェーンの初期化パラメーター
  IDXGISwapChain**            ppSwapChain,        //作成されるスワップチェーン
  ID3D11Device**              ppDevice,           //作成されるデバイス
  D3D_FEATURE_LEVEL*          pFeatureLevel,      //作成されたデバイスの機能レベル
  ID3D11DeviceContext**       ppImmediateContext  //作成されるデバイスコンテキスト
);

デバイスタイプ(第2引数)

指定できるタイプは D3D_DEVICE_TYPE を参照

最適なパフォーマンスを得るためにはGPUを使う必要があるのでほとんどの場合D3D_DRIVER_TYPE_HARDWAREを指定する事になるかと思います。

有効にするランタイムレイヤー(第4引数)

指定できるタイプは D3D11_CREATE_DEVICE_FLAG を参照

デバッグ中はD3D11_CREATE_DEVICE_DEBUGを有効にしておくと良さそうです。

スワップチェーンの初期化パラメータ(第8引数)

DXGI_SWAP_CHAIN_DESC を参照

指定例は以下のような感じ。

    CRect                rect;
    DXGI_SWAP_CHAIN_DESC scDesc;
        
    ::GetClientRect( hwnd, &rect );
    ::ZeroMemory( &scDesc, sizeof( scDesc ) );                // 構造体を0クリア
    scDesc.BufferCount        = 1;                                // スワップチェーンのバッファ数
    scDesc.BufferDesc.Width   = rect.Width();                     // スワップチェーンのバッファサイズ
    scDesc.BufferDesc.Height  = rect.Height();                    // スワップチェーンのバッファサイズ
    scDesc.BufferDesc.Format  = DXGI_FORMAT_R8G8B8A8_UNORM;       // スワップチェーンのバッファフォーマット
    scDesc.BufferUsage        = DXGI_USAGE_RENDER_TARGET_OUTPUT;  // バッファをレンダーターゲットとして使用
    scDesc.OutputWindow       = hwnd;                             // HWNDハンドル
    scDesc.SampleDesc.Count   = 1;                                // マルチサンプリングのピクセル単位の数
    scDesc.SampleDesc.Quality = 0;                                // マルチサンプリングの品質
    scDesc.Windowed           = TRUE;                             // ウィンドウモード

ImmediateContextとDeferredContext

DirectX11はマルチスレッドに対応しています。

対応はしてるけど、ID3D11DeviceContextをマルチスレッドで利用しようとした場合注意が必要です。

1つのDeviceContextオブジェクトに対して複数のスレッドからアクセスしてはいけません。

 

ID3D11DeviceContextにはImmediateContextDeferredContextの2つのタイプがあり、複数のスレッドから描画命令を行いたい場合2つのタイプを正しく使い分ける必要があります。

ImmediateContext

ImmediateContextは1つしか存在しません。

D3D11CreateDevice等の初期化メソッドで得られるDeviceContextはImmediateタイプです。

ImmediateContextで実行した描画命令は直ちにGPUへ発行されます。

DeferredContext

ID3D11Device::CreateDeferredContextメソッドを使って生成され、ImmediateContextをもつスレッドではない別スレッドから描画命令を実行したい場合に利用します。

DeferredContextで実行した描画命令はコマンドリスト(D3D11CommandList)へ保存され、ImmediateContextからExecuteCommandListを実行してもらう事で描画が開始されます。