22

GDI に代わる代替手段を探している間、私はWindows 7 でDelphi の 2010 TDirect2DCanvasのパフォーマンスをテストしようとしていました。

Direct2D を使用して巨大なポリラインを描画してテストしたところ、GDI を使用して同じテストを実行した量の 500 分の 1 のデータでさえ、結果はとてつもなく遅くなりました (そして、GDI でバックバッファーとしてビットマップを使用することさえしませんでした。フォームキャンバスに直接描画しただけです)。

したがって、次のいずれかだと思います。a
) Direct2D は GDI より遅い。
b) TDirect2DCanvas が遅い。
c)私は何か間違ったことをしてい
ます。うまくいけば、それは c) です。

私が書いたテストコードは次のとおりです。

unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, Direct2D, D2D1;

type
  TForm2 = class(TForm)
  private
    { Private declarations }
    FD2DCanvas: TDirect2DCanvas;
    FData: array[0..50000] of TPoint;
  public
    procedure CreateWnd; override;
    procedure WMSize(var Message: TWMSize); message WM_SIZE;
    procedure WMPaint(var Message: TWMPaint); message WM_PAINT;


    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

uses utils;

{$R *.dfm}

procedure TForm2.CreateWnd;
var
  i: Integer;
begin
  inherited;
  FD2DCanvas := TDirect2DCanvas.Create(Handle);

  for i := 0 to High(FData) do begin
    FData[i].X := Random(Self.ClientWidth  div 2);
    FData[i].Y := Random(Self.ClientHeight);
  end;
end;

procedure TForm2.WMPaint(var Message: TWMPaint);
var
  PaintStruct: TPaintStruct;
begin
  BeginPaint(Handle, PaintStruct);
  try
    FD2DCanvas.BeginDraw;

    try
      FD2DCanvas.Polyline(FData);
    finally
      FD2DCanvas.EndDraw;
    end;

  finally
    EndPaint(Handle, PaintStruct);
  end;

end;

procedure TForm2.WMSize(var Message: TWMSize);
begin
  if Assigned(FD2DCanvas) then begin
    ID2D1HwndRenderTarget(FD2DCanvas.RenderTarget).Resize(D2D1SizeU(ClientWidth, ClientHeight));
  end;
end;

end.

また、実際のコードで長いポリラインを描画したいと思っています。これは、私が取り組んでいるシステムが 2500 ポイントのポリライン (少なくとも 10K) を大量に描画する必要があるためです。

更新 (2010-11-06)

Direct2D がポリラインを好まないように思われることを以前に知りました。単一の線 (2 点のポリライン) を多く使用すると、より速く描画されます。

Chris Bensenのおかげで、アンチエイリアシングを使用しているときに大きなポリラインを使用すると速度が低下することがわかりました。そこで、Chris が提案したようにアンチエイリアシングを無効にすると、50k の線を描画するためにパフォーマンスが ~6000ms から ~3500ms になりました。

アンチエイリアシングを使用している間、Direct2D はポリラインを適切に処理しないため、まだ改善される可能性があります。アンチエイリアシングを無効にすると、まったく逆になります。

Direct2D で 50k の線を描画する時間は、アンチエイリアシングなしで大きなポリラインを描画した場合、約 50 ミリ秒です。いいね、えっ!

問題は、ビットマップに描画した場合、 GDI は Direct2D よりも高速であり、それが完了した後、結果をフォームに BitBlt で戻すと、 〜35msで描画され、同じグラフィックス品質で描画されます。また、Direct2D も既にバックバッファーを使用しているようです (EndDraw()呼び出されたときに描画するだけです)。

では、Direct2D の使用をスピード的に価値のあるものにするために、これを何らかの形で改善することはできますか?

更新されたコードは次のとおりです。

type
  TArray = array[0..1] of TPoint;
  PArray = ^TArray;

procedure TForm2.WMPaint(var Message: TWMPaint);
var
  PaintStruct: TPaintStruct;
begin
  FD2DCanvas.RenderTarget.SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
  BeginPaint(Handle, PaintStruct);
  try
    FD2DCanvas.BeginDraw;
    try
      FD2DCanvas.Pen.Color := clRed;
      FD2DCanvas.Polyline(FData);
    finally
      FD2DCanvas.EndDraw;
    end;   
  finally
    EndPaint(Handle, PaintStruct);
  end;
end;

ちなみに、事前にジオメトリを作成するというChrisの提案を使用しても、速度はGDIとほぼ同じ速度ですが、それでも速くはありません.

私のコンピューターは Direct3D および OpenGL アプリを正常に実行しており、dxDiag の出力は次のとおりです: http://mydxdiag.pastebin.com/mfagLWnZ

この遅さの理由を誰かが説明してくれたらうれしいです。サンプルコードは大歓迎です。

4

4 に答える 4

26

問題は、アンチエイリアスがオンになっていることです。アンチエイリアシングを無効にすると、Direct2D のパフォーマンスは GDI と同等かそれ以上になります。TDirect2DCanvas の作成後にこれを行うには、次の呼び出しを行います。


  FD2DCanvas.RenderTarget.SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);

