NvGpuFifo.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. using Ryujinx.Graphics.Gpu.State;
  2. namespace Ryujinx.Graphics.Gpu
  3. {
  4. /// <summary>
  5. /// GPU commands FIFO.
  6. /// </summary>
  7. class NvGpuFifo
  8. {
  9. private const int MacrosCount = 0x80;
  10. private const int MacroIndexMask = MacrosCount - 1;
  11. // Note: The size of the macro memory is unknown, we just make
  12. // a guess here and use 256kb as the size. Increase if needed.
  13. private const int MmeWords = 256 * 256;
  14. private GpuContext _context;
  15. /// <summary>
  16. /// Cached GPU macro program.
  17. /// </summary>
  18. private struct CachedMacro
  19. {
  20. public int Position { get; }
  21. private bool _executionPending;
  22. private int _argument;
  23. private MacroInterpreter _interpreter;
  24. /// <summary>
  25. /// Creates a new instance of the GPU cached macro program.
  26. /// </summary>
  27. /// <param name="position">Macro code start position</param>
  28. public CachedMacro(int position)
  29. {
  30. Position = position;
  31. _executionPending = false;
  32. _argument = 0;
  33. _interpreter = new MacroInterpreter();
  34. }
  35. /// <summary>
  36. /// Sets the first argument for the macro call.
  37. /// </summary>
  38. /// <param name="argument">First argument</param>
  39. public void StartExecution(int argument)
  40. {
  41. _argument = argument;
  42. _executionPending = true;
  43. }
  44. /// <summary>
  45. /// Starts executing the macro program code.
  46. /// </summary>
  47. /// <param name="mme">Program code</param>
  48. /// <param name="state">Current GPU state</param>
  49. public void Execute(int[] mme, GpuState state)
  50. {
  51. if (_executionPending)
  52. {
  53. _executionPending = false;
  54. _interpreter?.Execute(mme, Position, _argument, state);
  55. }
  56. }
  57. /// <summary>
  58. /// Pushes a argument to the macro call argument FIFO.
  59. /// </summary>
  60. /// <param name="argument">Argument to be pushed</param>
  61. public void PushArgument(int argument)
  62. {
  63. _interpreter?.Fifo.Enqueue(argument);
  64. }
  65. }
  66. private int _currMacroPosition;
  67. private int _currMacroBindIndex;
  68. private CachedMacro[] _macros;
  69. private int[] _mme;
  70. /// <summary>
  71. /// GPU sub-channel information.
  72. /// </summary>
  73. private class SubChannel
  74. {
  75. /// <summary>
  76. /// Sub-channel GPU state.
  77. /// </summary>
  78. public GpuState State { get; }
  79. /// <summary>
  80. /// Engine bound to the sub-channel.
  81. /// </summary>
  82. public ClassId Class { get; set; }
  83. /// <summary>
  84. /// Creates a new instance of the GPU sub-channel.
  85. /// </summary>
  86. public SubChannel()
  87. {
  88. State = new GpuState();
  89. }
  90. }
  91. private SubChannel[] _subChannels;
  92. /// <summary>
  93. /// Creates a new instance of the GPU commands FIFO.
  94. /// </summary>
  95. /// <param name="context">GPU emulation context</param>
  96. public NvGpuFifo(GpuContext context)
  97. {
  98. _context = context;
  99. _macros = new CachedMacro[MacrosCount];
  100. _mme = new int[MmeWords];
  101. _subChannels = new SubChannel[8];
  102. for (int index = 0; index < _subChannels.Length; index++)
  103. {
  104. _subChannels[index] = new SubChannel();
  105. context.Methods.RegisterCallbacks(_subChannels[index].State);
  106. }
  107. }
  108. /// <summary>
  109. /// Calls a GPU method.
  110. /// </summary>
  111. /// <param name="meth">GPU method call parameters</param>
  112. public void CallMethod(MethodParams meth)
  113. {
  114. if ((NvGpuFifoMeth)meth.Method == NvGpuFifoMeth.BindChannel)
  115. {
  116. _subChannels[meth.SubChannel].Class = (ClassId)meth.Argument;
  117. }
  118. else if (meth.Method < 0x60)
  119. {
  120. switch ((NvGpuFifoMeth)meth.Method)
  121. {
  122. case NvGpuFifoMeth.WaitForIdle:
  123. {
  124. _context.Methods.PerformDeferredDraws();
  125. _context.Renderer.FlushPipelines();
  126. break;
  127. }
  128. case NvGpuFifoMeth.SetMacroUploadAddress:
  129. {
  130. _currMacroPosition = meth.Argument;
  131. break;
  132. }
  133. case NvGpuFifoMeth.SendMacroCodeData:
  134. {
  135. _mme[_currMacroPosition++] = meth.Argument;
  136. break;
  137. }
  138. case NvGpuFifoMeth.SetMacroBindingIndex:
  139. {
  140. _currMacroBindIndex = meth.Argument;
  141. break;
  142. }
  143. case NvGpuFifoMeth.BindMacro:
  144. {
  145. int position = meth.Argument;
  146. _macros[_currMacroBindIndex++] = new CachedMacro(position);
  147. break;
  148. }
  149. }
  150. }
  151. else if (meth.Method < 0xe00)
  152. {
  153. _subChannels[meth.SubChannel].State.CallMethod(meth);
  154. }
  155. else
  156. {
  157. int macroIndex = (meth.Method >> 1) & MacroIndexMask;
  158. if ((meth.Method & 1) != 0)
  159. {
  160. _macros[macroIndex].PushArgument(meth.Argument);
  161. }
  162. else
  163. {
  164. _macros[macroIndex].StartExecution(meth.Argument);
  165. }
  166. if (meth.IsLastCall)
  167. {
  168. _macros[macroIndex].Execute(_mme, _subChannels[meth.SubChannel].State);
  169. _context.Methods.PerformDeferredDraws();
  170. }
  171. }
  172. }
  173. }
  174. }