【DirectX12】デスクリプタヒープの作成【初期化】
こんにちは、家に帰ってすぐにベッドインしてしまった、ここあです。
少し疲れ気味だったのか、久しぶりにゆっくりと寝ました。(寝すぎた)
更新が少し空いてしまいましたが休めたということは頑張れるので、今日からまた頑張っていきたいと思います。
今回は、レンダーターゲット用のデスクリプタヒープの作成について、解説していきます。
デスクリプタヒープの作成
デスクリプタヒープとは
デスクリプタヒープというのは、GPU上に作られるデスクリプタを保存するための配列です。
Direct3D 12 Overview Part 4: Heaps and Tables | Intel® Software
上の図では、デスクリプタヒープには、緑色のデスクリプタが配列の中に入っています。
そして、それぞれのデスクリプタが、テクスチャやモデル、バッファ、何らかのデータ配列が入っているのが、表されています。
デスクリプタとは
GPUメモリ上に存在する、様々なデータやバッファの種類や位置、大きさを示す構造体のようなものです。
Direct3D 12 Overview Part 4: Heaps and Tables | Intel® Software
上の図では、デスクリプタには、テクスチャの種類やフォーマット、ミップマップ数、GPUメモリ上のテクスチャへのポインタなどの、各種データが格納されています
CreateDescriptorHeap関数
デスクリプタヒープの作成にはID3D12Device::CreateDescriptorHeap関数を使用します。
- CreateDescriptorHeap関数
- 第1引数:D3D12_DESCRIPTOR_HEAP_DESC構造体へのポインタ
- 第2引数:各インタフェースの固有GUID
- 第3引数:ID3D12DescriptorHeapインタフェースのポインタを格納する変数のアドレス
ID3D12Device::CreateDescriptorHeap method | Microsoft Docs
基本的に今までと同様GUIDやインタフェースを格納した変数のアドレスに関しては、IID_PPV_ARGSマクロを使用することで、簡易的に指定することが可能です。
D3D12_DESCRIPTOR_HEAP_DESC構造体
- D3D12_DESCRIPTOR_HEAP_DESC構造体
- Type:デスクリプタヒープのタイプを設定。使いみちに応じて4つのタイプから設定
- CBV/SRV/UAV :配列やモデル、テクスチャ等のデータ用
- SAMPLER:テクスチャ読み込みのパラメータ用
- RTV:レンダーターゲットを指定 ← 今回作成
- DSV:深度やステンシルマスクの描画先を指定
- NumDescriptors:格納できるデスクリプタの数(デスクリプタヒープが配列の為、配列数の指定が必要)。通常レンダーターゲットはフレームバッファと1:1になるように作成する
- Flags:D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_NONEを設定。デスクリプタが指しているデータをシェーダから参照したい場合はD3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLEを設定。
- NodeMask:複数のGPUを使用する場合、どのGPU向けのデスクリプタヒープかを指定。GPUを1つしか使用しない場合、0を設定
- Type:デスクリプタヒープのタイプを設定。使いみちに応じて4つのタイプから設定
D3D12_DESCRIPTOR_HEAP_DESC | Microsoft Docs
※CBV:Constant Buffer View(配列等)
※SRV:Shader Resource View(テクスチャ、フレームバッファ、モデル等)
※UAV:Unordered Access View(SRVと同じですが、シェーダから直接書き込める点が違います)
※RTV:レンダーターゲットビューの略称
※DSV:Depth Stencil Viewの略称
※Flags:現状、意味のある値として設定できるのは、D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLEしかありません。今回は何も指定しないためNONEを設定しています
レンダーターゲットビュー用デスクリプタのバイト数を取得
ID3D12Device::GetDescriptorHandleIncrementSize関数を使用して、RTV用デスクリプタのバイト数を取得します。
デスクリプタヒープはデスクリプタの配列と説明しましたが、C/C++などの配列とは異なり、ヒープ配列は添字で参照することが出来ません。では、N番目の要素を参照したいといった場合に、どうやって参照するかというと、下のように計算をして参照します。
N番目の要素のアドレス=デスクリプタヒープの先頭アドレス+(要素のバイト数*N)
この計算式から分かるように、デスクリプタのバイト数が必要になってきます。このバイト数は、D3Dデバイスによって異なる可能性があるのでこのバイト数をD3Dデバイスから取得してきます。
ID3D12Device::GetDescriptorHandleIncrementSize method | Microsoft Docs
事前定義
ComPtr<ID3D12DescriptorHeap> g_rtvHeap; const UINT FRAME_COUNT = 2;
実装
D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {}; rtvHeapDesc.NumDescriptors = FRAME_COUNT; rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; if (FAILED(resource->g_device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&g_rtvHeap)))){ return FALSE; } resource->g_rtvDescriptorSize = g_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
終わりに
お疲れ様でした。今回でデスクリプタを格納するための準備が出来たので、次回はデスクリプタの作成をしていきます。
今回の実装内容はGitHubに上げてあります。
解説が間違っていたり、より良い方法などがあった場合は教えて頂けるとありがたいです。
それでは今回はこの辺りで。