Browse Source

Delay SKSurface disposal if context is lost

pull/9639/head
Nikita Tsukanov 3 years ago
parent
commit
be99231399
  1. 39
      src/Skia/Avalonia.Skia/Gpu/OpenGl/FboSkiaSurface.cs
  2. 14
      src/Skia/Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs

39
src/Skia/Avalonia.Skia/Gpu/OpenGl/FboSkiaSurface.cs

@ -1,11 +1,13 @@
using System;
using Avalonia.OpenGL;
using Avalonia.Platform;
using SkiaSharp;
using static Avalonia.OpenGL.GlConsts;
namespace Avalonia.Skia
{
public class FboSkiaSurface : ISkiaSurface
internal class FboSkiaSurface : ISkiaSurface
{
private readonly GlSkiaGpu _gpu;
private readonly GRContext _grContext;
private readonly IGlContext _glContext;
private readonly PixelSize _pixelSize;
@ -14,8 +16,9 @@ namespace Avalonia.Skia
private int _texture;
private static readonly bool[] TrueFalse = new[] { true, false };
public FboSkiaSurface(GRContext grContext, IGlContext glContext, PixelSize pixelSize, GRSurfaceOrigin surfaceOrigin)
public FboSkiaSurface(GlSkiaGpu gpu, GRContext grContext, IGlContext glContext, PixelSize pixelSize, GRSurfaceOrigin surfaceOrigin)
{
_gpu = gpu;
_grContext = grContext;
_glContext = glContext;
_pixelSize = pixelSize;
@ -93,19 +96,33 @@ namespace Avalonia.Skia
public void Dispose()
{
using (_glContext.EnsureCurrent())
try
{
Surface?.Dispose();
Surface = null;
var gl = _glContext.GlInterface;
if (_fbo != 0)
using (_glContext.EnsureCurrent())
{
gl.DeleteFramebuffer(_fbo);
gl.DeleteTexture(_texture);
gl.DeleteRenderbuffer(_depthStencil);
_fbo = _texture = _depthStencil = 0;
Surface?.Dispose();
Surface = null;
var gl = _glContext.GlInterface;
if (_fbo != 0)
{
gl.DeleteFramebuffer(_fbo);
gl.DeleteTexture(_texture);
gl.DeleteRenderbuffer(_depthStencil);
}
}
}
catch (PlatformGraphicsContextLostException)
{
if (Surface != null)
// We need to dispose SKSurface _after_ GRContext.Abandon was called,
// otherwise it will try to do OpenGL calls without a proper context
_gpu.AddPostDispose(Surface.Dispose);
Surface = null;
}
finally
{
_fbo = _texture = _depthStencil = 0;
}
}
public SKSurface Surface { get; private set; }

14
src/Skia/Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs

@ -14,6 +14,7 @@ namespace Avalonia.Skia
{
private GRContext _grContext;
private IGlContext _glContext;
private List<Action> _postDisposeCallbacks = new();
private bool? _canCreateSurfaces;
public GlSkiaGpu(IGlContext context, long? maxResourceBytes)
@ -83,7 +84,8 @@ namespace Avalonia.Skia
return null;
try
{
var surface = new FboSkiaSurface(_grContext, _glContext, size, session?.SurfaceOrigin ?? GRSurfaceOrigin.TopLeft);
var surface = new FboSkiaSurface(this, _grContext, _glContext, size,
session?.SurfaceOrigin ?? GRSurfaceOrigin.TopLeft);
_canCreateSurfaces = true;
return surface;
}
@ -110,6 +112,10 @@ namespace Avalonia.Skia
else
_grContext.AbandonContext(true);
_grContext.Dispose();
lock(_postDisposeCallbacks)
foreach (var cb in _postDisposeCallbacks)
cb();
}
public bool IsLost => _glContext.IsLost;
@ -121,5 +127,11 @@ namespace Avalonia.Skia
return this;
return null;
}
public void AddPostDispose(Action dispose)
{
lock (_postDisposeCallbacks)
_postDisposeCallbacks.Add(dispose);
}
}
}

Loading…
Cancel
Save