Browse Source

Support desktop OpenGL profiles via EGL (#21393)

pull/21394/head
Nikita Tsukanov 5 months ago
committed by GitHub
parent
commit
5bbbd5d6b2
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      samples/ControlCatalog/Pages/OpenGl/GlPageKnobs.xaml.cs
  2. 1
      samples/ControlCatalog/Pages/OpenGlPage.xaml.cs
  3. 10
      src/Avalonia.OpenGL/Egl/EglConsts.cs
  4. 18
      src/Avalonia.OpenGL/Egl/EglContext.cs
  5. 1
      src/Avalonia.OpenGL/Egl/EglDisplay.cs
  6. 78
      src/Avalonia.OpenGL/Egl/EglDisplayUtils.cs
  7. 3
      src/Avalonia.OpenGL/Egl/EglInterface.cs
  8. 9
      src/Avalonia.X11/X11Platform.cs
  9. 36
      src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32EglDisplay.cs

2
samples/ControlCatalog/Pages/OpenGl/GlPageKnobs.xaml.cs

@ -65,6 +65,6 @@ public partial class GlPageKnobs : UserControl
public string Info
{
get => _info;
private set => SetAndRaise(InfoProperty, ref _info, value);
set => SetAndRaise(InfoProperty, ref _info, value);
}
}

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

@ -76,6 +76,7 @@ namespace ControlCatalog.Pages
_knobs.Yaw, _knobs.Pitch, _knobs.Roll, _knobs.Disco);
if (_knobs.Disco > 0.01)
RequestNextFrameRendering();
_knobs?.Info = _content.Info;
}
}
}

10
src/Avalonia.OpenGL/Egl/EglConsts.cs

@ -125,17 +125,17 @@ namespace Avalonia.OpenGL.Egl
// public const int EGL_MULTISAMPLE_RESOLVE = 0x3099;
// public const int EGL_MULTISAMPLE_RESOLVE_DEFAULT = 0x309A;
// public const int EGL_MULTISAMPLE_RESOLVE_BOX = 0x309B;
// public const int EGL_OPENGL_API = 0x30A2;
// public const int EGL_OPENGL_BIT = 0x0008;
public const int EGL_OPENGL_API = 0x30A2;
public const int EGL_OPENGL_BIT = 0x0008;
// public const int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400;
public const int EGL_CONTEXT_MAJOR_VERSION = 0x3098;
public const int EGL_CONTEXT_MINOR_VERSION = 0x30FB;
// public const int EGL_CONTEXT_OPENGL_PROFILE_MASK = 0x30FD;
public const int EGL_CONTEXT_OPENGL_PROFILE_MASK = 0x30FD;
// public const int EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY = 0x31BD;
// public const int EGL_NO_RESET_NOTIFICATION = 0x31BE;
// public const int EGL_LOSE_CONTEXT_ON_RESET = 0x31BF;
// public const int EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT = 0x00000001;
// public const int EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT = 0x00000002;
public const int EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT = 0x00000001;
public const int EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT = 0x00000002;
// public const int EGL_CONTEXT_OPENGL_DEBUG = 0x31B0;
// public const int EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE = 0x31B1;
// public const int EGL_CONTEXT_OPENGL_ROBUST_ACCESS = 0x31B2;

18
src/Avalonia.OpenGL/Egl/EglContext.cs

