//----------------------------------------------------------------------- //----------------------------------------------------------------------- // file="FrameAsyncTask.cs" // Project: StgSharp // AuthorGroup: Nitload Space // Copyright (c) Nitload Space. All rights reserved. // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the “Software”), to deal in the Software without restriction, // including without limitation the rights to use, copy, modify, merge, // publish, distribute, sublicense, and/or sell copies of the Software, // and to permit persons to whom the Software is furnished to do so, // subject to the following conditions: // // The above copyright notice and // this permission notice shall be included in all copies // or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED “AS IS”, // WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH // THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //----------------------------------------------------------------------- //----------------------------------------------------------------------- using StgSharp.Math; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; namespace StgSharp.Graphics { internal sealed class FrameOperationBuffer { private IntPtr _func; private ConcurrentQueue _funcQueue; private readonly unsafe GLcontext* currentContext; public unsafe FrameOperationBuffer(IglFunc gl) { currentContext = gl.Context; _funcQueue = new ConcurrentQueue(); } public unsafe bool CallNext() { if (_funcQueue.TryDequeue(out _func)) { ((delegate*)_func)(this, currentContext); return true; } else { return false; } } #region gl param queue private ConcurrentQueue paramQueue = new ConcurrentQueue(); private ConcurrentQueue streamQueue = new ConcurrentQueue(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public void MethodEnqueue(IntPtr p) { _funcQueue.Enqueue(p); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ParamEnqueue(Vec4d v) { paramQueue.Enqueue(v); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ParamEnqueue(M128 m) { paramQueue.Enqueue(m); Console.WriteLine(paramQueue.Count + streamQueue.Count); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ParamEnqueue(uint u0) { M128 m = default; m.Write(0, u0); this.ParamEnqueue(m); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ParamEnqueue(uint u0, uint u1) { M128 m = default; m.Write(0, u0); m.Write(1, u1); this.ParamEnqueue(m); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ParamEnqueue(ulong u0, ulong u1) { M128 m = default; m.Write(0, u0); m.Write(1, u1); this.ParamEnqueue(m); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ParamEnqueue(uint u0, uint u1, uint u2) { M128 m = default; m.Write(0, u0); m.Write(1, u1); m.Write(2, u2); this.ParamEnqueue(m); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ParamEnqueue(float f0, float f1, float f2) { M128 m = default; m.Write(0, f0); m.Write(1, f1); this.ParamEnqueue(m); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ParamEnqueue(float f0, float f1, float f2, float f3) { M128 m = default; m.Write(0, f0); m.Write(1, f1); m.Write(2, f2); m.Write(3, f3); this.ParamEnqueue(m); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ParamEnqueue(IntPtr p0, IntPtr p1) { M128 m = default; m.Write(0, (ulong)p0); m.Write(1, (ulong)p1); this.ParamEnqueue(m); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ParamEnqueue(IntPtr p) { M128 m = default; m.Write(0, (ulong)p); this.ParamEnqueue(m); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void ParamEnqueue(glHandle handle) { M128 m = default; m.Write(0, (ulong)handle.valuePtr); this.ParamEnqueue(m); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void ParamEnqueue(glHandle handle, glHandle handle1) { M128 m = default; m.Write(0, (ulong)handle.valuePtr); m.Write(1, (ulong)handle1.valuePtr); this.ParamEnqueue(m); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ParamEnqueue(int i0) { M128 m = default; m.Write(0, i0); this.ParamEnqueue(m); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ParamEnqueue(int i0, int i1) { M128 m = default; m.Write(0, i0); m.Write(1, i1); this.ParamEnqueue(m); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ParamEnqueue(int i0, int i1, int i2) { M128 m = default; m.Write(0, i0); m.Write(1, i1); m.Write(2, i2); this.ParamEnqueue(m); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ParamEnqueue(int i0, int i1, int i2, int i3) { M128 m = default; m.Write(0, i0); m.Write(1, i1); m.Write(2, i2); m.Write(3, i3); this.ParamEnqueue(m); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ParamEnqueue(string str) { byte[] code = Encoding.UTF8.GetBytes(str); streamQueue.Enqueue(glArrayHandle.Alloc(code)); Console.WriteLine(paramQueue.Count + streamQueue.Count); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ParamEnqueue(T[] array) where T : struct { streamQueue.Enqueue(glArrayHandle.Alloc(array)); Console.WriteLine(paramQueue.Count + streamQueue.Count); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void TryDequeue(out glArrayHandle arrayHandle) { if (!streamQueue.TryDequeue(out arrayHandle)) { InternalIO.InternalWriteLog("No param in buffer when calling gl function:", LogType.Error); throw new Exception(); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryDequeue(out M128 m) { bool ret = paramQueue.TryDequeue(out m); return ret; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void TryDequeue(out Vec4d v) { M128 m; if (this.TryDequeue(out m)) { v = *(Vec4d*)&m; } else { InternalIO.InternalWriteLog("No param in buffer when calling gl function.", LogType.Error); throw new Exception(); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void TryDequeue(out T[] array) { glArrayHandle output = default; if (streamQueue.TryDequeue(out output)) { array = output.a as T[]; } else { InternalIO.InternalWriteLog("No param in buffer when calling gl function.", LogType.Error); throw new Exception(); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void TryDequeue(out int i0) { M128 ret; if (this.TryDequeue(out ret)) { i0 = ret.Read(0); } else { InternalIO.InternalWriteLog("No param in buffer when calling gl function.", LogType.Error); throw new Exception(); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void TryDequeue(out int i0, out int i1) { M128 ret; if (this.TryDequeue(out ret)) { i0 = ret.Read(0); i1 = ret.Read(1); } else { InternalIO.InternalWriteLog("No param in buffer when calling gl function.", LogType.Error); throw new Exception(); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void TryDequeue(out int i0, out int i1, out int i2) { M128 ret; if (this.TryDequeue(out ret)) { i0 = ret.Read(0); i1 = ret.Read(1); i2 = ret.Read(2); } else { InternalIO.InternalWriteLog("No param in buffer when calling gl function.", LogType.Error); throw new Exception(); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void TryDequeue(out int i0, out int i1, out int i2, out int i3) { M128 ret; if (this.TryDequeue(out ret)) { i0 = ret.Read(0); i1 = ret.Read(1); i2 = ret.Read(2); i3 = ret.Read(3); } else { InternalIO.InternalWriteLog("No param in buffer when calling gl function.", LogType.Error); throw new Exception(); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void TryDequeue(out IntPtr p) { M128 ret; if (this.TryDequeue(out ret)) { p = (IntPtr)ret.Read(0); } else { InternalIO.InternalWriteLog("No param in buffer when calling gl function.", LogType.Error); throw new Exception(); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void TryDequeue(out IntPtr p0, out IntPtr p1) { M128 ret; if (this.TryDequeue(out ret)) { p0 = (IntPtr)ret.Read(0); p1 = (IntPtr)ret.Read(1); } else { InternalIO.InternalWriteLog("No param in buffer when calling gl function.", LogType.Error); throw new Exception(); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void TryDequeue(out float f0, out float f1, out float f2, out float f3) { M128 ret; if (this.TryDequeue(out ret)) { f0 = ret.Read(0); f1 = ret.Read(1); f2 = ret.Read(2); f3 = ret.Read(3); } else { InternalIO.InternalWriteLog("No param in buffer when calling gl function.", LogType.Error); throw new Exception(); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void TryDequeue(out float f0, out float f1, out float f2) { M128 ret; if (this.TryDequeue(out ret)) { f0 = ret.Read(0); f1 = ret.Read(1); f2 = ret.Read(2); } else { InternalIO.InternalWriteLog("No param in buffer when calling gl function.", LogType.Error); throw new Exception(); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void TryDequeue(out uint u0) { M128 ret; if (this.TryDequeue(out ret)) { u0 = ret.Read(0); } else { InternalIO.InternalWriteLog("No param in buffer when calling gl function.", LogType.Error); throw new Exception(); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void TryDequeue(out uint u0, out uint u1) { M128 ret; if (this.TryDequeue(out ret)) { u0 = ret.Read(0); u1 = ret.Read(1); } else { InternalIO.InternalWriteLog("No param in buffer when calling gl function.", LogType.Error); throw new Exception(); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void TryDequeue(out uint u0, out uint u1, out uint u2) { M128 ret; if (this.TryDequeue(out ret)) { u0 = ret.Read(0); u1 = ret.Read(1); u2 = ret.Read(2); } else { InternalIO.InternalWriteLog("No param in buffer when calling gl function.", LogType.Error); throw new Exception(); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void TryDequeue(out uint u0, out uint u1, out uint u2, out uint u3) { M128 ret; if (this.TryDequeue(out ret)) { u0 = ret.Read(0); u1 = ret.Read(1); u2 = ret.Read(2); u3 = ret.Read(3); } else { InternalIO.InternalWriteLog("No param in buffer when calling gl function.", LogType.Error); throw new Exception(); } } /* internal void SetContext(GLcontext* p) { context = p; } /**/ #endregion gl param queue } //TODO 目前还不能加载任何任务 //TODO 任务的启动逻辑需要重构 public class FrameAsyncTask { protected SemaphoreSlim _frameCompleteSemaphore = new SemaphoreSlim(0, 1); protected SemaphoreSlim _refreshSemaphore; private Task _task; protected Action _taskTODO; protected Func _terminateSignature; internal FrameOperationBuffer opBuffer; public Action TaskTODO { get => _taskTODO; set => _taskTODO = value; } internal FrameAsyncTask(Action action, IglFunc gl) { _taskTODO = action; opBuffer = new FrameOperationBuffer(gl); } public static SemaphoreSlim CombineAsync(params FrameAsyncTask[] taskList) { if (taskList.Length == 0) { return null; } SemaphoreSlim refresh = new SemaphoreSlim(taskList.Length); foreach (FrameAsyncTask item in taskList) { item._refreshSemaphore = refresh; } return refresh; } public static SemaphoreSlim CombineAsync(List taskList) { if (taskList.Count == 0) { return null; } SemaphoreSlim refresh = new SemaphoreSlim(taskList.Count); foreach (FrameAsyncTask item in taskList) { item._refreshSemaphore = refresh; } return refresh; } public static void ExchangeBuffer(FrameAsyncTask task0, FrameAsyncTask task1) { FrameOperationBuffer cache = task0.opBuffer; task0.opBuffer = task1.opBuffer; task1.opBuffer = cache; } public virtual SemaphoreSlim StartAsync() { _task = new Task( () => { while (true) { _refreshSemaphore.Wait(); _taskTODO(); _frameCompleteSemaphore.Release(); } }); _task.Start(); return _frameCompleteSemaphore; } } internal sealed class AsyncUpdateDataTask : FrameAsyncTask { public AsyncUpdateDataTask(Form f) : base(f.Main, f.GL) { } } internal sealed class AsyncRenderFrameTask : FrameAsyncTask { public AsyncRenderFrameTask(Form f) : base(null, f.gl) { TaskTODO = new ( () => { while (true) { FrameOperation(); } }); } private void FrameOperation() { while (opBuffer.CallNext()){} } } }