StateManager サンプル
このサンプルでは、ID3DXEffectStateManager を使用して一連のコールバックを実装し、エフェクト システムで管理されるレンダリング ループでのステートの変化の数とタイプを計測する方法を示します。また、コールバックを使用して、ステート フィルタリングへのカスタム アプローチを実装するオプションをアプリケーションに提供する既定のステート管理をオーバーライドする方法も示しています。CPU の制約を受けるアプリケーションは、複雑なレンダリング ループで発生する冗長なステートの変化の量を制御することで、パフォーマンスが大幅に向上する可能性があります。
Path
ソース : | (SDK ルート)\Samples\C++\Direct3D\StateManager |
実行可能ファイル : | (SDK ルート)\Samples\C++\Direct3D\Bin\x86 or x64\StateManager.exe |
前提条件:
サンプルが動作するしくみ
このサンプルは、展望台、ツリー、岩、地形、観覧席など、複数のメッシュ オブジェクトから構成されているシーンをレンダリングします。各メッシュは、複数のマテリアル (雪、木材など) で構成することができます。各マテリアルは、異なるエフェクトにより実装されます。シーンの複雑さのために、レンダリング シーケンスはさまざまなマテリアルやオブジェクトをレンダリングするために多数のステートの変化を備えています。レンダリング シーケンスは、OnCreateDevice の以下の関数を呼び出した後に作成されます。
- BuildSceneFromX - このメソッドは、各メッシュおよびそのワールド トランスフォームを指定するシーンの .x ファイルを読み込みます。次に、エフェクト インスタンスと関連するテクスチャー (存在する場合) で構成される各メッシュは、対応するマテリアルを読み込みます。
- QueueAndSortRenderables - このメソッドは 2 つのことを実行します。まず、シーンのレンダリングに必要なすべてのステートの変化をレンダリング キューに追加します。次に、デバイスのタイプ、およびステート マネージャーに従ってキューの順序を変更します。
- SetStateManager - このメソッドは、レンダリングの準備のために、各エフェクトにステート マネージャーを伝達します。
このサンプルでは、デバイスごとに冗長なステートの変化をフィルタリングする利点を示します。デバイスを作成するとき (IDirect3D9::CreateDevice)、デバイスのタイプは D3DDEVTYPE で指定されます。ピュア デバイス (D3DCREATE_PUREDEVICE で作成) は、可能性のあるステート変化コマンドの小さなサブセットをフィルター処理します。これは、パイプライン コマンドを直接ハードウェアに流すため、きわめて高速です。ピュア デバイスは、パラメーターの検証を行いません。また、冗長なステートのフィルタリングをほとんどまたはまったく行いません。対照的に、非ピュア デバイス (D3DCREATE_PUREDEVICE を使用しないで作成) は、冗長性について各ステートの変化をチェックし、これらの冗長なステートの変化を破棄します。これにより、デバイスで実行する必要がある作業の量が減ります。
ID3DXEffectStateManager を使用すると、ステートの変化のカスタム ユーザー ハンドラーを記述できるようになります。発生しているステートの変化の数を計測することができます。または、カスタム処理 (冗長なステートの変化をフィルタリングするなど) を実行するハンドラーも記述できます。これが StateManager サンプルで実行される内容そのものです。サンプルを実行すると、サンプルは既定でピュア デバイスの実行、および ID3DXEffectStateManager を使用しての冗長なステートのフィルタリングを実行します。これは、ID3DXEffectStateManager から派生する CPureDeviceStateManager クラスを作成して実行されます。
CPureDeviceStateManager は、ステートの変化をカウントし、冗長な IDirect3DDevice9::SetRenderState、IDirect3DDevice9::SetSamplerState、および IDirect3DDevice9::SetTextureStageState コマンドをフィルター処理し、対応する Direct3D コマンドを呼び出します。フィルター処理された冗長なステートの変化の数は、アプリケーションに返されます。
次に例を示します。
ステートの変化 | フィルター処理されたステートの変化 | 岩の数 | ステートの変化の減少の割合 (%) |
---|---|---|---|
120 | 38 | 1 | -31 |
7971 | 3856 | 200 | -48 |
その他のパフォーマンス上のヒント:レンダリング シーケンスの順序変更
冗長なステートの変化をフィルタリングすることに加え、パフォーマンスを向上する別のオプションに、レンダリング シーケンスの順序変更があります。これは、非ピュア デバイスで、または (使用されるマテリアルの数とは反対に) 設定される行列トランスフォームの量によってさらに限定されるシナリオで特に影響があります。たとえば、各メッシュ オブジェクトにより順序設定されたレンダリング シーケンスを以下に示します。
// Render each mesh object
For each instance of mesh x
Setup transforms (ID3DXEffect SetMatrix)
For each material of mesh x
Set up material (ID3DXEffect Begin/BeginPass)
Draw
以下は、同じシーケンスをマテリアル別に順序変更しています。
// Render each effect to minimize state changes
For each material y
Set up material (ID3DXEffect Begin/Begin Pass)
For each instance of material y
Set up transforms (ID3DXEffect SetMatrix)
Draw
各シーケンスは、ある状況では適切であり、他の状況では不適切です。多数のマテリアルを持つアプリケーションでは、マテリアル別に順序を設定することで冗長なステートの変化の数を減らすことができます。
プロファイラーと同様のテクニックを使用して、CPU 制約シナリオのパフォーマンスを計測する詳細については、「Direct3D API 呼び出しの正確なプロファイリング (Direct3D 9)」を参照してください。