バッチ処理のパフォーマンスを向上させる方法


9

私はモバイルプラットフォーム用のスプライトベースの2Dゲームを開発しており、OpenGL(まあ、実際にはIrrlicht)を使用してグラフィックスをレンダリングしています。まず、シンプルな方法でスプライトレンダリングを実装しました。すべてのゲームオブジェクトは、独自のGPU描画呼び出しを持つクワッドとして描画されます。つまり、200のゲームオブジェクトがある場合、フレームごとに200描画呼び出しを行いました。もちろん、これは悪い選択であり、すべてのGPU描画呼び出しに関連付けられたCPUオーバーヘッドが少しあるため、私のゲームは完全にCPUバウンドでした。ほとんどの場合、GPUはアイドル状態のままでした。

今、私はオブジェクトを大きなバッチに収集し、これらのバッチを少数の描画呼び出しのみでレンダリングすることで、パフォーマンスを改善できると思いました。バッチ処理を実装し(同じテクスチャを共有するすべてのゲームオブジェクトが同じバッチでレンダリングされるように)、問題がなくなったと考えました...フレームレートが以前よりもさらに低いことを確認するだけです。

どうして?ええと、私には200(またはそれ以上)のゲームオブジェクトがあり、それらは1秒あたり60回更新されます。CPU内の頂点の新しい位置(変換と回転)を再計算する必要があるすべてのフレーム(モバイルプラットフォームのGPUはインスタンス化をサポートしていないため、そこで実行することはできません)。この計算は1秒あたり48000(200 * 60 * 4以降)すべてのスプライトには4つの頂点があります)、単に遅すぎるようです。

パフォーマンスを改善するために私ができることは何ですか?すべてのゲームオブジェクトが(ほぼ)すべてのフレームで移動/回転しているため、頂点の位置を再計算する必要があります。私が考えることができる最適化は、ローテーションのルックアップテーブルだけなので、計算する必要はありません。ポイントスプライトは役に立ちますか?厄介なハックはありますか?他に何か?

ありがとう。

回答:


5

アンドロイド用のirrlichtのポートを使用しましたか?AndroidとiPhoneの2Dスプライトの場合、私はあなたと同じトリックを使用します。バッチ処理です。OpenGL ES 1.xおよび2.xで多くのソリューションを試します。

  • z(視差)およびテクスチャで並べ替え、CPUで変換を行い、glDrawArraysまたはglDrawElementsを呼び出します(最速の方法)。可能であれば、1つの大きなテクスチャを使用します。
  • VBOと同じトリックですが、フレームごとにすべての情報を更新するため、高速ではありません。staticsスプライトに役立ちます。
  • OpenGL ES 2.xを使用し、頂点シェーダーを使用して位置を計算する(遅い)
  • PointSpritesを使用します(四角形ではなく、透明ピクセルが多すぎると塗りつぶし率が低下する場合の解決策はありません)
  • gldrawtexoes拡張機能を使用...
  • 各スプライトに描画呼び出しを使用する(最も遅いメソッド)

したがって、あなたと同じように、すべての変換はOGLES 1.xまたはOGLES 2.xのCPUによって行われます。ネオン命令がある場合は、それらを使用して計算を高速化できます。

PS:iPhoneまたはAndroidデバイスでは、CPU制限はありませんが、フィルレートは制限されています。したがって、オーバードローを制限することは非常に重要です。


すばらしい、これは私が探していたものです。私はあなたのIrrlichtポートを認識していませんでしたが、私のバージョンのIrrlichtはすでにiOSで実行されています。あなたはCPUに制限されていないと言っています-あなたはいくつのスプライトを描いていますか?そして、あなたのフレームレートは何ですか、例えば、iPhoneの100個のスプライトについて?200個のオブジェクトがある場合、1秒あたり48000回の計算を実行します。フィルレートについてのあなたのポイントは良いです。
user4241 2011年

静的スプライト(背景)はVBOにあります。視差ごとに1つのVBOを使用します。それ以外の場合、Mobloxに100から200のスプライトがあります。3Gを含むすべてのiphoneで、30fpsを超えています(覚えています)。しかし、大きなスプライトは....(fillrate問題)非常に高価である
エリス

私はパーティクルエンジンに取り組んでいます。CPUですべての位置の計算が行われ、最大20 000の粒子を使用でき、極端な設定(3GSおよびiPhone4)で10fpsを使用しています。したがって、3GSまたはiPhone4で1000スプライトが適切なフレームレートで可能でなければなりません。
Ellis

とても役に立ちました!パーティクルエンジンをどのように実装していますか?シェーダーをいじっていると思いますか?
user4241 2011年

