Is TDirect2DCanvas slow or am I doing something wrong?

后端 未结 4 1100
梦谈多话
梦谈多话 2021-02-01 18:43

While looking for alternatives to replace GDI, I was trying to test Delphi\'s 2010 TDirect2DCanvas performance in Windows 7.

I tested it by drawing a huge polyl

相关标签:
4条回答
  • 2021-02-01 19:09

    In all my benchmark tests OpenGL (with and without MSAA antialiasing) is faster than GDI, GDI+ or Direct2D, for the particular case of drawing 2D elements like polygons, lines, rectangles, etc.

    0 讨论(0)
  • 2021-02-01 19:09

    What about GDI+ speed, in comparison?

    We wrote a free/open source unit, able to render any VCL TCanvas content (using a TMetaFile) using the GDI+ engine.

    In practice, performance is very good, and anti-aliaising was on... We use this in several projects, drawing regular components content into a bitmap, then using this bitmap for drawing the form content on screen (this will avoid any flicker problem). And with anti-aliaising, marketing people were happy about the result, and other programmers (using C# or WPF) were wondering how it was working: the drawing is very fast and the applications are reactive (like well built Delphi apps), use very little memory, and the result on screen looks modern (especially if you use Calibri or such fonts if available on your system).

    See http://synopse.info/forum/viewtopic.php?id=10

    It will work with any version of Delphi (from Delphi 6 up to Delphi XE), and will work on any version of Windows (XP, Vista, Seven - need to deploy the standard gdiplus.dll with previous OS).

    Our unit uses pascal code for the GDI to GDI+ conversion on XP, and native Microsoft hidden API under Vista, Seven or if Office 2003/2007 is installed on the PC.

    0 讨论(0)
  • 2021-02-01 19:19

    Direct2D relies on the driver and hardware implementation, so you're bound to have performance oddities depending on the hardware and driver you're running on (same bag of issues as 3D rendering engines face).

    For instance on the issue of rendering lines, you'll likely face some (hidden) underlying hardware buffer issues: on a given hardware+driver, when drawing a polyline, if the underlying datasize is below a certain threshold, the performance could be high, with full hardware acceleration. Above that threshold, you could be falling back to a partially software or unoptimized path, and performance will plummet. The threshold will depend on hardware, driver and brush/drawing options, can be there, or not.

    These are the same issues as when rendering 2D or 3D via OpenGL or regular DirectX, if you stray outside of well trodden rendering paths, things aren't so rosy.

    As far as rendering non-antialiased graphics goes, my advice would be to stick with GDI, the implementations are solid with widespread hardware support.

    For antialiased graphics, GDI+, Graphics32, AGG, and by and large, software-only solutions are preferable IME whenever you have no control over the end-user hardware. Otherwise, prepare yourself for customer support issues.

    0 讨论(0)
  • 2021-02-01 19:26

    The problem is antialiasing is turned on. Disable antialiasing and the performance of Direct2D will be on par or faster than GDI. To do that after TDirect2DCanvas is created, make this call:

    
      FD2DCanvas.RenderTarget.SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
    

    TDirect2DCanvas is interface compatible where possible with TCanvas so it can be a drop in replacement with TCanvas, so some of the drawing routines are are a bit inefficient. For example, Polyline creates a geometry each time it is called and throws it away. To increase performance keeping the geometry around.

    Take a look at the implementation for TDirect2DCanvas.Polyline and hoist that out into your application for something like this:

    
    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;
    

    And then draw it like so:

    
    procedure TForm2.WMPaint(var Message: TWMPaint);
    begin
      FD2DCanvas.BeginDraw;
      FD2DCanvas.Pen.Color := clRed;
      FD2DCanvas.RenderTarget.DrawGeometry(FGeometry, FD2DCanvas.Pen.Brush.Handle);
      FD2DCanvas.EndDraw;
    end;
    
    0 讨论(0)
提交回复
热议问题