【第1部】シンプルバージョン編
1102.シンプルな三角形の描画(2)
GameDeviceクラス
さて、前項で
GameDeviceクラスを紹介しました。コンテンツ側にあるクラスで
GameDevice.h/cppに記述があります。
まずコンストラクタですが、以下の記述になっています。
GameDevice::GameDevice(UINT frameCount) :
BaseDevice(frameCount)
{
}
となっています。
frameCountは、前項で出てきた
void Scene::OnInit() {
ResetActiveBaseDevice<GameDevice>(2);
}
の
2です。このサンプルでは
フレーム数は
2個で作成します。
フレーム数というのは
バックバッファの数と考えて差し支えないでしょう。この後、
スワップチェーンや
レンダーターゲットビューそして
コマンドアロケータなどの作成に影響します。
初期化関数である、
GameDevice::OnInit()は
GameDevice.cppにあり、そこには以下の2行が書かれています。
void GameDevice::OnInit()
{
LoadPipeline();
LoadAssets();
}
すなわち
LoadPipeline()と
LoadAssets()という2つのサブ関数を呼び出しています。この書き方は
DirectX-Graphics-Samplesのサンプルに習ったもので
HelloTriangleサンプルも、このようになっています。
以下が
GameDeviceクラスにおける、その内容です。
// パイプラインの準備
void GameDevice::LoadPipeline()
{
//ファクトリ
ComPtr<IDXGIFactory4> factory = Dx12Factory::CreateDirect();
//デバイス
m_device = D3D12Device::CreateDefault(factory, m_useWarpDevice);
//コマンドキュー
m_commandQueue = CommandQueue::CreateDefault();
//スワップチェーン
m_swapChain = SwapChain::CreateDefault(factory,m_commandQueue, m_frameCount);
//フレームインデックスの初期値
m_frameIndex = m_swapChain->GetCurrentBackBufferIndex();
// デスクプリタヒープ
{
// レンダリングターゲットビュー
m_rtvHeap = DescriptorHeap::CreateRtvHeap(m_frameCount);
m_rtvDescriptorHandleIncrementSize
= GetID3D12Device()->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
}
// RTVとコマンドアロケータ
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart());
for (UINT n = 0; n < m_frameCount; n++)
{
ThrowIfFailed(m_swapChain->GetBuffer(n, IID_PPV_ARGS(&m_renderTargets[n])));
m_device->CreateRenderTargetView(m_renderTargets[n].Get(), nullptr, rtvHandle);
rtvHandle.Offset(1, m_rtvDescriptorHandleIncrementSize);
//コマンドアロケータ
m_commandAllocators[n] = CommandAllocator::CreateDefault();
}
}
さて、
HelloTriangleサンプルを手元で開いている人は、違いが判ると思いますが、少し
HelloTriangleサンプルの内容を紹介します。スワップチェーンの作成のところです。
// Describe and create the swap chain.
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
swapChainDesc.BufferCount = FrameCount;
swapChainDesc.Width = m_width;
swapChainDesc.Height = m_height;
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
swapChainDesc.SampleDesc.Count = 1;
ComPtr<IDXGISwapChain1> swapChain;
ThrowIfFailed(factory->CreateSwapChainForHwnd(
m_commandQueue.Get(), // Swap chain needs the queue so that it can force a flush on it.
Win32Application::GetHwnd(),
&swapChainDesc,
nullptr,
nullptr,
&swapChain
));
// This sample does not support fullscreen transitions.
ThrowIfFailed(factory->MakeWindowAssociation(Win32Application::GetHwnd(), DXGI_MWA_NO_ALT_ENTER));
ThrowIfFailed(swapChain.As(&m_swapChain));
これを、
GameDevice.cppでは以下のように記述しています。
//スワップチェーン
m_swapChain = SwapChain::CreateDefault(factory,m_commandQueue, m_frameCount);
このように
かなり省エネで記述が可能になっています。
SwapChain::CreateDefault()を右クリックし、
定義へ移動で、中で何をやってるか確認すると、
HelloTriangleサンプルと同じことをやってるのがわかると思います。
SwapChainは
namespaceとして実装され、ライブラリ側の
BasePipeline.hに記述があります。
BasePipeline.h/cppには、スワップチェーン以外にも
Dx12リソースを作成する場合に、ユーティリティ的に利用できる、namespaceやクラスがあります。
もちろん
BasePipeline.h/cppの中の関数やクラスを使わなくても、
HelloTriangleサンプルと同様の記述を
GameDevice::LoadPipeline()内に記述すれば、同じ意味になります。
つまり
BaseDx12シンプルバージョンは、
Dx12を使ったGPUのレンダリング処理の
手助けをするフレームワークとなっています。ですので、
DirectX-Graphics-Samplesのサンプル的な記述も、完全ではないですが、可能な設計になっています。
対して
BaseDx12フルバージョンは
スワップチェーンや
Dx12デバイスなどが、完全に隠されます。
直接いじることは、不可能ではありませんが、ちょっと厄介です。ただできないわけではないので、大部分を
BaseDx12フルバージョンに処理を任せ、部分的に自作するような処理には適していると思います。
それでは、次項から
Dx12リソースの、個別の解説に移りたいと思います。