delphi – TDirect2DCanvas是慢还是我做错了?

前端之家收集整理的这篇文章主要介绍了delphi – TDirect2DCanvas是慢还是我做错了?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在寻找替代GDI的替代品时,我试图在Windows 7中测试Delphi的2010年TDirect2DCanvas性能

我通过使用Direct2D绘制一个巨大的折线测试它,结果是荒谬的慢,即使是使用GDI运行相同测试的数据少了500倍的数据(我甚至没有使用位图作为GDI中的backbuffer,我直接画到窗体画布)。

所以我猜:
a)Direct2D比GDI慢;
b)TDirect2DCanvas缓慢;
c)我做错了事情
希望是c)。

我写的测试代码是:

  1. unit Unit2;
  2.  
  3. interface
  4.  
  5. uses
  6. Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,Dialogs,StdCtrls,ExtCtrls,Direct2D,D2D1;
  7.  
  8. type
  9. TForm2 = class(TForm)
  10. private
  11. { Private declarations }
  12. FD2DCanvas: TDirect2DCanvas;
  13. FData: array[0..50000] of TPoint;
  14. public
  15. procedure CreateWnd; override;
  16. procedure WMSize(var Message: TWMSize); message WM_SIZE;
  17. procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
  18.  
  19.  
  20. { Public declarations }
  21. end;
  22.  
  23. var
  24. Form2: TForm2;
  25.  
  26. implementation
  27.  
  28. uses utils;
  29.  
  30. {$R *.dfm}
  31.  
  32. procedure TForm2.CreateWnd;
  33. var
  34. i: Integer;
  35. begin
  36. inherited;
  37. FD2DCanvas := TDirect2DCanvas.Create(Handle);
  38.  
  39. for i := 0 to High(FData) do begin
  40. FData[i].X := Random(Self.ClientWidth div 2);
  41. FData[i].Y := Random(Self.ClientHeight);
  42. end;
  43. end;
  44.  
  45. procedure TForm2.WMPaint(var Message: TWMPaint);
  46. var
  47. PaintStruct: TPaintStruct;
  48. begin
  49. BeginPaint(Handle,PaintStruct);
  50. try
  51. FD2DCanvas.BeginDraw;
  52.  
  53. try
  54. FD2DCanvas.Polyline(FData);
  55. finally
  56. FD2DCanvas.EndDraw;
  57. end;
  58.  
  59. finally
  60. EndPaint(Handle,PaintStruct);
  61. end;
  62.  
  63. end;
  64.  
  65. procedure TForm2.WMSize(var Message: TWMSize);
  66. begin
  67. if Assigned(FD2DCanvas) then begin
  68. ID2D1HwndRenderTarget(FD2DCanvas.RenderTarget).Resize(D2D1SizeU(ClientWidth,ClientHeight));
  69. end;
  70. end;
  71.  
  72. end.

此外,我真的愿意在实际代码中绘制长折线,作为我正在开发的系统需要绘制大约2500点的折线(至少10K)。

更新(2010-11-06)

我以前发现Direct2D似乎不喜欢折线,如果你使用了很多单行(2点折线),它会更快地绘制。

感谢Chris Bensen,我发现使用反锯齿时,使用大折线时的缓慢。所以我禁止反锯齿,因为克里斯建议,性能从约6000ms到〜3500ms绘制5万行。

事情仍然可以改善,因为Direct2D在使用抗锯齿时不会处理好多线。消除抗锯齿功能恰恰相反。

现在用Direct2D绘制50k行的时候,如果我画大折线没有抗锯齿,就是〜50ms。好,呃!

事情是,如果我绘制一个位图,GDI仍然比Direct2D更快,在完成之后,我将BitBlt的结果返回到表单,它绘制在〜35ms,并具有相同的图形质量。而且,Direct2D也似乎使用了一个backbuffer(它只是在EndDraw()被调用时绘制)。

那么,可以用某种方式改进Direct2D的价值吗?

这里是更新的代码

  1. type
  2. TArray = array[0..1] of TPoint;
  3. PArray = ^TArray;
  4.  
  5. procedure TForm2.WMPaint(var Message: TWMPaint);
  6. var
  7. PaintStruct: TPaintStruct;
  8. begin
  9. FD2DCanvas.RenderTarget.SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
  10. BeginPaint(Handle,PaintStruct);
  11. try
  12. FD2DCanvas.BeginDraw;
  13. try
  14. FD2DCanvas.Pen.Color := clRed;
  15. FD2DCanvas.Polyline(FData);
  16. finally
  17. FD2DCanvas.EndDraw;
  18. end;
  19. finally
  20. EndPaint(Handle,PaintStruct);
  21. end;
  22. end;

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

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

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

解决方法

问题是抗锯齿是开启的。禁用抗锯齿功能,Direct2D的性能将与GDI相当或更快。要在创建TDirect2DCanvas之后进行此调用
  1. FD2DCanvas.RenderTarget.SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);

TDirect2DCanvas在可能的情况下与TCanvas接口兼容,所以它可以替代TCanvas,所以一些绘图例程有点低效。例如,Polyline在每次调用时创建几何,并将其抛弃。提高保持几何形状的性能

看看TDirect2DCanvas.Polyline的实现,并提出你的应用程序,如下所示:

  1. procedure TForm2.CreateWnd;
  2. var
  3. i: Integer;
  4. HR: HRESULT;
  5. Sink: ID2D1GeometrySink;
  6. begin
  7. ...
  8. D2DFactory.CreatePathGeometry(FGeometry);
  9. HR := FGeometry.Open(Sink);
  10. try
  11. Sink.BeginFigure(D2D1PointF(FData[0].X + 0.5,FData[0].Y + 0.5),D2D1_FIGURE_BEGIN_HOLLOW);
  12. try
  13. for I := Low(FData) + 1 to High(FData) - 1 do
  14. Sink.AddLine(D2D1PointF(FData[I].X + 0.5,FData[I].Y + 0.5));
  15. finally
  16. Sink.EndFigure(D2D1_FIGURE_END_OPEN);
  17. end;
  18. finally
  19. hr := Sink.Close;
  20. end;

然后画出如下所示:

  1. procedure TForm2.WMPaint(var Message: TWMPaint);
  2. begin
  3. FD2DCanvas.BeginDraw;
  4. FD2DCanvas.Pen.Color := clRed;
  5. FD2DCanvas.RenderTarget.DrawGeometry(FGeometry,FD2DCanvas.Pen.Brush.Handle);
  6. FD2DCanvas.EndDraw;
  7. end;

猜你在找的Delphi相关文章