@ -13,6 +13,7 @@ namespace Avalonia.OpenGL.Egl
private readonly EglDisplay _disp;
private readonly EglInterface _egl;
private readonly EglContext? _sharedWith;
private readonly int _api;
private bool _isLost;
private IntPtr _context;
private readonly Action? _disposeCallback;
@ -26,6 +27,7 @@ namespace Avalonia.OpenGL.Egl
_disp = display;
_egl = egl;
_sharedWith = sharedWith;
_api = display.Api;
_context = ctx;
_disposeCallback = disposeCallback;
OffscreenSurface = offscreenSurface;
@ -56,21 +58,28 @@ namespace Avalonia.OpenGL.Egl
private readonly object _l;
private readonly IntPtr _display;
private readonly IntPtr _context, _read, _draw;
private readonly int _api;
public RestoreContext(EglInterface egl, IntPtr defDisplay, object l)
{
_egl = egl;
_l = l;
_api = _egl.QueryApi();
_display = _egl.GetCurrentDisplay();
if (_display == IntPtr.Zero)
// Fallback display, it's invalid to call eglMakeCurrent without a display
_display = defDisplay;
_context = _egl.GetCurrentContext();
_read = _egl.GetCurrentSurface(EGL_READ);
_draw = _egl.GetCurrentSurface(EGL_DRAW);
else
{
_context = _egl.GetCurrentContext();
_read = _egl.GetCurrentSurface(EGL_READ);
_draw = _egl.GetCurrentSurface(EGL_DRAW);
}
}
public void Dispose()
{
_egl.BindApi(_api);
_egl.MakeCurrent(_display, _draw, _read, _context);
Monitor.Exit(_l);
}
@ -90,6 +99,7 @@ namespace Avalonia.OpenGL.Egl
{
var old = new RestoreContext(_egl, _disp.Handle, _lock);
var surf = surface ?? OffscreenSurface;
_egl.BindApi(_api);
_egl.MakeCurrent(_disp.Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
if (!_egl.MakeCurrent(_disp.Handle, surf?.DangerousGetHandle() ?? IntPtr.Zero,
surf?.DangerousGetHandle() ?? IntPtr.Zero, Context))
@ -154,7 +164,7 @@ namespace Avalonia.OpenGL.Egl
ShareWith = _sharedWith ?? this
});
public bool IsCurrent => _context != default && _egl.GetCurrentDisplay() == _disp.Handle && _egl.GetCurrentContext() == _context;
public bool IsCurrent => _context != default && _egl.GetCurrentDisplay() == _disp.Handle && _egl.GetCurrentContext() == _context && _egl.QueryApi() == _api;
public void Dispose()
{

1
src/Avalonia.OpenGL/Egl/EglDisplay.cs

@ -49,6 +49,7 @@ namespace Avalonia.OpenGL.Egl
}
public EglInterface EglInterface => _egl;
internal int Api => _config.Api;
public EglContext CreateContext(EglContextOptions? options)
{
if (SingleContext && _contexts.Any())

78
src/Avalonia.OpenGL/Egl/EglDisplayUtils.cs

@ -42,34 +42,64 @@ internal static class EglDisplayUtils
};
var cfgs = versions
.Where(x => x.Type == GlProfileType.OpenGLES)
.Select(x =>
{
var typeBit = EGL_OPENGL_ES3_BIT;
switch (x.Major)
if (x.Type == GlProfileType.OpenGLES)
{
case 2:
typeBit = EGL_OPENGL_ES2_BIT;
break;
var typeBit = EGL_OPENGL_ES3_BIT;
case 1:
typeBit = EGL_OPENGL_ES_BIT;
break;
}
switch (x.Major)
{
case 2:
typeBit = EGL_OPENGL_ES2_BIT;
break;
case 1:
typeBit = EGL_OPENGL_ES_BIT;
break;
}
return new
return new
{
Attributes = new[]
{
EGL_CONTEXT_MAJOR_VERSION, x.Major,
EGL_CONTEXT_MINOR_VERSION, x.Minor,
EGL_NONE
},
Api = EGL_OPENGL_ES_API,
RenderableTypeBit = typeBit,
Version = x
};
}
else
{
Attributes = new[]
var attrs = (x.Major > 3 || (x.Major == 3 && x.Minor >= 2))
? new[]
{
EGL_CONTEXT_MAJOR_VERSION, x.Major,
EGL_CONTEXT_MINOR_VERSION, x.Minor,
EGL_CONTEXT_OPENGL_PROFILE_MASK,
x.IsCompatibilityProfile
? EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT
: EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
EGL_NONE
}
: new[]
{
EGL_CONTEXT_MAJOR_VERSION, x.Major,
EGL_CONTEXT_MINOR_VERSION, x.Minor,
EGL_NONE
};
return new
{
EGL_CONTEXT_MAJOR_VERSION, x.Major,
EGL_CONTEXT_MINOR_VERSION, x.Minor,
EGL_NONE
},
Api = EGL_OPENGL_ES_API,
RenderableTypeBit = typeBit,
Version = x
};
Attributes = attrs,
Api = EGL_OPENGL_API,
RenderableTypeBit = EGL_OPENGL_BIT,
Version = x
};
}
});
foreach (var cfg in cfgs)
@ -101,7 +131,7 @@ internal static class EglDisplayUtils
egl.GetConfigAttrib(display, config, EGL_SAMPLES, out var sampleCount);
egl.GetConfigAttrib(display, config, EGL_STENCIL_SIZE, out var returnedStencilSize);
return new EglConfigInfo(config, cfg.Version, surfaceType, cfg.Attributes, sampleCount,
returnedStencilSize);
returnedStencilSize, cfg.Api);
}
}
@ -119,9 +149,10 @@ internal class EglConfigInfo
public int[] Attributes { get; }
public int SampleCount { get; }
public int StencilSize { get; }
public int Api { get; }
public EglConfigInfo(IntPtr config, GlVersion version, int surfaceType, int[] attributes, int sampleCount,
int stencilSize)
int stencilSize, int api)
{
Config = config;
Version = version;
@ -129,5 +160,6 @@ internal class EglConfigInfo
Attributes = attributes;
SampleCount = sampleCount;
StencilSize = stencilSize;
Api = api;
}
}

