EtheaDev / SVGIconImageList

Three engines to render SVG (Delphi Image32, Skia4Delphi, Direct2D wrapper) and four components to simplify use of SVG images (resize, fixedcolor, grayscale...)
Apache License 2.0
327 stars 96 forks source link

Cairo does not compile in Win64 #124

Closed pyscripter closed 4 years ago

pyscripter commented 4 years ago

Please replace all conditional defines from {$IFDEF WIN32} to {$IFDEF MSWINDOWS}

By the way try the factories on this one. Cairo is massively faster seaborn.zip

luebbe commented 4 years ago

I'll take care of the defines, The headers are "old". Thank you.

luebbe commented 4 years ago

Oh boy, "massively" is a nice understatement.

Here are the results "benchmark" (64-bit) on "seaborn" with one repetition on my work PC:

Repeat 1 times
Factory    |  Load  |  Draw  |  Total
Pascal     |  47375 |  39687 |  87062
Direct 2D  |    938 |   1141 |   2079
Cairo      |    281 |    109 |    390
pyscripter commented 4 years ago

In drawing in particular Cairo is 11x faster than D2D and 400x faster than Pascal!

I wonder what is the reason for that. Why don't we see similar results with smaller svgs...

luebbe commented 4 years ago

If you drop this SVG on Firefox it is also drawn a lot faster than D2D and Pascal, but not as fast as Cairo (not timed, just "feeling")

pyscripter commented 4 years ago

One encouraging thing is that at least all three factories produce the same visual output.

carloBarazzetta commented 4 years ago

Pull request merged.

carloBarazzetta commented 4 years ago

I can't wait to try Cairo with lots of "little icons" using SVGExplorer to measure performance again ;-)

pyscripter commented 4 years ago

@luebbe Could you please check https://github.com/preshing/cairo-windows This guy produces releases packaging all cairo functionality in a single dll:

This repository is meant to help create Cairo DLLs for Windows. Both 32-bit and 64-bit versions can be built. The resulting cairo.dll file is fully self-contained and does not depend on any other third-party DLLs. FreeType support is included.

The releases include DLLs compiled last month. It would a huge help to have to deploy one dll as opposed to 15.

Update: Actually it might not help much because it does not include librsvg, which is the one with many dependencies.

pyscripter commented 4 years ago

With the changes in SVG.pas (see attached)

Repeat 1 times
Factory    |  Load  |  Draw  |  Gray  |  Draw  |  Fixed |  Draw  |  Total |
Pascal     |    312 |   2141 |    313 |   2140 |    625 |   2078 |   7609 |
Direct 2D  |    719 |    859 |    688 |    906 |    735 |    921 |   4828 |
Cairo      |    204 |    203 |    109 |    188 |    109 |    187 |   1000 |

However the painting comparison is not fair for SVG.pas. It draws directly on the SVGIconImage Canvas whilst the other two do buffered painting. A fairer comparison would be to draw to a Bitmap. In a production setting you would set DoubleBuffered on on the SVGIconImage and when it is painted with SVG the painting would be on a bitmap.

SVG.zip

@carloBarazzetta Could you please commit the changes @luebbe Could you please change the BenchmarkDraw to paint to a bitmap?

pyscripter commented 4 years ago

You want believe this. With the above changes TSVG painting is super fast. Faster than Direct2D and comparable to Cairo. To try:

I 'd love to see the updated benchmarks on Bitmap.

Update TSVG draws this SVG faster than Cairo

pyscripter commented 4 years ago

One last thing. There are a number of Warnings when I build UBenchmark (mostly on the Cairo side). Could these warnings be eliminated?

carloBarazzetta commented 4 years ago

@carloBarazzetta Could you please commit the changes

Done, but changed FIdDict.TryAdd(Name, Result); as: if not FIdDict.ContainsKey(Name) then FIdDict.Add(Name, Result); for backward compatibility with XE6.

luebbe commented 4 years ago

One last thing. There are a number of Warnings when I build UBenchmark (mostly on the Cairo side). Could these warnings be eliminated?

These are thrown, because I haven't found time yet to implement the recoloring using xmllite. So the getters don't return a value. I can make them return default values and add a Todo until this is done...

pyscripter commented 4 years ago

Done, but changed FIdDict.TryAdd(Name, Result);

in TSVG.FindByID

if not FIdDict.ContainsKey(Name) then

