ProgramQueue.cs
  1  using Ryujinx.Graphics.GAL.Multithreading.Resources.Programs;
  2  using System;
  3  using System.Collections.Generic;
  4  using System.Threading;
  5  
  6  namespace Ryujinx.Graphics.GAL.Multithreading.Resources
  7  {
  8      /// <summary>
  9      /// A structure handling multithreaded compilation for programs.
 10      /// </summary>
 11      class ProgramQueue
 12      {
 13          private const int MaxConcurrentCompilations = 8;
 14  
 15          private readonly IRenderer _renderer;
 16  
 17          private readonly Queue<IProgramRequest> _toCompile;
 18          private readonly List<ThreadedProgram> _inProgress;
 19  
 20          public ProgramQueue(IRenderer renderer)
 21          {
 22              _renderer = renderer;
 23  
 24              _toCompile = new Queue<IProgramRequest>();
 25              _inProgress = new List<ThreadedProgram>();
 26          }
 27  
 28          public void Add(IProgramRequest request)
 29          {
 30              lock (_toCompile)
 31              {
 32                  _toCompile.Enqueue(request);
 33              }
 34          }
 35  
 36          public void ProcessQueue()
 37          {
 38              for (int i = 0; i < _inProgress.Count; i++)
 39              {
 40                  ThreadedProgram program = _inProgress[i];
 41  
 42                  ProgramLinkStatus status = program.Base.CheckProgramLink(false);
 43  
 44                  if (status != ProgramLinkStatus.Incomplete)
 45                  {
 46                      program.Compiled = true;
 47                      _inProgress.RemoveAt(i--);
 48                  }
 49              }
 50  
 51              int freeSpace = MaxConcurrentCompilations - _inProgress.Count;
 52  
 53              for (int i = 0; i < freeSpace; i++)
 54              {
 55                  // Begin compilation of some programs in the compile queue.
 56                  IProgramRequest program;
 57  
 58                  lock (_toCompile)
 59                  {
 60                      if (!_toCompile.TryDequeue(out program))
 61                      {
 62                          break;
 63                      }
 64                  }
 65  
 66                  if (program.Threaded.Base != null)
 67                  {
 68                      ProgramLinkStatus status = program.Threaded.Base.CheckProgramLink(false);
 69  
 70                      if (status != ProgramLinkStatus.Incomplete)
 71                      {
 72                          // This program is already compiled. Keep going through the queue.
 73                          program.Threaded.Compiled = true;
 74                          i--;
 75                          continue;
 76                      }
 77                  }
 78                  else
 79                  {
 80                      program.Threaded.Base = program.Create(_renderer);
 81                  }
 82  
 83                  _inProgress.Add(program.Threaded);
 84              }
 85          }
 86  
 87          /// <summary>
 88          /// Process the queue until the given program has finished compiling.
 89          /// This will begin compilation of other programs on the queue as well.
 90          /// </summary>
 91          /// <param name="program">The program to wait for</param>
 92          public void WaitForProgram(ThreadedProgram program)
 93          {
 94              Span<SpinWait> spinWait = stackalloc SpinWait[1];
 95  
 96              while (!program.Compiled)
 97              {
 98                  ProcessQueue();
 99  
100                  if (!program.Compiled)
101                  {
102                      spinWait[0].SpinOnce(-1);
103                  }
104              }
105          }
106      }
107  }