BackgroundContextWorker.cs
1 using Ryujinx.Common; 2 using System; 3 using System.Collections.Generic; 4 using System.Threading; 5 6 namespace Ryujinx.Graphics.OpenGL 7 { 8 unsafe class BackgroundContextWorker : IDisposable 9 { 10 [ThreadStatic] 11 public static bool InBackground; 12 private readonly Thread _thread; 13 private bool _running; 14 15 private readonly AutoResetEvent _signal; 16 private readonly Queue<Action> _work; 17 private readonly ObjectPool<ManualResetEventSlim> _invokePool; 18 private readonly IOpenGLContext _backgroundContext; 19 20 public BackgroundContextWorker(IOpenGLContext backgroundContext) 21 { 22 _backgroundContext = backgroundContext; 23 _running = true; 24 25 _signal = new AutoResetEvent(false); 26 _work = new Queue<Action>(); 27 _invokePool = new ObjectPool<ManualResetEventSlim>(() => new ManualResetEventSlim(), 10); 28 29 _thread = new Thread(Run); 30 _thread.Start(); 31 } 32 33 public bool HasContext() => _backgroundContext.HasContext(); 34 35 private void Run() 36 { 37 InBackground = true; 38 39 _backgroundContext.MakeCurrent(); 40 41 while (_running) 42 { 43 Action action; 44 45 lock (_work) 46 { 47 _work.TryDequeue(out action); 48 } 49 50 if (action != null) 51 { 52 action(); 53 } 54 else 55 { 56 _signal.WaitOne(); 57 } 58 } 59 60 _backgroundContext.Dispose(); 61 } 62 63 public void Invoke(Action action) 64 { 65 ManualResetEventSlim actionComplete = _invokePool.Allocate(); 66 67 lock (_work) 68 { 69 _work.Enqueue(() => 70 { 71 action(); 72 actionComplete.Set(); 73 }); 74 } 75 76 _signal.Set(); 77 78 actionComplete.Wait(); 79 actionComplete.Reset(); 80 81 _invokePool.Release(actionComplete); 82 } 83 84 public void Dispose() 85 { 86 _running = false; 87 _signal.Set(); 88 89 _thread.Join(); 90 _signal.Dispose(); 91 } 92 } 93 }