はこねのはこ

はこねさんの備忘録

DirectX12の魔導書 Chapter8 (8.3シェーダーへの転送と表示に関してのメモ)

はじめに

8.3のあたりで数時間躓いた。 Chapter8のサンプルコードは正直参考にならないくらい差分があったので自分が動いた環境を残しておく。

この内容はDirectX12の魔導書 初版 を読みながら書いています。

8.3.3のビューの作成までは記載の通り。

追記

8.4.6テクスチャ用ディスクリプタレンジとルートパラメーターでディスクリプタレンジの現状がどうなっているのか記載があった。 これを見るとCBVが2つだけのよう。SRVはなかった。 つまり8.3あたりの記述は正しそう? どこでこの記述に変わったんだ...

追記2

Chapter8のサンプルコードと照らし合わせて、順番の整理とと不要になっているものの削除を行った。すると正しく表示されるように、余計なSRVが設定されていたようだ。 どこかに消す、置き換えるような記述があったのかな?見逃したのかな。

ゴール

8.3.7の描画ごとにマテリアルの切り替えまでの動作確認をする。

以下は追記前でのこと。余計なSRVが残っている場合のもの。

8.3.4

レンジの設定について

テキストでは以下の内容。添え字が1番になっている。

descTblRange[1].NumDescriptors = 1;//デスクリプタヒープはたくさんあるが一度に使うのは1つ
descTblRange[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV;//種別は定数
descTblRange[1].BaseShaderRegister = 1;//1番スロットから
descTblRange[1].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;

これはChapter6時点では以下のようになっていて、すでに[1]が用意されている。

D3D12_DESCRIPTOR_RANGE descTblRange[2] = {};//テクスチャと定数の2つ
descTblRange[0].NumDescriptors = 1;//テクスチャひとつ
descTblRange[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;//種別はテクスチャ
descTblRange[0].BaseShaderRegister = 0;//0番スロットから
descTblRange[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;

descTblRange[1].NumDescriptors = 1;//定数ひとつ
descTblRange[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV;//種別は定数
descTblRange[1].BaseShaderRegister = 0;//0番スロットから
descTblRange[1].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;

[1]を上書きするのか、[2]の誤記かと思ったが、誤記表に何も記載がなかった。 Chapter7のサンプルコードを見るとなんと[1]が存在しなかった。

D3D12_DESCRIPTOR_RANGE descTblRange[1] = {};//テクスチャと定数の2つ
descTblRange[0].NumDescriptors = 1;//定数ひとつ
descTblRange[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV;//種別は定数
descTblRange[0].BaseShaderRegister = 0;//0番スロットから
descTblRange[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;

Chapter8では下記のようになっていて、順番も変わっていた。

//定数ひとつ目(座標変換用)
descTblRange[0].NumDescriptors = 1;//定数ひとつ
descTblRange[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV;//種別は定数
descTblRange[0].BaseShaderRegister = 0;//0番スロットから
descTblRange[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;

//定数ふたつめ(マテリアル用)
descTblRange[1].NumDescriptors = 1;//デスクリプタヒープはたくさんあるが一度に使うのは1つ
descTblRange[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV;//種別は定数
descTblRange[1].BaseShaderRegister = 1;//1番スロットから
descTblRange[1].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;

//テクスチャ1つ目(↑のマテリアルとペア)
descTblRange[2].NumDescriptors = 4;//テクスチャ4つ(基本とsphとspaとトゥーン)
descTblRange[2].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;//種別はテクスチャ
descTblRange[2].BaseShaderRegister = 0;//0番スロットから
descTblRange[2].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;

私の対応としては以下の通り一番下に[2]として追加。

// ディスクリプタテーブル
D3D12_DESCRIPTOR_RANGE descTblRange[3] = {};
// テクスチャ用レジスタ0番
descTblRange[0].NumDescriptors = 1; // テクスチャ1つ
descTblRange[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; // 種別はテクスチャ
descTblRange[0].BaseShaderRegister = 0; // 0番スロットから
descTblRange[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;

// 定数用レジスタ0番
descTblRange[1].NumDescriptors = 1; // 定数1つ
descTblRange[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV; // 種別は定数
descTblRange[1].BaseShaderRegister = 0; // 1番スロットから
descTblRange[1].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;

// テキストとは異なるが最後に追加してみる
// 定数用レジスタ1番
descTblRange[2].NumDescriptors = 1; // ディスクリプタヒープは複数だが、一度に使うのは一つ
descTblRange[2].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV; // 種別は定数
descTblRange[2].BaseShaderRegister = 1; // 1番スロットから
descTblRange[2].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;

ルートパラメータについて

ここがわからなくてつらかったところ。

テキストを写経してきている人は6.2.7でD3D12_SHADER_VISIBILITY_ALL設定をしていると思います。

テキストには、

ほぼ同じですが、座標変換のルートパラメーターと1つにまとめないのはディスクリプタヒープが異なるためです。ディスクリプタヒープが1つにまとまっていなければこれもまとめられるのですが、ディスクリプタヒープをまとめてしまうとわかりづらくなるため、個別のものに分けています。 とあります。

このため、

NumDescriptorRanges = 3;

のような書き方ではうまくいかないようです。
(この場合パイプラインステート_cmdList->SetPipelineState(pipelinestate);のあたりでアクセス違反が発生するかも?)

私の対応としては以下の通り別途追加。
レンジの設定の影響で&descTblRange[2]となっている。

D3D12_ROOT_PARAMETER rootparam[2] = {};
rootparam[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
rootparam[0].DescriptorTable.pDescriptorRanges = &descTblRange[0]; // 配列先頭アドレス
rootparam[0].DescriptorTable.NumDescriptorRanges = 2; // ディスクリプタレンジ数
rootparam[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; // すべてのシェーダから見える。

// 微調整している
rootparam[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
rootparam[1].DescriptorTable.pDescriptorRanges = &descTblRange[2]; // 配列先頭アドレス
rootparam[1].DescriptorTable.NumDescriptorRanges = 1; // ディスクリプタレンジ数
rootparam[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; // すべてのシェーダから見える。

rootSignatureDesc.pParameters = rootparam; // ルートパラメータの先頭アドレス
rootSignatureDesc.NumParameters = 2; // ルートパラメータの数

おわりに

サンプルコードがわかりにくすぎる。
写経している人のこと考えてなくない?