/ src / Ryujinx.Graphics.OpenGL / BackgroundContextWorker.cs
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  }