Shaojun Li 1 day ago
committed by GitHub
parent
commit
c79698d6f8
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      src/Avalonia.OpenGL/Egl/EglConsts.cs
  2. 5
      src/Avalonia.OpenGL/Egl/EglDisplay.cs
  3. 1
      src/Avalonia.OpenGL/Egl/EglDisplayOptions.cs
  4. 72
      src/Avalonia.OpenGL/Egl/EglDisplayUtils.cs
  5. 4
      src/Avalonia.OpenGL/Egl/EglInterface.cs
  6. 8
      src/Avalonia.OpenGL/Egl/EglPlatformGraphics.cs
  7. 40
      src/Avalonia.X11/X11Platform.cs
  8. 16
      src/Avalonia.X11/X11Structs.cs
  9. 21
      src/Avalonia.X11/X11Window.cs
  10. 3
      src/Avalonia.X11/XLib.cs

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

@ -35,7 +35,7 @@ namespace Avalonia.OpenGL.Egl
// public const int EGL_MAX_PBUFFER_PIXELS = 0x302B;
// public const int EGL_MAX_PBUFFER_WIDTH = 0x302C;
// public const int EGL_NATIVE_RENDERABLE = 0x302D;
// public const int EGL_NATIVE_VISUAL_ID = 0x302E;
public const int EGL_NATIVE_VISUAL_ID = 0x302E;
// public const int EGL_NATIVE_VISUAL_TYPE = 0x302F;
public const int EGL_NONE = 0x3038;
// public const int EGL_NON_CONFORMANT_CONFIG = 0x3051;

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

@ -20,6 +20,7 @@ namespace Avalonia.OpenGL.Egl
public IntPtr Handle => _display;
public IntPtr Config => _config.Config;
public int NativeVisualId { get; }
internal bool SingleContext => !_options.SupportsMultipleContexts;
private readonly List<EglContext> _contexts = new();
@ -45,7 +46,9 @@ namespace Avalonia.OpenGL.Egl
if(_display == IntPtr.Zero)
throw new ArgumentException();
_config = EglDisplayUtils.InitializeAndGetConfig(_egl, display, options.GlVersions);
_config = EglDisplayUtils.InitializeAndGetConfig(_egl, display, options);
_egl.GetConfigAttrib(_display, _config.Config, EGL_NATIVE_VISUAL_ID, out var id);
NativeVisualId = id;
}
public EglInterface EglInterface => _egl;

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

@ -12,6 +12,7 @@ public class EglDisplayOptions
public Func<bool>? DeviceLostCheckCallback { get; set; }
public Action? DisposeCallback { get; set; }
public IEnumerable<GlVersion>? GlVersions { get; set; }
public Func<EglInterface, nint, nint[], nint>? ChooseConfigCallback { get; set; }
}
public class EglContextOptions

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

@ -29,13 +29,13 @@ internal static class EglDisplayUtils
return display;
}
public static EglConfigInfo InitializeAndGetConfig(EglInterface egl, IntPtr display, IEnumerable<GlVersion>? versions)
public static EglConfigInfo InitializeAndGetConfig(EglInterface egl, IntPtr display, EglDisplayOptions options)
{
if (!egl.Initialize(display, out _, out _))
throw OpenGlException.GetFormattedException("eglInitialize", egl);
// TODO: AvaloniaLocator.Current.GetService<AngleOptions>()?.GlProfiles
versions ??= new[]
var versions = options.GlVersions ?? new[]
{
new GlVersion(GlProfileType.OpenGLES, 3, 0),
new GlVersion(GlProfileType.OpenGLES, 2, 0)
@ -77,38 +77,58 @@ internal static class EglDisplayUtils
if (!egl.BindApi(cfg.Api))
continue;
foreach (var surfaceType in new[] { EGL_PBUFFER_BIT | EGL_WINDOW_BIT, EGL_WINDOW_BIT })
foreach (var stencilSize in new[] { 8, 1, 0 })
foreach (var depthSize in new[] { 8, 1, 0 })
{
var attribs = new[]
foreach (var stencilSize in new[] { 8, 1, 0 })
{
EGL_SURFACE_TYPE, surfaceType,
EGL_RENDERABLE_TYPE, cfg.RenderableTypeBit,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_STENCIL_SIZE, stencilSize,
EGL_DEPTH_SIZE, depthSize,
EGL_NONE
};
if (!egl.ChooseConfig(display, attribs, out var config, 1, out int numConfigs))
continue;
if (numConfigs == 0)
continue;
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);
foreach (var depthSize in new[] { 8, 1, 0 })
{
var attribs = new[]
{
EGL_SURFACE_TYPE, surfaceType,
EGL_RENDERABLE_TYPE, cfg.RenderableTypeBit,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_STENCIL_SIZE, stencilSize,
EGL_DEPTH_SIZE, depthSize,
EGL_NONE
};
if (!egl.ChooseConfig(display, attribs, null, 0, out int numConfigs))
continue;
if (numConfigs == 0)
continue;
IntPtr config;
var configs = new IntPtr[numConfigs];
if (!egl.ChooseConfig(display, attribs, configs, numConfigs, out numConfigs))
continue;
if (options.ChooseConfigCallback != null)
{
config = options.ChooseConfigCallback(egl, display, configs);
}
else
{
config = configs[0];
}
if (config == IntPtr.Zero)
continue;
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);
}
}
}
}
throw new OpenGlException("No suitable EGL config was found");
}
}
internal class EglConfigInfo

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

