//----------------------------------------------------------------------- //----------------------------------------------------------------------- // file="FrameAsyncThread.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.Data; 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() { currentContext = GL.api; _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.Write(paramQueue.Count + streamQueue.Count); //Console.Write($":{m.ToString(16)}\n"); } [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) { m = new(); bool ret = paramQueue.TryDequeue(out m); Console.WriteLine(m.ToString(16)); 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 } public class FrameAsyncThread { private int _priority; private Thread _task; private volatile int _terminateToken; protected Barrier _frameSpeedSyncBarrier; protected Barrier _spanCompleteBarrier; protected ThreadStart _taskTODO; public FrameAsyncThread(ThreadStart action, int priority) { _taskTODO = action; _terminateToken = 1; _spanCompleteBarrier = new Barrier(2); _priority = priority; } public int Priority { get => _priority; internal set => _priority = value; } public ThreadStart TaskTODO { get => _taskTODO; set => _taskTODO = value; } public Barrier TodoCompleteBarrier => _spanCompleteBarrier; public void AsyncStart() { _task = new Thread( () => { while (true) { _frameSpeedSyncBarrier.SignalAndWait(); if (_terminateToken == 0) { break; } _taskTODO(); _spanCompleteBarrier.SignalAndWait(); } }); _task.Start(); } public static void AsyncStartAll(IEnumerable threadList) { foreach (FrameAsyncThread t in threadList) { t.AsyncStart(); } } public static (Barrier, Barrier) CombineAsync(bool needOuterMonitor, IEnumerable taskList) { if (taskList.Count() == 0) { return (null, null); } Barrier b_start = new Barrier(taskList.Count() + (needOuterMonitor ? 1 : 0)); Barrier b_complete = new Barrier(taskList.Count() + (needOuterMonitor ? 1 : 0)); foreach (FrameAsyncThread item in taskList) { item._frameSpeedSyncBarrier = b_start; item._spanCompleteBarrier = b_complete; } return (b_start, b_complete); } public static (Barrier, Barrier) CombineAsync(bool needOuterMonitor, params FrameAsyncThread[] taskList) { if (taskList.Length == 0) { return (null, null); } Barrier b_start = new Barrier(taskList.Length + (needOuterMonitor ? 1 : 0)); Barrier b_complete = new Barrier(taskList.Length + (needOuterMonitor ? 1 : 0)); foreach (FrameAsyncThread item in taskList) { item._frameSpeedSyncBarrier = b_start; item._spanCompleteBarrier = b_complete; } return (b_start, b_complete); } public static Barrier CombineAsyncAfter(Barrier begin, bool needOuterMonitor, IEnumerable taskList) { if (taskList.Count() == 0) { return null; } Barrier b_complete = new Barrier(taskList.Count() + (needOuterMonitor ? 1 : 0)); foreach (FrameAsyncThread item in taskList) { item._frameSpeedSyncBarrier = begin; item._spanCompleteBarrier = b_complete; } return b_complete; } public void Terminate() { Interlocked.Exchange(ref _terminateToken, 0); } public static void TerminateAll(params FrameAsyncThread[] threadList) { foreach (FrameAsyncThread t in threadList) { t.Terminate(); } } public static void TerminateAll(IEnumerable threadList) { foreach (FrameAsyncThread t in threadList) { t.Terminate(); } } public static void WaitAll(IEnumerable threadList) { foreach (FrameAsyncThread t in threadList) { t._task.Join(); } } } }