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 ConcurrentQueue glActionQueue; private static GLparamQueue paramQueue; private FrameTimeoutException refreshSignal = new(); internal GLonUpdate(GLcontext* context) { if (paramQueue == null) { paramQueue = new GLparamQueue(); } glActionQueue = new ConcurrentQueue(); } 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, uint index) { paramQueue.Enqueue((uint)bufferType, index); glActionQueue.Enqueue(BindBufferPtr ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] void IglFunc.BindTexture(uint type, uint texture) { glActionQueue.Enqueue( () => api->glBindTexture((uint)type, texture) ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] void IglFunc.BindVertexArray(uint index) { glActionQueue.Enqueue( () => api->glBindVertexArray((uint)index) ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] void IglFunc.Clear(MaskBufferBit mask) { glActionQueue.Enqueue( () => api->glClear((uint)mask) ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] void IglFunc.ClearColor(float R, float G, float B, float A) { glActionQueue.Enqueue(ClearColorPtr); } [MethodImpl(MethodImplOptions.AggressiveInlining)] void IglFunc.ClearGraphicError() { glActionQueue.Enqueue(ClearGraphicErrorPtr); } //TODO:双线程,换运行环境 void IglFunc.SwitchContext() { } 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 = new glHandle(1); glActionQueue.Enqueue( () => { int ret = (int)api->glCreateProgram(); Interlocked.Add(ref id, ret + 1); } ); return h; } [MethodImpl(MethodImplOptions.AggressiveInlining)] glHandleSet IglFunc.CreateProgram(int count) { throw new NotImplementedException(); } 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.glfw.CreateWindow( width, height, tittleBytes, monitor, IntPtr.Zero); } else { windowPtr = InternalIO.glfw.CreateWindow( 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 = new glHandle(1); glActionQueue.Enqueue( () => { Interlocked.Add(ref id, (int)(api->glCreateProgram() + 1)); } ); return h; } [MethodImpl(MethodImplOptions.AggressiveInlining)] unsafe void IglFunc.DeleteBuffer(uint handle) { glActionQueue.Enqueue( () => { uint target = handle; api->glDeleteBuffers(1, &target); } ); } unsafe void IglFunc.DeleteBuffers(glHandleSet handle) { glActionQueue.Enqueue( () => { uint[] h = handle; fixed (uint* p = h) { api->glDeleteBuffers(count, p); } } ); } unsafe void IglFunc.DeleteVertexArrays(glHandleSet arrays) { glActionQueue.Enqueue( () => { uint[] target = arrays; fixed (uint* ptr = target) { api->glDeleteVertexArrays(count, ptr); } } ); } void IglFunc.DrawElements(GepmetryType mode, uint count, Type type, IntPtr ptr) { uint a; switch (Type.GetTypeCode(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 {nameof(type)} method DrawElements. " + $"Only {typeof(uint).Name},{typeof(ushort).Name},{typeof(byte).Name} types are suporrted.", LogType.Error); return; } glActionQueue.Enqueue( () => { api->glDrawElements((uint)mode, count, a, (void*)ptr); } ); } unsafe void IglFunc.GenBuffers(uint count, glHandleSet handle) { glActionQueue.Enqueue( () => { } ); } unsafe void IglFunc.GenTextures(uint count, glHandleSet handle) { glActionQueue.Enqueue( () => { } ); } unsafe void IglFunc.GenVertexArrays(uint count, glHandleSet ptr) { glActionQueue.Enqueue( () => { api->glGenVertexArrays(count, ptr); } ); } public void GetGraphicError() { throw new NotImplementedException(); } void IglFunc.GetGraphicError() { throw new NotImplementedException(); } unsafe int IglFunc.GetUniformLocation(uint program, byte* ptr) { int ret = -1; glActionQueue.Enqueue( () => { int location = api->glGetUniformLocation(program, ptr); Interlocked.Add(ref ret, location + 1); } ); while (ret < 0) { } return ret; } [MethodImpl(MethodImplOptions.AggressiveInlining)] bool IglFunc.GetWindowShouldClose(Form form) { return InternalIO.glfw.WindowShouldClose(form.windowID) == 0; } public void GLswapBuffers(Form form) { if (form.windowID == IntPtr.Zero) { return; } InternalIO.glfw.SwapBuffers(form.windowID); } [MethodImpl(MethodImplOptions.AggressiveInlining)] void IglFunc.MakeContexCurrent(Form form) { if (form.windowID == IntPtr.Zero) { return; } InternalIO.glfw.MakeContextCurrent(form.windowID); } void IglFunc.SetBufferData(BufferType bufferType, T bufferData, BufferUsage usage) { glActionQueue.Enqueue( () => { T data = bufferData; int size = sizeof(T); api->glBufferData( (uint)bufferType, (UIntPtr)size, &data, (uint)usage); } ); } void IglFunc.SetBufferData(BufferType bufferType, T[] bufferArray, BufferUsage usage) { glActionQueue.Enqueue( () => { int size = bufferArray.Length * Marshal.SizeOf(typeof(T)); if (bufferArray == null) { return; } fixed (void* bufferPtr = bufferArray) api->glBufferData( (uint)bufferType, (UIntPtr)size, bufferPtr, (uint)usage); } ); } void IglFunc.SetFrameBufferSizeCallback(IntPtr id, FrameBufferSizeHandler handler) { IntPtr handlerPtr = Marshal.GetFunctionPointerForDelegate(handler); InternalIO.glfw.SetFramebufferSizeCallback(id, handlerPtr); } void IglFunc.SetVertexAttribute(uint index, int size, Type t, bool normalized, uint stride, int pointer) { glActionQueue.Enqueue( () => { uint type = InternalIO.GLtype[t]; api->glVertexAttribPointer(index, size, type, normalized, stride, (void*)pointer); api->glEnableVertexAttribArray(index); } ); } [MethodImpl(MethodImplOptions.AggressiveInlining)] unsafe void IglFunc.SetWindowShouldClose(Form form, bool mark) { InternalIO.glfw.SetWindowShouldClose(form.windowID, mark ? 1 : 0); } void IglFunc.SwapBuffers(Form form) { glActionQueue.Enqueue( () => { if (form.windowID == IntPtr.Zero) { return; } InternalIO.glfw.SwapBuffers(form.windowID); } ); } unsafe void IglFunc.TextureImage2d(uint target, int level, uint internalformat, uint width, uint height, uint format, uint type, void* pixels) { glActionQueue.Enqueue( () => { api->glTexImage2D(target, level, internalformat, width, height, 0, format, type, pixels); } ); } void IglFunc.TextureParameter(uint target, uint pname, int param) { glActionQueue.Enqueue( () => { api->glTextureParameteri(target, pname, param); } ); } void IglFunc.UseProgram(uint rogram) { glActionQueue.Enqueue( () => { api->glUseProgram(rogram); } ); } void IglFunc.Viewport(int x, int y, uint width, uint height) { glActionQueue.Enqueue( () => { api->glViewport(x, y, width, height); } ); } } }