Browse Source

Refactored GL version and context management

pull/3386/head
Nikita Tsukanov 7 years ago
parent
commit
e2bde7155f
  1. 8
      samples/ControlCatalog.NetCore/Program.cs
  2. 6
      samples/ControlCatalog/Pages/OpenGlPage.xaml.cs
  3. 56
      src/Avalonia.Native/GlPlatformFeature.cs
  4. 3
      src/Avalonia.Native/PopupImpl.cs
  5. 5
      src/Avalonia.Native/WindowImpl.cs
  6. 6
      src/Avalonia.Native/WindowImplBase.cs
  7. 15
      src/Avalonia.OpenGL/EglContext.cs
  8. 45
      src/Avalonia.OpenGL/EglDisplay.cs
  9. 5
      src/Avalonia.OpenGL/EglGlPlatformFeature.cs
  10. 8
      src/Avalonia.OpenGL/EglGlPlatformSurface.cs
  11. 4
      src/Avalonia.OpenGL/EglSurface.cs
  12. 8
      src/Avalonia.OpenGL/GlDisplayType.cs
  13. 22
      src/Avalonia.OpenGL/GlVersion.cs
  14. 5
      src/Avalonia.OpenGL/IGlContext.cs
  15. 10
      src/Avalonia.OpenGL/IGlDisplay.cs
  16. 2
      src/Avalonia.OpenGL/IGlPlatformSurfaceRenderingSession.cs
  17. 2
      src/Avalonia.OpenGL/IWindowingPlatformGlFeature.cs
  18. 18
      src/Avalonia.OpenGL/OpenGlControlBase.cs
  19. 14
      src/Avalonia.X11/Glx/Glx.cs
  20. 2
      src/Avalonia.X11/Glx/GlxConsts.cs
  21. 15
      src/Avalonia.X11/Glx/GlxContext.cs
  22. 99
      src/Avalonia.X11/Glx/GlxDisplay.cs
  23. 4
      src/Avalonia.X11/Glx/GlxGlPlatformSurface.cs
  24. 12
      src/Avalonia.X11/Glx/GlxPlatformFeature.cs
  25. 13
      src/Avalonia.X11/X11Platform.cs
  26. 2
      src/Avalonia.X11/X11Window.cs
  27. 15
      src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs
  28. 2
      src/Skia/Avalonia.Skia/Gpu/OpenGl/GlRenderTarget.cs
  29. 12
      src/Skia/Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs
  30. 3
      src/Windows/Avalonia.Win32/WindowImpl.cs

