web-dev-qa-db-ja.com

ハードウェアアクセラレーションされたGUIデータはGPUに保持されますか

ほとんどのハードウェアアクセラレーションGUIライブラリがどのように機能するかについて、いくつかの調査を行っています。ここでは、実際にはそれらのレンダリングバックエンドのみに関心があります。私は、自分自身をある種のサイドプロジェクトとして書き、書くための最良の方法を見つけようとしています。ここでは、過度に凝った機能ではなく、究極のパフォーマンスを目指しています。プリミティブ、テキスト、アニメーションを描けるようになりたいです。

私が知っているいくつかの優れたライブラリは、Qt、Skia、およびCairoです(ただし、HWAの状態が何であるかはわかりません)私はまた、きちんとしたフォローがあるように見える小さなライブラリーであるNanoVGを見ました。私はNanoVGでまともなパフォーマンスを達成することができませんでした...

私を驚かせた唯一のことは、これらのライブラリすべてが「ペイント」の概念を利用しているようであり、各プリミティブ形状がゼロから何度も何度も描かれているように見えることです。つまり、APIからは、形状がGPUで「オブジェクト」として作成されたかのように表示されず、用語が何であれ、そこに残されて「自動」でレンダリングされるようには見えません。言い換えれば、それらはいくつかの大きなループで再描画されるためにGPUのメモリに残されません。詳しく説明すると、描画する必要がある各長方形に対して、その長方形をレンダリングするためだけにOpenGL状態全体が設定され、その後再び破棄されるようです。これらのレンダリングされた形状は、少なくとも最終的な宛先でレンダリングされているように見えますが、GPUはシーン全体を構成できます。

これらのライブラリが機能することを期待していた方法は、実際にシーン全体をGPUに格納することです(恐ろしい用語を除きます)。たとえば、プリミティブは三角測量されてメモリに残され、その後、複雑なプロセスを使用してシーンのメインレンダリングループが作成されます。さらに、属性を更新したり、プリミティブを削除または追加するためのメカニズムが配置されます。これはかなり漠然とした説明ですが、あなたはその考えを理解していると思います。

私が今聞きたいのは、「保存」アプローチと比較して「ペイント」アプローチにパフォーマンス上の利点があるかどうかです(これらにも適切な名前があるかどうかはわかりません...)。おそらく、ある種の複雑なキャッシングメカニズムですか?それとも、これで作業する方がはるかに簡単ですか?

「保存」アプローチはGPUでより多くのメモリを使用する可能性があることを理解していますが、「ペイント」アプローチに必要なすべてのOpenGL呼び出しはそれほど高価ではありませんか?レンダリングされた形状をキャッシュすることでこれを補正できるかもしれないと思いますが、GPUは、特に通信を考慮して、CPUに比べてこのような一度限りの(またはあまり規則的でない)ラスタライゼーションを実行するときに非常に大きなメリットを提供しますオーバーヘッド?また、この通信オーバーヘッドは、すべてのフレームに対して描画を行わなければならないときに、アニメーションに深刻な問題を引き起こしませんか?

NanoVGに内部キャッシングメカニズムがないことは確かであり、これがかなり劣ったパフォーマンスの原因である可能性があると思います。一方、Qtは優れたパフォーマンスを持っているように見えるので、正しく動作しているはずです。グーグルはスキアをうまく​​活用することもできるようです。

PS。私はあらゆる種類の専門家ではなく、つい最近OpenGLを学び始めました。

編集:私が考えた別の可能性は、おそらく「描画」アプローチが純粋にメモリの利点のために必要であると考えられたということですか?私が思うのは、これらのすべてのライブラリはもちろん別の時代に始まったものであり、組み込みプラットフォームもターゲットにしているため、GPUメモリがターゲット(ed)プラットフォームでは非常に少なく、使用量が少ない可能性があるためです。パフォーマンスよりも重要です。繰り返しになりますが、このような状況では、通信オーバーヘッドがCPUを上回っていることを考えると、フレームごとのGPUラスタライゼーションがCPUを上回っているとは確信していません。

さらに、私は http://blog.qt.io/blog/2010/01/06/qt-graphics-and-performance-opengl/ を読みました。Qtは、プリコードされたセグメントのシェーダーコードをブレンドしているようです。実行時の「描画」前に、OGLコンパイラーが実行時にコードを適切にインライン化することを期待しています。これは、OGLの初期化オーバーヘッドがさらに増えるように思えます...

8
Gerharddc

ウィンドウ全体を単一のオブジェクトとしてGPUに保存し(VBOとして保存された四角形の束になります)、単一のOpenGL描画呼び出しでレンダリングすると高速になりますが、いくつかの欠点があります。

  • ジオメトリ全体を単一のシェーダーを使用してレンダリングする必要があります。個別のシェーダー(不透明コピー、透明コピー、グラデーションなど)を使用すると、さらに便利です。
  • ジオメトリ全体は、限られた量のテクスチャからのみ使用できます。アトラスを使用する場合でも、GUIには多くのテクスチャが必要です。 (GUIテーマのピース、アイコン、フォントなど)
  • 変更するたびに、オブジェクト全体を再構築してGPUにリロードする必要があります。
  • すべてのウィジェットは、2Dペインティングよりも抽象化が難しいジオメトリを作成できる必要があります。
  • 一部のGPUでは、3Dパイプラインを使用するよりも高速な2Dコマンドを使用して、2D要素(色で領域を塗りつぶし、画像から画像にコピーするなど)をレンダリングできます。

複数のオブジェクトに分割すると、最終的にオブジェクトごとに1つまたはいくつかの長方形ができます。オブジェクトを保存せずにレンダリングする方が簡単で高速です。

GUIフレームワークが行うことは、変更されたウィンドウの正確な部分を追跡し、それらのみを再描画することです。古いイメージはGPUにキャッシュされます。このアプローチは、OpenGL/DirectXアクセラレートレンダリングだけでなく、さまざまな描画バックエンドで使用できます。

OpengGL(または別の3D api)にフィードできるジオメトリを生成するGUIライブラリの例を確認したい場合は、 librocket を参照してください。実際には静的なジオメトリを一緒にベイクして1回の描画呼び出しでレンダリングできますが、頻繁に変更される要素や独自のシェーダーでレンダリングする必要のある要素は、分離したままにする必要があります。

6
michalsrb