@ -61,8 +61,8 @@ namespace Avalonia.OpenGL.Egl
[GetProcAddress("eglChooseConfig")]
public partial bool ChooseConfig(IntPtr display, int[] attribs,
out IntPtr surfaceConfig, int numConfigs, out int choosenConfig);
IntPtr[]? configs, int numConfigs, out int choosenConfig);
[GetProcAddress("eglCreateContext")]
public partial IntPtr CreateContext(IntPtr display, IntPtr config,
IntPtr share, int[] attrs);

8
src/Avalonia.OpenGL/Egl/EglPlatformGraphics.cs

@ -6,14 +6,14 @@ namespace Avalonia.OpenGL.Egl
{
public sealed class EglPlatformGraphics : IPlatformGraphics
{
private readonly EglDisplay _display;
public EglDisplay Display { get; }
public bool UsesSharedContext => false;
public IPlatformGraphicsContext CreateContext() => _display.CreateContext(null);
public IPlatformGraphicsContext CreateContext() => Display.CreateContext(null);
public IPlatformGraphicsContext GetSharedContext() => throw new NotSupportedException();
public EglPlatformGraphics(EglDisplay display)
{
_display = display;
Display = display;
}
public static EglPlatformGraphics? TryCreate() => TryCreate(() => new EglDisplay(new EglDisplayCreationOptions
@ -23,7 +23,7 @@ namespace Avalonia.OpenGL.Egl
SupportsMultipleContexts = true,
SupportsContextSharing = true
}));
public static EglPlatformGraphics? TryCreate(Func<EglDisplay> displayFactory)
{
try

40
src/Avalonia.X11/X11Platform.cs

@ -226,7 +226,45 @@ namespace Avalonia.X11
if (renderingMode == X11RenderingMode.Egl)
{
if (EglPlatformGraphics.TryCreate() is { } egl)
if (EglPlatformGraphics.TryCreate(() => new EglDisplay(new EglDisplayCreationOptions
{
Egl = new EglInterface(),
SupportsMultipleContexts = true,
SupportsContextSharing = true,
ChooseConfigCallback = (egl, display, configs) =>
{
if (configs.Length == 0)
{
return default;
}
XVisualInfo template = new XVisualInfo();
for (int i = 0; i < configs.Length; i++)
{
egl.GetConfigAttrib(display, configs[i], EglConsts.EGL_NATIVE_VISUAL_ID, out var visualId);
template.visualid = (nint)visualId;
var visualInfoPtr = XGetVisualInfo(info.Display, VisualInfoMasks.VisualIDMask, template, out var nitems);
if (nitems > 0 && visualInfoPtr != IntPtr.Zero)
{
unsafe
{
try
{
if (((XVisualInfo*)visualInfoPtr)->depth == 32)
{
// Prefer to use 32bit depth.
return configs[i];
}
}
finally
{
XFree(visualInfoPtr);
}
}
}
}
return configs.First();
},
})) is { } egl)
{
return egl;
}

16
src/Avalonia.X11/X11Structs.cs

@ -1786,6 +1786,22 @@ namespace Avalonia.X11 {
public ulong blue_mask;
private fixed byte funcs[128];
}
[Flags]
internal enum VisualInfoMasks : long
{
VisualNoMask = 0x0,
VisualIDMask = 0x1,
VisualScreenMask = 0x2,
VisualDepthMask = 0x4,
VisualClassMask = 0x8,
VisualRedMaskMask = 0x10,
VisualGreenMaskMask = 0x20,
VisualBlueMaskMask = 0x40,
VisualColormapSizeMask = 0x80,
VisualBitsPerRGBMask = 0x100,
VisualAllMask = 0x1FF,
}
[StructLayout(LayoutKind.Sequential)]
internal struct XVisualInfo

21
src/Avalonia.X11/X11Window.cs

@ -125,8 +125,9 @@ namespace Avalonia.X11
// OpenGL seems to be do weird things to it's current window which breaks resize sometimes
_useRenderWindow = glfeature != null;
var glx = glfeature as GlxPlatformGraphics;
var egl = glfeature as EglPlatformGraphics;
if (glx != null)
{
visualInfo = *glx.Display.VisualInfo;
@ -134,11 +135,23 @@ namespace Avalonia.X11
// the target sufrace currently is
_useCompositorDrivenRenderWindowResize = true;
}
else if (glfeature == null)
else if (egl != null)
{
XVisualInfo template = new XVisualInfo();
template.visualid = (nint)egl.Display.NativeVisualId;
var visualInfoPtr = XGetVisualInfo(_x11.Display, VisualInfoMasks.VisualIDMask, template, out var nitems);
if (nitems > 0 && visualInfoPtr != IntPtr.Zero)
{
visualInfo = *(XVisualInfo*)visualInfoPtr;
XFree(visualInfoPtr);
}
}
else
{
// Egl or software (no glfeature)
visualInfo = _x11.TransparentVisualInfo;
}
var egl = glfeature as EglPlatformGraphics;
var visual = IntPtr.Zero;
var depth = 24;
if (visualInfo != null)

3
src/Avalonia.X11/XLib.cs

@ -757,5 +757,8 @@ namespace Avalonia.X11
public static int XkbSetGroupForCoreState(int state, int newGroup)
=> (state & ~(0x3 << 13)) | ((newGroup & 0x3) << 13);
[DllImport(libX11)]
public static extern IntPtr XGetVisualInfo(IntPtr display, VisualInfoMasks vinfo_mask, in XVisualInfo vinfo_template, out int nitems_return);
}
}

Loading…
Cancel
Save