NvGpuFifo.cs 6.7 KB

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