4

GDI+ のパフォーマンスについて説明している信頼できる (そして願わくば広範な) 本や Web サイトを知っている人はいますか?

たとえば、私は最近、この優れた実験に出くわしました。Graphics.FillPath()私は最近、それが よりもはるかに速いことに気付きましたGraphics.DrawPath()。私が見逃している他の重要な情報を知りたいです。

のれん、デビッド

4

2 に答える 2

21

うーん。パスのアウトラインを描画する必要がある場合、FillPath が DrawPath よりも高速であることを知っていても意味がありません。

GDI+ を最適化する最善の方法は、他のコードの場合とまったく同じです。まず、最適化しないでください。その代わり:

  • 単純に動作するように記述することから始めて、実際に遅すぎるかどうかを判断します。
  • 次に、「アルゴリズム」を調べます。
    • 描画するものを単純化すると (描画するものの数を減らす)、高速になります (そして、ほとんどの場合、混乱を減らした方が見栄えが良くなります)。
    • 毎回ディスプレイ全体を描画していますか、それとも、更新する必要のない画像の一部を描画しないように、クリップの四角形を使用していますか?
    • 物事を描く方法を調べます。再描画ごとにリソース (ブラシやペンなど) を作成および破棄していますか? それらをメンバー変数にキャッシュします。同じピクセルを複数回オーバードローしていますか? (たとえば、背景を描画し、その上にビットマップを描画し、その上に四角形を描画します。おそらく、これらの再描画の一部を回避できます)。10 個のセグメントだけで十分に見える曲線を 100 個のポリゴン セグメントを使用して描いていますか? ウィンドウがスクロールするとき、OS に既存の画像を移動させて、新たに表示されたストリップのみを再描画する必要がありますか?それとも、ウィンドウ全体を再描画して時間を無駄にしますか?
    • 変換を使用していますか、それともコードで長い位置計算を行っていますか?
    • ループをチェックし、ループ内で使用する値を事前に計算するなど、できるだけ多くのコードをそれらから移動していることを確認してください。可能であれば、ループが CPU キャッシュに適した方向/方法でデータを反復処理するようにしてください。
    • 再描画中に処理しているデータはありますか? おそらく、これらの一部は、レンダリングに最適な形式で事前に計算または整理できます。たとえば、別のタイプのリストを使用すると、データを列挙するのが速くなりますか? 描画する必要がある 10 個のデータを見つけるために、1000 個のデータ項目を処理していますか?
    • 別のアプローチで同じ外観を実現できますか? 例)黒と白を交互に 64 個の正方形を描くことで、チェス盤を描くことができます。32 個の黒の正方形を描画してから 32 個の白の正方形を描画すると、四角形間の状態の変化を避けることができます。しかし、実際には、白い背景のクリア、4 つの黒い四角形、および 4 つの XOR 四角形 (64 ではなく 8 つの四角形 => はるかに高速なアルゴリズム) を使用して描画できます。
  • 頻繁に変更されないイメージの部分はありますか? 再描画ごとに「再構築」する必要がある量を最小限に抑えるために、オフスクリーン ビットマップにそれらをキャッシュしてみてください。オフスクリーン ビットマップをレンダリングし、その上にグラフィックス プリミティブを重ねることができることに注意してください。そのため、認識しているよりもはるかに多くの「静的な」イメージ領域が見つかる可能性があります。
  • ビットマップ画像をレンダリングしていますか? それらを描画するたびに GDI+ に変換させるのではなく、画面のピクセル形式に変換し、その「ネイティブ」形式でキャッシュしてみてください。
  • レンダリングを高速化するための低品質のトレードオフに満足している場合は、品質設定を下げます

これらのことをすべて終えたら、レンダリングの最適化に関する本を探し始めることができます。もちろん、それでも遅すぎる場合は。プロファイラーを実行して、レンダリングのどの部分が最も遅いかを調べます。

改善できると思われる場合は、さまざまなレンダリング方法を試すか (たとえば、Graphics.Clear() は、FillRectangle() で背景を塗りつぶすよりもはるかに高速である可能性が高い)、またはさまざまなレンダリング順序 (すべてのものを描画する) を試してください。状態の変更に時間がかかる場合に備えて、最初に 1 つの色を選択します - 最新のグラフィックス カードでは、バッチ操作が非常に重要になることがよくあります. 通常、複数のポリゴンを描画する単一の呼び出しは、複数の単一ポリゴンの呼び出しを行うよりも高速です。遅延レンダリング バッファを作成し、レンダリング パスの最後にそれらすべてをコミットしますか?)

その後、ハードウェアに近づくために GDI または DirectX の使用を検討する必要があるかもしれません。

于 2009-12-25T21:13:13.060 に答える
11

これはあなたが探している答えではないかもしれませんが、GDI+をまったく使用しないことを検討してください。最近、2D-CAMアプリケーションのレンダリングスタックを書き直す必要がありました。最も重要な要件は、適切なアンチエイリアス行を高速に取得することでした(アンチエイリアスは、既存のGDIレンダラーを書き直すきっかけとなりました)。

これが200アイテムのレンダリングで得られたいくつかの結果です(各アイテム自体はいくつかの線と小さな塗りつぶされた形状のマーカーです)。これらは(Windows 7の)フレームレートであるため、高いほど良いです。

200アイテム:GDI = 51、GDI + = 20、D2D = 59、WPF = 33、GL=59。

(D2DはDirect2D、GLはOpenGLです)。すでに、GDI+が後れを取っていることがわかります。WPFは保持モードAPIであるという点でおそらく障害がありますが、OpenGLもダブルバッファリングされており、同じようにスムーズに見えます。

1000アイテムでは、違いがより顕著になります。

GDI = 23、GDI + = 5、D2D = 17、WPF = 2、GL=40。

そうです、WPFは現在2 FPSに低下しており、GDI+は5FPSでクロールしています。したがって、D2Dを検討するか、単にOpenGLに戻ってください。それが私たちが現在使用しているものであり、書き直しから3か月後、私たちは正しい選択をしたと思います。プログラミングモデル自体は、D2Dのように見えるよりもはるかにクリーンです。

使用しているWPFレンダリングは高度に最適化されていることに注意してください。コールバック、イベント、バインディングはありません。DrawingContextを取得し、最下位レベルのプリミティブを使用して各フレームにすべてを描画するだけなので、イベントのオーバーヘッドは発生しません。

興味のある方はお知らせください。使用したテストスイートをお送りしますので、いじってみてください。

(GDI +を回避する理由の1つは、ハードウェアアクセラレーションが行われる可能性が低いことです)。

于 2009-12-26T04:37:15.563 に答える