CPF/CPF.Skia/GlContexts/Wgl/WglContext.cs
2023-11-21 23:05:03 +08:00

236 lines
8.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using CPF.Drawing;
using SkiaSharp;
namespace CPF.Skia
{
internal class WglContext : GlContext
{
public const int WGL_CONTEXT_MAJOR_VERSION_ARB = 0x2091;
public const int WGL_CONTEXT_MINOR_VERSION_ARB = 0x2092;
public const int WGL_CONTEXT_LAYER_PLANE_ARB = 0x2093;
public const int WGL_CONTEXT_PROFILE_MASK_ARB = 0x9126;
public const int GL_FRAMEBUFFER_BINDING = 0x8CA6;
private static readonly object fLock = new object();
//private static ushort gWC;
//private static IntPtr fWindow;
//private static IntPtr fDeviceContext;
//private IntPtr fPbuffer;
private IntPtr fPbufferDC;
private IntPtr fPbufferGlContext;
static WglContext()
{
//var wc = new WNDCLASS
//{
// cbClsExtra = 0,
// cbWndExtra = 0,
// hbrBackground = IntPtr.Zero,
// hCursor = User32.LoadCursor(IntPtr.Zero, (int)User32.IDC_ARROW),
// hIcon = User32.LoadIcon(IntPtr.Zero, (IntPtr)User32.IDI_APPLICATION),
// hInstance = Kernel32.CurrentModuleHandle,
// lpfnWndProc = (WNDPROC)User32.DefWindowProc,
// lpszClassName = "Griffin",
// lpszMenuName = null,
// style = User32.CS_HREDRAW | User32.CS_VREDRAW | User32.CS_OWNDC
//};
//gWC = User32.RegisterClass(ref wc);
//if (gWC == 0)
//{
// throw new Exception("Could not register window class.");
//}
//fWindow = User32.CreateWindow(
// "Griffin",
// "The Invisible Man",
// WindowStyles.WS_OVERLAPPEDWINDOW,
// 0, 0,
// 1, 1,
// IntPtr.Zero, IntPtr.Zero, Kernel32.CurrentModuleHandle, IntPtr.Zero);
//if (fWindow == IntPtr.Zero)
//{
// throw new Exception($"Could not create window.");
//}
//fDeviceContext = User32.GetDC(fWindow);
//if (fDeviceContext == IntPtr.Zero)
//{
// DestroyWindow();
// throw new Exception("Could not get device context.");
//}
//if (!Wgl.HasExtension(fDeviceContext, "WGL_ARB_pixel_format") ||
// !Wgl.HasExtension(fDeviceContext, "WGL_ARB_pbuffer"))
//{
// DestroyWindow();
// throw new Exception("DC does not have extensions.");
//}
}
public WglContext(IRenderTarget renderTarget)
{
// var iAttrs = new int[]
// {
// Wgl.WGL_ACCELERATION_ARB, Wgl.WGL_FULL_ACCELERATION_ARB,
// Wgl.WGL_DRAW_TO_WINDOW_ARB, Wgl.TRUE,
////Wgl.WGL_DOUBLE_BUFFER_ARB, (doubleBuffered ? TRUE : FALSE),
//Wgl.WGL_SUPPORT_OPENGL_ARB, Wgl.TRUE,
// Wgl.WGL_RED_BITS_ARB, 8,
// Wgl.WGL_GREEN_BITS_ARB, 8,
// Wgl.WGL_BLUE_BITS_ARB, 8,
// Wgl.WGL_ALPHA_BITS_ARB, 8,
// Wgl.WGL_STENCIL_BITS_ARB, 8,
// Wgl.NONE, Wgl.NONE
// };
// var piFormats = new int[1];
// uint nFormats;
// lock (fLock)
// {
// // HACK: This call seems to cause deadlocks on some systems.
// Wgl.wglChoosePixelFormatARB(fDeviceContext, iAttrs, null, (uint)piFormats.Length, piFormats, out nFormats);
// }
// if (nFormats == 0)
// {
// Dispose();
// throw new Exception("Could not get pixel formats.");
// }
// fPbuffer = Wgl.wglCreatePbufferARB(fDeviceContext, piFormats[0], 1, 1, null);
// if (fPbuffer == IntPtr.Zero)
// {
// Dispose();
// throw new Exception("Could not create Pbuffer.");
// }
// fPbufferDC = Wgl.wglGetPbufferDCARB(fPbuffer);
// if (fPbufferDC == IntPtr.Zero)
// {
// Dispose();
// throw new Exception("Could not get Pbuffer DC.");
// }
// var prevDC = Wgl.wglGetCurrentDC();
// var prevGLRC = Wgl.wglGetCurrentContext();
// System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
// stopwatch.Start();
// fPbufferGlContext = Wgl.wglCreateContext(fPbufferDC);
// stopwatch.Stop();
// System.Diagnostics.Debug.WriteLine(stopwatch.ElapsedMilliseconds);
// Wgl.wglMakeCurrent(prevDC, prevGLRC);
// if (fPbufferGlContext == IntPtr.Zero)
// {
// Dispose();
// throw new Exception("Could not creeate Pbuffer GL context.");
// }
var dc = ((CPF.Platform.HDCRenderTarget)renderTarget).Hdc;
var dummyPFD = new PIXELFORMATDESCRIPTOR();
dummyPFD.nSize = (ushort)Marshal.SizeOf(dummyPFD);
dummyPFD.nVersion = 1;
dummyPFD.dwFlags = Gdi32.PFD_DRAW_TO_WINDOW | Gdi32.PFD_SUPPORT_OPENGL;
dummyPFD.iPixelType = Gdi32.PFD_TYPE_RGBA;
dummyPFD.cColorBits = 24;
dummyPFD.cDepthBits = 32;
dummyPFD.cStencilBits = 0;
dummyPFD.iLayerType = Gdi32.PFD_MAIN_PLANE;
var dummyFormat = Gdi32.ChoosePixelFormat(dc, ref dummyPFD);
Gdi32.SetPixelFormat(dc, dummyFormat, ref dummyPFD);
var rc = Wgl.wglCreateContext(dc);
//var rc = Wgl.WglCreateContextAttribsArb(dc, IntPtr.Zero,
// new[]
// {
// // major
// WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
// // minor
// WGL_CONTEXT_MINOR_VERSION_ARB, 0,
// // core profile
// WGL_CONTEXT_PROFILE_MASK_ARB, 1,
// // debug
// // WGL_CONTEXT_FLAGS_ARB, 1,
// // end
// 0, 0
// });
if (rc == IntPtr.Zero)
{
throw new Exception("Could not create GL context.");
}
fPbufferDC = dc;
fPbufferGlContext = rc;
}
public override void MakeCurrent()
{
if (!Wgl.wglMakeCurrent(fPbufferDC, fPbufferGlContext))
{
Dispose();
throw new Exception("Could not set the context.");
}
}
public override void SwapBuffers()
{
if (!Gdi32.SwapBuffers(fPbufferDC))
{
Dispose();
throw new Exception("Could not complete SwapBuffers.");
}
}
public override void Dispose()
{
if (!Wgl.HasExtension(fPbufferDC, "WGL_ARB_pbuffer"))
{
// ASSERT
}
Wgl.wglDeleteContext(fPbufferGlContext);
//Wgl.wglReleasePbufferDCARB?.Invoke(fPbuffer, fPbufferDC);
//Wgl.wglDestroyPbufferARB?.Invoke(fPbuffer);
}
public override GRGlTextureInfo CreateTexture(SKSizeI textureSize)
{
var textures = new uint[1];
Wgl.glGenTextures(textures.Length, textures);
var textureId = textures[0];
Wgl.glBindTexture(Wgl.GL_TEXTURE_2D, textureId);
Wgl.glTexImage2D(Wgl.GL_TEXTURE_2D, 0, Wgl.GL_RGBA, textureSize.Width, textureSize.Height, 0, Wgl.GL_RGBA, Wgl.GL_UNSIGNED_BYTE, IntPtr.Zero);
Wgl.glBindTexture(Wgl.GL_TEXTURE_2D, 0);
return new GRGlTextureInfo
{
Id = textureId,
Target = Wgl.GL_TEXTURE_2D,
Format = Wgl.GL_RGBA8
};
}
public override void DestroyTexture(uint texture)
{
Wgl.glDeleteTextures(1, new[] { texture });
}
public override void GetFramebufferInfo(out int framebuffer, out int samples, out int stencil)
{
Wgl.glGetIntegerv(GL_FRAMEBUFFER_BINDING, out framebuffer);
Wgl.glGetIntegerv(3415, out stencil);
Wgl.glGetIntegerv(32937, out samples);
}
}
}