- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在寻找替代 GDI 的替代方案时,我试图在 Windows 7 中测试 Delphi 2010 TDirect2DCanvas 性能。
我通过使用 Direct2D 绘制一条巨大的折线来测试它,结果速度慢得离谱,即使数据量比我使用 GDI 运行相同测试的数据量少 500 倍(而且我什至没有使用位图作为后缓冲区)在 GDI 中,我只是直接绘制到表单 Canvas )。
所以我猜:
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)。
我之前发现 Direct2D 似乎不喜欢折线,如果您使用大量单线(2 点折线),它绘制速度会更快。
多亏了Chris Bensen,我发现使用抗锯齿时,大型折线的速度很慢。。因此,我按照 Chris 的建议禁用了抗锯齿功能,绘制 50k 条线时,性能从约 6000 毫秒提高到约 3500 毫秒。
事情仍有待改进,因为 Direct2D 在使用抗锯齿时无法很好地处理多段线。禁用抗锯齿功能则恰恰相反。
现在,如果我在没有抗锯齿的情况下绘制大折线,则使用 Direct2D 绘制 50k 条线的时间约为 50 毫秒。不错,嗯!
事实是,如果我绘制位图,并且在完成后我将结果 BitBlt 返回到表单,则 GDI 仍然比 Direct2D 更快,它以大约 35 毫秒的速度绘制>,并且具有相同的图形质量。而且,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
如果有人能向我解释为什么这么慢,我会很高兴。非常感谢示例代码。
最佳答案
问题是抗锯齿功能已打开。禁用抗锯齿功能后,Direct2D 的性能将与 GDI 相当或更快。要在创建 TDirect2DCanvas 后执行此操作,请进行以下调用:
FD2DCanvas.RenderTarget.SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
TDirect2DCanvas 尽可能与 TCanvas 接口(interface)兼容,因此它可以作为 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;
关于delphi - TDirect2DCanvas 速度慢还是我做错了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4055456/
我是一名优秀的程序员,十分优秀!