【第1部】シンプルバージョン編
1106.シンプルな三角形の描画(6)
この項から個別のオブジェクトの初期化関数である
GameDevice::LoadAssets()に入ります。
ルートシグネチャー
まず、
ルートシグネチャーというインターフェイスを作成します。
ルートシグネチャー(直訳すればルート署名)は、
シェーダーに何を渡すかを定義します。
シェーダーは以下の種類があります。(
Shader Model 5の場合)
*頂点シェーダ
*ピクセルシェーダ
*ジオメトリシェーダ
*ハルシェーダ
*ドメインシェーダ
*計算シェーダ
これらのシェーダを使って、パイプラインに命令を流す場合、
どのシェーダにどのような方法でどのデータを渡すのかを、細かく定義するのが
ルートシグネチャーと言えます。
ここで
計算シェーダは、描画するためのシェーダではなく
GPUを使った計算をするためのものなので、ちょっとわきに置いておきます。
しかしながら、今回のサンプルでは
シェーダに渡すのはメッシュの情報のみなので、一番シンプルな
ルートシグネチャーを作成します。ですので
ルートシグネチャーに対する細かい説明は、次のサンプル以降になります。
GameDevice::LoadAssets()に記述がある、
ルートシグネチャーの初期化は以下になります。
//一番シンプル
m_rootSignature = RootSignature::CreateSimple();
そしてその内容は以下になります。赤くなっている部分が呼ばれる関数です。
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> CreateSimple() {
CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc;
rootSignatureDesc.Init_1_1(
0,
nullptr,
0,
nullptr,
D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT
);
return CreateDirect(rootSignatureDesc);
}
//中略
}
ここでは
CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC構造体を設定します。この構造体は
D3D12_VERSIONED_ROOT_SIGNATURE_DESC構造体を継承した、ユーティリティクラスです。ライブラリ中の
d3dx12.hに記載されています。
この構造体には
Init_1_1というメンバ関数があり、パラメータは以下です。
inline void Init_1_1(
UINT numParameters, //パラメータの数
_In_reads_opt_(numParameters) const D3D12_ROOT_PARAMETER1* _pParameters, //パラメータのポインタ
UINT numStaticSamplers = 0, //スタティックサンプラーの数
_In_reads_opt_(numStaticSamplers) const D3D12_STATIC_SAMPLER_DESC* _pStaticSamplers = nullptr,
//スタティックサンプラーのポインタ
D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE //フラグ
入力されるパラメータをを見ますと
D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE
だけが、
D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUTになっているのがわかります。
このパラメータは
インプットレイアウトがパイプラインに入力されることを意味します。
この後
CreateSimple()関数は
CreateDirect()関数を呼び出すわけですが、この関数は、他のタイプの
ルートシグネチャ作成と共有する関数です。
ルートシグネチャーはどう作成すべきか
ここでちょっとわき道にそれますが、
ルートシグネチャに関する、MS社のガイドブックには、日本語翻訳として
複数のパイプライン状態オブジェクト (PSO) グループで同じルート署名を共有している状態が理想的です。 パイプラインでルート署名を設定したら、それによって定義されるすべてのバインド (記述子テーブル、記述子、定数) を、バンドルへの継承も含めて個別に設定または変更できます。
アプリでは、必要な記述子テーブルの数と、ルート署名に必要なインライン記述子の数 (より多くのスペースを使用するが間接参照を解消) やインライン定数 (間接参照なし) の数の間で独自にバランスを取ることができます。
アプリケーションでは、ルート署名の使用をできるだけ控えて、ヒープや記述子ヒープなどのアプリケーションが制御するメモリを利用してバルク データを表すようにする必要があります。
という記述があります。
この記述は、非常に重要で、ようは、
ルートシグネチャーはあまりたくさんの種類を作るなということです。
ゲームにおける各オブジェクトの描画方法はまちまちです。3Dのリアルなオブジェクトもあれば、ライフや残り時間を指すインターフェイスもあります。そして、エフェクトもあります。
それらを一括して管理する場合、
リアルな3D用のルートシグネチャー、インターフェイス用のルートシグネチャー、エフェクト用のルートシグネチャーと別に作るのではなく、それらを包括する
ルートシグネチャーを最小限の数だけ作成しなさい、ということです。
ここで、MS社のドキュメントが
一種類しか作るなと言っているわけではありません。
ルート署名の使用をできるだけ控えてというので、ゲーム中に、複数のルートシグネチャーによる描画があってもよいということです。ただその数はあんまり増やさないように、ということです。
ですので、このサンプルでは
一番シンプルなルートシグネチャーを紹介してますが、これを、実際のゲームの一部として使うのは意味がありません。フレームワーク(つまり、複数タイプのゲーム制作に耐えられるエンジン)を作成するためには、もっと
いろんなことが可能なルートシグネチャーを定義する必要があります。
これは
BaseDx12フルバージョンにおける、
ルートシグネチャーにつながります。
BaseDx12フルバージョンは、
2種類のルートシグネチャーしか定義しません。それは
2Dオンリーか
2D3D混在かの2種類です。
しかし
BaseDx12シンプルバージョンでは、ルートシグネチャは
コンテンツ側に置かれます。
BaseDx12シンプルバージョンをベースに
フレームワークを作成するには、
オリジナルなルートシグネチャをいくつか作成してライブラリ化することで、よりオリジナルな表現を実装することが可能です。
ルートシグネチャの説明はこのサンプルではこのくらいにして、次に移ります。