すっかり紹介を忘れていた、強力なデバッギングツールの PIX(Performance Investigator for DirectX) for Windows です。 これを知っているのと知らないのでは、開発効率に天と地との差があります。
"for Windows" とあるように、"Not for windows" もあります。
と、いうか、そもそも PIX は、Xbox 用のツールとして開発されたらしいです。
いやぁ、規格が決まっている Xbox から、色々な環境が混在する Windows なんて無理もいいとこです。
大助かりです。
ぜひ、OpenGL 用とか、他の環境にも…
今回は、簡単で楽しい、フレームキャプチャ機能で遊びます。
この機能は、あるフレームのコマンドを全て記録しておいて、
オフライン実行や、はてはピクセル単位のデバッグまでしてくれます。
PIX を使うには、メニューの DirectX の「DirectX Utiliies」の項目から、「PIX for Windows」を選択して実行します。
立ち上がると、次のような画面になります。
ここに、デバッグしたいプログラムをドラッグ&ドロップしてみると、「Program path」のところにプログラムが登録されます。
あとは、「A single-frame capture of Direct3D whenever F12 is pressed」を選択したら、「Start Experiment」です。
すると、いつものプログラムが、左上に変なのが付いて実行されると思います。
これが、プログラムが PIX の奴隷になった証拠です。
後は、F12 を押してみると、ちょっと(だいぶ?)止まって、再び動き出すと思います。
そしたらプログラムを終わりましょう。
終わると、PIX の画面がばばばって動いて、色々なウィンドウが開くと思います。
これが、スナップとかされないのでしょぼいと思うのですが、それはここではおいといて、
左下の「Run1: Events」のウィンドウの「frame ###(あなたがF12を押したフレーム)」の「+」を押して開いてみましょう。
狭いので、下にあるウィンドウをそれぞれ上に引き伸ばしました。
ごちゃごちゃ書いてありますが、これがそのフレームであなたが呼び出した Direct3D のコマンドです。
ためしに、IDirect3DDevice::SetRenderTarget の2つめの引数の16進数をクリックしてみてください(SetRenderTargetをつかってないときは、右側のウィンドウの「Render」のタブをクリック)。
その時点での、クリックしたバッファに記録された画像が右側に表示されます。
そのまま、下のコマンドを選択すると、その時点で記録されたバッファの内容が画面に表示されます。
これで、画面が壊れたときに、どの時点でおかしくなったかが追えると思います。
で、上の画面は、なんかチェック模様が入っていますが、これは、アルファ値に0が設定されていて透けた画面です。 標準の表示は、アルファ成分を不透明度とした表示がされるので、うざいときは、画像の上の「Channel(s)」を「RGB」にすると、抜きが無くなって良い感じになります。
他にも、深度バッファのアドレスをクリックして「Depth」にすると深度値が確認できます(その右のスライドバーで見え方が調整できますです)。
で、さらに詳細にデバッグしましょう。
モデルの描画がされないときがあると思いますが、その時頂点処理が悪いかどうかは、PIX でばっちりわかります。
正常に表示されないメッシュの「DrawSubset」のコマンド等を選択して、右側のタブの「Mesh」を押してください。
すると、そのメッシュにおける「頂点処理前の状態」、「頂点処理後の状態」、「画面での見栄え」の図が表示されるとともに、その頂点データ(ディフォルトでは入力されたデータ)が列挙されます。
これを見ることによって、入力されたデータが悪いのか、頂点処理が悪いのか、それとも画面からはみ出しているだけなのかがわかります。
さらに、真ん中のタブを「PostVS」にすると、頂点処理後のデータの値が列挙されます。
運が良いと、頂点番号をクリックすることによって、デバッグが可能ですが、まだ機能的に不十分で完全にはデバッグできないようです。もう少し待ちましょう。
頂点が正しく出ていることがわかれば、次はピクセルの情報です。
右側の絵が出ているウィンドウで、よさげな場所で右クリックして「Debug This Pixel」を選択してください。
すると、カーソルのあったピクセルが、何時のコマンドで、何色に変更されたのかが列挙されます。 ここで、確認したいコマンドのところで「Debug pixel shader」を選択すると、シェーダのデバッグ画面に移ります。
この画面で、適当にブレークポイントを指定して実行したりすると、その行で止まってそのときのレジスタの値などが確認できます。
HLSL でないのが少々残念ですが、短いシェーダならなんとなく感じがつかめると思います。
で、以上で基本は終わりですが、ここで覚えとくとよい機能を紹介しておきます。
PIX の左下のコマンド一覧は、名前をつけてまとめることができます。
たとえば、下の画面では、普通に画面を更新した「Render Scene」と、その後のメニューや画面情報を表示した「Debug Status」の名前をつけました。
この名前付けは、下のように、「D3DPERF_BeginEvent」と「D3DPERF_EndEvent」ではさんでDirect3D の命令を実行することによって実現できます。
色も指定してますが、どこに出てるんでしょうかねぇ???
main.cpp void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext ) { D3DPERF_BeginEvent(D3DCOLOR_RGBA(0xff, 0,0,0), L"Render Scene"); // 普通に描画 D3DPERF_EndEvent(); D3DPERF_BeginEvent(D3DCOLOR_RGBA(0,0,0,0), L"Debug Status"); // メニューやデバッグ情報の表示 D3DPERF_EndEvent(); }
これで確認するときに範囲が絞れるので、デバッグが容易になります。
上のウィンドウの「Timeline」もそれぞれの名前で記されるので、どの処理にどの程度かかっているのかを確認することが可能です。
PIX は、NVPerfKIT と連携することによって、さらに強力なツールになるのですが、
まぁ、今回は入門編ということでこんなとこで。
まだまだ発展途上なツールだと思いますが、これだけでも OpenGL を捨てて DirectX 派になる強力な動機になると思います。