レンダリング、バッチ、グラフィカルカード、パフォーマンスなどに関する情報+ XNA?


12

タイトルは少しあいまいですが、私が本当に探しているものを説明するのは難しいですが、ここに行きます。

CPUレンダリングに関しては、パフォーマンスはほとんど推定が容易で簡単ですが、GPUに関しては技術的な背景情報が不足しているため、手がかりがありません。私はXNAを使用しているので、理論がそれに関連していればいいと思います。

私が実際に知りたいのは、特定の描画アクションを行うと、いつどこで何が起こるかということです(CPU / GPU)。バッチとは何ですか?効果、投影などはどのような影響を与えますか?データはグラフィックカードに保持されますか、それともすべてのステップで転送されますか?帯域幅について話すとき、グラフィックカードの内部帯域幅について話していますか、それともCPUからGPUへのパイプラインについて話していますか?
注:描画プロセスがどのように行われるについての情報を実際に探しているわけではありませんそれはGPUのビジネスです。それに先行するすべてのオーバーヘッドに興味があります。

アクションXを実行したときに何が起こっているのかを理解し、それにアーキテクチャとプラクティスを適合させたいと思います。

より良いゲームを書く方法についてより多くの洞察を与える記事(おそらくコード例付き)、情報、リンク、チュートリアルは大歓迎です。ありがとう:)


2
これは元々XNAでしたが、DirectXタグを基礎技術として追加しました-より良い答えを得るのに役立つかもしれません。また、適切な出発点を提供する可能性があるこの回答も確認してください。
アンドリューラッセル

@AndrewRussellどうもありがとう:)。私は実際に、そのトピックに関するさまざまな記事をすでに読んでいます。しかし、それは私が知りたいすべてをカバーしていません。
アイディアカピ

回答:


20

パフォーマンスを「制限」の観点から考えるのが好きです。これは、かなり複雑で相互接続されたシステムを概念化する便利な方法です。パフォーマンスの問題が発生した場合、「私は何の限界に達しているのですか?」(または:「私は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れます。

この時点でSetDataEffects だけでなく、呼び出すことができるもの(テクスチャ、頂点、インデックスバッファなど)はすべてGPUメモリに残っていると言う必要があります。GPUに常に再送信されるわけではありません。そのデータを参照する描画コマンドは、そのデータへのポインターとともに送信されます。

(また、メインスレッドからのみ描画コマンドを送信できますがSetData、どのスレッドでも送信できます。)

XNAは、ややそのレンダリング状態クラス(で物事を複雑にするBlendStateDepthStencilStateなど)。この状態データ、描画呼び出しごとに(各バッチで)送信されます。100%確信はありませんが、遅延して送信されているという印象を受けています(変更された状態のみを送信します)。いずれにせよ、状態の変更は、バッチのコストに比べて、無料という点で安価です。

最後に、最後に言及するのは内部GPUパイプラインです。まだ読み取る必要があるデータに書き込んだり、まだ書き込む必要があるデータを読み取ったりして、強制的にフラッシュする必要はありません。パイプラインフラッシュは、データのアクセス時にすべてが一貫した状態になるように、操作が完了するまで待機することを意味します。

注意すべき2つの特定のケースは次のとおりです。GetData動的なRenderTarget2Dもの、特にGPUが書き込みを行う可能性のあるものを呼び出します。これはパフォーマンスにとって非常に悪いです-しないでください。

もう1つのケースはSetData、頂点/インデックスバッファーを呼び出すことです。これを頻繁に行う必要がある場合は、DynamicVertexBuffer(またDynamicIndexBuffer)を使用します。これにより、GPUは頻繁に変更されることを認識し、パイプラインフラッシュを回避するために内部でバッファリングマジックを実行できます。

(動的バッファはDrawUser*メソッドよりも高速ですが、必要な最大サイズで事前に割り当てる必要があることに注意してください。)

...そして、XNAパフォーマンスについて私が知っていることはほとんどすべてです:)


どうもありがとうございます!これはまさに私が探し求めていたものです:)。
アイディアカピ

1
フレームあたり数百のバッチは、悲観的に聞こえます。私がいつも聞いた経験則は、フレームごとに2Kから3Kのバッチです。一部のゲームはPCで最大10Kになることが知られていますが、それを実現するには細心の注意が必要だと思います。
ネイサンリード

まったく正しい。「数百」という数字は、「バッチバッチバッチ」の紙に由来します-「1GHz CPUの100%で25kバッチ/秒」と記載されています。しかし、その論文は10年前になり、それ以来、ドライバーとCPUが大幅に改善されました。これを(および他の人も)更新して、「数千」と読みます。
アンドリューラッセル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.