BaseDx12(Dx12研究とフレームワーク)

【第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サンプルと同じことをやってるのがわかると思います。
 SwapChainnamespaceとして実装され、ライブラリ側のBasePipeline.hに記述があります。
 BasePipeline.h/cppには、スワップチェーン以外にもDx12リソースを作成する場合に、ユーティリティ的に利用できる、namespaceやクラスがあります。
 もちろんBasePipeline.h/cppの中の関数やクラスを使わなくても、HelloTriangleサンプルと同様の記述をGameDevice::LoadPipeline()内に記述すれば、同じ意味になります。
 つまりBaseDx12シンプルバージョンは、Dx12を使ったGPUのレンダリング処理の手助けをするフレームワークとなっています。ですので、DirectX-Graphics-Samplesのサンプル的な記述も、完全ではないですが、可能な設計になっています。
 対してBaseDx12フルバージョンスワップチェーンDx12デバイスなどが、完全に隠されます。
 直接いじることは、不可能ではありませんが、ちょっと厄介です。ただできないわけではないので、大部分をBaseDx12フルバージョンに処理を任せ、部分的に自作するような処理には適していると思います。
 それでは、次項からDx12リソースの、個別の解説に移りたいと思います。