mono / SkiaSharp

SkiaSharp is a cross-platform 2D graphics API for .NET platforms based on Google's Skia Graphics Library. It provides a comprehensive 2D API that can be used across mobile, server and desktop models to render images.
MIT License
4.51k stars 538 forks source link

[QUESTION] How to keep canvas from beeing completly redrawn in SKGLView at InvalidateSurface. #1346

Open pilotshamn opened 4 years ago

pilotshamn commented 4 years ago

Hi In a Xamarin Forms app i use a SKGLView to write spokes to a circle via the GPU, the thing is the whole canvas gets completly redrawn(cleared) with every call to Dispatcher.BeginInvokeOnMainThread(() =>{SKGLView.InvalidateSurface(); }); not just update the spoke of 10 degrees. But if i use a SKCanvasView instead with the same code the canvas keeps the rest of the circle and only updates the spoke as expected. Using the SKCanvasView is far to slow! The Dispatcher.BeginInvokeOnMainThread(() is called from an SignalR.On event.. I know SKGLView redraws the surface at InvalidateSurface and SKCanvasView redraws the canvas at InvalidateSurface but i was under the impression that the functionality was the same,how to solve this? The SKCanvasView/SKGLView is declared in the .xaml file. All this is done on an Android emulator with Visual Studio 2019 16.6.2 Versions: Project .NET Standard 2.0 Xamarin Forms 4.6.0.847 SkiaSharp.Views.Forms 1.68.3 SkiaSharp.Svg 1.60.0 SkiaSharp.Extended 1.60.0 SkiaSharp 1.68.3 Thx Peder

mattleibow commented 4 years ago

The canvas is always totally redrawn - technically. In the case of the SKCanvasView you are technically redrawing the whole canvas, you just can't see it - almost. Typically, if you use antialiasing or transparency, you will notice things get darker and darker. and then if something happens to change the surface size - such as a screen rotate or app pause/resume, then the canvas is recreated and you have to redraw everything. It is just a side effect to have it exist - in fact, you may even get a case where the surface starts with some artifacts from a previous surface - because the memory is just reused.

So, what you are seeing is that the GL view is always cleared, and the canvas view is not (technically a bug).

The correct way is to always clear the canvas before drawing.

If you do want "caching" of drawings, then the best way is to use bitmaps/images/other surfaces and draw a whole bitmap. For example, it you are drawing some background, then some animation, then some foreground, you would have 2 cache bitmaps: background and foreground. When you draw, you first DrawImage(background), then draw the animation, then DrawImage(foreground). This way, you draw in a single (mostly) cheap operation.

If you really want true partial updates, the easiest will be to use a back buffer and always draw to that. Then, when the update happens, you can just do a single cheap operation to draw the bitmap to the screen.

So as a summary... the correct way is to always clear the surface and redraw everything.

the fact that you don't need to always clear on some vies is a bug and probably will be fixed in the new version (v2) of SkiaSharp.

pilotshamn commented 4 years ago

Hi Matthew Thank you for your elaborate answer, so you can say I was lucky to get it working the way it did with CanvasView, my question then is how can i achieve best performance and use gpu with a bitmap in which you update one spokes at a time the whole lap all the time (new data for each spokes comes all the time). is there is some good example of painting on gpu in backround then updating foreground canvas . Thank you very much Peder