使用フラグは、アプリケーションがリソース データを使用して、可能な限り最もパフォーマンスの高いメモリ領域にリソースを配置する方法を示します。 リソース データは、CPU または GPU がパフォーマンスに影響を与えずにアクセスできるように、リソース間でコピーされます。
リソースは、ビデオ メモリまたはシステム メモリに作成されていると考えたり、ランタイムがメモリを管理する必要があるかどうかを判断したりする必要はありません。 WDDM (Windows ディスプレイ ドライバー モデル) のアーキテクチャでは、アプリケーションがリソース データを使用する方法を示すさまざまな使用フラグを持つ Direct3D リソースを作成します。 このドライバー モデルは、リソースによって使用されるメモリを仮想化します。予想される使用量を考えると、可能な限り最もパフォーマンスの高いメモリ領域にリソースを配置するのは、オペレーティング システム/ドライバー/メモリ マネージャーの責任です。
既定のケースは、GPU でリソースを使用できるようにするためです。 リソース データを CPU で使用できる必要がある場合があります。 パフォーマンスに影響を与えずに適切なプロセッサがアクセスできるようにリソース データをコピーするには、API メソッドの動作に関する知識が必要です。
リソース データのコピー
リソースは、Direct3D が Create 呼び出しを実行するとメモリ内に作成されます。 ビデオ メモリ、システム メモリ、またはその他の種類のメモリに作成できます。 WDDM ドライバー モデルではこのメモリが仮想化されるため、アプリケーションで作成されるメモリ リソースの種類を追跡する必要がなくなりました。
GPU がすぐにアクセスできるように、すべてのリソースがビデオ メモリに配置されるのが理想的です。 ただし、CPU がリソース データを読み取ったり、CPU が書き込んだリソース データに GPU がアクセスしたりする必要がある場合があります。 Direct3D は、アプリケーションに使用量の指定を要求することで、これらのさまざまなシナリオを処理し、必要に応じてリソース データをコピーするためのいくつかの方法を提供します。
リソースの作成方法によっては、基になるデータに直接アクセスできるわけではありません。 これは、リソース データをソース リソースから、適切なプロセッサがアクセスできる別のリソースにコピーする必要があることを意味する場合があります。 Direct3D では、既定のリソースは GPU から直接アクセスでき、動的リソースとステージング リソースには CPU から直接アクセスできます。
リソースが作成されると、その使用状況を変更することはできません。 代わりに、1 つのリソースの内容を、別の使用状況で作成された別のリソースにコピーします。 あるリソースから別のリソースにリソース データをコピーするか、メモリからリソースにデータをコピーします。
主に、マップ可能リソースと非マップ可能リソースの 2 種類があります。 動的またはステージングの使用で作成されたリソースはマップ可能ですが、既定または不変の使用で作成されたリソースはマップできません。
これは最も一般的なケースであり、適切なパフォーマンスを得るために最適化されているため、マップできないリソース間でのデータのコピーは非常に高速です。 これらのリソースは CPU から直接アクセスできないため、GPU ですばやく操作できるように最適化されています。
マップ可能なリソース間でのデータのコピーは、リソースが作成された使用状況によってパフォーマンスが異なるため、より問題になります。 たとえば、GPU は動的リソースをかなり迅速に読み取ることができますが、それらに書き込むことができず、GPU はステージング リソースに対して直接読み取りまたは書き込みを行うことはできません。
既定の使用状況のリソースからステージング使用率のリソースにデータをコピーするアプリケーション (CPU がデータを読み取れるようにするため、つまり GPU の読み取り戻しの問題) は注意して行う必要があります。 以下 のリソース データへのアクセスを参照してください。
リソース データへのアクセス
リソースにアクセスするには、リソースのマッピングが必要です。マッピングは基本的に、アプリケーションがメモリへの CPU アクセスを許可しようとしていることを意味します。 CPU が基になるメモリにアクセスできるようにリソースをマッピングするプロセスは、パフォーマンスのボトルネックを引き起こす可能性があるため、このタスクを実行する方法とタイミングに注意する必要があります。
アプリケーションが間違ったタイミングでリソースをマップしようとすると、パフォーマンスが停止する可能性があります。 その操作が完了する前に、アプリケーションが操作の結果にアクセスしようとすると、パイプラインのストールが発生します。
間違ったタイミングでマップ操作を実行すると、GPU と CPU が強制的に相互に同期され、パフォーマンスが大幅に低下する可能性があります。 この同期は、CPU がマップできるリソースへの GPU のコピーが完了する前に、アプリケーションがリソースにアクセスする必要がある場合に発生します。
パフォーマンスに関する考慮事項
PC は、1 つ以上の CPU と 1 つ以上の GPU の 2 種類のプロセッサを備えた並列アーキテクチャとして実行されているマシンと考えるのが最善です。 並列アーキテクチャと同様に、各プロセッサがアイドル状態にならないように十分なタスクでスケジュールされている場合や、あるプロセッサの作業が別のプロセッサの作業を待機していない場合に、最適なパフォーマンスが得られます。
GPU/CPU 並列処理の最悪のシナリオは、あるプロセッサが別のプロセッサによって実行された作業の結果を待つ必要がある場合です。 Direct3D では、コピー メソッドを非同期にすることで、このコストが削減されます。コピーは、メソッドが返す時点までに必ずしも実行されるとは限りません。
この利点は、CPU がデータ (Map が呼び出されたとき) にアクセスするまで、アプリケーションが実際にデータをコピーするパフォーマンス コストを支払わないという点です。 データが実際にコピーされた後に Map メソッドが呼び出された場合、パフォーマンスの低下は発生しません。 一方、データがコピーされる前に Map メソッドが呼び出されると、パイプラインのストールが発生します。
Direct3D の非同期呼び出し (メソッドの大部分、特にレンダリング呼び出し) は、 コマンド バッファーと呼ばれるものに格納されます。 このバッファーはグラフィックス ドライバーの内部であり、基になるハードウェアへの呼び出しをバッチ処理するために使用されるため、Microsoft Windows のユーザー モードからカーネル モードへのコストの高い切り替えは、可能な限りまれに発生します。
コマンド バッファーがフラッシュされるため、次の 4 つの状況のいずれかでユーザー/カーネル モード スイッチが発生します。
- Present が呼び出されます。
- フラッシュが呼び出されます。
- コマンド バッファーがいっぱいです。そのサイズは動的であり、オペレーティング システムとグラフィックス ドライバーによって制御されます。
- CPU は、コマンド バッファーでの実行を待機しているコマンドの結果にアクセスする必要があります。
上記の 4 つの状況のうち、4 番目の状況がパフォーマンスにとって最も重要です。 アプリケーションがリソースまたはサブリソースをコピーする呼び出しを発行した場合、この呼び出しはコマンド バッファーにキューに入れられます。
その後、コマンド バッファーがフラッシュされる前にコピー呼び出しのターゲットであったステージング リソースをアプリケーションがマップしようとすると、Copy メソッド呼び出しを実行する必要があるだけでなく、コマンド バッファー内の他のすべてのバッファー内のコマンドも同様に実行する必要があるため、パイプライン ストールが発生します。 これにより、GPU がコマンド バッファーを空にし、最後に CPU に必要なリソースを満たす間に、CPU がステージング リソースへのアクセスを待機するため、GPU と CPU が同期します。 GPU がコピーを完了すると、CPU はステージング リソースへのアクセスを開始しますが、この間、GPU はアイドル状態になります。
実行時にこれを頻繁に実行すると、パフォーマンスが大幅に低下します。 そのため、既定の使用状況で作成されたリソースのマッピングは慎重に行う必要があります。 アプリケーションは、コマンド バッファーが空になるまで十分な時間待機する必要があるため、対応するステージング リソースのマップを試みる前に、これらのコマンドの実行がすべて完了します。
アプリケーションはどのくらいの時間待機する必要がありますか? これにより、CPU と GPU の間の並列処理を最大限に活用できるため、少なくとも 2 つのフレーム。 GPU の動作は、アプリケーションがコマンド バッファーへの呼び出しを送信してフレーム N を処理している間に、GPU が前のフレーム N-1 からの呼び出しを実行中にビジー状態になっているということです。
そのため、アプリケーションがビデオ メモリに由来し、フレーム N でリソースをコピーするリソースをマップする場合、アプリケーションが次のフレームの呼び出しを送信するときに、この呼び出しは実際にはフレーム N+ 1 で実行を開始します。 コピーは、アプリケーションがフレーム N+2 を処理しているときに完了する必要があります。
フレーム | GPU/CPU の状態 |
---|---|
N |
|
N+1 |
|
N+2 |
|
N+3 |
|
N+4 | ... |
関連トピック