DirectX12 発生していたD3D12ERRORを片っ端から潰していった話
- あいさつ
- SET_VERTEX_BUFFERS_INVALID
- INVALID_DESCRIPTOR_HANDLE、COMMAND_LIST_MULTIPLE_SWAPCHAIN_BUFFER_REFERENCES
- EXECUTECOMMANDLISTS_FAILEDCOMMANDLIST
- DEVICE_REMOVAL_PROCESS_AT_FAULT
- COMMAND_LIST_CLOSED
- あとがき
あいさつ
どうも、はかせです。
今日も今日とて基礎勉強しながら
ロードトゥMMDを歩んでいるわけですが、
未だ道は長い・・・・
今回はD3D12ERRORを潰しまくったので
その潰したエラーと対処法を残します。
SET_VERTEX_BUFFERS_INVALID
名前の通りIASetVertexBuffersでVertexBufferを
設定しようとして失敗したってやつです。
同様のものにSET_INDEX_BUFFER_INVALIDがあります。
こちらはIASetIndexBuffersが失敗したやつですね。
ちなみにエラー文はこんな感じです。
D3D12 ERROR: ID3D12CommandList::IASetVertexBuffers: 0x16789EF0 + SizeInBytes - 1 (0x00000000129a6611) exceeds end of the virtual address range of Resource (0x16789EF0:'Unnamed ID3D12Resource Object', GPU VA Range: 0x0000000012918000 - 0x000000001291bbf2). [ EXECUTION ERROR #726: SET_VERTEX_BUFFERS_INVALID]
見やすいよう改行してますが、
実際は改行無しで一列にダーッっと並んでて
ちょっと読みづらいです。
色々書いてますが読むべきはここだけです。
exceeds end of the virtual address range
これをgoogle先生に訳してもらいます。
端的に言うとサイズ指定ミスってるから
入れようとしているメモリが入れられないよってことです。
これは極めて単純なミスで私が
D3D12_RESOURCE_DESCのWidthの値に
本来なら頂点サイズ*頂点数を入れなきゃいけないのに
頂点サイズのみ入れてたため発生しました。
実際入ってくる値のサイズは頂点サイズ*頂点数なので
溢れてしまったわけですね。
ちなみにインデックスバッファでも同じミスしてました。
逆にこのエラーが出てくるのはおそらくそれくらいでしょう。
(他はほとんどテンプレ設定で行けるし)
INVALID_DESCRIPTOR_HANDLE、COMMAND_LIST_MULTIPLE_SWAPCHAIN_BUFFER_REFERENCES
このエラーはどちらも同様の箇所が原因だったので
ひとまとめにします。
まずはそれぞれエラー文を見ます。
INVALID_DESCRIPTOR_HANDLE
D3D12 ERROR: ID3D12CommandList::OMSetRenderTargets: Specified CPU descriptor handle ptr=0x16812A90 does not refer to a location in a descriptor heap.4 pRenderTargetDescriptors[0] is the issue. [ EXECUTION ERROR #646: INVALID_DESCRIPTOR_HANDLE]
pRenderTargetDescriptors[0]に問題があって
descriptor heapを参照しないって言ってますね。
COMMAND_LIST_MULTIPLE_SWAPCHAIN_BUFFER_REFERENCES
D3D12 ERROR: ID3D12GraphicsCommandList::*: A single command list cannot write to multiple buffers within a particular swapchain. [ STATE_SETTING ERROR #904: COMMAND_LIST_MULTIPLE_SWAPCHAIN_BUFFER_REFERENCES]
一つのコマンドリストじゃ複数のスワップチェイン内の
バッファに書き込むことはできないって言われてますね。
一見全く関係なさそうな二つのエラーですが、
原因は同じレンダーターゲットビューです。
私は今まで11でレンダーターゲットビューを
管理するということはしてませんでした。
作ってパイプラインにあてがって
はい終わりって感じ。
ただ12ではそれじゃだめで
ちゃんとフロントバッファとバックバッファを
切り替える必要があります。
(フロントバッファ=ユーザーが見ている描画済みのバッファ
バックバッファ=ユーザーが見ていない描画中ないし描画するバッファ
って認識なんですがあってるんですかね)
やり方は簡単でまず予めフロント用とバック用の
二つのレンダーターゲットビューを作ります。
//レンダーターゲットを作成する処理 //積まれているGPUによって各データのサイズが変わるためどれだけずらしていけばいいかを取得する UINT size = mDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); //RTV_NUM = 2 for (UINT i = 0; i < RTV_NUM; ++i) { //スワップチェインからバッファを受け取る ThrowFailed(mSwapChain->GetBuffer(i, IID_PPV_ARGS(&mRenderTarget[i]))); //デスクリプタヒープの先頭アドレスを取得 mRenderTargetViewHandleArray[i] = mRenderTargetViewDescriptorHeap->GetCPUDescriptorHandleForHeapStart(); //目的の要素までポインタをインクリメント mRenderTargetViewHandleArray[i].ptr += size * i; mDevice->CreateRenderTargetView(mRenderTarget[i].Get(), nullptr, mRenderTargetViewHandleArray[i]); }
前回と同じコードです。
前回はデスクリプタヒープ内にある
デスクリプタへのアクセス例としてあげましたが
今回はレンダーターゲットビューの作りの例であげます。
レンダーターゲットビューを二つ作って
配列に格納しています。
あとはどっち使うかを決めてやります。
とはいってもこちらはプログラマーが
特別何か処理機構を作るわけではなく、
IDXGISwapChain3::GetCurrentBackBufferIndexを呼びます。
こいつは現在のバックバッファのインデックスを返してくれます。
あとはこのインデックスをさっき作った配列の添え字にして
切り替えれば問題なく実行できます。
この対策をするだけでこの二つのエラーは解決しました。
EXECUTECOMMANDLISTS_FAILEDCOMMANDLIST
こっからはあっさり行きます。
(あっさり解決できたから)
まずはエラー文
D3D12 ERROR: ID3D12CommandQueue::ExecuteCommandLists: Command lists must be successfully closed before execution. [ EXECUTION ERROR #838: EXECUTECOMMANDLISTS_FAILEDCOMMANDLIST]
コマンド実行する前にはちゃんとクローズしろってやつです。
もちろんクローズは呼び出してましたが、
先述のエラーによりクローズが失敗していました。
なので実際のコールのタイミングにクローズされておらず
このエラーが出ました。
先述のエラーを解決したことで
無事クローズすることができるようになり
それに伴いこのエラーもなくなりました。
DEVICE_REMOVAL_PROCESS_AT_FAULT
D3D12 ERROR: ID3D12Device::RemoveDevice: Device removal has been triggered for the following reason (DXGI_ERROR_INVALID_CALL: There is strong evidence that the application has performed an illegal or undefined operation, and such a condition could not be returned to the application cleanly through a return code). [ EXECUTION ERROR #232: DEVICE_REMOVAL_PROCESS_AT_FAULT]
D3D12デバイスが削除されてるよってやつです。
さっきのコマンド失敗のエラーの後にD3D12: Removing Device.
ってのが出てたんでDirectX12ではコマンドリストの実行に失敗したら
同時にデバイスの破棄も走るって感じなのかなと思っています。
COMMAND_LIST_CLOSED
D3D12 ERROR: ID3D12GraphicsCommandList::*: This API cannot be called on a closed command list. [ EXECUTION ERROR #547: COMMAND_LIST_CLOSED]
クローズされているコマンドリストに
コマンドは積めないよとのことです。
まぁこれは当たり前なんで
特に語ることもないです。
クローズされているのは
エラーが起こってたからですね。
これもさっきからあげている
エラーを潰してったら直りました。
あとがき
今回は発生していたD3D12ERROR撲滅回でした
エラーの原因の10割がケアレスミスだったり、
私の理解不足という形でしたね。
ただこれでコンソールに出てたエラーは全て潰したはず。
いでよ!モデル!
・・・・・・
人生そんな甘くないですよね(´;ω;`)
それでは今回はこの辺でノシ