NvGpuFifo.cs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  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, GpuState shadowState)
  54. {
  55. if (_executionPending)
  56. {
  57. _executionPending = false;
  58. _interpreter?.Execute(mme, Position, _argument, shadowCtrl, state, shadowState);
  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. /// Sub-channel shadow GPU state (used as backup storage to restore MME changes).
  86. /// </summary>
  87. public GpuState ShadowState { get; }
  88. /// <summary>
  89. /// Engine bound to the sub-channel.
  90. /// </summary>
  91. public ClassId Class { get; set; }
  92. /// <summary>
  93. /// Creates a new instance of the GPU sub-channel.
  94. /// </summary>
  95. public SubChannel()
  96. {
  97. State = new GpuState();
  98. ShadowState = new GpuState();
  99. }
  100. }
  101. private SubChannel[] _subChannels;
  102. private SubChannel _fifoChannel;
  103. /// <summary>
  104. /// Creates a new instance of the GPU commands FIFO.
  105. /// </summary>
  106. /// <param name="context">GPU emulation context</param>
  107. public NvGpuFifo(GpuContext context)
  108. {
  109. _context = context;
  110. _macros = new CachedMacro[MacrosCount];
  111. _mme = new int[MmeWords];
  112. _fifoChannel = new SubChannel();
  113. _context.Methods.RegisterCallbacksForFifo(_fifoChannel.State);
  114. _subChannels = new SubChannel[8];
  115. for (int index = 0; index < _subChannels.Length; index++)
  116. {
  117. _subChannels[index] = new SubChannel();
  118. _context.Methods.RegisterCallbacks(_subChannels[index].State);
  119. }
  120. }
  121. /// <summary>
  122. /// Send macro code/data to the MME
  123. /// </summary>
  124. /// <param name="index">The index in the MME</param>
  125. /// <param name="data">The data to use</param>
  126. public void SendMacroCodeData(int index, int data)
  127. {
  128. _mme[index] = data;
  129. }
  130. /// <summary>
  131. /// Bind a macro index to a position for the MME
  132. /// </summary>
  133. /// <param name="index">The macro index</param>
  134. /// <param name="position">The position of the macro</param>
  135. public void BindMacro(int index, int position)
  136. {
  137. _macros[index] = new CachedMacro(position);
  138. }
  139. /// <summary>
  140. /// Change the shadow RAM setting
  141. /// </summary>
  142. /// <param name="shadowCtrl">The new Shadow RAM setting</param>
  143. public void SetMmeShadowRamControl(ShadowRamControl shadowCtrl)
  144. {
  145. _shadowCtrl = shadowCtrl;
  146. }
  147. /// <summary>
  148. /// Calls a GPU method.
  149. /// </summary>
  150. /// <param name="meth">GPU method call parameters</param>
  151. public void CallMethod(MethodParams meth)
  152. {
  153. if ((MethodOffset)meth.Method == MethodOffset.BindChannel)
  154. {
  155. _subChannels[meth.SubChannel] = new SubChannel
  156. {
  157. Class = (ClassId)meth.Argument
  158. };
  159. _context.Methods.RegisterCallbacks(_subChannels[meth.SubChannel].State);
  160. }
  161. else if (meth.Method < 0x60)
  162. {
  163. // TODO: check if macros are shared between subchannels or not. For now let's assume they are.
  164. _fifoChannel.State.CallMethod(meth);
  165. }
  166. else if (meth.Method < 0xe00)
  167. {
  168. SubChannel sc = _subChannels[meth.SubChannel];
  169. sc.ShadowState.Write(meth.Method, meth.Argument);
  170. sc.State.CallMethod(meth);
  171. }
  172. else
  173. {
  174. int macroIndex = (meth.Method >> 1) & MacroIndexMask;
  175. if ((meth.Method & 1) != 0)
  176. {
  177. _macros[macroIndex].PushArgument(meth.Argument);
  178. }
  179. else
  180. {
  181. _macros[macroIndex].StartExecution(meth.Argument);
  182. }
  183. if (meth.IsLastCall)
  184. {
  185. SubChannel sc = _subChannels[meth.SubChannel];
  186. _macros[macroIndex].Execute(_mme, _shadowCtrl, sc.State, sc.ShadowState);
  187. _context.Methods.PerformDeferredDraws();
  188. }
  189. }
  190. }
  191. }
  192. }