Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SKCanvas rendering rotated image very slow compared to System.Drawing (4x slower) #758

Closed
MathieuJack opened this issue Jan 14, 2019 · 8 comments · Fixed by #1007
Closed
Assignees
Labels
area/libSkiaSharp.native area/SkiaSharp Issues that relate to the C# binding of SkiaSharp.
Milestone

Comments

@MathieuJack
Copy link

MathieuJack commented Jan 14, 2019

Rendering a rotated bitmap with SKCanvas is slow, compared with System.Drawing (4x slower)
See below code, it produces following output:
rotation: 20°
Skia: 6860ms
System.Drawing: 1643ms

       float rotation = 20;
        Console.WriteLine("rotation: "+rotation+"°");

        // Skia part...
        MemoryStream imageStream = new MemoryStream(new WebClient().DownloadData(@"https://via.placeholder.com/450"));
        SKBitmap skBitmapToBlit = SKBitmap.Decode(imageStream);
        SKBitmap renderSkBitmap = new SKBitmap(512, 512, isOpaque: false);
        SKCanvas canvas = new SKCanvas(renderSkBitmap);
        SKPaint paint = new SKPaint()
        {
            FilterQuality = SKFilterQuality.High
        };
        canvas.RotateDegrees(rotation);
        var sw = Stopwatch.StartNew();
        for (int i=0; i<100; i++)
        {             
            canvas.DrawBitmap(skBitmapToBlit, new SKPoint(10, 10), paint);
        };
        Console.WriteLine("Skia: "+sw.ElapsedMilliseconds + "ms");

        // System.Drawing part...
        imageStream = new MemoryStream(new WebClient().DownloadData(@"https://via.placeholder.com/450"));
        Bitmap gdiBitmapToBlit = new Bitmap(imageStream);
        Bitmap renderGdiBitmap = new Bitmap(512, 512, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
        Graphics graphics = Graphics.FromImage(renderGdiBitmap);
        graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bicubic;
        graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;
        var matrix = new Matrix();
        matrix.Rotate(rotation);
        graphics.Transform=matrix;
        sw = Stopwatch.StartNew();
        for (int i = 0; i < 100; i++)
        {
            graphics.DrawImage(gdiBitmapToBlit, new PointF(10, 10));
        };
        Console.WriteLine("System.Drawing: " + sw.ElapsedMilliseconds + "ms");

Note that, without rotating, Skia is much faster than System.Drawing (36x faster).

Symptom : Skia 4x slower than System.Drawing, with provided code.
Expected : Skia faster than System.Drawing, with provided code.

  • Version with issue: 1.68.0
  • Last known good version: N/A
  • IDE: Visual Studio
  • Platform Target Frameworks: .net framework 4.7

VS bug #776803

@TabishRafiq
Copy link

Having the same issue. did u find any solution?

@mattleibow
Copy link
Contributor

Interesting. How does the draw speed compare when the rotation is 0, and when at 90? Also, What happens if you drop the filter quality?

I'll have to setup some benchmarks - but it may be related to #686. In the skia forums, there are orders of magnitude improvements for clang. I am busy having a look at clang for Linux #767 and going to do some tests.

@MathieuJack
Copy link
Author

@mattleibow If I drop filter quality, then performances get "normal" again (about as fast as System.Drawing with same quality)
But quality is then too low to be used when working with images, so this solution should not be considered as a workaround.

I don't understand the #686 Clang compiler discussion, since I thought Skia was HW accelerated. Talking about a compiler optimisation let us think that image rotation is done by SW. Is it the case?

@pauldendulk
Copy link

@mattleibow For Mapsui this is a blocking issue. Moving the map around is very choppy even with a single image. Our next release will be with 1.60.3.

@pauldendulk
Copy link

@mattleibow Are you aware of any changes that could have improved this issue in the new prerelease?

@mattleibow
Copy link
Contributor

So I got some benchmarks up and running, and I see there is an issue somewhere. It just appears to have a MASSIVE spike for all combos for a non 90 degree rotation. Even with all the options turned up, if it is 0, 90 or 180 degrees, it is fast. With everything turned off, a small rotation of 20 degrees basically grinds it to a standstill.

BenchmarkDotNet=v0.12.0, OS=Windows 10.0.17763.805 (1809/October2018Update/Redstone5)
Intel Xeon CPU E5-2673 v4 2.30GHz, 1 CPU, 2 logical and 2 physical cores
.NET Core SDK=3.0.100
  [Host]     : .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), X64 RyuJIT
  Job-BOOPOE : .NET Framework 4.8 (4.8.3761.0), X64 RyuJIT

