BackgroundContextWorker.cs 2.1 KB

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