CPF/CPF.Linux/OpenGL/GlxContext.cs
2023-11-21 23:05:03 +08:00

171 lines
5.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using CPF.Drawing;
using SkiaSharp;
namespace CPF.Linux.OpenGL
{
internal class GlxContext : CPF.OpenGL.IGlContext
{
private IntPtr fDisplay;
//private IntPtr fPixmap;
//private IntPtr fGlxPixmap;
private IntPtr fContext;
IntPtr handle;
public GlxContext(X11Window window)
{
this.handle = window.Handle;
//fDisplay = XLib.XOpenDisplay(IntPtr.Zero);
//if (fDisplay == IntPtr.Zero) {
// Dispose();
// throw new Exception("Failed to open X display.");
//}
fDisplay = LinuxPlatform.Platform.Display;
var visualAttribs = new[] {
Glx.GLX_X_RENDERABLE, Glx.True,
Glx.GLX_DRAWABLE_TYPE, Glx.GLX_WINDOW_BIT | Glx.GLX_PBUFFER_BIT,
Glx.GLX_RENDER_TYPE, Glx.GLX_RGBA_BIT,
Glx.GLX_DOUBLEBUFFER, Glx.True,
Glx.GLX_RED_SIZE, 8,
Glx.GLX_GREEN_SIZE, 8,
Glx.GLX_BLUE_SIZE, 8,
Glx.GLX_ALPHA_SIZE, 8,
Glx.GLX_DEPTH_SIZE, 1,
Glx.GLX_STENCIL_SIZE, 8,
// Glx.GLX_SAMPLE_BUFFERS, 1,
// Glx.GLX_SAMPLES, 4,
Glx.None
};
try
{
int glxMajor, glxMinor;
if (!Glx.glXQueryVersion(fDisplay, out glxMajor, out glxMinor) ||
(glxMajor < 1) ||
(glxMajor == 1 && glxMinor < 3))
{
Console.WriteLine($"GLX version 1.3 or higher required ({glxMajor}.{glxMinor} provided).");
return;
}
var fbc = Glx.ChooseFBConfig(fDisplay, LinuxPlatform.Platform.Info.DefaultScreen, visualAttribs);
if (fbc.Length == 0)
{
Console.WriteLine("Failed to retrieve a framebuffer config.");
return;
}
var bestFBC = IntPtr.Zero;
var bestNumSamp = -1;
for (int i = 0; i < fbc.Length; i++)
{
int sampleBuf, samples;
Glx.glXGetFBConfigAttrib(fDisplay, fbc[i], Glx.GLX_SAMPLE_BUFFERS, out sampleBuf);
Glx.glXGetFBConfigAttrib(fDisplay, fbc[i], Glx.GLX_SAMPLES, out samples);
var visual = Glx.GetVisualFromFBConfig(fDisplay, fbc[i]);
if (bestFBC == IntPtr.Zero || (sampleBuf > 0 && samples > bestNumSamp || visual.depth == 32))
{
bestFBC = fbc[i];
bestNumSamp = samples;
}
}
fContext = Glx.glXCreateNewContext(fDisplay, bestFBC, Glx.GLX_RGBA_TYPE, IntPtr.Zero, Glx.True);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
public IntPtr Context { get { return fContext; } }
IntPtr oldHandle;
IntPtr oldDisplay;
IntPtr oldContext;
public void MakeCurrent()
{
oldContext = Glx.glXGetCurrentContext();
oldDisplay = Glx.glXGetCurrentDisplay();
oldHandle = Glx.glXGetCurrentDrawable();
if (!Glx.glXMakeCurrent(fDisplay, handle, fContext))
{
Dispose();
throw new Exception("Failed to set the context.");
}
}
public void SwapBuffers()
{
Glx.glXSwapBuffers(fDisplay, handle);
Glx.glXMakeCurrent(oldDisplay, oldHandle, oldContext);
}
public void Dispose()
{
if (fDisplay != IntPtr.Zero)
{
//Glx.glXMakeCurrent(fDisplay, IntPtr.Zero, IntPtr.Zero);
if (fContext != IntPtr.Zero)
{
Glx.glXDestroyContext(fDisplay, fContext);
fContext = IntPtr.Zero;
}
//if (fGlxPixmap != IntPtr.Zero) {
// Glx.glXDestroyGLXPixmap(fDisplay, fGlxPixmap);
// fGlxPixmap = IntPtr.Zero;
//}
//if (fPixmap != IntPtr.Zero) {
// XLib.XFreePixmap(fDisplay, fPixmap);
// fPixmap = IntPtr.Zero;
//}
fDisplay = IntPtr.Zero;
}
GRContext?.Dispose();
GRContext = null;
}
public IntPtr GetProcAddress(string name)
{
return Glx.glXGetProcAddressARB(name);
}
//public override GRGlTextureInfo CreateTexture(SKSizeI textureSize)
//{
// var textures = new uint[1];
// Glx.glGenTextures(textures.Length, textures);
// var textureId = textures[0];
// Glx.glBindTexture(Glx.GL_TEXTURE_2D, textureId);
// Glx.glTexImage2D(Glx.GL_TEXTURE_2D, 0, Glx.GL_RGBA, textureSize.Width, textureSize.Height, 0, Glx.GL_RGBA, Glx.GL_UNSIGNED_BYTE, IntPtr.Zero);
// Glx.glBindTexture(Glx.GL_TEXTURE_2D, 0);
// return new GRGlTextureInfo {
// Id = textureId,
// Target = Glx.GL_TEXTURE_2D,
// Format = Glx.GL_RGBA8
// };
//}
//public override void DestroyTexture(uint texture)
//{
// Glx.glDeleteTextures(1, new[] { texture });
//}
public const int GL_FRAMEBUFFER_BINDING = 0x8CA6;
public IDisposable GRContext { get; set; }
public void GetFramebufferInfo(out int framebuffer, out int samples, out int stencil)
{
Glx.glGetIntegerv(GL_FRAMEBUFFER_BINDING, out framebuffer);
Glx.glGetIntegerv(3415, out stencil);
Glx.glGetIntegerv(32937, out samples);
}
}
}