Runtime=.NET 4.7.2  InvocationCount=1  UnrollFactor=1  
Method N Rotation Quality AntiAlias Mean Error StdDev Median Ratio
DrawBitmap 1000 0 None False 78.235 us 2.0679 us 3.5114 us 78.500 us 1.00
DrawImage 1000 0 None False 78.742 us 1.3132 us 1.0966 us 79.150 us 1.00
DrawBitmap 1000 0 None True 88.332 us 6.7036 us 19.5548 us 78.700 us 1.00
DrawImage 1000 0 None True 82.427 us 1.6064 us 1.5026 us 83.100 us 1.00
DrawBitmap 1000 0 Low False 79.829 us 3.1807 us 8.8138 us 75.900 us 1.00
DrawImage 1000 0 Low False 92.787 us 6.4176 us 18.3098 us 83.350 us 1.00
DrawBitmap 1000 0 Low True 81.236 us 3.2120 us 8.9005 us 79.000 us 1.00
DrawImage 1000 0 Low True 87.394 us 4.6204 us 12.8031 us 82.900 us 1.00
DrawBitmap 1000 0 Medium False 76.536 us 4.8806 us 5.9938 us 74.600 us 1.00
DrawImage 1000 0 Medium False 89.547 us 6.1462 us 17.7332 us 79.950 us 1.00
DrawBitmap 1000 0 Medium True 77.033 us 1.2530 us 0.9782 us 77.500 us 1.00
DrawImage 1000 0 Medium True 87.269 us 3.8341 us 10.8767 us 83.800 us 1.00
DrawBitmap 1000 0 High False 84.295 us 4.8017 us 13.6994 us 78.100 us 1.00
DrawImage 1000 0 High False 79.135 us 2.2615 us 2.3224 us 79.500 us 1.00
DrawBitmap 1000 0 High True 84.970 us 4.0155 us 10.9922 us 79.600 us 1.00
DrawImage 1000 0 High True 89.028 us 4.2697 us 12.0428 us 83.300 us 1.00
DrawBitmap 1000 20 None False 23,597.744 us 462.1396 us 647.8552 us 23,457.200 us 1.00
DrawImage 1000 20 None False 23,294.559 us 446.7078 us 458.7360 us 23,280.600 us 1.00
DrawBitmap 1000 20 None True 23,678.858 us 460.1095 us 511.4104 us 23,479.200 us 1.00
DrawImage 1000 20 None True 23,776.709 us 509.7546 us 644.6763 us 23,729.400 us 1.00
DrawBitmap 1000 20 Low False 49,567.407 us 826.4274 us 732.6064 us 49,504.050 us 1.00
DrawImage 1000 20 Low False 48,675.607 us 719.3593 us 637.6933 us 48,705.150 us 1.00
DrawBitmap 1000 20 Low True 49,541.653 us 595.0952 us 556.6524 us 49,454.400 us 1.00
DrawImage 1000 20 Low True 49,066.650 us 970.8287 us 1,038.7758 us 48,999.350 us 1.00
DrawBitmap 1000 20 Medium False 48,698.687 us 621.9337 us 581.7571 us 48,754.000 us 1.00
DrawImage 1000 20 Medium False 48,391.433 us 708.0053 us 552.7640 us 48,469.850 us 1.00
DrawBitmap 1000 20 Medium True 49,087.271 us 766.8361 us 679.7802 us 49,056.000 us 1.00
DrawImage 1000 20 Medium True 49,285.200 us 827.1142 us 773.6832 us 49,313.300 us 1.00
DrawBitmap 1000 20 High False 48,887.589 us 916.4579 us 1,018.6405 us 48,814.200 us 1.00
DrawImage 1000 20 High False 49,074.174 us 810.0930 us 900.4162 us 49,113.300 us 1.00
DrawBitmap 1000 20 High True 49,498.129 us 795.5635 us 705.2464 us 49,498.650 us 1.00
DrawImage 1000 20 High True 50,171.820 us 956.0931 us 894.3301 us 50,024.600 us 1.00
DrawBitmap 1000 90 None False 2.112 us 0.0460 us 0.1221 us 2.100 us 1.00
DrawImage 1000 90 None False 2.082 us 0.0487 us 0.1038 us 2.100 us 1.00
DrawBitmap 1000 90 None True 2.232 us 0.0486 us 0.1165 us 2.200 us 1.00
DrawImage 1000 90 None True 1.957 us 0.0431 us 0.0963 us 2.000 us 1.00
DrawBitmap 1000 90 Low False 2.144 us 0.0465 us 0.0838 us 2.100 us 1.00
DrawImage 1000 90 Low False 1.921 us 0.0563 us 0.1643 us 1.950 us 1.00
DrawBitmap 1000 90 Low True 2.148 us 0.0652 us 0.1913 us 2.100 us 1.00
DrawImage 1000 90 Low True 2.069 us 0.0438 us 0.0953 us 2.050 us 1.00
DrawBitmap 1000 90 Medium False 1.925 us 0.0422 us 0.1113 us 1.900 us 1.00
DrawImage 1000 90 Medium False 2.036 us 0.0441 us 0.0699 us 2.000 us 1.00
DrawBitmap 1000 90 Medium True 2.139 us 0.0465 us 0.1078 us 2.100 us 1.00
DrawImage 1000 90 Medium True 1.950 us 0.0423 us 0.0874 us 1.900 us 1.00
DrawBitmap 1000 90 High False 2.157 us 0.0467 us 0.1270 us 2.200 us 1.00
DrawImage 1000 90 High False 1.823 us 0.0457 us 0.1347 us 1.800 us 1.00
DrawBitmap 1000 90 High True 2.140 us 0.0444 us 0.1169 us 2.100 us 1.00
DrawImage 1000 90 High True 1.938 us 0.0475 us 0.1362 us 1.900 us 1.00
DrawBitmap 1000 180 None False 1.711 us 0.0382 us 0.1096 us 1.700 us 1.00
DrawImage 1000 180 None False 1.490 us 0.0392 us 0.1144 us 1.500 us 1.00
DrawBitmap 1000 180 None True 1.692 us 0.0412 us 0.1196 us 1.700 us 1.00
DrawImage 1000 180 None True 1.334 us 0.0321 us 0.0927 us 1.400 us 1.00
DrawBitmap 1000 180 Low False 1.600 us 0.0442 us 0.1283 us 1.600 us 1.00
DrawImage 1000 180 Low False 1.553 us 0.0408 us 0.1171 us 1.550 us 1.00
DrawBitmap 1000 180 Low True 1.610 us 0.0371 us 0.0958 us 1.650 us 1.00
DrawImage 1000 180 Low True 1.481 us 0.0458 us 0.1315 us 1.500 us 1.00
DrawBitmap 1000 180 Medium False 1.580 us 0.0409 us 0.1172 us 1.600 us 1.00
DrawImage 1000 180 Medium False 1.484 us 0.0334 us 0.0727 us 1.500 us 1.00
DrawBitmap 1000 180 Medium True 1.649 us 0.0369 us 0.0959 us 1.600 us 1.00
DrawImage 1000 180 Medium True 1.519 us 0.0408 us 0.1190 us 1.500 us 1.00
DrawBitmap 1000 180 High False 1.727 us 0.0384 us 0.1025 us 1.700 us 1.00
DrawImage 1000 180 High False 1.562 us 0.0352 us 0.0876 us 1.600 us 1.00
DrawBitmap 1000 180 High True 1.681 us 0.0370 us 0.1078 us 1.650 us 1.00
DrawImage 1000 180 High True 1.564 us 0.0509 us 0.1501 us 1.600 us 1.00

