【第1部】シンプルバージョン編
1104.シンプルな三角形の描画(4)
では、前項に続きまして
GameDevice::LoadPipeline()関数の中身を解説したいと思います。
コマンドキュー
続いて
コマンドキューを作成します。
Dx12は
コマンドリストという
描画命令をまとめたものを積み上げていって、いくつかのタイミングで
一気に実行します。
その際
コマンドリストを実行するという役割を果たすのが
コマンドキューです。
コマンドキューは、以下のように作成します。
//コマンドキュー
m_commandQueue = CommandQueue::CreateDefault();
この呼び出しは、以下のようなコードになります。
namespace CommandQueue {
static inline ComPtr<ID3D12CommandQueue> CreateDirect(const D3D12_COMMAND_QUEUE_DESC& desc) {
auto device = App::GetID3D12Device();
ComPtr<ID3D12CommandQueue> queue;
ThrowIfFailed(device->CreateCommandQueue(&desc, IID_PPV_ARGS(&queue)));
return queue;
}
static inline ComPtr<ID3D12CommandQueue> CreateDefault() {
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
return CreateDirect(queueDesc);
}
}
このように、まず、赤くなってる
CommandQueue::CreateDefault()が呼び出され、そこから、
CreateDirect()関数を呼び出します。
CreateDirect()関数内では
ThrowIfFailed(device->CreateCommandQueue(&desc, IID_PPV_ARGS(&queue)));
と実行して、
queueを初期化し、そのままリターンします。
コマンドキューも特別なパラメータをつける必要もないでしょう(
DirectX-Graphics-Samplesと同じで良いと思います)。
スワップチェーン
続いて
スワップチェーンです。GPUは
バックバッファに書き込みが終わると、その
バックバッファを
フロントバッファに交換して
プレゼンテーションという処理を行いますが、この処理を行うのが
スワップチェーンです。
バックバッファは、複数設定でき、このサンプルでは2つ使用しますが、それらに対して、
順番に書き込みフロントバッファに移動の処理を、
スワッププチェーンは行います。
スワッププチェーンに渡すパラメータは、3つ、
ファクトリ、コマンドキュー、そして、フレーム数です。
//スワップチェーン
m_swapChain = SwapChain::CreateDefault(factory,m_commandQueue, m_frameCount);
のように初期化します。中で行われている処理は、以下の内容です。
namespace SwapChain {
static inline ComPtr<IDXGISwapChain3>
CreateDirect(
ComPtr<IDXGIFactory4> factory,
const DXGI_SWAP_CHAIN_DESC1& desc,
ComPtr<ID3D12CommandQueue> queue
) {
ComPtr<IDXGISwapChain1> swapChain;
ThrowIfFailed(factory->CreateSwapChainForHwnd(
queue.Get(), // Swap chain needs the queue so that it can force a flush on it.
App::GetHwnd(),
&desc,
nullptr,
nullptr,
&swapChain
));
//Alt+Enterでフルスクリーンにならない
ThrowIfFailed(factory->MakeWindowAssociation(App::GetHwnd(), DXGI_MWA_NO_ALT_ENTER));
ComPtr<IDXGISwapChain3> swapChain3;
ThrowIfFailed(swapChain.As(&swapChain3));
return swapChain3;
}
static inline ComPtr<IDXGISwapChain3>
CreateDefault(ComPtr<IDXGIFactory4> factory,ComPtr<ID3D12CommandQueue> queue,UINT framecount) {
// Describe and create the swap chain.
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
swapChainDesc.BufferCount = framecount;
swapChainDesc.Width = App::GetGameWidth();
swapChainDesc.Height = App::GetGameHeight();
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
swapChainDesc.SampleDesc.Count = 1;
return CreateDirect(factory,swapChainDesc, queue);
}
}
赤くなっているところが、
GameDevice::LoadPipeline()から呼ばれる関数です。
この中では
スワップチェーンを作成するために、まとめておく構造体
DXGI_SWAP_CHAIN_DESC1を定義します。
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
で、内容を0にします。
swapChainDesc.BufferCount = framecount;
は
フレーム数の設定ですね。このサンプルでは
2です
swapChainDesc.Width = App::GetGameWidth();
swapChainDesc.Height = App::GetGameHeight();
は、ウインドウの大きさです。
Appクラスに登録されているので持ってきます。
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
は、RGBA(Red、Green、Blue、Alpha)の、各8ビット正規化整数形式、です。
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
は、スワップチェーンが
レンダーターゲット出力用として使用する設定です。
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
は
プレゼントした後に、バックバッファの内容を破棄するよう設定します。
swapChainDesc.SampleDesc.Count = 1;
ピクセルごとのマルチサンプルの数で、ここでは、
1を指定しています。
ここに出てきてない設定は、
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
で
0に初期化されていますので、
0や
falseふが設定されています。
設定が終わったら、
return CreateDirect(factory,swapChainDesc, queue);
と
CreateDirect()関数を、定義済み構造体を渡して呼び出し、その戻り値を直接返します。
CreateDirect()関数では、まず、ウィンドウのハンドルをもとに
スワップチェーンを作成します。
ComPtr<IDXGISwapChain1> swapChain;
ThrowIfFailed(factory->CreateSwapChainForHwnd(
queue.Get(), // Swap chain needs the queue so that it can force a flush on it.
App::GetHwnd(),
&desc,
nullptr,
nullptr,
&swapChain
));
ただここで作成されるのは
IDXGISwapChain1インターフェイスです。
サンプルで使用するのは
IDXGISwapChain3インターフェイスなので、もう少し作業があります。
まず、
Alt+Enterでフルスクリーンにならないようにします。
DirectXは伝統的に
Alt+Enterでフルスクリーンに切り替えができますが、その機能はできなくします。
ただしその設定は
IDXGISwapChain1インターフェイスを使って設定しますので
//Alt+Enterでフルスクリーンにならない
ThrowIfFailed(factory->MakeWindowAssociation(App::GetHwnd(), DXGI_MWA_NO_ALT_ENTER));
を実行します。こうすると
Alt+Enterでフルスクリーンにならない設定になります。
最後に
ComPtr<IDXGISwapChain3> swapChain3;
ThrowIfFailed(swapChain.As(&swapChain3));
return swapChain3;
と
IDXGISwapChain3インターフェイスにバージョンアップして、それをリターンします。
このようにして
IDXGISwapChain3インターフェイスの作成が終わります。
GameDevice::LoadPipeline()ではこの戻り値を
m_swapChainに代入します。
その後
//フレームインデックスの初期値
m_frameIndex = m_swapChain->GetCurrentBackBufferIndex();
と
フレームのインデックスを設定します。この値は、m_swapChain経由で取得します。
次項では、
デスクプリタヒープの設定をします。
デスクプリタヒープは、
Dx12の中でも、
1,2を争うよくわからないオブジェクトだと思います。
しかし、細かく見ていけば、その存在理由もわかってくると思います。