TDirect2DCanvas是慢还是我做错了什么?

Tri*_*dad 22 delphi gdi direct2d delphi-2010 delphi-xe

在寻找替代GDI的替代方案时,我试图在Windows 7中测试Delphi的2010 TDirect2DCanvas性能.

我通过使用Direct2D绘制一条巨大的折线来测试它,结果非常慢,即使数据量少于我使用GDI进行相同测试的数量少500倍(我甚至没有在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.
Run Code Online (Sandbox Code Playgroud)

另外,我真的很愿意借鉴长折线在实际的代码,作为一个系统我工作的需要制定大量的〜2500点的折线(其中至少有10K).

更新时间(2010-11-06)

我早些时候的Direct2D似乎并不喜欢折线发现,它吸引更快,如果你使用了大量的单行(2分多义线).

由于克里斯·本森,我发现了缓慢是大的多段线,同时使用抗锯齿.所以我禁用抗锯齿克里斯建议和性能〜6000ms到〜3500ms去绘制50K线.

事情可能仍有待提高,因为Direct2D的只是没有处理好折线,而使用抗锯齿.禁用抗锯齿功能正好相反.

现在用Direct2D绘制50k线的时间,如果我绘制没有抗锯齿的大折线,是~50ms.很好,呃!

问题是,如果我绘制到位图,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;
Run Code Online (Sandbox Code Playgroud)

顺便说一句,即使我使用Chris建议事先创建几何体,速度与GDI的速度大致相同,但仍然不会更快.

我的电脑正常运行Direct3D和OpenGL应用程序,这里是dxDiag输出:http://mydxdiag.pastebin.com/mfagLWnZ

如果有人能解释我为什么这么慢,我会很高兴的.示例代码非常感谢.

Chr*_*sen 26

问题是打开了抗锯齿功能.禁用抗锯齿功能,Direct2D的性能将与GDI相当或更快.要在创建TDirect2DCanvas之后执行此操作,请进行以下调用:


  FD2DCanvas.RenderTarget.SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
Run Code Online (Sandbox Code Playgroud)

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;
Run Code Online (Sandbox Code Playgroud)

然后像这样绘制它:


procedure TForm2.WMPaint(var Message: TWMPaint);
begin
  FD2DCanvas.BeginDraw;
  FD2DCanvas.Pen.Color := clRed;
  FD2DCanvas.RenderTarget.DrawGeometry(FGeometry, FD2DCanvas.Pen.Brush.Handle);
  FD2DCanvas.EndDraw;
end;
Run Code Online (Sandbox Code Playgroud)

  • 欢迎来到SO,克里斯! (6认同)