using System.Collections.Concurrent; using System.Drawing; using Dashboard.OpenGL; using Dashboard.Windowing; using OpenTK.Mathematics; using OpenTK.Platform; using TK = OpenTK.Platform.Toolkit; namespace Dashboard.OpenTK.PAL2 { public class OpenGLDeviceContext : IGLContext, IGLDisposable { public OpenGLContextHandle ContextHandle { get; } public WindowHandle WindowHandle { get; } public ISwapGroup SwapGroup { get; } public int ContextGroup { get; } public Size FramebufferSize { get { TK.Window.GetFramebufferSize(WindowHandle, out Vector2i size); return new Size(size.X, size.Y); } } public event Action? Disposed; public OpenGLDeviceContext(WindowHandle window, OpenGLContextHandle context, ISwapGroup? group = null) { WindowHandle = window; ContextHandle = context; SwapGroup = group ?? new DummySwapGroup(context); ContextGroup = GetContextGroup(context); } public void MakeCurrent() { TK.OpenGL.SetCurrentContext(ContextHandle); } private bool _isDisposed = false; public void Dispose() => Dispose(true); public void Dispose(bool safeExit) { if (_isDisposed) return; _isDisposed = true; if (SwapGroup is IGLDisposable glDisposable) { glDisposable.Dispose(safeExit); } else if (SwapGroup is IDisposable disposable) { disposable.Dispose(); } Disposed?.Invoke(); } private static int _contextGroupId = 0; private static ConcurrentDictionary _contextGroupRootContexts = new ConcurrentDictionary(); private static int GetContextGroup(OpenGLContextHandle handle) { OpenGLContextHandle? shared = TK.OpenGL.GetSharedContext(handle); if (shared == null) { if (_contextGroupRootContexts.TryGetValue(handle, out int group)) return group; group = Interlocked.Increment(ref _contextGroupId); _contextGroupRootContexts.TryAdd(handle, group); return GetContextGroup(handle); } else { if (_contextGroupRootContexts.TryGetValue(shared, out int group)) return group; return GetContextGroup(shared); } } public class DummySwapGroup : ISwapGroup { public OpenGLContextHandle ContextHandle { get; } public int SwapInterval { get { TK.OpenGL.SetCurrentContext(ContextHandle); return TK.OpenGL.GetSwapInterval(); } set { TK.OpenGL.SetCurrentContext(ContextHandle); TK.OpenGL.SetSwapInterval(value); } } public DummySwapGroup(OpenGLContextHandle handle) { ContextHandle = handle; } public void Swap() { TK.OpenGL.SwapBuffers(ContextHandle); } } } }