こんばんわ。Pocolです。
最近ずっとGPUクラッシュ調査の仕事をやっていて疲弊しています。
基本的には,DREDとAftermathを使っています。
DREDを使うと,自動でパンくずリストを作ってくれます。
これ,基本的にはマーカー名とどこまで進んだかを教えてくれます。
GPUクラッシュは大半がTDRかPageFaultだと思います。
TDRでよくあるのは,ループ終了条件を定数バッファのメンバとして渡すパターン。
バッファがどっかで壊れて,終了条件値が想定外の値になって,無限ループ扱いになってクラッシュするとかが良くあります。
で、クラッシュ調査時に欲しいのはどのシェーダ?設定されているのはどのバッファ?中身どうなっている?
…あたりの情報が知りたくなります。
そこで,思いました。
DREDの自動パンくずリストをやめて,自前でカスタムのパンくずリストを作った方が便利なのでは?
そう思ったので,パンくずリストについて調査してみます。
Githubやググったんですが,まともな情報がほぼありません。
FidelityFX Breadcrumbs 1.0が唯一信じられるまともな実装です。
これを調査してみます。
ドキュメントは下記です。
https://gpuopen.com/manuals/fidelityfx_sdk/fidelityfx_sdk-page_techniques_breadcrumbs/
ソースコードは
- https://github.com/GPUOpen-LibrariesAndSDKs/FidelityFX-SDK/blob/main/sdk/include/FidelityFX/host/ffx_breadcrumbs.h
- https://github.com/GPUOpen-LibrariesAndSDKs/FidelityFX-SDK/tree/main/sdk/src/components/breadcrumbs
- https://github.com/GPUOpen-LibrariesAndSDKs/FidelityFX-SDK/blob/main/sdk/src/backends/dx12/ffx_dx12.cpp
- https://github.com/GPUOpen-LibrariesAndSDKs/FidelityFX-SDK/blob/main/sdk/src/backends/vk/ffx_vk.cpp
…あたりを見ると良いです。
基本的な仕組みとしては,
D3D12の場合は,WriteBufferImmedidate() で実行済みフラグを立てていくだけみたいです。
Vulkanの場合は,AMD拡張が使える場合は,vkCmdWriteBufferMaker2AMD()やvkCmdWriteBufferMarkerAMD(),そうでない場合はvkCmdFillBuffer()を使って実行済みフラグを立てていくようです。
現在困っているのは,D3D12環境なので以下D3D12として説明します。
で、WriteBufferImmediate()でどこに書き込むか?なのですが,次のような感じで書き込むメモリを用意するようです。
・VirtualAlloc(nullptr, bufferSize, MEM_COMMIT, PAGE_READWRITE)でメモリを用意。— (A)
・(A)で用意したメモリを引数として,ID3D12Device3::OpenExistingHeapFromAddress() をコールして,ID3D12Heapを取得し,CreatePlacedResource()でID3D12Resourceを生成。 — (B)
・(B)に失敗した場合は,CreateCommittedResource()でID3D12Resourceを生成し,メモリはMap()して取る — (C)
・(B)または(C)にてID3D12Resourceが出来上がるので,ID3D12Resource::GetGPUVirtualAddress()して,BaseAddressを取得 — (D)
・(D)で取得したBaseAddressを開始点として,uint(4byte)で,フラグをWriteBufferImmedidate()で書き込んでいく。
これでコマンドリストに記録されるようになるので,あとはクラッシュした際に(B)または(C)で用意してあるメモリをReadしていきます。これで書き込まれていればフラグが立っていくはずなので,どこまでコマンドが進んだかどうかが判定できます。
マーカー名などのデータはCPU側で管理して,Readしたデータと照合して一致させて,デバッグログなどに表示させれば良いようです。
細かい実装は,FidelityFX Breadcrumbsのソースコードを参照してみてください。
…というわけで,パンくずリストを自前実装する際の基本的な仕組みが分かりました。
あとは,CPU側で管理するデータをリッチにしていけば,色々とデータが取れそうです。
まずは、これらの情報を元にカスタムパンくずリストの実装を始めてみようかなと思いました。
そんなわけで、パンくずリストの話でした。
もし、ノウハウを色々とお持ちの方は是非教えてください。