BackgroundContextWorker.cs 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. using OpenTK;
  2. using OpenTK.Graphics;
  3. using Ryujinx.Common;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Threading;
  7. namespace Ryujinx.Graphics.OpenGL
  8. {
  9. class BackgroundContextWorker : IDisposable
  10. {
  11. [ThreadStatic]
  12. public static bool InBackground;
  13. private GameWindow _window;
  14. private GraphicsContext _context;
  15. private Thread _thread;
  16. private bool _running;
  17. private AutoResetEvent _signal;
  18. private Queue<Action> _work;
  19. private ObjectPool<ManualResetEventSlim> _invokePool;
  20. public BackgroundContextWorker(IGraphicsContext baseContext)
  21. {
  22. _window = new GameWindow(
  23. 100, 100, GraphicsMode.Default,
  24. "Background Window", OpenTK.GameWindowFlags.FixedWindow, OpenTK.DisplayDevice.Default,
  25. 3, 3, GraphicsContextFlags.ForwardCompatible, baseContext, false);
  26. _window.Visible = false;
  27. _context = (GraphicsContext)_window.Context;
  28. _context.MakeCurrent(null);
  29. _running = true;
  30. _signal = new AutoResetEvent(false);
  31. _work = new Queue<Action>();
  32. _invokePool = new ObjectPool<ManualResetEventSlim>(() => new ManualResetEventSlim(), 10);
  33. _thread = new Thread(Run);
  34. _thread.Start();
  35. }
  36. private void Run()
  37. {
  38. InBackground = true;
  39. _context.MakeCurrent(_window.WindowInfo);
  40. while (_running)
  41. {
  42. Action action;
  43. lock (_work)
  44. {
  45. _work.TryDequeue(out action);
  46. }
  47. if (action != null)
  48. {
  49. action();
  50. }
  51. else
  52. {
  53. _signal.WaitOne();
  54. }
  55. }
  56. _window.Dispose();
  57. }
  58. public void Invoke(Action action)
  59. {
  60. ManualResetEventSlim actionComplete = _invokePool.Allocate();
  61. lock (_work)
  62. {
  63. _work.Enqueue(() =>
  64. {
  65. action();
  66. actionComplete.Set();
  67. });
  68. }
  69. _signal.Set();
  70. actionComplete.Wait();
  71. actionComplete.Reset();
  72. _invokePool.Release(actionComplete);
  73. }
  74. public void Dispose()
  75. {
  76. _running = false;
  77. _signal.Set();
  78. _thread.Join();
  79. _signal.Dispose();
  80. }
  81. }
  82. }