SkiaSharp icon indicating copy to clipboard operation
SkiaSharp copied to clipboard

[BUG] Slow performance of canvas.DrawBitmap compared to 2.80.4

Open MichalJan008 opened this issue 1 year ago • 3 comments

Description

My app uses canvas.DrawBitmap to get large image fraction to display it on screen using SkCanvasView. Prior to update the code was amazingly fast. But after update to 2.88.0 pinching and panning of the large image on screen gets really slow.
I made some measurement, and prior to upgrade getting image fraction with Canvas.DrawBitmap takes on average 3[ms] - regardless of the Source bitmap size. After upgrade however, the larger source bitmap, the slower it runs. For 12 Megapixel source image - it lasts on average 7[ms]. For 42 Megapixel source - it lasts on average 19[ms]. Overall experience is then severely degraded.

See these two videos showing the difference. 2.80.4 (fast) https://youtu.be/ZN3ki_IpPUg

2.88.0 (slow) https://youtu.be/jNvGh4R19cA

Code

Just calling this method with some wrappers, extension method... canvas.DrawBitmap(sourceBitmap, sourceRect, destRect, paint);

Expected Behavior

A constant performance - regardless of source image size Performance matching previous version (2.80.4)

Actual Behavior

Slow execution.

Basic Information

  • Version with issue: 2.88.0
  • Last known good version: 2.80.4
  • IDE: Visual Studio for Mac
  • Platform Target Frameworks: Xamarin Forms - running on iOS 15.5
  • iOS: 15.5
  • Target Devices:
    iPhone 11, Simulator running on M1

MichalJan008 avatar Jul 26 '22 22:07 MichalJan008

I noticed the same behaviour on Windows, but SKBitmap I think is more useful for rendering to anyway. If immutability is OK then maybe you could change it to render an SKImage instead?

molesmoke avatar Jul 27 '22 21:07 molesmoke

Duplicate of #2112

molesmoke avatar Jul 27 '22 22:07 molesmoke

Yeah, I'm not sure what broke this in the last release, but it broke hard.

imerzan avatar Jul 31 '22 01:07 imerzan

Could you attach a small repro that I can use to debug the process? Mainly I think I need some large images and some drawing code.

This appears to be the same as #2112, but that says GPU/GL and this is using raster. Not sure if this is a sign of bitmap drawing slow...

Also some machine hardware numbers - like GPU model/spec.

mattleibow avatar Aug 12 '22 10:08 mattleibow

@mattleibow Hi, please find attached a small piece of code reproducing the issue. PerfTestSkiaSharp.cs.zip

To use the code simply call the public method like in the following code snippet:

var test = new PerfTestSkiaSharp();
test.RunTests(
  1000,  //iterations 
  12.0f,  //source SkBitmap size (in Megapixels) 
  2.0f,   //target bitmap to draw on  
  out float averageLoopPassTimeMilis);

test.RunTests(
  1000,
  42.0f, //this time for 42 Megapixel source image 
  2.0f, 
  out averageLoopPassTimeMilis);

On my setup I get the following results

  • iPhone 11, version 2.80.4

    • 12 Mpx source bitmap: 3.2[ms] average single loop pass exec time
    • 42 Mpx source bitmap: 3.2[ms] (also), what is expected for this type of operation.
  • iPhone 11, version 2.88.0

    • 12 Mpx source bitmap: 6.6[ms] (2 times slower)
    • 42 Mpx source bitmap: 14.1[ms] (almost 5 times slower)

The code was executed inside Xamarin Forms Application (ver. 5.0.0.2515).

So, the code is both slower, and it appears that slowdown is dependant on the source bitmap size.
When running the code on iOS Simulator (M1 cpu), the slowdown is also apparent (but interestingly, for 42Mpx source image the execution time (8[ms]) appears to be shorter than for the 12Mpx - 10[ms]). In both cases however the slowdown is severe.

MichalJan008 avatar Aug 12 '22 20:08 MichalJan008

I am wondering if it is actually this change in 82:

 Removed drawBitmap and related functions from SkDevice; all public drawBitmap functions on SkCanvas automatically wrap the bitmap in an SkImage and call the equivalent drawImage function. Drawing mutable SkBitmaps will now incur a mandatory copy. Switch to using SkImage directly or mark the bitmap as immutable before drawing.

https://github.com/mono/skia/blob/xamarin-mobile-bindings/RELEASE_NOTES.txt#L369-L372

mattleibow avatar Aug 15 '22 07:08 mattleibow

I am wondering if it is actually this change in 82:

Good catch! Yep, sounds like it.

This issue might be related:

https://bugs.chromium.org/p/chromium/issues/detail?id=449197

ziriax avatar Aug 15 '22 09:08 ziriax

Great-ish. We got the problem/feature and have a way around it. Not so great that we have to do it.

Anyways, closing this issue as it is some core optimization in skia and they did warn us years ago that bitmap is not the future.

mattleibow avatar Aug 16 '22 08:08 mattleibow

I've applied the hint (to let the bitmap know that it is immutable). Now, the performance is stunningly great. (c.a. 3x faster compared to previously considered fast, version 2.80.4) The same test now on 2.88.0 needs only 1ms (on iPhone) to execute (0.7ms on iOS simulator)

iPhone 11, version 2.88.0 12 Mpx source bitmap: 1.0 [ms] (6.6[ms] without the hint) 42 Mpx source bitmap: 1.0 [ms] (14.1[ms] without the hint)

Thanks!!

MichalJan008 avatar Aug 17 '22 18:08 MichalJan008