A few days ago I was doing VCL application modernisation workshop in Utrecht and thought it would be good to take an existing VCL application and see what it takes to make it parallel.
A few years ago I was playing with different ways of accessing individual pixels in the VCL bitmap on the example of "Color to Gray" algorithm. Clearly using bitmap’s scanline is a few levels of magnitude faster than access through "Pixels" property. The differences in speed are discussed here: http://blogs.embarcadero.com/pawelglowacki/2010/04/15/39051
In the "color to gray" algorithm the color of every pixel is calculated independently from each other is a nested "for" loop. This is a perfect case where we can benefit from refactoring the code to use a parallel loop instead.
Let’s consider a simple example of an existing code that we would like to convert:
procedure ToGrayPixelsNoParallel(aBitmap: Graphics.TBitmap; cg: TColor2Grayscale = c2gLuminosity); var w, h: integer; begin if aBitmap <> nil then for h := 0 to aBitmap.Height - 1 do for w := 0 to aBitmap.Width - 1 do aBitmap.Canvas.Pixels[w,h] := ColorToGray(aBitmap.Canvas.Pixels[w,h], cg); end;
Here we have two nested "for" loops. On my machine I have only two virtual cores and on a physical one - just four. That is why there is no point in turning both loops to "parallel". We only want to convert the "outer" one. Here is the code after "parallelization":
procedure ToGrayPixelsParallel(aBitmap: Graphics.TBitmap; cg: TColor2Grayscale = c2gLuminosity); var h: integer; begin if aBitmap <> nil then TParallel.For(0, aBitmap.Height-1, procedure(h: integer) var w: integer; begin for w := 0 to aBitmap.Width - 1 do aBitmap.Canvas.Pixels[w,h] := ColorToGray(aBitmap.Canvas.Pixels[w,h], cg); end ); end;
The key thing to look for is using local variables. Notice that I had to move "w: integer" local variable into the body of the anonymous method that is being executed. If I would not do it, the same variable would be shared by different threads of execution leading to errors.
And yes. The parallel versions of both "pixels" and "scan line" color to gray are working as expected on average two times faster on my two virtual cores inside of my virtual Windows machine running on Mac.
The source code of the test "PixelsVsScanLineParallelToGray" Delphi XE7 VCL project is available for download from Embarcadero Code Central.