各パーティクルサイズを設定するにはgl_PointSizeが必要なので、シェーダーを使用します。古い電話は私の対象ではないので、OGLES 1.xではもう作業しません。まず、私のコードはすべてOGLES 1.x、次にOGLES 1.xとOGLES 2.x(パフォーマンスの向上なし)、そして今度はOGLES 2.x(レンダリングの向上)でした。
Ellis

1

私はVBOを用意することをお勧めします。各頂点には、レンダリングされた各オブジェクトの位置/回転が含まれ、あなたがしているようなテクスチャに基づいてバッチ処理されます。私はogl ESにあまり詳しくないので、サポートされているglslのバージョンはわかりませんが、一連のテクスチャに基づいてバッチ処理し、渡した4つほどのテクスチャのどれを保存することもできます。頂点の内側を使用します。ポイントスプライトを使用すると、送信するデータの量が大幅に削減されるため、パフォーマンスが確実に向上します。正しく実行している場合は、バッチ処理によってパフォーマンスが低下することはありません。また、シェーダーの回転を計算し、int / float値をパラメーターまたは頂点自体の内部に渡すだけで、パフォーマンスを少し向上させることもできます。(paramsはより速く、


お返事ありがとうございます。シェーダーで回転計算を行うことについてのあなたの提案は優れていますが、残念ながら私はシェーダーをサポートしていないOpenGL ES 1を使用しているため、固定パイプラインで立ち往生しています。ポイントスプライトを試してみますが、サイズに上限があるため、すべてのケースで使用できるわけではありません。私はまだVBOについて少し悲観的です、各頂点の位置をフレームごとに再計算している場合、VBOはどのように役立ちますか?
user4241

これにより、頂点データをgpuに留めることができ、フレームごとにgpuに送信する必要があるデータの量が減ります。これを利用するためにシェーダーは必要ありません。頂点データを変更する必要はまったくありません。各スプライトのベース位置(原点など)がある場合は、次のようにしてワールドマトリックスを変更できます。 drawを呼び出す前に変換されます。ただし、バッチ処理の場合、これは難しい場合があります。固定機能を使用する場合、少なくとも今のところはVBOに切り替えてバッチ処理をドロップする方がおそらくメリットがあり、確実にブーストが得られます。
シンガー

あなたの言ってる事がわかります。結局のところ、バッチ処理についてではなく、1つの描画呼び出しを使用して1つのゲームオブジェクトを描画するだけです。私は間違いなく、バッチ処理なしのVBOがゲームのFPSにどのように影響するかをテストしますが、フレームごとに200の描画呼び出しは大きすぎるように聞こえます... 他の回答が表示されない場合、私はあなたの回答を受け入れます。
user4241

1

あなたはインスタンス化されていないモバイルプラットフォームについて言及します。しかし、まだ頂点シェーダーはありますか?

その場合でも、非常に高速な疑似インスタンス化を行うことができます。コーナーポイント(スプライトの中心点を基準にして-1 / -1、1 / -1、1/1、-1/1など)と必要なテクスチャ座標をVBO(GL_STATIC_DRAW)に作成します。 。
次に、スプ​​ライトの中心点へのすべての描画呼び出しに対して一般的な頂点属性の1つを設定し、バッファがバインドされた2つの三角形を描画します。頂点シェーダー内で、一般的な頂点属性を読み取り、頂点の座標を追加します。

これにより、すべてのスプライトのデータ転送をブロックする手間が省け、はるかに高速になります。描画呼び出しの実際の数はそれほど重要ではなく、その間のブロッキング/ストールが重要です。


これは、OpenGL ES 2.0の優れたソリューションのようです。残念ながら、シェーダーがまったくないES 1を使用しています。
user4241 2011年

0

問題は、フレームごとにGPUに送信するデータの量にあります。バッチごとにVBOを作成して1度入力するだけで、バッチを描画するときに対応する変換マトリックス(glMultMatrix、またはES 2.0を使用している場合はシェーダー)を適用します。


独自の変換を備えた200個の個別のゲームオブジェクトがある場合、これがどのように役立つのか理解できません。glMultMatrixを使用すると、すべてのオブジェクトに同じ変換が適用されますが、これは私が望むものではありません。また、GPUへのデータ送信はボトルネックではありません。CPU側の変換を削除すると、パフォーマンスが非常に向上します。
user4241 '28

はい。ただし、VBOを正しく適用すると、パフォーマンスが向上する可能性があります。現在200オブジェクトをどのようにレンダリングしていますか?glBegin / glEndを使用していますか?
TheBuzzSaw

1
カスタムシーンノードでIrrlicht 3Dエンジンを使用しているため、OpenGLを直接使用していません(ただし、この場合は単純なglBegin / glEndを使用していると思います)。フレームごとにバッファ全体を変更する必要があるため、VBOは本当に役に立ちますか?また、頂点変換の計算のため、これはCPUバウンドであるという根本的な問題を解決しません。とにかく答えてくれてありがとう!
user4241 '28
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.