8
samples/ControlCatalog.NetCore/Program.cs

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
@ -6,6 +7,7 @@ using System.Threading;
using Avalonia;
using Avalonia.ReactiveUI;
using Avalonia.Dialogs;
using Avalonia.OpenGL;
namespace ControlCatalog.NetCore
{
@ -58,7 +60,11 @@ namespace ControlCatalog.NetCore
.With(new X11PlatformOptions
{
EnableMultiTouch = true,
UseDBusMenu = true
UseDBusMenu = true,
GlProfiles = new List<GlVersion>
{
new GlVersion(GlProfileType.OpenGLES, 2, 0)
}
})
.With(new Win32PlatformOptions
{

6
samples/ControlCatalog/Pages/OpenGlPage.xaml.cs

@ -91,12 +91,12 @@ namespace ControlCatalog.Pages
private string GetShader(bool fragment, string shader)
{
var version = (DisplayType == GlDisplayType.OpenGl ?
var version = (GlVersion.Type == GlProfileType.OpenGL ?
RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 150 : 120 :
100);
var data = "#version " + version + "\n";
if (DisplayType == GlDisplayType.OpenGLES)
data += "precision mediump float\n";
if (GlVersion.Type == GlProfileType.OpenGLES)
data += "precision mediump float;\n";
if (version >= 150)
{
shader = shader.Replace("attribute", "in");

56
src/Avalonia.Native/GlPlatformFeature.cs

@ -16,21 +16,30 @@ namespace Avalonia.Native
var immediate = display.CreateContext(null);
var deferred = display.CreateContext(immediate);
GlDisplay = new GlDisplay(display, immediate.SampleCount, immediate.StencilSize);
ImmediateContext = new GlContext(GlDisplay, immediate);
DeferredContext = new GlContext(GlDisplay, deferred);
int major, minor;
using (immediate.MakeCurrent())
{
GlDisplay.GlInterface.GetIntegerv(GlConsts.GL_MAJOR_VERSION, out major);
GlDisplay.GlInterface.GetIntegerv(GlConsts.GL_MINOR_VERSION, out minor);
}
_version = new GlVersion(GlProfileType.OpenGL, major, minor);
ImmediateContext = new GlContext(GlDisplay, immediate, _version);
DeferredContext = new GlContext(GlDisplay, deferred, _version);
}
public IGlContext ImmediateContext { get; }
internal IGlContext ImmediateContext { get; }
public IGlContext MainContext => DeferredContext;
internal GlContext DeferredContext { get; }
internal GlDisplay GlDisplay;
public IGlDisplay Display => GlDisplay;
private readonly GlVersion _version;
public IGlContext CreateContext() => new GlContext(GlDisplay,
_display.CreateContext(((GlContext)ImmediateContext).Context));
_display.CreateContext(((GlContext)ImmediateContext).Context), _version);
}
class GlDisplay : IGlDisplay
class GlDisplay
{
private readonly IAvnGlDisplay _display;
@ -48,8 +57,6 @@ namespace Avalonia.Native
});
}
public GlDisplayType Type => GlDisplayType.OpenGl;
public GlInterface GlInterface { get; }
public int SampleCount { get; }
@ -61,16 +68,20 @@ namespace Avalonia.Native
class GlContext : IGlContext
{
private readonly GlDisplay _display;
public IAvnGlContext Context { get; private set; }
public GlContext(GlDisplay display, IAvnGlContext context)
public GlContext(GlDisplay display, IAvnGlContext context, GlVersion version)
{
Display = display;
_display = display;
Context = context;
Version = version;
}
public IGlDisplay Display { get; }
public GlVersion Version { get; }
public GlInterface GlInterface => _display.GlInterface;
public int SampleCount => _display.SampleCount;
public int StencilSize => _display.StencilSize;
public IDisposable MakeCurrent() => Context.MakeCurrent();
public void Dispose()
@ -84,15 +95,18 @@ namespace Avalonia.Native
class GlPlatformSurfaceRenderTarget : IGlPlatformSurfaceRenderTarget
{
private IAvnGlSurfaceRenderTarget _target;
public GlPlatformSurfaceRenderTarget(IAvnGlSurfaceRenderTarget target)
private readonly IGlContext _context;
public GlPlatformSurfaceRenderTarget(IAvnGlSurfaceRenderTarget target, IGlContext context)
{
_target = target;
_context = context;
}
public IGlPlatformSurfaceRenderingSession BeginDraw()
{
var feature = (GlPlatformFeature)AvaloniaLocator.Current.GetService<IWindowingPlatformGlFeature>();
return new GlPlatformSurfaceRenderingSession(feature.GlDisplay, _target.BeginDrawing());
return new GlPlatformSurfaceRenderingSession(_context, _target.BeginDrawing());
}
public void Dispose()
@ -106,13 +120,13 @@ namespace Avalonia.Native
{
private IAvnGlSurfaceRenderingSession _session;
public GlPlatformSurfaceRenderingSession(GlDisplay display, IAvnGlSurfaceRenderingSession session)
public GlPlatformSurfaceRenderingSession(IGlContext context, IAvnGlSurfaceRenderingSession session)
{
Display = display;
Context = context;
_session = session;
}
public IGlDisplay Display { get; }
public IGlContext Context { get; }
public PixelSize Size
{
@ -138,14 +152,16 @@ namespace Avalonia.Native
class GlPlatformSurface : IGlPlatformSurface
{
private readonly IAvnWindowBase _window;
private readonly IGlContext _context;
public GlPlatformSurface(IAvnWindowBase window)
public GlPlatformSurface(IAvnWindowBase window, IGlContext context)
{
_window = window;
_context = context;
}
public IGlPlatformSurfaceRenderTarget CreateGlRenderTarget()
{
return new GlPlatformSurfaceRenderTarget(_window.CreateGlRenderTarget());
return new GlPlatformSurfaceRenderTarget(_window.CreateGlRenderTarget(), _context);
}
}

3
src/Avalonia.Native/PopupImpl.cs

@ -24,7 +24,8 @@ namespace Avalonia.Native
_glFeature = glFeature;
using (var e = new PopupEvents(this))
{
Init(factory.CreatePopup(e, _opts.UseGpu ? glFeature?.DeferredContext.Context : null), factory.CreateScreens());
var context = _opts.UseGpu ? glFeature?.DeferredContext : null;
Init(factory.CreatePopup(e, context?.Context), factory.CreateScreens(), context);
}
PopupPositioner = new ManagedPopupPositioner(new OsxManagedPopupPositionerPopupImplHelper(parent, MoveResize));
}

5
src/Avalonia.Native/WindowImpl.cs

@ -5,6 +5,7 @@ using System;
using Avalonia.Controls;
using Avalonia.Controls.Platform;
using Avalonia.Native.Interop;
using Avalonia.OpenGL;
using Avalonia.Platform;
using Avalonia.Platform.Interop;
@ -24,8 +25,8 @@ namespace Avalonia.Native
_glFeature = glFeature;
using (var e = new WindowEvents(this))
{
Init(_native = factory.CreateWindow(e,
_opts.UseGpu ? glFeature?.DeferredContext.Context : null), factory.CreateScreens());
var context = _opts.UseGpu ? glFeature?.DeferredContext : null;
Init(_native = factory.CreateWindow(e, context?.Context), factory.CreateScreens(), context);
}
NativeMenuExporter = new AvaloniaNativeMenuExporter(_native, factory);

6
src/Avalonia.Native/WindowImplBase.cs

@ -59,6 +59,7 @@ namespace Avalonia.Native
private Size _lastRenderedLogicalSize;
private double _savedScaling;
private GlPlatformSurface _glSurface;
private IGlContext _glContext;
internal WindowBaseImpl(AvaloniaNativePlatformOptions opts, GlPlatformFeature glFeature)
{
@ -70,13 +71,14 @@ namespace Avalonia.Native
_cursorFactory = AvaloniaLocator.Current.GetService<IStandardCursorFactory>();
}
protected void Init(IAvnWindowBase window, IAvnScreens screens)
protected void Init(IAvnWindowBase window, IAvnScreens screens, IGlContext glContext)
{
_native = window;
_glContext = glContext;
Handle = new MacOSTopLevelWindowHandle(window);
if (_gpu)
_glSurface = new GlPlatformSurface(window);
_glSurface = new GlPlatformSurface(window, _glContext);
Screen = new ScreenImpl(screens);
_savedLogicalSize = ClientSize;
_savedScaling = Scaling;

15
src/Avalonia.OpenGL/EglContext.cs

@ -11,17 +11,26 @@ namespace Avalonia.OpenGL
private readonly EglInterface _egl;
private readonly object _lock = new object();
public EglContext(EglDisplay display, EglInterface egl, IntPtr ctx, EglSurface offscreenSurface)
public EglContext(EglDisplay display, EglInterface egl, IntPtr ctx, EglSurface offscreenSurface,
GlVersion version, int sampleCount, int stencilSize)
{
_disp = display;
_egl = egl;
Context = ctx;
OffscreenSurface = offscreenSurface;
Version = version;
SampleCount = sampleCount;
StencilSize = stencilSize;
GlInterface = GlInterface.FromNativeUtf8GetProcAddress(b => _egl.GetProcAddress(b));
}
public IntPtr Context { get; }
public EglSurface OffscreenSurface { get; }
public IGlDisplay Display => _disp;
public GlVersion Version { get; }
public GlInterface GlInterface { get; }
public int SampleCount { get; }
public int StencilSize { get; }
public EglDisplay Display => _disp;
public IDisposable Lock()
{
@ -52,7 +61,7 @@ namespace Avalonia.OpenGL
}
}
public IDisposable MakeCurrent()
{
var old = new RestoreContext(_egl, _disp.Handle);

45
src/Avalonia.OpenGL/EglDisplay.cs

@ -6,7 +6,7 @@ using static Avalonia.OpenGL.EglConsts;
namespace Avalonia.OpenGL
{
public class EglDisplay : IGlDisplay
public class EglDisplay
{
private readonly EglInterface _egl;
private readonly IntPtr _display;
@ -16,6 +16,9 @@ namespace Avalonia.OpenGL
public IntPtr Handle => _display;
private AngleOptions.PlatformApi? _angleApi;
private int _sampleCount;
private int _stencilSize;
private GlVersion _version;
public EglDisplay(EglInterface egl) : this(egl, -1, IntPtr.Zero, null)
{
@ -76,13 +79,6 @@ namespace Avalonia.OpenGL
foreach (var cfg in new[]
{
new
{
Attributes = new[] {EGL_NONE},
Api = EGL_OPENGL_API,
RenderableTypeBit = EGL_OPENGL_BIT,
Type = GlDisplayType.OpenGl
},
new
{
Attributes = new[]
@ -92,7 +88,7 @@ namespace Avalonia.OpenGL
},
Api = EGL_OPENGL_ES_API,
RenderableTypeBit = EGL_OPENGL_ES2_BIT,
Type = GlDisplayType.OpenGLES
Version = new GlVersion(GlProfileType.OpenGLES, 2, 0)
}
})
{
@ -120,7 +116,9 @@ namespace Avalonia.OpenGL
continue;
_contextAttributes = cfg.Attributes;
_surfaceType = surfaceType;
Type = cfg.Type;
_version = cfg.Version;
_egl.GetConfigAttrib(_display, _config, EGL_SAMPLES, out _sampleCount);
_egl.GetConfigAttrib(_display, _config, EGL_STENCIL_SIZE, out _stencilSize);
goto Found;
}
@ -128,8 +126,6 @@ namespace Avalonia.OpenGL
Found:
if (_contextAttributes == null)
throw new OpenGlException("No suitable EGL config was found");
GlInterface = GlInterface.FromNativeUtf8GetProcAddress(b => _egl.GetProcAddress(b));
}
public EglDisplay() : this(new EglInterface())
@ -137,8 +133,6 @@ namespace Avalonia.OpenGL
}
public GlDisplayType Type { get; }
public GlInterface GlInterface { get; }
public EglInterface EglInterface => _egl;
public EglContext CreateContext(IGlContext share)
{
@ -156,7 +150,8 @@ namespace Avalonia.OpenGL
});
if (surf == IntPtr.Zero)
throw OpenGlException.GetFormattedException("eglCreatePBufferSurface", _egl);
var rv = new EglContext(this, _egl, ctx, new EglSurface(this, _egl, surf));
var rv = new EglContext(this, _egl, ctx, new EglSurface(this, _egl, surf),
_version, _sampleCount, _stencilSize);
return rv;
}
@ -165,7 +160,7 @@ namespace Avalonia.OpenGL
var ctx = _egl.CreateContext(_display, _config, share?.Context ?? IntPtr.Zero, _contextAttributes);
if (ctx == IntPtr.Zero)
throw OpenGlException.GetFormattedException("eglCreateContext", _egl);
var rv = new EglContext(this, _egl, ctx, offscreenSurface);
var rv = new EglContext(this, _egl, ctx, offscreenSurface, _version, _sampleCount, _stencilSize);
rv.MakeCurrent(null);
return rv;
}
@ -177,23 +172,5 @@ namespace Avalonia.OpenGL
throw OpenGlException.GetFormattedException("eglCreateWindowSurface", _egl);
return new EglSurface(this, _egl, s);
}
public int SampleCount
{
get
{
_egl.GetConfigAttrib(_display, _config, EGL_SAMPLES, out var rv);
return rv;
}
}
public int StencilSize
{
get
{
_egl.GetConfigAttrib(_display, _config, EGL_STENCIL_SIZE, out var rv);
return rv;
}
}
}
}