@mattleibow
Copy link
Contributor

Now, those numbers are scary actually... 50000 vs 80.
I crated a fiddle that consistently shows 10x slower: https://fiddle.skia.org/c/b83a5b08608c2611f3cb88153548d70b

There is also this discussion: https://groups.google.com/forum/#!topic/skia-discuss/ZZ7Ol3alB-I

I see that my mac also shows slowdown, but also just 10x. I think this may be a bad thing because Windows is using MSVC. I am going to have to switch to clang. UWP is going to be a bit of a pain as it is not officially supported, but with a 150x slowdown with MSVC, we are going to have to do it.

@mattleibow
Copy link
Contributor

With this PR (#1007) we will switch to Clang to fix the issues with MSVC - or rather use the Compiler skia is optimized for.

BenchmarkDotNet=v0.12.0, OS=Windows 10.0.17763.805 (1809/October2018Update/Redstone5)
Intel Xeon CPU E5-2673 v4 2.30GHz, 1 CPU, 2 logical and 2 physical cores
.NET Core SDK=3.0.100
  [Host]     : .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), X64 RyuJIT
  Job-BNLYMT : .NET Framework 4.8 (4.8.3761.0), X64 RyuJIT

Runtime=.NET 4.7.2  InvocationCount=1  UnrollFactor=1  
Method N Rotation Quality AntiAlias Mean Error StdDev Median Ratio
DrawBitmap 1000 0 None False 76.919 us 3.6501 us 10.1750 us 74.800 us 1.00
DrawImage 1000 0 None False 85.225 us 5.6761 us 16.3767 us 78.350 us 1.00
DrawBitmap 1000 0 None True 76.747 us 4.2486 us 12.0525 us 74.100 us 1.00
DrawImage 1000 0 None True 81.153 us 5.2322 us 14.7575 us 78.400 us 1.00
DrawBitmap 1000 0 Low False 84.008 us 4.7684 us 13.9096 us 78.000 us 1.00
DrawImage 1000 0 Low False 82.868 us 5.0940 us 14.5334 us 77.800 us 1.00
DrawBitmap 1000 0 Low True 82.641 us 5.7075 us 16.0981 us 75.200 us 1.00
DrawImage 1000 0 Low True 84.740 us 5.4855 us 15.5614 us 77.800 us 1.00
DrawBitmap 1000 0 Medium False 84.368 us 5.2141 us 14.8760 us 78.350 us 1.00
DrawImage 1000 0 Medium False 86.891 us 6.8876 us 19.7618 us 78.300 us 1.00
DrawBitmap 1000 0 Medium True 74.094 us 3.3199 us 8.9756 us 74.100 us 1.00
DrawImage 1000 0 Medium True 89.664 us 7.8186 us 22.5585 us 83.450 us 1.00
DrawBitmap 1000 0 High False 74.563 us 4.6076 us 12.6131 us 68.400 us 1.00
DrawImage 1000 0 High False 83.260 us 5.1533 us 14.7857 us 77.800 us 1.00
DrawBitmap 1000 0 High True 91.916 us 8.1213 us 23.8183 us 77.800 us 1.00
DrawImage 1000 0 High True 86.253 us 5.5250 us 15.6735 us 79.500 us 1.00
DrawBitmap 1000 20 None False 707.638 us 18.9982 us 54.2030 us 703.700 us 1.00
DrawImage 1000 20 None False 684.397 us 19.6312 us 56.6404 us 683.800 us 1.00
DrawBitmap 1000 20 None True 769.668 us 24.2528 us 71.5100 us 763.800 us 1.00
DrawImage 1000 20 None True 780.389 us 22.1859 us 63.6556 us 771.650 us 1.00
DrawBitmap 1000 20 Low False 1,983.916 us 40.1079 us 92.9562 us 1,963.200 us 1.00
DrawImage 1000 20 Low False 1,971.851 us 39.0769 us 104.9776 us 1,966.850 us 1.00
DrawBitmap 1000 20 Low True 2,108.067 us 42.0658 us 120.0160 us 2,086.800 us 1.00
DrawImage 1000 20 Low True 2,200.403 us 44.0033 us 115.1489 us 2,180.350 us 1.00
DrawBitmap 1000 20 Medium False 2,148.203 us 41.7982 us 70.9765 us 2,137.200 us 1.00
DrawImage 1000 20 Medium False 1,987.384 us 39.5782 us 100.0191 us 1,985.600 us 1.00
DrawBitmap 1000 20 Medium True 2,147.047 us 42.9163 us 113.0586 us 2,114.800 us 1.00
DrawImage 1000 20 Medium True 2,155.466 us 42.8849 us 94.1335 us 2,137.150 us 1.00
DrawBitmap 1000 20 High False 1,998.591 us 39.8161 us 105.5865 us 1,989.350 us 1.00
DrawImage 1000 20 High False 1,970.158 us 39.3258 us 53.8296 us 1,976.500 us 1.00
DrawBitmap 1000 20 High True 2,159.443 us 43.1887 us 91.0997 us 2,146.800 us 1.00
DrawImage 1000 20 High True 2,162.765 us 48.9867 us 139.7619 us 2,145.300 us 1.00
DrawBitmap 1000 90 None False 1.948 us 0.0464 us 0.1354 us 1.950 us 1.00
DrawImage 1000 90 None False 1.668 us 0.0555 us 0.1628 us 1.600 us 1.00
DrawBitmap 1000 90 None True 2.004 us 0.0496 us 0.1463 us 2.000 us 1.00
DrawImage 1000 90 None True 1.691 us 0.0520 us 0.1501 us 1.700 us 1.00
DrawBitmap 1000 90 Low False 1.905 us 0.0594 us 0.1722 us 1.900 us 1.00
DrawImage 1000 90 Low False 1.717 us 0.0530 us 0.1520 us 1.700 us 1.00
DrawBitmap 1000 90 Low True 1.894 us 0.0458 us 0.1329 us 1.900 us 1.00
DrawImage 1000 90 Low True 1.832 us 0.0394 us 0.1016 us 1.850 us 1.00
DrawBitmap 1000 90 Medium False 1.955 us 0.0551 us 0.1589 us 2.000 us 1.00
DrawImage 1000 90 Medium False 1.718 us 0.0524 us 0.1495 us 1.700 us 1.00
DrawBitmap 1000 90 Medium True 2.022 us 0.0498 us 0.1461 us 2.000 us 1.00
DrawImage 1000 90 Medium True 1.811 us 0.0401 us 0.0937 us 1.800 us 1.00
DrawBitmap 1000 90 High False 1.871 us 0.0420 us 0.1176 us 1.900 us 1.00
DrawImage 1000 90 High False 1.796 us 0.0429 us 0.1239 us 1.800 us 1.00
DrawBitmap 1000 90 High True 2.009 us 0.0493 us 0.1429 us 2.000 us 1.00
DrawImage 1000 90 High True 1.746 us 0.0425 us 0.1234 us 1.700 us 1.00
DrawBitmap 1000 180 None False 1.454 us 0.0574 us 0.1637 us 1.500 us 1.00
DrawImage 1000 180 None False 1.354 us 0.0582 us 0.1679 us 1.300 us 1.00
DrawBitmap 1000 180 None True 1.431 us 0.0451 us 0.1331 us 1.400 us 1.00
DrawImage 1000 180 None True 1.384 us 0.0509 us 0.1468 us 1.400 us 1.00
DrawBitmap 1000 180 Low False 1.523 us 0.0437 us 0.1275 us 1.500 us 1.00
DrawImage 1000 180 Low False 1.372 us 0.0402 us 0.1178 us 1.400 us 1.00
DrawBitmap 1000 180 Low True 1.427 us 0.0468 us 0.1358 us 1.450 us 1.00
DrawImage 1000 180 Low True 1.340 us 0.0352 us 0.0981 us 1.300 us 1.00
DrawBitmap 1000 180 Medium False 1.444 us 0.0329 us 0.0921 us 1.400 us 1.00
DrawImage 1000 180 Medium False 1.239 us 0.0461 us 0.1346 us 1.250 us 1.00
DrawBitmap 1000 180 Medium True 1.523 us 0.0502 us 0.1463 us 1.500 us 1.00
DrawImage 1000 180 Medium True 1.428 us 0.0422 us 0.1238 us 1.400 us 1.00
DrawBitmap 1000 180 High False 1.570 us 0.0493 us 0.1446 us 1.600 us 1.00
DrawImage 1000 180 High False 1.390 us 0.0435 us 0.1262 us 1.400 us 1.00
DrawBitmap 1000 180 High True 1.461 us 0.0474 us 0.1376 us 1.450 us 1.00
DrawImage 1000 180 High True 1.497 us 0.0503 us 0.1474 us 1.500 us 1.00

@mattleibow mattleibow added this to the v1.68.1 milestone Nov 21, 2019
@ghost ghost locked as resolved and limited conversation to collaborators Aug 19, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area/libSkiaSharp.native area/SkiaSharp Issues that relate to the C# binding of SkiaSharp.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants