Multithreaded painting in Delphi? Yes it's possible!

Multithreaded painting in Delphi? Yes it's possible!

I did some quick hacking to see if I could make painting in a subthread possible (TCanvas etc).
I made a stress test with FastReport printing in a subthread and heavy TMS painting in the main thread. Initialy I got acces violations in GDI32.dll after 18 pages, but I have now over 400 without problems! (in FinePrint, to save the trees :) ).

The main problem in Delphi VCL Graphics.pas is the usage of a global var for "StockPen", "StockBrush" and "StockFont". These global vars are used for each paint, at least when you change the Canvas.Pen etc (and you do, if you want to paint something :) ).

After changing these globals var into a threadvar (which is slower!), the same for FontManager, PenManager and BrushManager you get multithreaded painting in Delphi!
(tested with 2010).

Next problem are memory leaks: stuff needs to be cleaned up after each thread termination...

Note: I had to save Graphics.pas to an other directory and add it to my project. Same for pngimage.pas, GIFImg.pas, AxCtrls.pas and jpeg.pas ("unit compiled with different version of graphics.pas").

Note2: I have to do some test to see how much slower painting gets with threadvar's...

threadvar
  StockPen: HPEN;
  StockBrush: HBRUSH;
  StockFont: HFONT;
  StockIcon: HICON;

...

threadvar
  _FontManager: TResourceManager;
  _PenManager: TResourceManager;
  _BrushManager: TResourceManager;

function FontManager: TResourceManager;
begin
  if _FontManager = nil then
    _FontManager := TResourceManager.Create(SizeOf(TFontData));
  Result := _FontManager;
end;

function PenManager: TResourceManager;
begin
  if _PenManager = nil then
    _PenManager := TResourceManager.Create(SizeOf(TpenData));
  Result := _PenManager;
end;

function BrushManager: TResourceManager;
begin
  if _BrushManager = nil then
    _BrushManager := TBrushResourceManager.Create(SizeOf(TbrushData));
  Result := _BrushManager;
end;

Comments

  1. Interesting. I thought the UI was always controlled by a single thread.. Nice to see it can be done

    ReplyDelete
  2. update: 1200 pages printed in background thread without problems :)

    About speed: no measurable changes (complex screen paints in 5ms (form.Refresh) in both versions) on Win7

    ReplyDelete
  3. I wonder, can we get EMBT to fix it too?

    ReplyDelete
  4. Lars Fosdal Theoretical yes...
    By the way, it is a fairly simple fix, just wondering why it hasn't been done before... no prio?
    Or no changes to VCL anymore due to FMX?

    ReplyDelete
  5. That's pretty neat! But isn't it more convenient to do threaded painting onto a buffer bitmap with locking mechanisms and paint it to the canvas later on?

    ReplyDelete
  6. Frédéric Hannes yes, but for printing (Fast Report) that's quite a big change of their source code...

    ReplyDelete
  7. André Mussche Ah ok, I have no experience with Fast Report, so I wasn't sure how it works.

    ReplyDelete

Post a Comment