StructuredBuffer
メッシュのボーン行列をシェーダにわたす定義は、定数バッファで固定の配列にしていた。
struct _Bone {
float4x4 Bones[255] ;
} ;
ConstantBuffer<_Bone> Bone : register(b1) ;
実際に渡す個数はボーンの数分だけで、利用するインデックスも渡した分だけを指すようになっているので問題ない。
ただ、この固定の書き方が気持ち悪いのと、読み込んだメッシュのボーンが固定値を超える場合に調整が必要になるのでなんとかしたい。
構造化バッファ(StructuredBuffer)の場合、可変の配列定義が許されているのでリソースのタイプに追加することにした。
前にテクスチャのミップマップを作る際、GPU側(ComputeShader)で更新するリソースを用意したけど、今度はCPU側から更新するタイプのSRVリソースとなる。
D3D12_HEAP_TYPE_UPLOADとD3D12_HEAP_TYPE_DEFAULTの2リソースを用意して、Uploadの方はMapしっぱなしで更新時にmemcpyしつつ、CopyBufferRegionでDefaltの方に反映する。
このコピーを行うコマンドリストは、汎用的に使えるように用意したDIRECT版のコマンドリストを使っていて、ステータス遷移(D3D12_RESOURCE_STATE_COPY_DEST)、CopyBufferRegionを追加する。
StructuredBuffer<float4x4> Bone : register(t1) ;
シェーダの定義はこんな感じになって、Bone[Index]という風に使える。
疑問点が1つあって、定数バッファはフレームのバッファ数分用意する必要がある。
マイクロソフトのサンプルでは、ダブルバッファの場合必要サイズの2倍データ領域を用意して、毎フレーム交互に書き込み、参照していく。
構造化バッファの場合、今のところ1つで済んでいる。
中間レンダーバッファの時も思ったけど、SRVをベースにしていると1つで済むのか?
ただし、UAV経由で更新する場合は領域が2つ必要だった。
更新時UploadとDefaultの2つが絡んでいるから、これが2つ分扱いになっているのか?
謎。
CopyQueue
ボーンのバッファは毎フレーム更新を行うことになるけど、そのデータのコピーについて今まで使ってなかった専用のコピーキューを用意してやってみようと思う。
D3D12_COMMAND_LIST_TYPE_COPYでCreateCommandQueueを作成する。
コマンドリスト、アロケータも同様にD3D12_COMMAND_LIST_TYPE_COPYで作成して、利用してみるとエラーになった。
D3D12 ERROR: ID3D12CommandList::ResourceBarrier: D3D12_RESOURCE_STATES has invalid flags for copy command list. [ RESOURCE_MANIPULATION ERROR #537: RESOURCE_BARRIER_INVALID_COMMAND_LIST_TYPE]
コピーで作ったリストにはコピーコマンドしか入れることができず、リソースの状態遷移はできないのか?
いろいろ調べてみるとコピーコマンドリストが理解できるステータスなら許容されるみたいだ。Beforeステータスには現在のステータスを設定していたが、これをD3D12_RESOURCE_STATE_COMMONにしてしまえばコピーコマンドのリストでも状態遷移ができた。真面目に今の状態をセットしていたのに、適当な値でいいなんて・・・。それまでは別のDIRECTコマンドのリストで遷移させていたがプログラムが多少スッキリした。
![]() |
| 改善前 |
処理時間を計測してみた結果、改善前は11usぐらいで改善後は14us秒ぐらい掛かっている。
![]() |
| 改善前のComputeコマンド |
改善前は状態遷移で5us、コピーに1us、Dispatch前の状態遷移に0us、Dispatchに4us掛かっている。
![]() |
| 改善後のCopyコマンド |
![]() |
| 改善後のComputeコマンド |
改善後は、状態遷移に2us、コピーに1us、Dispatch前の状態遷移に7us、Dispatchに4us掛かっている。
これは失敗か?
更に改良を加えて、表示するメッシュを10に増やして測ってみた。
加えた改造は、状態遷移に時間が掛かっているように見えたので処理前にまとめて状態遷移をさせてしまうようにした。
今までは、対象メッシュが使うリソースを状態遷移させてシェーダ実行、次のメッシュが使うリソースを状態遷移させてシェーダ実行、というように状態遷移とシェーダ実行を交互に行っていた。それを描画対象のメッシュすべてのリソースを状態遷移させてから、シェーダ実行するようにした結果がこれ。
![]() |
| 改善前 |
![]() |
| 改善後 |
改善前は45usで、改善後は18us程度。
改善前は描画対象のメッシュが増えると処理も線形に延びていってしまう感じだが、改善後は1メッシュが14usで10メッシュでも18usなので、ほとんど増えていない。
![]() |
| 改善前のComputeコマンド |
改善前は並列に処理することが出来ず、何かする度に待ち時間が発生してしまっている感じになっている。
![]() |
| 改善後のCopyコマンド |
![]() |
| 改善後のComputeコマンド |
改善後はほとんど並列に処理できている。
ResourceBarrierは至るところにまとめてやれという風に書かれていたので、シェーダで使う単位ではまとめて遷移させるようにしていたけど、メッシュを横断してまとめてやった結果、かなり改善されてびっくり。1つだけの場合は逆に処理時間延びてまずいと思ったけど、数が増えるほど効果が出そう。










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