在寻找替代GDI的方案时,我试图测试Delphi 2010的TDirect2DCanvas在Windows 7上的性能表现。
我通过使用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.
此外,我很愿意在实际代码中画出长的折线,因为我正在开发的系统需要绘制大量的 ~2500 点的折线(至少有 10K 条)。
更新(2010-11-06)
我之前发现 Direct2D 似乎不喜欢折线,在使用许多单线段(两点折线)时绘制更快。
感谢 Chris Bensen,我发现缓慢是由于 启用抗锯齿 时绘制大折线造成的。所以我像 Chris 建议的那样禁用了抗锯齿,性能从 ~6000ms 提高到 ~3500ms,可以绘制 50k 条线。
Direct2D 在 启用抗锯齿 时无法很好地处理折线,而在禁用抗锯齿时则相反。
如果我没有启用抗锯齿来绘制大型折线,使用 Direct2D 绘制 50k 条线的时间为 ~50ms。很不错,对吧!
问题在于,如果我将结果绘制到位图上并在完成后 BitBlt 回表单,GDI 仍然比 Direct2D 快,在 ~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
如果有人可以解释为什么会出现这种缓慢,我会很高兴。欢迎提供示例代码。