using System.Collections.Concurrent; using System.Drawing; using Dashboard.OpenGL; using Dashboard.Pal; using Dashboard.Windowing; using OpenTK.Mathematics; using OpenTK.Platform; using TK = OpenTK.Platform.Toolkit; namespace Dashboard.OpenTK.PAL2 { public class Pal2GLContext : IGLContext, IDisposable { 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 Pal2GLContext(WindowHandle window, OpenGLContextHandle context) { WindowHandle = window; ContextHandle = context; SwapGroup = new DummySwapGroup(context); ContextGroup = GetContextGroup(ContextHandle); } public void MakeCurrent() { TK.OpenGL.SetCurrentContext(ContextHandle); } public IntPtr GetProcAddress(string procName) { return TK.OpenGL.GetProcedureAddress(ContextHandle, procName); } public void Dispose() => Dispose(true); protected void Dispose(bool isDisposing) { if (SwapGroup is IGLDisposable glDisposable) { glDisposable.Dispose(isDisposing); } 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); } } } }