5
src/Avalonia.OpenGL/EglGlPlatformFeature.cs

@ -6,12 +6,13 @@ namespace Avalonia.OpenGL
public class EglGlPlatformFeature : IWindowingPlatformGlFeature
{
private EglDisplay _display;
public IGlDisplay Display => _display;
public EglDisplay Display => _display;
public IGlContext CreateContext()
{
return _display.CreateContext(DeferredContext);
}
public EglContext DeferredContext { get; set; }
public EglContext DeferredContext { get; private set; }
public IGlContext MainContext => DeferredContext;
public static void TryInitialize()
{

8
src/Avalonia.OpenGL/EglGlPlatformSurface.cs

@ -16,9 +16,9 @@ namespace Avalonia.OpenGL
private readonly EglContext _context;
private readonly IEglWindowGlPlatformSurfaceInfo _info;
public EglGlPlatformSurface(EglDisplay display, EglContext context, IEglWindowGlPlatformSurfaceInfo info)
public EglGlPlatformSurface(EglContext context, IEglWindowGlPlatformSurfaceInfo info)
{
_display = display;
_display = context.Display;
_context = context;
_info = info;
}
@ -96,7 +96,7 @@ namespace Avalonia.OpenGL
public void Dispose()
{
_context.Display.GlInterface.Flush();
_context.GlInterface.Flush();
_display.EglInterface.WaitGL();
_glSurface.SwapBuffers();
_display.EglInterface.WaitClient();
@ -106,7 +106,7 @@ namespace Avalonia.OpenGL
_lock.Dispose();
}
public IGlDisplay Display => _context.Display;
public IGlContext Context => _context;
public PixelSize Size => _info.Size;
public double Scaling => _info.Scaling;
public bool IsYFlipped { get; }

4
src/Avalonia.OpenGL/EglSurface.cs

@ -21,8 +21,6 @@ namespace Avalonia.OpenGL
}
public override bool IsInvalid => handle == IntPtr.Zero;
public IGlDisplay Display => _display;
public void SwapBuffers() => _egl.SwapBuffers(_display.Handle, handle);
}
}
}

