A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

139 lines
4.5 KiB

using System;
using System.Collections.Generic;
using System.Reactive.Disposables;
using System.Threading;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Features;
namespace Avalonia.X11.Glx
{
class GlxContext : IGlContext
{
public IntPtr Handle { get; }
public GlxInterface Glx { get; }
private readonly GlxContext _sharedWith;
private readonly X11Info _x11;
private readonly IntPtr _defaultXid;
private readonly bool _ownsPBuffer;
private readonly object _lock = new object();
private ExternalObjectsOpenGlExtensionFeature? _externalObjects;
public GlxContext(GlxInterface glx, IntPtr handle, GlxDisplay display,
GlxContext sharedWith,
GlVersion version, int sampleCount, int stencilSize,
X11Info x11, IntPtr defaultXid,
bool ownsPBuffer)
{
Handle = handle;
Glx = glx;
_sharedWith = sharedWith;
_x11 = x11;
_defaultXid = defaultXid;
_ownsPBuffer = ownsPBuffer;
Display = display;
Version = version;
SampleCount = sampleCount;
StencilSize = stencilSize;
using (MakeCurrent())
{
GlInterface = new GlInterface(version, GlxInterface.SafeGetProcAddress);
_externalObjects = ExternalObjectsOpenGlExtensionFeature.TryCreate(this);
}
}
public GlxDisplay Display { get; }
public GlVersion Version { get; }
public GlInterface GlInterface { get; }
public int SampleCount { get; }
public int StencilSize { get; }
class RestoreContext : IDisposable
{
private GlxInterface _glx;
private IntPtr _defaultDisplay;
private readonly object _l;
private IntPtr _display;
private IntPtr _context;
private IntPtr _read;
private IntPtr _draw;
public RestoreContext(GlxInterface glx, IntPtr defaultDisplay, object l)
{
_glx = glx;
_defaultDisplay = defaultDisplay;
_l = l;
_display = _glx.GetCurrentDisplay();
_context = _glx.GetCurrentContext();
_read = _glx.GetCurrentReadDrawable();
_draw = _glx.GetCurrentDrawable();
}
public void Dispose()
{
var disp = _display == IntPtr.Zero ? _defaultDisplay : _display;
_glx.MakeContextCurrent(disp, _draw, _read, _context);
Monitor.Exit(_l);
}
}
public IDisposable MakeCurrent() => MakeCurrent(_defaultXid);
public bool IsLost => false;
public IDisposable EnsureCurrent()
{
if(IsCurrent)
return Disposable.Empty;
return MakeCurrent();
}
public bool IsSharedWith(IGlContext context)
{
var c = (GlxContext)context;
return c == this
|| c._sharedWith == this
|| _sharedWith == context
|| _sharedWith != null && _sharedWith == c._sharedWith;
}
public bool CanCreateSharedContext => true;
public IGlContext CreateSharedContext(IEnumerable<GlVersion> preferredVersions = null) =>
Display.CreateContext(_sharedWith ?? this);
public IDisposable MakeCurrent(IntPtr xid)
{
Monitor.Enter(_lock);
var success = false;
try
{
var old = new RestoreContext(Glx, _x11.Display, _lock);
if (!Glx.MakeContextCurrent(_x11.Display, xid, xid, Handle))
throw new OpenGlException("glXMakeContextCurrent failed ");
success = true;
return old;
}
finally
{
if (!success)
Monitor.Exit(_lock);
}
}
public bool IsCurrent => Glx.GetCurrentContext() == Handle;
public void Dispose()
{
Glx.DestroyContext(_x11.Display, Handle);
if (_ownsPBuffer)
Glx.DestroyPbuffer(_x11.Display, _defaultXid);
}
public object TryGetFeature(Type featureType)
{
if (featureType == typeof(IGlContextExternalObjectsFeature))
return _externalObjects;
return null;
}
}
}