`This is not needed, since we checked above with TryGetValue

carloBarazzetta commented 4 years ago

Is this correct?

function TSVG.FindByID(const Name: string): TSVGObject;
begin
   if not FIdDict.TryGetValue(Name, Result) then
   begin
     Result := inherited FindById(Name);
     if Assigned(Result) then
       FIdDict.Add(Name, Result);
   end;
end;
pyscripter commented 4 years ago
function TSVG.FindByID(const Name: string): TSVGObject;
begin
   if not FIdDict.TryGetValue(Name, Result) then
   begin
     Result := inherited FindById(Name);
     FIdDict.Add(Name, Result);
   end;
end;

Even if the Result is nil we still add it, so that we do not search for the same Name again.

luebbe commented 4 years ago

@luebbe Could you please change the BenchmarkDraw to paint to a bitmap?

@pyscripter Hi Kiriakos, I made some changes to the benchmark form and functionality, but don't quite understand how to do this? SvgIconImageCollection just has a Draw to Canvas method?!?

pyscripter commented 4 years ago

@luebbe Could you please change the BenchmarkDraw to paint to a bitmap?

@pyscripter Hi Kiriakos, I made some changes to the benchmark form and functionality, but don't quite understand how to do this? SvgIconImageCollection just has a Draw to Canvas method?!?

Create a bitmap of the right size (same as SVGIconImage) and draw to the Bitmap.Canvas.

There is somewhere the code CreateBitmaps if you want to have a look.

luebbe commented 4 years ago

OK, but that means that the painting itself is not visible, if I understand you correctly?

pyscripter commented 4 years ago

means that the painting itself is not visible, if I understand you correctly?

Yes. We are still comparing painting speed on the same basis for all factories. Otherwise with TSVG you got the screen updating after every SVG element is painted and this is not a fair comparison.

Generally you prevent that by setting DoubleBuffering to True, but this has no effect if you paint on the SVGIconImage.Canvas outside the Paint method.

luebbe commented 4 years ago

I made the drawing on TBitmap.Canvas an option in #128. Default is visible. OK this way?

Maybe we should turn all three options off by default, because cairo can't recolor yet and thus gains an undeserved advantage, since it does nothing.

pyscripter commented 4 years ago

TSVG is the fastest! Paints 3 times as fast as Cairo!

Benchmark: Repeat 10 times. Draw invisible.
Factory    |  Load  |  Draw  |  Total
Pascal     |   2312 |    329 |   2656
Direct 2D  |   6266 |   7734 |  14000
Cairo      |   1860 |    984 |   2844

Also load seaborn.svg and try to resize the form with each of the 3 factories.

@luebbe Nice job with UBenchmark...

luebbe commented 4 years ago

Thanks 🥰 ! The compliments go back to @pyscripter for your work on TSVG. This should improve resizing of Imagelists dramatically.

carloBarazzetta commented 4 years ago

I've pushed now a new version of Benchmark project, compatible also with XE6.

luebbe commented 4 years ago

Just saw it. Any reason why you removed the option to draw on an invisible Bitmap?

luebbe commented 4 years ago

Yeehaaaw!

Using the "Butterfly":

Benchmark: Repeat 50 times. Draw visible.
Factory    |  Load  |  Draw  |  Total
Pascal     |    250 |    250 |    500
Direct 2D  |    359 |    391 |    765
Cairo      |    110 |    297 |    407

Benchmark: Repeat 50 times. Draw invisible.
Factory    |  Load  |  Draw  |  Total
Pascal     |    250 |     16 |    266
Direct 2D  |    265 |    360 |    625
Cairo      |    125 |     62 |    187

We should update our Benchmark in the Readme 😎

luebbe commented 4 years ago

I repeated the "invisible" draw several times. Pascal and Cairo times are pretty much consistent, but D2D can sometimes be unlucky.

Benchmark: Repeat 50 times. Draw invisible.
Factory    |  Load  |  Draw  |  Total
Pascal     |    250 |     16 |    266
Direct 2D  |    265 |    360 |    625
Cairo      |    125 |     62 |    187

Benchmark: Repeat 50 times. Draw invisible.
Factory    |  Load  |  Draw  |  Total
Pascal     |    235 |     15 |    250
Direct 2D  |    110 |    140 |    250
Cairo      |     94 |     62 |    156

Benchmark: Repeat 50 times. Draw invisible.
Factory    |  Load  |  Draw  |  Total
Pascal     |    235 |     15 |    250
Direct 2D  |    125 |    219 |    344
Cairo      |    109 |     63 |    172

Benchmark: Repeat 50 times. Draw invisible.
Factory    |  Load  |  Draw  |  Total
Pascal     |    235 |     15 |    250
Direct 2D  |    125 |     94 |    219
Cairo      |    125 |     62 |    187

Benchmark: Repeat 50 times. Draw invisible.
Factory    |  Load  |  Draw  |  Total
Pascal     |    235 |     15 |    250
Direct 2D  |    125 |    125 |    266
Cairo      |    125 |     47 |    187

Benchmark: Repeat 50 times. Draw invisible.
Factory    |  Load  |  Draw  |  Total
Pascal     |    234 |     16 |    250
Direct 2D  |    125 |     93 |    218
Cairo      |    125 |     47 |    172

Benchmark: Repeat 50 times. Draw invisible.
Factory    |  Load  |  Draw  |  Total
Pascal     |    235 |     15 |    250
Direct 2D  |    109 |     94 |    203
Cairo      |    110 |     62 |    172
pyscripter commented 4 years ago

One thing is sure. TSVG vastly outperfomrs the others in Drawing speed. And you typically load once but paint many times. There are still many areas of potential improvement it TSVG.

One thing to try is the UseGPU flag for D2D. In my computers it makes things worse or has not impact. But I do not have fast GPUs installed. Does it have any impact in your hardware?