次の方法で共有


リソース データのコピーとアクセス (Direct3D 10)

もう、リソースをビデオ メモリーで作成するか、システム メモリーで作成するかを考える必要はありません。また、ランタイムでメモリーを管理するかどうかについても同じです。新しい WDDM (Windows Display Driver Model) のアーキテクチャにより、アプリケーションでは、アプリケーションでリソース データを使用する際の用途を示すさまざまな使用法フラグを付けて、Direct3D 10 リソースを作成するようになりました。この新しいドライバー モデルは、リソースが使用するメモリーを仮想化します。想定された使用法の下で、可能な限りパフォーマンスが高い領域にリソースを配置することが、オペレーティング システム、ドライバー、およびメモリー マネージャーの役割になります。

既定のケースは、GPU で使用できるリソースを対象としています。もちろん、そのリソース データを CPU が使用する必要がある場合もあります。パフォーマンスに影響を与えずに適切なプロセッサでアクセスできるように、リソース データのコピーには、API メソッドの動作についての知識が必要です。

  • リソース データのコピー
  • リソース データへのアクセス

リソース データのコピー

リソースは、Direct3D が Create の呼び出しを実行する際に、メモリーに作成されます。このリソースは、ビデオ メモリー、システム メモリー、またはその他任意の種類のメモリーに作成できます。WDDM ドライバー モデルはこのメモリーを仮想化するので、アプリケーションでは、作成されたメモリー リソースの種類を追跡する必要がなくなりました。

理想的には、GPU が直ちにアクセスできるように、すべてのリソースをビデオ メモリーに配置します。ただし、CPU がリソース データを読み取ったり、CPU が書き込んだリソース データに GPU がアクセスしたりする必要がある場合があります。Direct3D 10 では、アプリケーションが使用法を指定するように要求することにより、これらのさまざまなシナリオを処理し、さらに必要に応じてリソース データをコピーするためのメソッドをいくつか提供します。

リソースの作成方法によっては、基になるデータに直接アクセスできないことがあります。これは、リソース データをソース リソースから、適切なプロセッサからアクセス可能な別のリソースへコピーする必要があることを意味している場合があります。Direct3D 10 に関しては、既定のリソースには GPU から直接アクセスでき、動的リソースおよびステージング リソースには、CPU から直接アクセスできます。

リソースが一度作成されると、その使用法は変更できません。代わりに、リソースの内容を、異なる使用法で作成された別のリソースへコピーします。Direct3D 10 では、異なる 3 つのメソッドでこの機能を提供します。最初の 2 つのメソッド (ID3D10Device::CopyResourceID3D10Device::CopySubresourceRegion) は、あるリソースから別のリソースへリソース データをコピーするように設計されています。3 番目のメソッド (ID3D10Device::UpdateSubresource) は、データをメモリーからリソースにコピーするように設計されています。

リソースには主に 2 種類があります。マッピング可能なものと、マッピング不可能なものです。動的またはステージングの使用法で作成されたリソースはマッピング可能ですが、既定または固定の使用法で作成されたリソースはマッピング不可能です。

マッピング不可能なリソース間でのデータのコピーは、最も一般的なケースであり、適切に実行されるよう最適化されているため、非常に高速です。これらのリソースは CPU から直接アクセスできないため、GPU から高速に操作できるように最適化されています。

マッピング可能なリソース間でのデータのコピーは、リソースの作成時の使用法によりパフォーマンスが異なるので、より問題が生じやすくなります。たとえば、GPU は動的リソースをかなり高速で読み取ることができますが、書き込むことができません。また、GPU はステージング リソースの直接読み取り、または書き込みができません。

使用法が既定のリソースから、使用法がステージングのリソースへデータをコピーしようとする (CPU でデータを読み取ることができるようにするため、つまり GPU のリードバックの問題) アプリケーションは、注意して実行する必要があります。この最後のケースの詳細については、「リソース データへのアクセス」を参照してください。

リソース データへのアクセス

リソースにアクセスするには、リソースをマッピングする必要があります。マッピングとは、基本的には、アプリケーションが CPU からメモリーへのアクセスを行おうとすることです。CPU から基になるメモリーへアクセスできるようリソースをマッピングするプロセスでは、何らかのパフォーマンス ボトルネックが発生する場合があります。このため、このタスクをいつどのように実行するかについて、注意を払う必要があります。

アプリケーションが不適切なときにリソースをマッピングしようとすると、パフォーマンスが大幅に低下することがあります。ある操作が終了する前に、アプリケーションがその操作の結果にアクセスしようとすると、パイプライン ストールが発生します。

不適切なときにマッピング操作を実行すると、GPU および CPU が互いに強制的に同期させられ、パフォーマンスの深刻な低下を引き起こす潜在的な可能性があります。この同期化は、CPU がマッピング可能なリソースに GPU がリソースをコピーし終わる前に、アプリケーションがそのリソースにアクセスしようとすると発生します。

CPU は、D3D10_USAGE_STAGING フラグで作成されたリソースのみから読み取ることができます。このフラグで作成されたリソースはパイプラインの出力として設定することができないので、GPU によって生成されたリソースのデータを CPU で読み取ろうとする場合、そのデータはステージング フラグで作成されたリソースにコピーする必要があります。これは、ID3D10Device::CopyResource メソッドまたは ID3D10Device::CopySubresourceRegion メソッドを使用して、あるリソースの内容を別のリソースにコピーすることで実行できます。その場合、アプリケーションは適切な Map メソッドを呼び出すことで、このリソースにアクセスできるようになります。リソースへのアクセスが不要になったときには、対応する Unmap メソッドをアプリケーションで呼び出す必要があります。たとえば、ID3D10Texture2D::マップID3D10Texture2D::Unmap です。Map メソッドが異なると、その入力フラグに応じて、いくつか特定の値が返されます。詳細については、マップに関する解説を参照してください。

