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