Windows WPF application and Skia GPU rendering

26 views
Skip to first unread message

Peter Nelson

unread,
Jul 11, 2024, 11:42:43 PM (10 days ago) Jul 11
to skia-discuss
Hello all,

Sorry for this long post/question.

I am working on a WPF application (for making maps for games and worldbuilding) that can potentially work with large bitmaps (3840x2160 or more). The maps consist of 20+ layers, each with a backing bitmap and canvas that get composited to a final canvas/bitmap for display on the screen in a control that handles zooming and panning (so I don't have to mess with the math for that). It works well for the most part, but some of the components of the map (landforms) get drawn by the user in real time by building a Skia path from circles added to the path as the user moves the mouse. Obviously, a whole lot of data is getting moved and there's a lot of number crunching to compute perimeters of paths, etc., especially for large maps. Up to about 2K resolution, it works pretty well. Above that, it bogs down and becomes basically unusable.

From the reading I've done, it appears that a Windows WPF application will "automatically" render on the GPU when it can, but it appears to me that my application either isn't using the GPU, or (probably more likely) it is having to move a lot of data between the CPU and GPU, so there isn't any performance benefit.

So, I have 2 questions:
1) In a WPF application, do I have to do anything to get Skia to render on the GPU, like set up an OpenGL context, etc., or will Skia just use the GPU because the WPF app does?
2) If I do have to set up an OpenGL context, it seems like I would have to set up an OpenGL context and surface and derive a canvas from the surface for each layer. Is that correct?

I'm hoping to improve the performance of the application so that users can draw smoothly with the mouse even on 4K or larger maps with a lot of layers. Any architecture/implementation advice on how to achieve that would be super appreciated!

Thanks.

Brian Osman

unread,
Jul 11, 2024, 11:50:42 PM (10 days ago) Jul 11
to skia-d...@googlegroups.com
The answer to your first question depends on how exactly you're using Skia. If you're using SkiaSharp, then you'd need to check with that library's authors to see about the GPU context binding. If you're using a native copy of Skia linked in to your WPF application, then you won't get GPU rendering automatically - Skia surfaces need to be explicitly constructed to be either CPU or GPU backed (and using the GPU does require an active GL context, or similar, depending on the backend API).

--
You received this message because you are subscribed to the Google Groups "skia-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to skia-discuss...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/skia-discuss/928bbe53-c7bd-4198-b687-4ddbb4c9374dn%40googlegroups.com.

Peter Nelson

unread,
Jul 11, 2024, 11:58:26 PM (10 days ago) Jul 11
to skia-discuss
Thanks for the  quick reply, Brian. I am using SkiaSharp. I've constructed an OpenGL context for the main display canvas (but not for the layer canvases) and gotten it to work, but it actually made the performance worse, I guess because there's a ton of pixels being moved between the CPU and GPU. I'm thinking that I'll have to work on constructing a GPU context, surface, and canvas for each layer as well as the display canvas, but I don't know if that would actually help - I'm not very experienced with OpenGL or GPU rendering.

Peter Nelson

unread,
Jul 12, 2024, 1:33:28 AM (10 days ago) Jul 12
to skia-discuss
I tried constructing an OpenGL context, surface, and canvas for all of the map layers. I got the application to compile and run, but nothing was displayed, so I backed out the changes. Also, as I moved the mouse on a large map with the GPU canvas in place, the cursor was still laggy, so I think the performance I was hoping for still wouldn't be there. It's likely I made some mistakes in how I implemented the GPU canvas and context, since I don't really know what I'm doing, but it might be that I just need to fundamentally rethink the app architecture.

Tiko Tiko

unread,
Jul 12, 2024, 4:36:34 AM (10 days ago) Jul 12
to skia-d...@googlegroups.com
I assume you are using the SKGLElement?

I have also found similar performance results to yourself. In most cases, it actually seems to be slower to use the GL binding. The only cases where I have seen it to be quicker is with something like DrawAtlas.

A simple example of where it's slower is DrawPoints(), the CPU version is noticeably quicker. Although I am not sure where the bottleneck is, where its something in SkiasSharp or Skia

Brian, is this because geometry is reconstructed and sent to the GPU every frame?

John Stiles

unread,
Jul 12, 2024, 9:19:50 AM (10 days ago) Jul 12
to skia-d...@googlegroups.com
Thinking through this scenario a bit. If you have an RGBA 3840x2160 texture, that's about 32MB of data on the GPU. If you have twenty, that's 640MB of texture memory. 

What sort of GPU are you testing on? If it has less than 1GB of dedicated texture memory, you will probably not have enough to fit all these textures on the GPU at all; at that point, the GPU would be constantly swapping textures in and out of graphics memory, which is very slow. 

In theory, the actual workload of compositing these textures is probably very manageable if they all fit in memory. You might want to make a tiny test app which lets you experiment with the problem in isolation. My guess is that it will work great for a certain number of textures, then performance will pretty rapidly fall off of a cliff as you exceed the GPU's memory limits. The exact number of textures will vary based on your exact system configuration.

Then again, if you aren't actually seeing the results on screen, it's entirely possible you are doing something wrong which is leading Skia down a slow/expensive path. You should try to resolve that before drawing any final conclusions.


Loïc Baumann

unread,
Jul 12, 2024, 10:33:41 AM (10 days ago) Jul 12
to skia-discuss
I've come across a similar requirement, things are not up to date in the SkiaSharp GitHub site and doc, but you can do:
1. Install OpenTK 4.3.1 package
2. Install SkiaSharp.Views.WPF (3.0.0-preview.3.1)
3. You can use this with a .net 8-windows application profile.

Then use the SKGLElement and you're good to go:

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp4"
        xmlns:skgl.Wpf="clr-namespace:SkiaSharp.Views.WPF;assembly=SkiaSharp.Views.WPF"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <skgl.Wpf:SKGLElement PaintSurface="SKGLElement_PaintSurface"/>

</Window>

Reply all
Reply to author
Forward
0 new messages