パフォーマンスに関する考慮事項

PC は、主に 2 種類のプロセッサを含む並列アーキテクチャとして動作しているマシンと考えてください。2 種類のプロセッサとは、1 つ以上の CPU と 1 つ以上の GPU です。どの並列アーキテクチャでも、最高のパフォーマンスが得られるのは、各プロセッサがアイドル状態にならないように十分なタスクをスケジュールしているときと、1 つのプロセッサでの作業が別のプロセッサでの作業を待機していないときです。

GPU および CPU の並列処理の最悪のケースのシナリオは、あるプロセッサが別のプロセッサが行った仕事の結果を待機する必要があるという場合です。Direct3D 10 では、ID3D10Device::CopyResource メソッドと ID3D10Device::CopySubresourceRegion メソッドを非同期にすることにより、この損失を取り除こうとしています。コピーは、メソッドが返されるときまでに必ずしも実行しておく必要はありません。この方法の利点は、Map が呼び出されて CPU がデータにアクセスするまで、データを実際にコピーするというパフォーマンスのコストをアプリケーションが負担しないことです。データが実際にコピーされた後に Map メソッドが呼び出されると、パフォーマンスの損失が発生しません。一方、データがコピーされる前に Map メソッドが呼び出される場合は、パイプライン ストールが発生します。

Direct3D 10 の非同期呼び出し (メソッドの大多数の呼び出しおよび、特にレンダリング呼び出し) は、コマンド バッファーと呼ばれる場所に格納されます。このバッファーは、グラフィックス ドライバー内部にあり、Microsoft Windows のユーザー モードからカーネル モードへの負荷の大きい切り替えができるだけ発生しないように、基になるハードウェアへの呼び出しをバッチ処理するために使用されます。

以下の 4 つの状況のいずれかで、コマンド バッファーがフラッシュされ、ユーザー モードとカーネル モードの切り替えが発生します。

  1. Present が呼び出されます。
  2. ID3D10Device::Flush が呼び出されます。
  3. コマンド バッファーがいっぱいです。コマンド バッファーのサイズは動的で、オペレーティング システムとグラフィックス ドライバーで制御されます。
  4. CPU は、コマンド バッファーで実行を待っているコマンドの結果にアクセスする必要があります。

前述の 4 つの状況で、4 番目がパフォーマンスにおいて最も重要です。アプリケーションが ID3D10Device::CopyResource 呼び出しまたは ID3D10Device::CopySubresourceRegion 呼び出しを発行する場合、この呼び出しはコマンド バッファーにキューイングされます。そこでアプリケーションが、コピー呼び出しの対象だったステージング リソースを、コマンド バッファーがフラッシュされる前にマッピングしようとすると、Copy メソッドの呼び出しを実行する必要があるだけでなく、コマンド バッファー内にバッファーされたその他すべてのコマンドも実行しなければならないため、パイプライン ストールが発生します。これにより、GPU がコマンド バッファーを空にし、CPU が必要とするリソースに最終的にデータを格納する間、CPU はステージング リソースへのアクセスを待機するので、GPU と CPU の同期が発生します。GPU がコピーを終了すると、CPU はステージング リソースへのアクセスを開始します。しかしこの間、GPU はアイドル状態となります。

ランタイムにこれを頻繁に行うと、パフォーマンスが著しく低下します。そのため、既定の使用法で作成されたリソースのマッピングは、注意して行う必要があります。アプリケーションは、コマンド バッファーが空になるのに十分な時間待機し、対応するステージング リソースにマッピングしようとする前に、こうしたコマンドをすべて実行し終える必要があります。アプリケーションはどれだけ待機すればよいのでしょうか。少なくとも 2 フレームです。これにより CPU と GPU 間の並列処理が最大限利用できるからです。GPU がどのように動作するかというと、アプリケーションがコマンド バッファーに呼び出しを送信することにより N 番目のフレームを処理する間、GPU は前のフレームである N-1 番目からの呼び出しの実行でビジー状態です。

そこで、アプリケーションがビデオ メモリーにあるリソースをマッピングしようとし、N 番目のフレームで ID3D10Device::CopyResource または ID3D10Device::CopySubresourceRegion を呼び出す場合、この呼び出しは実際には、アプリケーションが次のフレームの呼び出しを送信しているとき、N + 1 番目のフレームで実行を開始します。コピーは、アプリケーションが N + 2 番目のフレームを処理しているときに完了します。

フレーム GPU/CPU の状態
N
  • CPU が現在のフレームのレンダリング呼び出しを行います。
N + 1
  • N 番目のフレームの間、GPU は CPU から送信された呼び出しを実行しています。
  • CPU が現在のフレームのレンダリング呼び出しを行います。
N + 2
  • N 番目のフレームの間に、GPU は CPU から送信された呼び出しの実行を完了しました。結果の準備ができています。
  • N + 1 番目のフレームの間、GPU は CPU から送信された呼び出しを実行しています。
  • CPU が現在のフレームのレンダリング呼び出しを行います。
N + 3
  • N + 1 番目のフレームの間に、GPU は CPU から送信された呼び出しの実行を完了しました。結果の準備ができています。
  • N + 2 番目のフレームの間、GPU は CPU から送信された呼び出しを実行しています。
  • CPU が現在のフレームのレンダリング呼び出しを行います。
N + 4 ...

関連項目

リソース (Direct3D 10)