日別アーカイブ: 2007年8月5日

Direct3D 10 の便利な点 DEVICELOST

Vista + Direct3D 10 になって API 回りも一新、便利な機能が増えています。
特に OS との親和性が高まったおかげか、管理周りの負担が減りました。
これは非常に歓迎すべきことです。
例えば D3D9 までは常に頭を悩ませていた DEVICELOST 対策が、D3D10 では
ほぼいらなくなりました。

D3D10 の新機能も別に使わないし、能力的にも DirectX9 までで満足しているし、
といった場合でも、これはきっと気になるポイントでしょう。

Windows 上では 1つのアプリケーションが GPU や VRAM を占有するわけでは
ないので、常にリソースの競合が発生します。
ほぼ占有可能なフルスクリーンモードでも、いわゆる ALT+TAB で
Task を切り替えるとリソースを明け渡さなければなりません。

このとき DirectX9 以前の API は D3DERR_DEVICELOST を返し、リソースが
他の Task に取られたため実行できないことを訴えます。
こうなったら描画動作の続行をあきらめるしかありません。
TestCooperativeLevel() を呼び出して再び利用可能になるのを待ち続けます。
利用可能な状態に戻ったことを確認したら、VRAM 内容や各種 GPU ステートを
戻してプログラムが継続できるよう復帰させる必要があるわけです。

もちろん DEVICELOST はフルスクリーンモードに限らず Window Mode でも
起こります。例えばスクリーンセーバーなど、突然他のアプリが全画面を
占拠して描画を始めることも十分ありえるからです。

D3D9 の場合でも、D3DPOOL_MANAGED を使えば VRAM 内容の復帰までは自動で
行ってくれるようになっています。これはこれでかなり手間が減りました。
それ以外のリソースは、明示的にリセットしたり作り直しです。
例えば RenderTaget 用の Surface とか、ID3DXEffect とか、
IDirect3DQuery9 など。

Direct3D 10 になると Vista がより深く Direct3D を活用するおかげか
この辺の GPU リソースもしっかり管理してくれます。
DEVICELOST 時の後始末をアプリケーションが行わなくても、ALT-TAB の
切り替えからでも、スクリーンセーバーからでも、きちんと復帰して動作を
続けてくれます。(ちょっと感動)

ただ、アプリケーションが完全にバックグラウンドに切り替わってしまったのに、
何もしないで CPU を消費し続けるのはあまり好ましいとはいえません。
画面描画可能な状態かどうかは、やっぱりアプリケーション側でも
責任を持ってきちんと判別しておく必要があります。

Direct3D 10 では SwapChain の Present() が D3DERR_DEVICELOST
の代わりに DXGI_STATUS_OCCLUDED を返します。
フルスクリーンモードからの切り替わり、スクリーンセーバー、ユーザーの
切り替えなど、バックグラウンドに回る可能性はいくらでもあるわけです。

GPU の状態を調べる ID3D10Query も、DEVIELOST 等によってインターフェース
を作成しなおす必要がなくなりました。
ただその代わり、途中で DEVICELOST 相当の状態が発生すると計測値の正当性が
失われてしまいます。この状況は TIMESTAMP_DISJOINT で調べれば判定可能
なのですが、従来は無かった動作だけに新たな処理が必要になりそうです。