TDirect2DCanvas は可能な限り TCanvas と互換性のあるインターフェイスであるため、TCanvas との置き換えでドロップすることができます。そのため、一部の描画ルーチンは少し非効率的です。たとえば、Polyline は呼び出されるたびにジオメトリを作成し、破棄します。ジオメトリを保持してパフォーマンスを向上させるため。

TDirect2DCanvas.Polyline の実装を見て、次のようにアプリケーションに組み込みます。


procedure TForm2.CreateWnd;
var
  i: Integer;
  HR: HRESULT;
  Sink: ID2D1GeometrySink;
begin
...
  D2DFactory.CreatePathGeometry(FGeometry);
  HR := FGeometry.Open(Sink);
  try
    Sink.BeginFigure(D2D1PointF(FData[0].X + 0.5, FData[0].Y + 0.5), 
      D2D1_FIGURE_BEGIN_HOLLOW);
    try
      for I := Low(FData) + 1 to High(FData) - 1 do
        Sink.AddLine(D2D1PointF(FData[I].X + 0.5, FData[I].Y + 0.5));
    finally
      Sink.EndFigure(D2D1_FIGURE_END_OPEN);
    end;
  finally
    hr := Sink.Close;
  end;

そして、次のように描きます。


procedure TForm2.WMPaint(var Message: TWMPaint);
begin
  FD2DCanvas.BeginDraw;
  FD2DCanvas.Pen.Color := clRed;
  FD2DCanvas.RenderTarget.DrawGeometry(FGeometry, FD2DCanvas.Pen.Brush.Handle);
  FD2DCanvas.EndDraw;
end;
于 2010-11-05T16:44:20.710 に答える
3

Direct2Dはドライバーとハードウェアの実装に依存しているため、実行しているハードウェアとドライバーによってはパフォーマンスがおかしくなることになります(3Dレンダリングエンジンが直面する問題と同じ問題があります)。

たとえば、ラインのレンダリングの問題では、いくつかの(隠れた)基礎となるハードウェアバッファの問題に直面する可能性があります。特定のハードウェア+ドライバで、ポリラインを描画するときに、基礎となるデータサイズが特定のしきい値を下回ると、パフォーマンスが高くなる可能性があります。 、完全なハードウェアアクセラレーションを備えています。そのしきい値を超えると、部分的にソフトウェアまたは最適化されていないパスにフォールバックする可能性があり、パフォーマンスが急落します。しきい値は、ハードウェア、ドライバー、ブラシ/描画オプションによって異なり、存在する場合と存在しない場合があります。

これらは、OpenGLまたは通常のDirectXを介して2Dまたは3Dをレンダリングする場合と同じ問題です。よく踏まれたレンダリングパスの外に迷い込んだ場合、物事はそれほどバラ色ではありません。

アンチエイリアス処理されていないグラフィックスのレンダリングに関する限り、私のアドバイスはGDIに固執することです。実装はしっかりしており、ハードウェアが広くサポートされています。

アンチエイリアス処理されたグラフィックスの場合、GDI +、Graphics32、AGG、および概して、エンドユーザーのハードウェアを制御できない場合は常にソフトウェアのみのソリューションが望ましいIMEです。それ以外の場合は、カスタマーサポートの問題に備えてください。

于 2010-11-08T07:49:12.137 に答える
3

私のすべてのベンチマーク テストで、OpenGL (MSAA アンチエイリアシングの有無にかかわらず) は、多角形、線、四角形などの 2D 要素を描画する特定のケースでは、GDI、GDI+、または Direct2D よりも高速です。

于 2012-11-16T10:18:46.030 に答える
1

比較して、GDI+ の速度はどうですか?

GDI+ エンジンを使用して (TMetaFile を使用して) VCL TCanvas コンテンツをレンダリングできる、フリー/オープン ソースのユニットを作成しました。

実際には、パフォーマンスは非常に良好で、アンチエイリアシングがオンになっていました...これをいくつかのプロジェクトで使用し、通常のコンポーネントのコンテンツをビットマップに描画し、このビットマップを使用してフォームのコンテンツを画面に描画します (これにより、ちらつきの問題が回避されます) )。アンチエイリアシングを使用すると、マーケティング担当者はその結果に満足し、他のプログラマー (C# または WPF を使用) はそれがどのように機能するのか不思議に思っていました。メモリが少なく、画面上の結果がモダンに見えます (特に、Calibri やシステムで利用可能なフォントを使用している場合)。

http://synopse.info/forum/viewtopic.php?id=10を参照してください。

Delphi の任意のバージョン (Delphi 6 から Delphi XE まで) で動作し、Windows の任意のバージョン (XP、Vista、Seven - 以前の OS で標準の gdiplus.dll を展開する必要があります) で動作します。

私たちのユニットは、XP での GDI から GDI+ への変換にパスカル コードを使用し、Vista、Seven、または Office 2003/2007 が PC にインストールされている場合は、ネイティブの Microsoft 隠し API を使用します。

于 2010-11-07T06:36:58.193 に答える