using StgSharp.Logic; using StgSharp.Math; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; namespace StgSharp.Graphics { internal unsafe partial class GLonUpdate : IglFunc { private static ConcurrentQueue glActionQueue; private static GLparamQueue paramQueue; private FrameTimeoutException refreshSignal = new(); private IntPtr SwapBufferPtr = (IntPtr)(delegate*)&InternalIO.glfwSwapBuffers; internal GLonUpdate(GLcontext* context) { if (paramQueue == null) { paramQueue = new GLparamQueue(); } glActionQueue = new ConcurrentQueue(); } internal static GLparamQueue ParamQueue { get { return paramQueue; } } internal ConcurrentQueue GLactionQueue { get { return glActionQueue; } } void IglFunc.ActiveTexture(uint type) { paramQueue.Enqueue(type); glActionQueue.Enqueue(ActiveTexturePtr); } void IglFunc.AfterAlign(Form form, Action action) { throw new NotImplementedException(); } void IglFunc.AlignFrame(Form form) { if (form.timer.alignSign.byte0 > 0) { throw new InvalidOperationException(); } form.timer.alignSign.byte0++; form.timer.WaitNextFrame(); throw refreshSignal; } [MethodImpl(MethodImplOptions.AggressiveInlining)] unsafe void IglFunc.AttachShader(glHandle program, glHandle shader) { paramQueue.Enqueue(program, shader); glActionQueue.Enqueue(AttachShaderPtr); } [MethodImpl(MethodImplOptions.AggressiveInlining)] void IglFunc.BindBuffer(BufferType bufferType, glHandle handle) { M128 m = default; m.UInt32[0] = (uint)bufferType; m.IntPtr1 = handle.Handle; paramQueue.Enqueue(m); glActionQueue.Enqueue(BindBufferPtr); } [MethodImpl(MethodImplOptions.AggressiveInlining)] void IglFunc.BindTexture(uint type, glHandle texture) { M128 m = new M128 { IntPtr1 = (IntPtr)texture.valuePtr }; m.UInt32[0] = (uint)type; paramQueue.Enqueue(m); glActionQueue.Enqueue(BindTexturePtr); } [MethodImpl(MethodImplOptions.AggressiveInlining)] void IglFunc.BindVertexArray(glHandle index) { paramQueue.Enqueue(index); glActionQueue.Enqueue(BindVertexArrayPtr); } [MethodImpl(MethodImplOptions.AggressiveInlining)] void IglFunc.Clear(MaskBufferBit mask) { glActionQueue.Enqueue(ClearPtr); } [MethodImpl(MethodImplOptions.AggressiveInlining)] void IglFunc.ClearColor(float R, float G, float B, float A) { paramQueue.Enqueue(R, G, B, A); glActionQueue.Enqueue(ClearColorPtr); } [MethodImpl(MethodImplOptions.AggressiveInlining)] void IglFunc.ClearGraphicError() { glActionQueue.Enqueue(ClearGraphicErrorPtr); } glHandleSet IglFunc.CompileShader(ShaderType shaderType, params string[] shaderCode) { int l = shaderCode.Length; if (l == 0) { throw new ArgumentException("Should input at least one piece of shader code"); } glHandleSet shaderHandle = new glHandleSet(shaderCode.Length); paramQueue.Enqueue((int)shaderType, l); for (int i = 0; i < l; i++) { GCHandle codePtr = GCHandle.Alloc(Encoding.UTF8.GetBytes(shaderCode[i] + '\0'), GCHandleType.Pinned); paramQueue.Enqueue((IntPtr)shaderHandle.handle + i, codePtr.AddrOfPinnedObject()); } glActionQueue.Enqueue(CompileShaderPtr); return shaderHandle; } [MethodImpl(MethodImplOptions.AggressiveInlining)] glHandle IglFunc.CreateProgram() { glHandle h = glHandle.Alloc(1); paramQueue.Enqueue(h); glActionQueue.Enqueue(CreateProgramPtr); return h; } [MethodImpl(MethodImplOptions.AggressiveInlining)] glHandleSet IglFunc.CreateProgram(int count) { M128 m = default; glHandleSet h = new glHandleSet(count); m.IntPtr0 = (IntPtr)h.handle; m.Int32[2] = count; paramQueue.Enqueue(m); glActionQueue.Enqueue(CreateProgramSetPtr); return h; } IntPtr IglFunc.CreateWindowHandle(int width, int height, string tittle, IntPtr monitor, Form share) { byte[] tittleBytes = Encoding.UTF8.GetBytes(tittle); IntPtr windowPtr; if (share == null) { windowPtr = InternalIO.glfwCreateWindow( width, height, tittleBytes, monitor, IntPtr.Zero); } else { windowPtr = InternalIO.glfwCreateWindow( width, height, tittleBytes, monitor, share.windowID); } if ((long)windowPtr == -1 || (long)windowPtr == -2) { throw new Exception("Cannot create window instance!"); } else { return windowPtr; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] glHandle IglFunc.CreatGraphicProgram() { glHandle h = glHandle.Alloc(1); paramQueue.Enqueue(h); glActionQueue.Enqueue(CreateProgramPtr); return h; } [MethodImpl(MethodImplOptions.AggressiveInlining)] unsafe void IglFunc.DeleteBuffer(glHandle handle) { M128 m = new M128() { IntPtr0 = handle.Handle }; m.UInt32[2] = 1; paramQueue.Enqueue(m); glActionQueue.Enqueue(DeleBufferPtr); } unsafe void IglFunc.DeleteBuffers(glHandleSet handle) { M128 m = default; m.UInt32[2] = (uint)handle.length; m.IntPtr0 = (IntPtr)handle.handle; paramQueue.Enqueue(m); glActionQueue.Enqueue(DeleBufferPtr); } unsafe void IglFunc.DeleteVertexArrays(glHandleSet arrays) { M128 m = new() { IntPtr1 = (IntPtr)arrays.handle }; m.Int32[0] = arrays.length; paramQueue.Enqueue(m); glActionQueue.Enqueue(DeleteVertexArrayPtr); } void IglFunc.DrawElements(GepmetryType mode, uint count, TypeCode type, IntPtr ptr) { uint a; switch (type) { case TypeCode.UInt32: a = GLconst.UNSIGNED_INT; break; case TypeCode.UInt16: a = GLconst.UNSIGNED_SHORT; break; case TypeCode.Byte: a = GLconst.UNSIGNED_BYTE; break; default: InternalIO.InternalWriteLog( $"Parameter error in parameter {type} method DrawElements. " + $"Only {TypeCode.Byte}, {TypeCode.UInt16}, {TypeCode.UInt32} types are suporrted.", LogType.Error); return; } paramQueue.Enqueue((uint)mode, count, a); paramQueue.Enqueue(ptr); glActionQueue.Enqueue(DrawElementsPtr); } unsafe glHandleSet IglFunc.GenBuffers(int count) { glHandleSet h = new glHandleSet(count); M128 m = default; m.UInt32[2] = (uint)count; m.IntPtr0 = (IntPtr)h.handle; paramQueue.Enqueue(m); glActionQueue.Enqueue(GenBufferPtr); return h; } unsafe glHandleSet IglFunc.GenTextures(int count) { glHandleSet h = new glHandleSet(count); M128 m = default; m.UInt32[2] = (uint)count; m.IntPtr0 = (IntPtr)h.handle; paramQueue.Enqueue(m); glActionQueue.Enqueue(GenTexturesPtr); return h; } unsafe glHandleSet IglFunc.GenVertexArrays(int count) { glHandleSet h = new glHandleSet(count); M128 m = default; m.UInt32[2] = (uint)count; m.IntPtr0 = (IntPtr)h.handle; paramQueue.Enqueue(m); glActionQueue.Enqueue(GenTexturesPtr); return h; } [MethodImpl(MethodImplOptions.AggressiveInlining)] unsafe glSHandle IglFunc.GetUniformLocation(glHandle program, string ptr) { glSHandle h = glSHandle.Alloc(0); M128 m; m.IntPtr0 = program.Handle; m.IntPtr1 = GCHandle.Alloc(Encoding.UTF8.GetBytes(ptr)).AddrOfPinnedObject(); paramQueue.Enqueue(m); paramQueue.Enqueue((IntPtr)h.valuePtr); glActionQueue.Enqueue(GetUniformLocationPtr); return h; } [MethodImpl(MethodImplOptions.AggressiveInlining)] bool IglFunc.GetWindowShouldClose(Form form) { return InternalIO.glfwWindowShouldClose(form.windowID) == 0; } public void GLswapBuffers(Form form) { if (form.windowID == IntPtr.Zero) { return; } InternalIO.glfwSwapBuffers(form.windowID); } [MethodImpl(MethodImplOptions.AggressiveInlining)] void IglFunc.MakeContexCurrent(Form form) { if (form.windowID == IntPtr.Zero) { return; } InternalIO.glfwMakeContextCurrent(form.windowID); } void IglFunc.SetBufferData(BufferType bufferType, T bufferData, BufferUsage usage) { paramQueue.Enqueue((uint)bufferType, (uint)usage); paramQueue.Enqueue((IntPtr)sizeof(T), GCHandle.Alloc(bufferData).AddrOfPinnedObject()); glActionQueue.Enqueue(BufferDataPtr); } void IglFunc.SetBufferData(BufferType bufferType, T[] bufferArray, BufferUsage usage) { paramQueue.Enqueue((uint)bufferType, (uint)usage); paramQueue.Enqueue((IntPtr)(Marshal.SizeOf() * bufferArray.Length), GCHandle.Alloc(bufferArray).AddrOfPinnedObject()); glActionQueue.Enqueue(BufferDataPtr); } void IglFunc.SetVertexAttribute(uint index, int size, TypeCode t, bool normalized, uint stride, int pointer) { uint type = InternalIO.GLtype[t]; paramQueue.Enqueue(index, type, stride); paramQueue.Enqueue(size, normalized ? 1 : 0, pointer); glActionQueue.Enqueue(SetVertexArrayPtr); } //TODO:双线程,换运行环境 void IglFunc.SwitchContext() { } unsafe void IglFunc.TextureImage2d(int target, int level, uint internalformat, uint width, uint height, uint format, uint type, T[] pixels) { IntPtr source = GCHandle.Alloc(pixels, GCHandleType.Pinned).AddrOfPinnedObject(); paramQueue.Enqueue(source); paramQueue.Enqueue((uint)level, internalformat, width, height); paramQueue.Enqueue((uint)target, format, type); glActionQueue.Enqueue(textureImage2dPtr); } void IglFunc.TextureParameter(int target, uint pname, int param) { M128 m = default; m.Int32[0] = target; m.UInt32[2] = pname; m.Int32[3] = param; paramQueue.Enqueue(m); glActionQueue.Enqueue(TextureParameterPtr); } void IglFunc.UseProgram(glHandle program) { paramQueue.Enqueue((IntPtr)program.valuePtr); glActionQueue.Enqueue(UseProgramPtr); } void IglFunc.Viewport(int x, int y, uint width, uint height) { Vec4d v = new Vec4d(x, y, (int)width, (int)height); paramQueue.Enqueue(v); glActionQueue.Enqueue(ViewPortPtr); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void frameworkHandleEnqueue(IntPtr methodHandle, params M128[] param) { glActionQueue.Enqueue(methodHandle); foreach (M128 item in param) { paramQueue.Enqueue(item); } } } }