3
src/Avalonia.OpenGL/Egl/EglInterface.cs

@ -69,6 +69,9 @@ namespace Avalonia.OpenGL.Egl
[GetProcAddress("eglBindAPI")]
public partial bool BindApi(int api);
[GetProcAddress("eglQueryAPI")]
public partial int QueryApi();
[GetProcAddress("eglChooseConfig")]
public partial bool ChooseConfig(IntPtr display, int[] attribs,
out IntPtr surfaceConfig, int numConfigs, out int choosenConfig);

9
src/Avalonia.X11/X11Platform.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using Avalonia.Controls.Platform;
using Avalonia.FreeDesktop;
using Avalonia.FreeDesktop.AtSpi;
@ -226,7 +227,13 @@ namespace Avalonia.X11
if (renderingMode == X11RenderingMode.Egl)
{
if (EglPlatformGraphics.TryCreate() is { } egl)
if (EglPlatformGraphics.TryCreate(()=>new EglDisplay(new EglDisplayCreationOptions()
{
SupportsContextSharing = true,
SupportsMultipleContexts = true,
GlVersions = opts.GlProfiles,
Egl = new EglInterface()
})) is { } egl)
{
return egl;
}

36
src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32EglDisplay.cs

@ -21,17 +21,24 @@ namespace Avalonia.Win32.OpenGl.Angle
protected override bool DisplayLockIsSharedWithContexts => true;
static EglDisplayOptions GetDisplayOptions(EglInterface egl,
Func<bool>? deviceLostCheckCallback = null,
Action? disposeCallback = null) => new()
{
Egl = egl,
ContextLossIsDisplayLoss = true,
GlVersions = AvaloniaLocator.Current.GetService<AngleOptions>()?.GlProfiles
.Where(x => x.Type == GlProfileType.OpenGLES),
DeviceLostCheckCallback = deviceLostCheckCallback,
DisposeCallback = disposeCallback
};
public static AngleWin32EglDisplay CreateD3D9Display(EglInterface egl)
{
var display = egl.GetPlatformDisplayExt(EGL_PLATFORM_ANGLE_ANGLE, IntPtr.Zero,
new[] { EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE, EGL_NONE });
return new AngleWin32EglDisplay(display, egl, new EglDisplayOptions()
{
Egl = egl,
ContextLossIsDisplayLoss = true,
GlVersions = AvaloniaLocator.Current.GetService<AngleOptions>()?.GlProfiles
}, AngleOptions.PlatformApi.DirectX9);
return new AngleWin32EglDisplay(display, egl, GetDisplayOptions(egl), AngleOptions.PlatformApi.DirectX9);
}
public static AngleWin32EglDisplay CreateSharedD3D11Display(EglInterface egl)
@ -39,12 +46,7 @@ namespace Avalonia.Win32.OpenGl.Angle
var display = egl.GetPlatformDisplayExt(EGL_PLATFORM_ANGLE_ANGLE, IntPtr.Zero,
new[] { EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_NONE });
return new AngleWin32EglDisplay(display, egl, new EglDisplayOptions()
{
Egl = egl,
ContextLossIsDisplayLoss = true,
GlVersions = AvaloniaLocator.Current.GetService<AngleOptions>()?.GlProfiles
}, AngleOptions.PlatformApi.DirectX11);
return new AngleWin32EglDisplay(display, egl, GetDisplayOptions(egl), AngleOptions.PlatformApi.DirectX11);
}
public static unsafe AngleWin32EglDisplay CreateD3D11Display(Win32AngleEglInterface egl)
@ -155,14 +157,8 @@ namespace Avalonia.Win32.OpenGl.Angle
var rv = new AngleWin32EglDisplay(display, egl,
new EglDisplayOptions
{
DisposeCallback = Cleanup,
Egl = egl,
ContextLossIsDisplayLoss = true,
DeviceLostCheckCallback = () => d3dDevice.DeviceRemovedReason != 0,
GlVersions = AvaloniaLocator.Current.GetService<AngleOptions>()?.GlProfiles
}, AngleOptions.PlatformApi.DirectX11);
GetDisplayOptions(egl, () => d3dDevice.DeviceRemovedReason != 0, Cleanup),
AngleOptions.PlatformApi.DirectX11);
success = true;
return rv;
}

Loading…
Cancel
Save