【第1部】シンプルバージョン編
1202.複数のオブジェクトの描画(2)
前項に引き続き
SimpleSample102の解説です。
GameDevice::LoadAssets()関数
前項では
GameDevice::LoadPipeline()関数を説明しました。
この項では、
GameDevice::LoadAssets()関数を説明します。この関数は、
個別のオブジェクトの準備のような意味合いです。
以下に関数全体を紹介します。
void GameDevice::LoadAssets()
{
// ルートシグネチャー
{
//SrvとSmpとCbv付ルートシグネチャ
m_rootSignature = RootSignature::CreateSrvSmpCbv();
}
// 頂点などのリソース構築用のコマンドリスト
m_commandList = CommandList::CreateSimple(m_commandAllocators[m_frameIndex]);
//シーンに各オブジェクトの構築を任せる
App::GetSceneBase().OnInitAssets();
//コマンドラインクローズおよびキューの実行
CommandList::Close(m_commandList);
CommandList::Excute(m_commandQueue, m_commandList);
//同期オブジェクトおよびGPUの処理待ち
SyncAndWaitForGpu();
}
赤くなっている部分が
SimpleSample101と違うところです。
ルートシグネチャの設定
SrvとSmpとCbv付ルートシグネチャというのは
シェーダリソースビュー、サンプラービュー、そしてコンスタントバッファビューという意味です。
ルートシグネチャは、シェーダーに流すデータの種類と数をあらかじめ定義するものです。
SimpleSample101の場合は
頂点データしか渡さなかったので、シンプルなものでしたが、今回は上記の3種類を渡します。
RootSignature::CreateSrvSmpCbv()関数は以下になります。
namespace RootSignature {
static inline ComPtr<ID3D12RootSignature> CreateDirect(const CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC& desc) {
auto device = App::GetID3D12Device();
D3D12_FEATURE_DATA_ROOT_SIGNATURE featureData = {};
featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1;
if (FAILED(device->CheckFeatureSupport(D3D12_FEATURE_ROOT_SIGNATURE, &featureData, sizeof(featureData))))
{
featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_0;
}
ComPtr<ID3DBlob> signature;
ComPtr<ID3DBlob> error;
ComPtr<ID3D12RootSignature> ret;
ThrowIfFailed(D3DX12SerializeVersionedRootSignature(&desc, featureData.HighestVersion, &signature, &error),
L"ルートシグネチャのシリアライズに失敗しました",
L"D3DX12SerializeVersionedRootSignature(&rootSignatureDesc, featureData.HighestVersion, &signature, &error)",
L"RootSignature::CreateDirect()"
);
ThrowIfFailed(
device->CreateRootSignature(0, signature->GetBufferPointer(),
signature->GetBufferSize(), IID_PPV_ARGS(&ret)),
L"ルートシグネチャの作成に失敗しました",
L"device->CreateRootSignature()",
L"RootSignature::CreateDirect()"
);
return ret;
}
//中略
//シェーダリソースとサンプラーとコンスタントバッファ
static inline ComPtr<ID3D12RootSignature> CreateSrvSmpCbv() {
CD3DX12_DESCRIPTOR_RANGE1 ranges[3];
ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC);
ranges[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 0);
ranges[2].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC);
CD3DX12_ROOT_PARAMETER1 rootParameters[3];
rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_PIXEL);
rootParameters[1].InitAsDescriptorTable(1, &ranges[1], D3D12_SHADER_VISIBILITY_PIXEL);
rootParameters[2].InitAsDescriptorTable(1, &ranges[2], D3D12_SHADER_VISIBILITY_ALL);
CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc;
rootSignatureDesc.Init_1_1(
_countof(rootParameters),
rootParameters,
0,
nullptr,
D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT
);
return CreateDirect(rootSignatureDesc);
}
}
ここでは、どのシェーダーの何番スロットに何を入れるのか、の設定を行います。
まず
デスクプリタレンジですが
CD3DX12_DESCRIPTOR_RANGE1 ranges[3];
ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC);
ranges[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 0);
ranges[2].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC);
のようになっています。ここで
ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC);
というのは、
1つのSRVを0番スロットに、D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATICフラグで設定という意味です。
これによりシェーダでは
t0というテクスチャを使用できます。
同様、サンプラーは
s0、コンスタントバッファは
b0で取得できます。
D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATICというのは、
ルートシグネチャバージョン1.1から導入されたフラグで、
コマンドリストが発行されたあとはディスクプリタヒープに変更がないことを保証するものです。
BaseDx12は
CsvSrvUavは、コマンドリスト発行後は変更しない設計になっているので、このパラメータを使用できます。
このパラメータは、特に
コンスタントバッファについては、高速化につながるようです。
続く
CD3DX12_ROOT_PARAMETER1 rootParameters[3];
rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_PIXEL);
rootParameters[1].InitAsDescriptorTable(1, &ranges[1], D3D12_SHADER_VISIBILITY_PIXEL);
rootParameters[2].InitAsDescriptorTable(1, &ranges[2], D3D12_SHADER_VISIBILITY_ALL);
は、
rangesの内容を、どのシェーダに送るかを設定します。
rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_PIXEL);
というのは
ピクセルシェーダを指し、
rootParameters[2].InitAsDescriptorTable(1, &ranges[2], D3D12_SHADER_VISIBILITY_ALL);
というのは
全てのシェーダを指します。
今回のサンプルでは、
コンスタントバッファはすべてのシェーダ(ここでは頂点とピクセル)で参照できるようにしています。
各オブジェクトの初期化
GameDevice::LoadAssets()関数では、このあと
// 頂点などのリソース構築用のコマンドリスト
m_commandList = CommandList::CreateSimple(m_commandAllocators[m_frameIndex]);
とコマンドリストを構築し、
//シーンに各オブジェクトの構築を任せる
App::GetSceneBase().OnInitAssets();
と
シーンに初期化をまかせます。その内容は次項で説明します。