Browse Source

EGL refactoring and locks

pull/2108/head
Nikita Tsukanov 7 years ago
parent
commit
8fec3bb113
  1. 4
      src/Avalonia.Native/GlPlatformFeature.cs
  2. 44
      src/Avalonia.OpenGL/EglContext.cs
  3. 53
      src/Avalonia.OpenGL/EglDisplay.cs
  4. 4
      src/Avalonia.OpenGL/EglGlPlatformFeature.cs
  5. 32
      src/Avalonia.OpenGL/EglGlPlatformSurface.cs
  6. 28
      src/Avalonia.OpenGL/EglSurface.cs
  7. 4
      src/Avalonia.OpenGL/IGlContext.cs
  8. 10
      src/Avalonia.OpenGL/IGlSurface.cs
  9. 2
      src/Skia/Avalonia.Skia/PlatformRenderInterface.cs

4
src/Avalonia.Native/GlPlatformFeature.cs

@ -58,10 +58,8 @@ namespace Avalonia.Native
public IGlDisplay Display { get; }
public void MakeCurrent(IGlSurface surface)
public void MakeCurrent()
{
if (surface != null)
throw new ArgumentException(nameof(surface));
Context.MakeCurrent();
}
}

44
src/Avalonia.OpenGL/EglContext.cs

@ -0,0 +1,44 @@
using System;
using System.Reactive.Disposables;
using System.Threading;
namespace Avalonia.OpenGL
{
public class EglContext : IGlContext
{
private readonly EglDisplay _disp;
private readonly EglInterface _egl;
private readonly object _lock = new object();
public EglContext(EglDisplay display, EglInterface egl, IntPtr ctx, IntPtr offscreenSurface)
{
_disp = display;
_egl = egl;
Context = ctx;
OffscreenSurface = offscreenSurface;
}
public IntPtr Context { get; }
public IntPtr OffscreenSurface { get; }
public IGlDisplay Display => _disp;
public IDisposable Lock()
{
Monitor.Enter(_lock);
return Disposable.Create(() => Monitor.Exit(_lock));
}
public void MakeCurrent()
{
if (!_egl.MakeCurrent(_disp.Handle, IntPtr.Zero, IntPtr.Zero, Context))
throw new OpenGlException("eglMakeCurrent failed");
}
public void MakeCurrent(EglSurface surface)
{
var surf = ((EglSurface)surface)?.DangerousGetHandle() ?? OffscreenSurface;
if (!_egl.MakeCurrent(_disp.Handle, surf, surf, Context))
throw new OpenGlException("eglMakeCurrent failed");
}
}
}

53
src/Avalonia.OpenGL/EglDisplay.cs

@ -12,7 +12,8 @@ namespace Avalonia.OpenGL
private readonly IntPtr _display;
private readonly IntPtr _config;
private readonly int[] _contextAttributes;
public IntPtr Handle => _display;
public EglDisplay(EglInterface egl)
{
_egl = egl;
@ -121,7 +122,7 @@ namespace Avalonia.OpenGL
});
if (surf == IntPtr.Zero)
throw new OpenGlException("eglCreatePbufferSurface failed");
var rv = new EglContext(this, ctx, surf);
var rv = new EglContext(this, _egl, ctx, surf);
rv.MakeCurrent(null);
return rv;
}
@ -132,12 +133,12 @@ namespace Avalonia.OpenGL
throw new OpenGlException("eglMakeCurrent failed");
}
public IGlSurface CreateWindowSurface(IntPtr window)
public EglSurface CreateWindowSurface(IntPtr window)
{
var s = _egl.CreateWindowSurface(_display, _config, window, new[] {EGL_NONE, EGL_NONE});
if (s == IntPtr.Zero)
throw new OpenGlException("eglCreateWindowSurface failed");
return new EglSurface(this, s);
return new EglSurface(this, _egl, s);
}
public int SampleCount
@ -157,49 +158,5 @@ namespace Avalonia.OpenGL
return rv;
}
}
class EglSurface : SafeHandle, IGlSurface
{
private readonly EglDisplay _display;
public EglSurface(EglDisplay display, IntPtr surface) : base(surface, true)
{
_display = display;
}
protected override bool ReleaseHandle()
{
_display._egl.DestroySurface(_display._display, handle);
return true;
}
public override bool IsInvalid => handle == IntPtr.Zero;
public IGlDisplay Display => _display;
public void SwapBuffers() => _display._egl.SwapBuffers(_display._display, handle);
}
class EglContext : IGlContext
{
private readonly EglDisplay _disp;
public EglContext(EglDisplay display, IntPtr ctx, IntPtr offscreenSurface)
{
_disp = display;
Context = ctx;
OffscreenSurface = offscreenSurface;
}
public IntPtr Context { get; }
public IntPtr OffscreenSurface { get; }
public IGlDisplay Display => _disp;
public void MakeCurrent(IGlSurface surface)
{
var surf = ((EglSurface)surface)?.DangerousGetHandle() ?? OffscreenSurface;
if (!_disp._egl.MakeCurrent(_disp._display, surf, surf, Context))
throw new OpenGlException("eglMakeCurrent failed");
}
}
}
}

4
src/Avalonia.OpenGL/EglGlPlatformFeature.cs