8
src/Avalonia.OpenGL/GlDisplayType.cs

@ -1,8 +0,0 @@
namespace Avalonia.OpenGL
{
public enum GlDisplayType
{
OpenGl,
OpenGLES
}
}

22
src/Avalonia.OpenGL/GlVersion.cs

@ -0,0 +1,22 @@
namespace Avalonia.OpenGL
{
public enum GlProfileType
{
OpenGL,
OpenGLES
}
public struct GlVersion
{
public GlProfileType Type { get; }
public int Major { get; }
public int Minor { get; }
public GlVersion(GlProfileType type, int major, int minor)
{
Type = type;
Major = major;
Minor = minor;
}
}
}

5
src/Avalonia.OpenGL/IGlContext.cs

@ -4,7 +4,10 @@ namespace Avalonia.OpenGL
{
public interface IGlContext : IDisposable
{
IGlDisplay Display { get; }
GlVersion Version { get; }
GlInterface GlInterface { get; }
int SampleCount { get; }
int StencilSize { get; }
IDisposable MakeCurrent();
}
}

10
src/Avalonia.OpenGL/IGlDisplay.cs

@ -1,10 +0,0 @@
namespace Avalonia.OpenGL
{
public interface IGlDisplay
{
GlDisplayType Type { get; }
GlInterface GlInterface { get; }
int SampleCount { get; }
int StencilSize { get; }
}
}

2
src/Avalonia.OpenGL/IGlPlatformSurfaceRenderingSession.cs

