文字列描画の際、スプライト描画の要領で使うテクスチャは1つで、描画は数百文字同時に一括指定などで効率的に描画していた。
ただし、テクスチャ自体が複数枚で、それを一括で描画する仕組みを用意していなかったためテクスチャ毎に描画命令を呼び出していた。
これを改善しようと思う。
テクスチャの無制限配列指定
HLSL変数宣言
Texture2D Tex[] : register(t0) ;
こんな感じでテクスチャを指定して、Tex[n]のように使いたい。
定義自体は可能で、Shader Model 5.1以降で使える模様。
RootSignature宣言
RootSignatureのテクスチャ指定部分は下記のようにする
DescriptorTable( SRV(t0, flags=DESCRIPTORS_VOLATILE, numDescriptors=unbounded)...
flagsにはDATA_STATICか、DATA_STATIC_WHILE_SET_AT_EXECUTEを指定していたけど、無制限の場合はDESCRIPTORS_VOLATILEになるらしい。
numDescriptorsにはunboundedを指定する。
問題はデスクリプタヒープをどう指定するか。
現状初期化時に、CBV、SRV、UAV用と、サンプラ用の大きなヒープで作成しており、描画毎に同じヒープをCommandList->SetDescriptorHeapsに指定している。
テクスチャ部分はTex[0]~描画指定数分利用することになるが、SetDescriptorHeapsに配列順になっているデスクリプタヒープを渡す必要がある。
今までのデスクリプタヒープを静的なものとすると、今度は動的なデスクリプタヒープを用意することになる。
Dynamic Descriptor Heap
静的デスクリプタヒープと同様にな動的デスクリプタヒープを初期化時に用意する。
今まで渡していた静的デスクリプタヒープに加えて、動的デスクリプタヒープをSetDescriptorHeapsに渡そうとしたがエラーになる。同じタイプ(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)のものを渡せないらしく、動的デスクリプタヒープを渡したい場合は静的デスクリプタヒープは渡せなくなる。
静的デスクリプタヒープに加えて、配列分のデータを動的デスクリプタヒープで渡そうとしたけど、サンプラ以外はすべて動的デスクリプタヒープで渡すことになる。
そのため、静的デスクリプタヒープの初期化でFlagsに指定していたD3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLEをD3D12_DESCRIPTOR_HEAP_FLAG_NONEに変更して、動的デスクリプタヒープのFlagsにD3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLEを指定する。
実際描画する際、静的デスクリプタヒープと動的デスクリプタヒープのD3D12_CPU_DESCRIPTOR_HANDLEを用意して、Device->CopyDescriptorsSimple関数でコピーする。静的デスクリプタヒープでは空いている部分をアサインして、利用が終わったら返却しているため、使うリソースの順番はばらばらだったけど、動的デスクリプタヒープを使って、順番を指定できるようになったため、配列で使用できることになる。
定数バッファ(CB)や、構造化バッファ(SB)はサイズを増やせば複数描画分をまとめて渡すことが元々出来た。テクスチャも動的デスクリプタヒープを利用することで、使用するテクスチャを順番に並べることができるようになる。
これで複数枚のテクスチャ全部描画する際、複数回描画命令を実行していたのが1回の描画命令でまとめて描画が可能になった。
ある状況下で比べてみるとCPU使用率が約半分になって、GPU使用率はほぼ変わらずだった。

0 件のコメント:
コメントを投稿