Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Avalonia.OpenGL/Egl/EglConsts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public static class EglConsts
// 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;
Expand Down
5 changes: 4 additions & 1 deletion src/Avalonia.OpenGL/Egl/EglDisplay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public class EglDisplay : IDisposable

public IntPtr Handle => _display;
public IntPtr Config => _config.Config;
public int NativeVisualId { get; }
internal bool SingleContext => !_options.SupportsMultipleContexts;
private readonly List<EglContext> _contexts = new();

Expand All @@ -45,7 +46,9 @@ public EglDisplay(IntPtr display, EglDisplayOptions options)
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;
Expand Down
1 change: 1 addition & 0 deletions src/Avalonia.OpenGL/Egl/EglDisplayOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
72 changes: 46 additions & 26 deletions src/Avalonia.OpenGL/Egl/EglDisplayUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ public static IntPtr CreateDisplay(EglDisplayCreationOptions options)
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)
Expand Down Expand Up @@ -77,38 +77,58 @@ public static EglConfigInfo InitializeAndGetConfig(EglInterface egl, IntPtr disp
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
Expand Down
4 changes: 2 additions & 2 deletions src/Avalonia.OpenGL/Egl/EglInterface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ static Func<string, IntPtr> Load(string library)

[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);
Expand Down
8 changes: 4 additions & 4 deletions src/Avalonia.OpenGL/Egl/EglPlatformGraphics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -23,7 +23,7 @@ public EglPlatformGraphics(EglDisplay display)
SupportsMultipleContexts = true,
SupportsContextSharing = true
}));

public static EglPlatformGraphics? TryCreate(Func<EglDisplay> displayFactory)
{
try
Expand Down
40 changes: 39 additions & 1 deletion src/Avalonia.X11/X11Platform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,45 @@ private static bool ShouldUseXim()

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;
}
Expand Down
16 changes: 16 additions & 0 deletions src/Avalonia.X11/X11Structs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1786,6 +1786,22 @@ internal unsafe struct XImage
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
Expand Down
21 changes: 17 additions & 4 deletions src/Avalonia.X11/X11Window.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,20 +121,33 @@ public X11Window(AvaloniaX11Platform platform, IWindowImpl? popupParent, X11Wind

// 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;
// TODO: We should query this from the active render surface, however we don't actually track what
// 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)
Expand Down
3 changes: 3 additions & 0 deletions src/Avalonia.X11/XLib.cs
Original file line number Diff line number Diff line change
Expand Up @@ -749,5 +749,8 @@ public static int XkbGetGroupForCoreState(int state)

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