パフォーマンスを「制限」の観点から考えるのが好きです。これは、かなり複雑で相互接続されたシステムを概念化する便利な方法です。パフォーマンスの問題が発生した場合、「私は何の限界に達しているのですか?」(または:「私はCPU / GPUにバインドされていますか?」)
それを複数のレベルに分解できます。最高レベルには、CPUとGPUがあります。CPUバウンド(GPUがアイドル状態でCPUを待機している)またはGPUバウンド(CPUがGPUで待機中)である可能性があります。このトピックに関する優れたブログ記事を次に示します。
さらに細分化できます。でのCPU側には、CPUのキャッシュ内に既にデータにすべてのあなたのサイクルを使用している場合があります。または、メモリが制限されている可能性があり、CPUがアイドル状態のままでメインメモリからデータが入ってくるのを待っています(データレイアウトを最適化します)。さらにそれを分解することができます。
(XNAに関するパフォーマンスの広範な概要を説明している間、参照タイプ(でclass
はないstruct
)の割り当ては、通常は安価ですが、ガベージコレクターをトリガーする可能性があり、特にXbox 360で多くのサイクルを消費する可能性があることを指摘します。ここを参照してください)詳細については。
上のGPU側、私はあなたを指していることから始めましょう。この優れたブログの記事の詳細の多くを持っています。あなたがしたい場合は非常識なパイプラインの詳細レベルを、読んでブログ記事のこのシリーズを。(これはもっと簡単なものです)。
ここに簡単に言えば、いくつかの大きなものがあります:「塗りつぶし制限」(バックバッファーに書き込むことができるピクセル数-多くの場合、オーバードローをどれだけ持つことができるか)、「シェーダー制限」(シェーダーがどれだけ複雑になるか、プッシュできるデータ量)、「テクスチャフェッチ/テクスチャバンド幅制限」(アクセスできるテクスチャデータの量)。
そして、今、私たちはあなたが本当に求めているものである大きなものに来ます-CPUとGPUが(さまざまなAPIとドライバを介して)相互作用する必要があります。大まかに「バッチ制限」と「帯域幅」があります」があります。(注ことをパート1私は先に述べた一連のはに入る豊富な詳細が表示されます。)
しかし、基本的には、(既に知っているように)バッチは、GraphicsDevice.Draw*
機能(またはXNAの一部を、のようなSpriteBatch
、あなたのためにこれを行います)。間違いなくすでに読んでいるので、フレームごとにこれらの数千*を取得します。これはCPU制限です。したがって、他のCPU使用量と競合します。基本的には、ドライバーが描画するように指示したものすべてをパッケージ化し、GPUに送信します。
そして、GPUへの帯域幅があります。これは、そこに転送できる生データの量です。これには、バッチに関連するすべての状態情報が含まれます-レンダリング状態とシェーダー定数/パラメーター(world / view / projectマトリックスなどを含む)の設定から、DrawUser*
関数を使用するときの頂点までのすべて。また、テクスチャ、頂点バッファなどへの呼び出し、SetData
およびその呼び出しも含まGetData
れます。
この時点でSetData
、Effect
s だけでなく、呼び出すことができるもの(テクスチャ、頂点、インデックスバッファなど)はすべてGPUメモリに残っていると言う必要があります。GPUに常に再送信されるわけではありません。そのデータを参照する描画コマンドは、そのデータへのポインターとともに送信されます。
(また、メインスレッドからのみ描画コマンドを送信できますがSetData
、どのスレッドでも送信できます。)
XNAは、ややそのレンダリング状態クラス(で物事を複雑にするBlendState
、DepthStencilState
など)。この状態データは、描画呼び出しごとに(各バッチで)送信されます。100%確信はありませんが、遅延して送信されているという印象を受けています(変更された状態のみを送信します)。いずれにせよ、状態の変更は、バッチのコストに比べて、無料という点で安価です。
最後に、最後に言及するのは内部GPUパイプラインです。まだ読み取る必要があるデータに書き込んだり、まだ書き込む必要があるデータを読み取ったりして、強制的にフラッシュする必要はありません。パイプラインフラッシュは、データのアクセス時にすべてが一貫した状態になるように、操作が完了するまで待機することを意味します。
注意すべき2つの特定のケースは次のとおりです。GetData
動的なRenderTarget2D
もの、特にGPUが書き込みを行う可能性のあるものを呼び出します。これはパフォーマンスにとって非常に悪いです-しないでください。
もう1つのケースはSetData
、頂点/インデックスバッファーを呼び出すことです。これを頻繁に行う必要がある場合は、DynamicVertexBuffer
(またDynamicIndexBuffer
)を使用します。これにより、GPUは頻繁に変更されることを認識し、パイプラインフラッシュを回避するために内部でバッファリングマジックを実行できます。
(動的バッファはDrawUser*
メソッドよりも高速ですが、必要な最大サイズで事前に割り当てる必要があることに注意してください。)
...そして、XNAパフォーマンスについて私が知っていることはほとんどすべてです:)