@ -4,7 +4,7 @@ namespace Avalonia.OpenGL
{
public interface IGlPlatformSurfaceRenderingSession : IDisposable
{
IGlDisplay Display { get; }
IGlContext Context { get; }
PixelSize Size { get; }
double Scaling { get; }
bool IsYFlipped { get; }

2
src/Avalonia.OpenGL/IWindowingPlatformGlFeature.cs

@ -2,7 +2,7 @@ namespace Avalonia.OpenGL
{
public interface IWindowingPlatformGlFeature
{
IGlDisplay Display { get; }
IGlContext CreateContext();
IGlContext MainContext { get; }
}
}

18
src/Avalonia.OpenGL/OpenGlControlBase.cs

@ -16,7 +16,7 @@ namespace Avalonia.OpenGL
private OpenGlTextureBitmap _bitmap;
private PixelSize _oldSize;
private bool _glFailed;
protected GlDisplayType DisplayType { get; private set; }
protected GlVersion GlVersion { get; private set; }
public sealed override void Render(DrawingContext context)
{
if(!EnsureInitialized())
@ -26,7 +26,7 @@ namespace Avalonia.OpenGL
{
using (_bitmap.Lock())
{
var gl = _context.Display.GlInterface;
var gl = _context.GlInterface;
gl.BindFramebuffer(GL_FRAMEBUFFER, _fb);
if (_oldSize != GetPixelSize())
ResizeTexture(gl);
@ -46,7 +46,7 @@ namespace Avalonia.OpenGL
{
using (_context.MakeCurrent())
{
var gl = _context.Display.GlInterface;
var gl = _context.GlInterface;
gl.BindTexture(GL_TEXTURE_2D, 0);
gl.BindFramebuffer(GL_FRAMEBUFFER, 0);
gl.DeleteFramebuffers(1, new[] { _fb });
@ -59,7 +59,7 @@ namespace Avalonia.OpenGL
try
{
if (callUserDeinit)
OnOpenGlDeinit(_context.Display.GlInterface, _fb);
OnOpenGlDeinit(_context.GlInterface, _fb);
}
finally
{
@ -100,7 +100,7 @@ namespace Avalonia.OpenGL
return false;
}
DisplayType = feature.Display.Type;
GlVersion = _context.Version;
try
{
_bitmap = new OpenGlTextureBitmap();
@ -120,7 +120,7 @@ namespace Avalonia.OpenGL
try
{
_oldSize = GetPixelSize();
var gl = _context.Display.GlInterface;
var gl = _context.GlInterface;
var oneArr = new int[1];
gl.GenFramebuffers(1, oneArr);
_fb = oneArr[0];
@ -153,7 +153,7 @@ namespace Avalonia.OpenGL
}
if (!_glFailed)
OnOpenGlInit(_context.Display.GlInterface, _fb);
OnOpenGlInit(_context.GlInterface, _fb);
}
if (_glFailed)
@ -171,7 +171,7 @@ namespace Avalonia.OpenGL
gl.GetIntegerv( GL_TEXTURE_BINDING_2D, out var oldTexture);
gl.BindTexture(GL_TEXTURE_2D, _texture);
gl.TexImage2D(GL_TEXTURE_2D, 0,
DisplayType == GlDisplayType.OpenGLES ? GL_RGBA : GL_RGBA8,
GlVersion.Type == GlProfileType.OpenGLES ? GL_RGBA : GL_RGBA8,
size.Width, size.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, IntPtr.Zero);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@ -184,7 +184,7 @@ namespace Avalonia.OpenGL
_renderBuffer = oneArr[0];
gl.BindRenderbuffer(GL_RENDERBUFFER, _renderBuffer);
gl.RenderbufferStorage(GL_RENDERBUFFER,
DisplayType == GlDisplayType.OpenGLES ? GL_DEPTH_COMPONENT16 : GL_DEPTH_COMPONENT,
GlVersion.Type == GlProfileType.OpenGLES ? GL_DEPTH_COMPONENT16 : GL_DEPTH_COMPONENT,
size.Width, size.Height);
gl.FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _renderBuffer);
gl.BindRenderbuffer(GL_RENDERBUFFER, oldRenderBuffer);

14
src/Avalonia.X11/Glx/Glx.cs

@ -97,12 +97,16 @@ namespace Avalonia.X11.Glx
[GlEntryPointAttribute("glXWaitGL")]
public GlxWaitGL WaitGL { get; }
public delegate void GlxWaitGL();
public delegate void GlxWaitGL();
public delegate int GlGetError();
[GlEntryPoint("glGetError")]
public GlGetError GetError { get; }
public delegate IntPtr GlxQueryExtensionsString(IntPtr display, int screen);
[GlEntryPoint("glXQueryExtensionsString")]
public GlxQueryExtensionsString QueryExtensionsString { get; }
public GlxInterface() : base(SafeGetProcAddress)
{
}
@ -122,5 +126,13 @@ namespace Avalonia.X11.Glx
}
private static readonly Func<string, bool, IntPtr> GlxConverted = ConvertNative(GlxGetProcAddress);
public string[] GetExtensions(IntPtr display)
{
var s = Marshal.PtrToStringAnsi(QueryExtensionsString(display, 0));
return s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Trim()).ToArray();
}
}
}

2
src/Avalonia.X11/Glx/GlxConsts.cs

@ -100,6 +100,8 @@ namespace Avalonia.X11.Glx
public const int GLX_CONTEXT_FLAGS_ARB = 0x2094;
public const int GLX_CONTEXT_CORE_PROFILE_BIT_ARB = 0x00000001;
public const int GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB = 0x00000002;
public const int GLX_CONTEXT_ES2_PROFILE_BIT_EXT = 0x00000004;
public const int GLX_CONTEXT_PROFILE_MASK_ARB = 0x9126;
}

15
src/Avalonia.X11/Glx/GlxContext.cs

@ -13,7 +13,9 @@ namespace Avalonia.X11.Glx
private readonly bool _ownsPBuffer;
private readonly object _lock = new object();
public GlxContext(GlxInterface glx, IntPtr handle, GlxDisplay display, X11Info x11, IntPtr defaultXid,
public GlxContext(GlxInterface glx, IntPtr handle, GlxDisplay display,
GlVersion version, int sampleCount, int stencilSize,
X11Info x11, IntPtr defaultXid,
bool ownsPBuffer)
{
Handle = handle;
@ -22,10 +24,17 @@ namespace Avalonia.X11.Glx
_defaultXid = defaultXid;
_ownsPBuffer = ownsPBuffer;
Display = display;
Version = version;
SampleCount = sampleCount;
StencilSize = stencilSize;
GlInterface = new GlInterface(GlxInterface.SafeGetProcAddress);
}
public GlxDisplay Display { get; }
IGlDisplay IGlContext.Display => Display;
public GlVersion Version { get; }
public GlInterface GlInterface { get; }
public int SampleCount { get; }
public int StencilSize { get; }
public IDisposable Lock()
{
@ -58,7 +67,7 @@ namespace Avalonia.X11.Glx
_glx.MakeContextCurrent(disp, _draw, _read, _context);
}
}
public IDisposable MakeCurrent() => MakeCurrent(_defaultXid);
public IDisposable MakeCurrent(IntPtr xid)

99
src/Avalonia.X11/Glx/GlxDisplay.cs

@ -1,27 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.OpenGL;
using static Avalonia.X11.Glx.GlxConsts;
namespace Avalonia.X11.Glx
{
unsafe class GlxDisplay : IGlDisplay
unsafe class GlxDisplay
{
private readonly X11Info _x11;
private readonly List<GlVersion> _probeProfiles;
private readonly IntPtr _fbconfig;
private readonly XVisualInfo* _visual;
public GlDisplayType Type => GlDisplayType.OpenGl;
public GlInterface GlInterface { get; }
private string[] _displayExtensions;
private GlVersion? _version;
public XVisualInfo* VisualInfo => _visual;
public int SampleCount { get; }
public int StencilSize { get; }
public GlxContext DeferredContext { get; }
public GlxInterface Glx { get; } = new GlxInterface();
public GlxDisplay(X11Info x11)
public GlxDisplay(X11Info x11, List<GlVersion> probeProfiles)
{
_x11 = x11;
_probeProfiles = probeProfiles.ToList();
_displayExtensions = Glx.GetExtensions(_x11.Display);
var baseAttribs = new[]
{
@ -37,7 +38,8 @@ namespace Avalonia.X11.Glx
GLX_STENCIL_SIZE, 8,
};
int sampleCount = 0;
int stencilSize = 0;
foreach (var attribs in new[]
{
//baseAttribs.Concat(multiattribs),
@ -70,9 +72,9 @@ namespace Avalonia.X11.Glx
if (_visual == null)
throw new OpenGlException("Unable to get visual info from FBConfig");
if (Glx.GetFBConfigAttrib(_x11.Display, _fbconfig, GLX_SAMPLES, out var samples) == 0)
SampleCount = samples;
sampleCount = samples;
if (Glx.GetFBConfigAttrib(_x11.Display, _fbconfig, GLX_STENCIL_SIZE, out var stencil) == 0)
StencilSize = stencil;
stencilSize = stencil;
var pbuffers = Enumerable.Range(0, 2).Select(_ => Glx.CreatePbuffer(_x11.Display, _fbconfig, new[]
{
@ -81,13 +83,14 @@ namespace Avalonia.X11.Glx
XLib.XFlush(_x11.Display);
DeferredContext = CreateContext(CreatePBuffer(), null, true);
DeferredContext = CreateContext(CreatePBuffer(), null,
sampleCount, stencilSize, true);
using (DeferredContext.MakeCurrent())
{
GlInterface = new GlInterface(GlxInterface.SafeGetProcAddress);
if (GlInterface.Version == null)
var glInterface = new GlInterface(GlxInterface.SafeGetProcAddress);
if (glInterface.Version == null)
throw new OpenGlException("GL version string is null, aborting");
if (GlInterface.Renderer == null)
if (glInterface.Renderer == null)
throw new OpenGlException("GL renderer string is null, aborting");
if (Environment.GetEnvironmentVariable("AVALONIA_GLX_IGNORE_RENDERER_BLACKLIST") != "1")
@ -96,9 +99,9 @@ namespace Avalonia.X11.Glx
?.GlxRendererBlacklist;
if (blacklist != null)
foreach (var item in blacklist)
if (GlInterface.Renderer.Contains(item))
if (glInterface.Renderer.Contains(item))
throw new OpenGlException(
$"Renderer '{GlInterface.Renderer}' is blacklisted by '{item}'");
$"Renderer '{glInterface.Renderer}' is blacklisted by '{item}'");
}
}
@ -111,40 +114,72 @@ namespace Avalonia.X11.Glx
public GlxContext CreateContext() => CreateContext(DeferredContext);
GlxContext CreateContext(IGlContext share) => CreateContext(CreatePBuffer(), share, true);
GlxContext CreateContext(IntPtr defaultXid, IGlContext share, bool ownsPBuffer)
GlxContext CreateContext(IGlContext share) => CreateContext(CreatePBuffer(), share,
share.SampleCount, share.StencilSize, true);
GlxContext CreateContext(IntPtr defaultXid, IGlContext share,
int sampleCount, int stencilSize, bool ownsPBuffer)
{
var sharelist = ((GlxContext)share)?.Handle ?? IntPtr.Zero;
IntPtr handle = default;
foreach (var ver in new[]
{
new Version(4, 0), new Version(3, 2),
new Version(3, 0), new Version(2, 0)
})
GlxContext Create(GlVersion profile)
{
var profileMask = GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
if (profile.Type == GlProfileType.OpenGLES)
profileMask = GLX_CONTEXT_ES2_PROFILE_BIT_EXT;
var attrs = new[]
var attrs = new int[]
{
GLX_CONTEXT_MAJOR_VERSION_ARB, ver.Major,
GLX_CONTEXT_MINOR_VERSION_ARB, ver.Minor,
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
GLX_CONTEXT_MAJOR_VERSION_ARB, profile.Major,
GLX_CONTEXT_MINOR_VERSION_ARB, profile.Minor,
GLX_CONTEXT_PROFILE_MASK_ARB, profileMask,
0
};
try
{
handle = Glx.CreateContextAttribsARB(_x11.Display, _fbconfig, sharelist, true, attrs);
if (handle != IntPtr.Zero)
break;
{
_version = profile;
return new GlxContext(new GlxInterface(), handle, this, profile,
sampleCount, stencilSize, _x11, defaultXid, ownsPBuffer);
}
}
catch
{
break;
return null;
}
return null;
}
GlxContext rv = null;
if (_version.HasValue)
{
rv = Create(_version.Value);
}
if (handle == IntPtr.Zero)
throw new OpenGlException("Unable to create direct GLX context");
return new GlxContext(new GlxInterface(), handle, this, _x11, defaultXid, ownsPBuffer);
foreach (var v in _probeProfiles)
{
if (v.Type == GlProfileType.OpenGLES
&& !_displayExtensions.Contains("GLX_EXT_create_context_es2_profile"))
continue;
rv = Create(v);
if (rv != null)
{
_version = v;
break;
}
}
if (rv != null)
return rv;
throw new OpenGlException("Unable to create direct GLX context");
}
public void SwapBuffers(IntPtr xid) => Glx.SwapBuffers(_x11.Display, xid);

4
src/Avalonia.X11/Glx/GlxGlPlatformSurface.cs

@ -59,6 +59,7 @@ namespace Avalonia.X11.Glx
private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info;
private IDisposable _lock;
private readonly IDisposable _clearContext;
public IGlContext Context => _context;
public Session(GlxContext context, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo info,
IDisposable @lock, IDisposable clearContext)
@ -71,7 +72,7 @@ namespace Avalonia.X11.Glx
public void Dispose()
{
_context.Display.GlInterface.Flush();
_context.GlInterface.Flush();
_context.Glx.WaitGL();
_context.Display.SwapBuffers(_info.Handle);
_context.Glx.WaitX();
@ -79,7 +80,6 @@ namespace Avalonia.X11.Glx
_lock.Dispose();
}
public IGlDisplay Display => _context.Display;
public PixelSize Size => _info.Size;
public double Scaling => _info.Scaling;
public bool IsYFlipped { get; }

12
src/Avalonia.X11/Glx/GlxPlatformFeature.cs

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using Avalonia.Logging;
using Avalonia.OpenGL;
@ -8,13 +9,12 @@ namespace Avalonia.X11.Glx
{
public GlxDisplay Display { get; private set; }
public IGlContext CreateContext() => Display.CreateContext();
IGlDisplay IWindowingPlatformGlFeature.Display => Display;
public GlxContext DeferredContext { get; private set; }
public IGlContext MainContext => DeferredContext;
public static bool TryInitialize(X11Info x11)
public static bool TryInitialize(X11Info x11, List<GlVersion> glProfiles)
{
var feature = TryCreate(x11);
var feature = TryCreate(x11, glProfiles);
if (feature != null)
{
AvaloniaLocator.CurrentMutable.Bind<IWindowingPlatformGlFeature>().ToConstant(feature);
@ -24,11 +24,11 @@ namespace Avalonia.X11.Glx
return false;
}
public static GlxGlPlatformFeature TryCreate(X11Info x11)
public static GlxGlPlatformFeature TryCreate(X11Info x11, List<GlVersion> glProfiles)
{
try
{
var disp = new GlxDisplay(x11);
var disp = new GlxDisplay(x11, glProfiles);
return new GlxGlPlatformFeature
{
Display = disp,

13
src/Avalonia.X11/X11Platform.cs

@ -67,7 +67,7 @@ namespace Avalonia.X11
if (options.UseEGL)
EglGlPlatformFeature.TryInitialize();
else
GlxGlPlatformFeature.TryInitialize(Info);
GlxGlPlatformFeature.TryInitialize(Info, Options.GlProfiles);
}
@ -97,6 +97,17 @@ namespace Avalonia
public bool OverlayPopups { get; set; }
public bool UseDBusMenu { get; set; }
public List<GlVersion> GlProfiles { get; set; } = new List<GlVersion>
{
new GlVersion(GlProfileType.OpenGL, 4, 0),
new GlVersion(GlProfileType.OpenGL, 3, 2),
new GlVersion(GlProfileType.OpenGL, 3, 0),
new GlVersion(GlProfileType.OpenGLES, 3, 2),
new GlVersion(GlProfileType.OpenGLES, 3, 0),
new GlVersion(GlProfileType.OpenGLES, 2, 0),
new GlVersion(GlProfileType.OpenGL, 2, 0)
};
public List<string> GlxRendererBlacklist { get; set; } = new List<string>
{
// llvmpipe is a software GL rasterizer. If it's returned by glGetString,

2
src/Avalonia.X11/X11Window.cs

@ -165,7 +165,7 @@ namespace Avalonia.X11
if (egl != null)
surfaces.Insert(0,
new EglGlPlatformSurface((EglDisplay)egl.Display, egl.DeferredContext,
new EglGlPlatformSurface(egl.DeferredContext,
new SurfaceInfo(this, _x11.DeferredDisplay, _handle, _renderHandle)));
if (glx != null)
surfaces.Insert(0, new GlxGlPlatformSurface(glx.Display, glx.DeferredContext,

15
src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs

@ -15,6 +15,8 @@ namespace Avalonia.LinuxFramebuffer.Output
private readonly EglGlPlatformSurface _eglPlatformSurface;
public PixelSize PixelSize => _mode.Resolution;
public double Scaling { get; set; }
public IGlContext MainContext => _deferredContext;
public DrmOutput(string path = null)
{
var card = new DrmCard(path);
@ -132,8 +134,8 @@ namespace Avalonia.LinuxFramebuffer.Output
using (_deferredContext.MakeCurrent(_eglSurface))
{
_eglDisplay.GlInterface.ClearColor(0, 0, 0, 0);
_eglDisplay.GlInterface.Clear(GlConsts.GL_COLOR_BUFFER_BIT | GlConsts.GL_STENCIL_BUFFER_BIT);
_deferredContext.GlInterface.ClearColor(0, 0, 0, 0);
_deferredContext.GlInterface.Clear(GlConsts.GL_COLOR_BUFFER_BIT | GlConsts.GL_STENCIL_BUFFER_BIT);
_eglSurface.SwapBuffers();
}
@ -154,8 +156,8 @@ namespace Avalonia.LinuxFramebuffer.Output
for(var c=0;c<2;c++)
using (CreateGlRenderTarget().BeginDraw())
{
_eglDisplay.GlInterface.ClearColor(0, 0, 0, 0);
_eglDisplay.GlInterface.Clear(GlConsts.GL_COLOR_BUFFER_BIT | GlConsts.GL_STENCIL_BUFFER_BIT);
_deferredContext.GlInterface.ClearColor(0, 0, 0, 0);
_deferredContext.GlInterface.Clear(GlConsts.GL_COLOR_BUFFER_BIT | GlConsts.GL_STENCIL_BUFFER_BIT);
}
}
@ -191,7 +193,7 @@ namespace Avalonia.LinuxFramebuffer.Output
public void Dispose()
{
_parent._eglDisplay.GlInterface.Flush();
_parent._deferredContext.GlInterface.Flush();
_parent._eglSurface.SwapBuffers();
var nextBo = gbm_surface_lock_front_buffer(_parent._gbmTargetSurface);
@ -233,7 +235,7 @@ namespace Avalonia.LinuxFramebuffer.Output
}
public IGlDisplay Display => _parent._eglDisplay;
public IGlContext Context => _parent._deferredContext;
public PixelSize Size => _parent._mode.Resolution;
@ -248,7 +250,6 @@ namespace Avalonia.LinuxFramebuffer.Output
}
}
public IGlDisplay Display => _eglDisplay;
public IGlContext CreateContext()
{
throw new NotImplementedException();

2
src/Skia/Avalonia.Skia/Gpu/OpenGl/GlRenderTarget.cs

@ -59,7 +59,7 @@ namespace Avalonia.Skia
bool success = false;
try
{
var disp = glSession.Display;
var disp = glSession.Context;
var gl = disp.GlInterface;
gl.GetIntegerv(GL_FRAMEBUFFER_BINDING, out var fb);

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

@ -11,14 +11,12 @@ namespace Avalonia.Skia
public GlSkiaGpu(IWindowingPlatformGlFeature gl)
{
var immediateContext = gl.CreateContext();
using (immediateContext.MakeCurrent())
var context = gl.MainContext;
using (context.MakeCurrent())
{
var display = gl.Display;
using (var iface = display.Type == GlDisplayType.OpenGl ?
GRGlInterface.AssembleGlInterface((_, proc) => display.GlInterface.GetProcAddress(proc)) :
GRGlInterface.AssembleGlesInterface((_, proc) => display.GlInterface.GetProcAddress(proc)))
using (var iface = context.Version.Type == GlProfileType.OpenGL ?
GRGlInterface.AssembleGlInterface((_, proc) => context.GlInterface.GetProcAddress(proc)) :
GRGlInterface.AssembleGlesInterface((_, proc) => context.GlInterface.GetProcAddress(proc)))
{
_grContext = GRContext.Create(GRBackend.OpenGL, iface);
}

3
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -67,8 +67,7 @@ namespace Avalonia.Win32
CreateWindow();
_framebuffer = new FramebufferManager(_hwnd);
if (Win32GlManager.EglFeature != null)
_gl = new EglGlPlatformSurface((EglDisplay)Win32GlManager.EglFeature.Display,
Win32GlManager.EglFeature.DeferredContext, this);
_gl = new EglGlPlatformSurface(Win32GlManager.EglFeature.DeferredContext, this);
s_instances.Add(this);
}

Loading…
Cancel
Save