web-dev-qa-db-ja.com

VBOが「単純な」OpenGLプリミティブ(glBegin())よりも速いのはいつですか?

Vertex Buffer Objects(VBO)について何年も聞いた後、私はついにそれらを試してみることにしました(私のものは通常、パフォーマンスが重要ではないことは明らかです...)

以下に私の実験について説明しますが、簡単に言うと、「単純な」ダイレクトモード(glBegin()/ glEnd())、頂点配列(CPU側)、VBO(GPU側)の間で区別できないパフォーマンスが見られます。レンダリングモード。私はこれがなぜであるか、そしてどのような条件下でVBOが彼らの原始的な(しゃれを意図した)祖先を大幅に凌駕するのを見ることができるかを理解しようとしています。

実験の詳細

実験のために、私は多数の点の(静的な)3Dガウス雲を生成しました。各ポイントには、頂点と色の情報が関連付けられています。次に、「軌道を回る」動作のように、連続するフレームでカメラを雲の周りで回転させました。繰り返しますが、ポイントは静的であり、目だけが移動します(gluLookAt()を介して)。データは、レンダリングの前に1回生成され、レンダリングループで使用するために2つの配列に格納されます。

直接レンダリングの場合、データセット全体が単一のglBegin()/ glEnd()ブロックにレンダリングされ、ループにはそれぞれglColor3fv()およびglVertex3fv()への単一の呼び出しが含まれます。

頂点配列とVBOレンダリングの場合、データセット全体が1回のglDrawArrays()呼び出しでレンダリングされます。

次に、タイトなループで1分ほど実行し、高性能タイマーを使用して平均FPSを測定します。

パフォーマンス結果##

上記のように、パフォーマンスはデスクトップマシン(XP x64、8GB RAM、512 MB Quadro 1700)とラップトップ(XP32、4GB RAM、256 MB Quadro NVS 110)の両方で区別できませんでした。ただし、ポイント数に応じて期待どおりにスケーリングされました。もちろん、vsyncも無効にしました。

ラップトップの実行からの特定の結果(GL_POINTSを使用したレンダリング):

glBegin()/ glEnd():

  • 1Kポイント-> 603 FPS
  • 10Kポイント-> 401 FPS
  • 100Kポイント-> 97 FPS
  • 1Mポイント-> 14 FPS

頂点配列(CPU側):

  • 1Kポイント-> 603 FPS
  • 10Kポイント-> 402 FPS
  • 100Kポイント-> 97 FPS
  • 1Mポイント-> 14 FPS

頂点バッファオブジェクト(GPU側):

  • 1Kポイント-> 604 FPS
  • 10Kポイント-> 399 FPS
  • 100Kポイント-> 95 FPS
  • 1Mポイント-> 14 FPS

同じデータをGL_TRIANGLE_STRIPでレンダリングしたところ、同様に区別できなくなりました(ただし、余分なラスタライズが原因で予想どおりに遅くなりました)。誰かが欲しいなら、私もそれらの番号を投稿することができます。 。

質問

  • 何が得られますか?
  • VBOの約束されたパフォーマンスの向上を実現するには、何をする必要がありますか?
  • 何が足りないのですか?
36
Drew Hall

3Dレンダリングを最適化するための多くの要因があります。通常、4つのボトルネックがあります。

  • CPU(頂点の作成、APU呼び出し、その他すべて)
  • バス(CPU <-> GPU転送)
  • 頂点(固定関数パイプライン実行上の頂点シェーダー)
  • ピクセル(塗りつぶし、フラグメントシェーダーの実行、およびrops)

頂点またはピクセルのスループットを最大化しながらCPU(およびバス)が大量にあるため、テストの結果は歪んでいます。 VBOは、CPUを下げるために使用されます(API呼び出しが少なく、CPU DMA転送と並行して)。CPUにバインドされていないため、ゲインは得られません。これが最適化101です。たとえばCPUは、大量のAPI呼び出しを発行するだけでなく、AIや物理学などの他の目的で必要になるため、貴重になります。頂点データ(たとえば、3つのフロート)をメモリポインターに直接書き込む方がはるかに高速であることが簡単にわかります。 3つのfloatをメモリに書き込む関数を呼び出すよりも、少なくとも呼び出しのサイクルを節約できます。

27
starmole

足りないものがいくつかあるかもしれません:

  1. これは大げさな推測ですが、ラップトップのカードにはこの種の操作がまったくない可能性があります(つまり、エミュレートします)。

  2. データをGPUのメモリにコピーしていますか(glBufferDataGL_ARRAY_BUFFERGL_STATIC_DRAWまたはGL_DYNAMIC_DRAW paramのいずれかを使用)、またはメイン(非GPU)配列へのポインターを使用していますか?メモリ?(フレームごとにコピーする必要があるため、パフォーマンスが低下します)

  3. インデックスglBufferDataおよびGL_ELEMENT_ARRAY_BUFFERパラメータを介して送信される別のバッファとして渡していますか?

これらの3つのことを行うと、パフォーマンスが大幅に向上します。 Python(v/pyOpenGl)の場合、数100要素よりも大きい配列では約1000倍、C++では最大5倍高速ですが、配列では50k〜10mの頂点です。

これがc ++(Core2Duo/8600GTS)のテスト結果です。

 pts   vbo glb/e  ratio
 100  3900  3900   1.00
  1k  3800  3200   1.18
 10k  3600  2700   1.33
100k  1500   400   3.75
  1m   213    49   4.34
 10m    24     5   4.80

したがって、10mの頂点でも通常のフレームレートでしたが、glB/eでは遅くなりました。

10
Slava V

補足として:
「ダイレクトモード」(glBegin/glEnd)は、次ではサポートされていません。

  • OpenGLES。
  • OpenGL3.x。
  • したがって、アプリケーションをモバイルプラットフォーム(iPhoneなど)に移植する予定がある場合は、それに慣れないでください。

    私は大学でOpenGLを教えていますが、glBegin/glEndを説明するスライドの周りには、太字の「使用しない」ヘッダーが付いた大きな赤いボックスがあります。

    頂点配列を使用すると、あと2行で、最初からサイクルを節約できます。

    4
    Andreas

    レッドブックを読んで、VBOの方がおそらく速いと述べた箇所を覚えていますハードウェアによって異なります。一部のハードウェアはそれらを最適化しますが、他のハードウェアは最適化しません。ハードウェアがそうではない可能性があります。

    2
    Will Mc

    14Mpoints/sはそれほど多くはありません。疑わしいです。描画を行う完全なコードと初期化を確認できますか? (その14M/sをSlavaVishnyakovが取得する240M/s(!)と比較してください)。 1Kのドローで640K/sに低下することはさらに疑わしいです(とにかく、〜3800 SwapBuffersで制限されているように見える彼の3.8M/sと比較して)。

    私は、テストがあなたがそれが測定すると思うものを測定しないに違いない。

    1
    Bahbar