diff --git a/src/Avalonia.Native/GlPlatformFeature.cs b/src/Avalonia.Native/GlPlatformFeature.cs index 97785e4a81..e39680bdee 100644 --- a/src/Avalonia.Native/GlPlatformFeature.cs +++ b/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(); } } diff --git a/src/Avalonia.OpenGL/EglContext.cs b/src/Avalonia.OpenGL/EglContext.cs new file mode 100644 index 0000000000..27b1abe411 --- /dev/null +++ b/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"); + } + } +} diff --git a/src/Avalonia.OpenGL/EglDisplay.cs b/src/Avalonia.OpenGL/EglDisplay.cs index ea0a9bf087..90a70adcb7 100644 --- a/src/Avalonia.OpenGL/EglDisplay.cs +++ b/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"); - } - } } } diff --git a/src/Avalonia.OpenGL/EglGlPlatformFeature.cs b/src/Avalonia.OpenGL/EglGlPlatformFeature.cs index 535e32924e..86411b89da 100644 --- a/src/Avalonia.OpenGL/EglGlPlatformFeature.cs +++ b/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) diff --git a/src/Avalonia.OpenGL/EglGlPlatformSurface.cs b/src/Avalonia.OpenGL/EglGlPlatformSurface.cs index c99c869c4f..f5dd413b0f 100644 --- a/src/Avalonia.OpenGL/EglGlPlatformSurface.cs +++ b/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; diff --git a/src/Avalonia.OpenGL/EglSurface.cs b/src/Avalonia.OpenGL/EglSurface.cs new file mode 100644 index 0000000000..90bb1e36d0 --- /dev/null +++ b/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); + } +} \ No newline at end of file diff --git a/src/Avalonia.OpenGL/IGlContext.cs b/src/Avalonia.OpenGL/IGlContext.cs index 954567fe2e..04aa1b98e4 100644 --- a/src/Avalonia.OpenGL/IGlContext.cs +++ b/src/Avalonia.OpenGL/IGlContext.cs @@ -3,6 +3,6 @@ namespace Avalonia.OpenGL public interface IGlContext { IGlDisplay Display { get; } - void MakeCurrent(IGlSurface surface); + void MakeCurrent(); } -} \ No newline at end of file +} diff --git a/src/Avalonia.OpenGL/IGlSurface.cs b/src/Avalonia.OpenGL/IGlSurface.cs deleted file mode 100644 index 499d0a3c90..0000000000 --- a/src/Avalonia.OpenGL/IGlSurface.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace Avalonia.OpenGL -{ - public interface IGlSurface : IDisposable - { - IGlDisplay Display { get; } - void SwapBuffers(); - } -} \ No newline at end of file diff --git a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs index dfd277ec86..9b10d74c64 100644 --- a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs +++ b/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); } }