@ -7,7 +7,7 @@ namespace Avalonia.OpenGL
{
public IGlDisplay Display { get; set; }
public IGlContext ImmediateContext { get; set; }
public IGlContext DeferredContext { get; set; }
public EglContext DeferredContext { get; set; }
public static void TryInitialize()
{
@ -26,7 +26,7 @@ namespace Avalonia.OpenGL
{
Display = disp,
ImmediateContext = ctx,
DeferredContext = disp.CreateContext(ctx)
DeferredContext = (EglContext)disp.CreateContext(ctx)
};
}
catch(Exception e)

32
src/Avalonia.OpenGL/EglGlPlatformSurface.cs

@ -1,4 +1,5 @@
using System;
using System.Threading;
namespace Avalonia.OpenGL
{
@ -12,10 +13,10 @@ namespace Avalonia.OpenGL
}
private readonly EglDisplay _display;
private readonly IGlContext _context;
private readonly EglContext _context;
private readonly IEglWindowGlPlatformSurfaceInfo _info;
public EglGlPlatformSurface(EglDisplay display, IGlContext context, IEglWindowGlPlatformSurfaceInfo info)
public EglGlPlatformSurface(EglDisplay display, EglContext context, IEglWindowGlPlatformSurfaceInfo info)
{
_display = display;
_context = context;
@ -30,11 +31,11 @@ namespace Avalonia.OpenGL
class RenderTarget : IGlPlatformSurfaceRenderTarget
{
private readonly IGlContext _context;
private readonly IGlSurface _glSurface;
private readonly EglContext _context;
private readonly EglSurface _glSurface;
private readonly IEglWindowGlPlatformSurfaceInfo _info;
public RenderTarget(IGlContext context, IGlSurface glSurface, IEglWindowGlPlatformSurfaceInfo info)
public RenderTarget(EglContext context, EglSurface glSurface, IEglWindowGlPlatformSurfaceInfo info)
{
_context = context;
_glSurface = glSurface;
@ -45,21 +46,33 @@ namespace Avalonia.OpenGL
public IGlPlatformSurfaceRenderingSession BeginDraw()
{
_context.MakeCurrent(_glSurface);
return new Session(_context, _glSurface, _info);
var l = _context.Lock();
try
{
_context.MakeCurrent(_glSurface);
return new Session(_context, _glSurface, _info, l);
}
catch
{
l.Dispose();
throw;
}
}
class Session : IGlPlatformSurfaceRenderingSession
{
private readonly IGlContext _context;
private readonly IGlSurface _glSurface;
private readonly EglSurface _glSurface;
private readonly IEglWindowGlPlatformSurfaceInfo _info;
private IDisposable _lock;
public Session(IGlContext context, IGlSurface glSurface, IEglWindowGlPlatformSurfaceInfo info)
public Session(IGlContext context, EglSurface glSurface, IEglWindowGlPlatformSurfaceInfo info,
IDisposable @lock)
{
_context = context;
_glSurface = glSurface;
_info = info;
_lock = @lock;
}
public void Dispose()
@ -67,6 +80,7 @@ namespace Avalonia.OpenGL
_context.Display.GlInterface.Flush();
_glSurface.SwapBuffers();
_context.Display.ClearContext();
_lock.Dispose();
}
public IGlDisplay Display => _context.Display;

28
src/Avalonia.OpenGL/EglSurface.cs

@ -0,0 +1,28 @@
using System;
using System.Runtime.InteropServices;
namespace Avalonia.OpenGL
{
public class EglSurface : SafeHandle
{
private readonly EglDisplay _display;
private readonly EglInterface _egl;
public EglSurface(EglDisplay display, EglInterface egl, IntPtr surface) : base(surface, true)
{
_display = display;
_egl = egl;
}
protected override bool ReleaseHandle()
{
_egl.DestroySurface(_display.Handle, handle);
return true;
}
public override bool IsInvalid => handle == IntPtr.Zero;
public IGlDisplay Display => _display;
public void SwapBuffers() => _egl.SwapBuffers(_display.Handle, handle);
}
}

4
src/Avalonia.OpenGL/IGlContext.cs

@ -3,6 +3,6 @@ namespace Avalonia.OpenGL
public interface IGlContext
{
IGlDisplay Display { get; }
void MakeCurrent(IGlSurface surface);
void MakeCurrent();
}
}
}

10
src/Avalonia.OpenGL/IGlSurface.cs

@ -1,10 +0,0 @@
using System;
namespace Avalonia.OpenGL
{
public interface IGlSurface : IDisposable
{
IGlDisplay Display { get; }
void SwapBuffers();
}
}

2
src/Skia/Avalonia.Skia/PlatformRenderInterface.cs

@ -28,7 +28,7 @@ namespace Avalonia.Skia
var iface = display.Type == GlDisplayType.OpenGL2
? GRGlInterface.AssembleGlInterface((_, proc) => display.GlInterface.GetProcAddress(proc))
: GRGlInterface.AssembleGlesInterface((_, proc) => display.GlInterface.GetProcAddress(proc));
gl.ImmediateContext.MakeCurrent(null);
gl.ImmediateContext.MakeCurrent();
GrContext = GRContext.Create(GRBackend.OpenGL, iface);
}
}

Loading…
Cancel
Save