source/SkiaSharp.Views/SkiaSharp.Views.WinUI/SKSwapChainPanel.cs (86 lines of code) (raw):
using System;
using SkiaSharp.Views.GlesInterop;
using Windows.Foundation;
#if WINDOWS
namespace SkiaSharp.Views.Windows
#else
namespace SkiaSharp.Views.UWP
#endif
{
public class SKSwapChainPanel : AngleSwapChainPanel
{
private const SKColorType colorType = SKColorType.Rgba8888;
private const GRSurfaceOrigin surfaceOrigin = GRSurfaceOrigin.BottomLeft;
private GRGlInterface glInterface;
private GRContext context;
private GRGlFramebufferInfo glInfo;
private GRBackendRenderTarget renderTarget;
private SKSurface surface;
private SKCanvas canvas;
private SKSizeI lastSize;
public SKSwapChainPanel()
{
}
public SKSize CanvasSize => lastSize;
public GRContext GRContext => context;
public event EventHandler<SKPaintGLSurfaceEventArgs> PaintSurface;
protected virtual void OnPaintSurface(SKPaintGLSurfaceEventArgs e)
{
// invoke the event
PaintSurface?.Invoke(this, e);
}
protected override void OnRenderFrame(Rect rect)
{
// clear everything
Gles.glClear(Gles.GL_COLOR_BUFFER_BIT | Gles.GL_DEPTH_BUFFER_BIT | Gles.GL_STENCIL_BUFFER_BIT);
// create the SkiaSharp context
if (context == null)
{
glInterface = GRGlInterface.Create();
context = GRContext.CreateGl(glInterface);
}
// get the new surface size
var newSize = new SKSizeI((int)rect.Width, (int)rect.Height);
// manage the drawing surface
if (renderTarget == null || lastSize != newSize || !renderTarget.IsValid)
{
// create or update the dimensions
lastSize = newSize;
// read the info from the buffer
Gles.glGetIntegerv(Gles.GL_FRAMEBUFFER_BINDING, out var framebuffer);
Gles.glGetIntegerv(Gles.GL_STENCIL_BITS, out var stencil);
Gles.glGetIntegerv(Gles.GL_SAMPLES, out var samples);
var maxSamples = context.GetMaxSurfaceSampleCount(colorType);
if (samples > maxSamples)
samples = maxSamples;
glInfo = new GRGlFramebufferInfo((uint)framebuffer, colorType.ToGlSizedFormat());
// destroy the old surface
surface?.Dispose();
surface = null;
canvas = null;
// re-create the render target
renderTarget?.Dispose();
renderTarget = new GRBackendRenderTarget(newSize.Width, newSize.Height, samples, stencil, glInfo);
}
// create the surface
if (surface == null)
{
surface = SKSurface.Create(context, renderTarget, surfaceOrigin, colorType);
canvas = surface.Canvas;
}
using (new SKAutoCanvasRestore(canvas, true))
{
// start drawing
OnPaintSurface(new SKPaintGLSurfaceEventArgs(surface, renderTarget, surfaceOrigin, colorType));
}
// update the control
canvas.Flush();
context.Flush();
}
protected override void OnDestroyingContext()
{
base.OnDestroyingContext();
lastSize = default;
canvas?.Dispose();
canvas = null;
surface?.Dispose();
surface = null;
renderTarget?.Dispose();
renderTarget = null;
glInfo = default;
context?.AbandonContext(false);
context?.Dispose();
context = null;
glInterface?.Dispose();
glInterface = null;
}
}
}