161 lines
4.7 KiB
C#
161 lines
4.7 KiB
C#
using System.Collections.Concurrent;
|
|
using System.Collections.Immutable;
|
|
using Dashboard.OpenGL;
|
|
using Dashboard.Pal;
|
|
using OpenTK;
|
|
using OpenTK.Graphics;
|
|
using OpenTK.Graphics.OpenGL;
|
|
|
|
namespace Dashboard.Drawing.OpenGL.Pal
|
|
{
|
|
internal class GLContextBindingsContext(IGLContext context) : IBindingsContext
|
|
{
|
|
public IntPtr GetProcAddress(string procName)
|
|
{
|
|
return context.GetProcAddress(procName);
|
|
}
|
|
}
|
|
|
|
public class GLDeviceContext : DeviceContext
|
|
{
|
|
public IGLContext GLContext { get; }
|
|
|
|
public override string DriverName => "Dashboard OpenGL Device Context";
|
|
public override string DriverVendor => "Dashboard";
|
|
public override Version DriverVersion => new Version(0, 1, 0);
|
|
|
|
public Version GLVersion { get; }
|
|
public string GLRenderer { get; }
|
|
public string GLVendor { get; }
|
|
public ImmutableHashSet<string> Extensions { get; }
|
|
|
|
public Thread RendererThread { get; } = Thread.CurrentThread;
|
|
public bool IsRenderThread => RendererThread == Thread.CurrentThread;
|
|
|
|
private readonly ConcurrentQueue<Task> _beforeDrawActions = new ConcurrentQueue<Task>();
|
|
private readonly ConcurrentQueue<Task> _afterDrawActions = new ConcurrentQueue<Task>();
|
|
|
|
public GLDeviceContext(IGLContext context)
|
|
{
|
|
GLContext = context;
|
|
context.MakeCurrent();
|
|
GLLoader.LoadBindings(new GLContextBindingsContext(context));
|
|
|
|
context.Disposed += Dispose;
|
|
|
|
GL.GetInteger(GetPName.MajorVersion, out int major);
|
|
GL.GetInteger(GetPName.MinorVersion, out int minor);
|
|
GLVersion = new Version(major, minor);
|
|
|
|
GLRenderer = GL.GetString(StringName.Renderer) ?? string.Empty;
|
|
GLVendor = GL.GetString(StringName.Vendor) ?? string.Empty;
|
|
|
|
HashSet<string> extensions = new HashSet<string>();
|
|
GL.GetInteger(GetPName.NumExtensions, out int extensionCount);
|
|
for (uint i = 0; i < extensionCount; i++)
|
|
{
|
|
string? ext = GL.GetStringi(StringName.Extensions, i);
|
|
if (ext != null)
|
|
extensions.Add(ext);
|
|
}
|
|
|
|
Extensions = extensions.ToImmutableHashSet();
|
|
|
|
ExtensionPreload<GLTextureExtension>();
|
|
}
|
|
|
|
public bool IsGLExtensionAvailable(string name)
|
|
{
|
|
return Extensions.Contains(name);
|
|
}
|
|
|
|
public void AssertGLExtension(string name)
|
|
{
|
|
if (IsGLExtensionAvailable(name))
|
|
return;
|
|
|
|
throw new NotSupportedException($"The OpenGL extension \"{name}\" is not supported by this context.");
|
|
}
|
|
|
|
public void InvokeBeforeDraw(Task task) => _beforeDrawActions.Enqueue(task);
|
|
|
|
public void InvokeAfterDraw(Task task) => _afterDrawActions.Enqueue(task);
|
|
|
|
public Task InvokeBeforeDraw(Action action)
|
|
{
|
|
Task task = new Task(action);
|
|
_beforeDrawActions.Enqueue(task);
|
|
return task;
|
|
}
|
|
|
|
public Task InvokeAfterDraw(Action action)
|
|
{
|
|
Task task = new Task(action);
|
|
_afterDrawActions.Enqueue(task);
|
|
return task;
|
|
}
|
|
|
|
public Task<T> InvokeBeforeDraw<T>(Func<T> function)
|
|
{
|
|
Task<T> task = new Task<T>(function);
|
|
_beforeDrawActions.Enqueue(task);
|
|
return task;
|
|
}
|
|
|
|
public Task<T> InvokeAfterDraw<T>(Func<T> function)
|
|
{
|
|
Task<T> task = new Task<T>(function);
|
|
_afterDrawActions.Enqueue(task);
|
|
return task;
|
|
}
|
|
|
|
public Task InvokeOnRenderThread(Action action)
|
|
{
|
|
if (IsRenderThread)
|
|
{
|
|
action();
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
return InvokeBeforeDraw(action);
|
|
}
|
|
|
|
public Task<T> InvokeOnRenderThread<T>(Func<T> function)
|
|
{
|
|
return IsRenderThread ? Task.FromResult(function()) : InvokeBeforeDraw(function);
|
|
}
|
|
|
|
public override void Begin()
|
|
{
|
|
base.Begin();
|
|
|
|
GLContext.MakeCurrent();
|
|
|
|
while (_beforeDrawActions.TryDequeue(out Task? action))
|
|
{
|
|
action.RunSynchronously();
|
|
}
|
|
}
|
|
|
|
public override void End()
|
|
{
|
|
base.End();
|
|
|
|
while (_afterDrawActions.TryDequeue(out Task? action))
|
|
{
|
|
action.RunSynchronously();
|
|
}
|
|
}
|
|
|
|
protected override void Dispose(bool isDisposing)
|
|
{
|
|
base.Dispose(isDisposing);
|
|
|
|
if (isDisposing)
|
|
{
|
|
GLContext.Disposed -= Dispose;
|
|
}
|
|
}
|
|
}
|
|
}
|