1

I use Delphi 10.3 and .Net 5.0. I know tCanvas is GDI and Graphics is GDI+ which outperforms the former. But in the following simple codes tCanvas is faster. The 5 times average milliseconds of Delphi is 185.00 and .Net is 351.20.

Why is tCanvas faster than Graphics, or is there any flaw in my codes?

Delphi

procedure TForm1.PaintBox1Click(Sender: TObject);
var
  _Rectangle: TRect;
  _Rectangles: TList<TRect>;
  _Stopwatch: TStopwatch;
  i: Integer;
begin
  PaintBox1.Canvas.Brush.Color := clWhite;

  _Rectangle.Left := 0;
  _Rectangle.Top := 0;
  _Rectangle.Width := PaintBox1.Width;
  _Rectangle.Height := PaintBox1.Height;

  PaintBox1.Canvas.FillRect(_Rectangle);

  _Rectangles := TList<TRect>.Create;

  for i := 0 to 9999 do
  begin
    _Rectangle.Left := Random(1000);
    _Rectangle.Top := Random(1000);
    _Rectangle.Right := _Rectangle.Left + 5;
    _Rectangle.Bottom := _Rectangle.Top + 5;

    _Rectangles.Add(_Rectangle);
  end;

  PaintBox1.Canvas.Brush.Color := clBlack;

  _Stopwatch := TStopwatch.StartNew;

  for i := 0 to 9999 do
  begin
    PaintBox1.Canvas.FillRect(_Rectangles.List[i]);
  end;

  Caption := IntToStr(_Stopwatch.ElapsedMilliseconds);

  _Rectangles.Free;
end;

.Net

private void panel1_Click(object sender, EventArgs e)
{
    Graphics _Graphics = panel1.CreateGraphics();
    List<Rectangle> _Rectangles = new();
    Random _Random = new();
    Rectangle _Rectangle = new(0, 0, panel1.Width, panel1.Height);
    SolidBrush _SolidBrush = new(Color.White);

    _Graphics.FillRectangle(_SolidBrush, _Rectangle);

    for (int i = 0; i < 10000; i++)
    {
        _Rectangle = new(_Random.Next(1000), _Random.Next(1000), 5, 5);

        _Rectangles.Add(_Rectangle);
    }

    _SolidBrush.Color = Color.Black;

    Stopwatch _Stopwatch = new();

    _Stopwatch.Start();

    foreach (var item in _Rectangles)
    {
        _Graphics.FillRectangle(_SolidBrush, item);
    }

    Text = _Stopwatch.ElapsedMilliseconds.ToString();

    _Graphics.Dispose();
    _SolidBrush.Dispose();
}
SHIN JaeGuk
  • 494
  • 1
  • 5
  • 14
  • 1
    Consider moving to Direct2D. – Andreas Rejbrand Jul 10 '21 at 15:46
  • 1
    You just look at the VCL, but there is also FMX framework! – Delphi Coder Jul 10 '21 at 16:14
  • @AndreasRejbrand wow. the delphi direct2d code shows 13.4 milliseconds. but using in .net seems terrible. – SHIN JaeGuk Jul 10 '21 at 16:20
  • 3
    Draw to an off screen bitmap and then push that to the screen – David Heffernan Jul 10 '21 at 18:23
  • 1
    my experience is that VCL encapsulated GDI (TCanvas from BCB) is usually faster than the same coded in MSVC++ especially true for direct pixel access on bitmaps (using `TScanLine`) also `.Net` is slower on average not just for rendering ... If you need true speed use [OpenGL ... You can easily combine VCL components with OpenGL](https://stackoverflow.com/a/20679773/2521214) (I mean buttons, and stuff still works )... – Spektre Jul 11 '21 at 06:42
  • Do the images from your 2 examples look the same? I would have thought that the .net would be antialiased whereas the Delphi VCL one would not be. If so then that's the main reason that VCL is faster, but your test isn't showing this because rectangles don't have angled or curved edges. Delphi FMX has the benefit of being antialised and very fast because it uses the GPU. – XylemFlow Jul 12 '21 at 09:57
  • @XylemFlow It's a WindowsForms not a WPF. I know WindowsForms doesn't support AntiAlias. – SHIN JaeGuk Jul 12 '21 at 15:01

1 Answers1

1

Following David's advice, using Bitmap enhanced the performance much to 48.2 milliseconds.

private void button1_Click(object sender, EventArgs e)
{
    Bitmap _Bitmap = new(1000, 1000);

    Graphics _BitmapGraphics = Graphics.FromImage(_Bitmap);
    Graphics _PanelGraphics = panel1.CreateGraphics();
    List<Rectangle> _Rectangles = new();
    Rectangle _Rectangle;
    Random _Random = new();
    SolidBrush _SolidBrush = new(Color.Black);

    _BitmapGraphics.Clear(Color.White);

    for (int i = 0; i < 10000; i++)
    {
        _Rectangle = new(_Random.Next(1000), _Random.Next(1000), 5, 5);

        _Rectangles.Add(_Rectangle);
    }

    Stopwatch _Stopwatch = new();

    _Stopwatch.Start();

    foreach (var item in _Rectangles)
    {
        _BitmapGraphics.FillRectangle(_SolidBrush, item);
    }

    _PanelGraphics.DrawImage(_Bitmap, Point.Empty);
        
    button1.Text = _Stopwatch.ElapsedMilliseconds.ToString();

    _Bitmap.Dispose();
    _BitmapGraphics.Dispose();
    _PanelGraphics.Dispose();
    _SolidBrush.Dispose();
}
SHIN JaeGuk
  • 494
  • 1
  • 5
  • 14