GPFifoProcessor.cs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. using Ryujinx.Graphics.Gpu.Memory;
  2. using Ryujinx.Graphics.Gpu.State;
  3. using System;
  4. using System.Runtime.CompilerServices;
  5. namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
  6. {
  7. /// <summary>
  8. /// Represents a GPU General Purpose FIFO command processor.
  9. /// </summary>
  10. class GPFifoProcessor
  11. {
  12. private const int MacrosCount = 0x80;
  13. private const int MacroIndexMask = MacrosCount - 1;
  14. private readonly GpuContext _context;
  15. private readonly GpuChannel _channel;
  16. public MemoryManager MemoryManager => _channel.MemoryManager;
  17. /// <summary>
  18. /// Internal GPFIFO state.
  19. /// </summary>
  20. private struct DmaState
  21. {
  22. public int Method;
  23. public int SubChannel;
  24. public int MethodCount;
  25. public bool NonIncrementing;
  26. public bool IncrementOnce;
  27. }
  28. private DmaState _state;
  29. private readonly GpuState[] _subChannels;
  30. private readonly GPFifoClass _fifoClass;
  31. /// <summary>
  32. /// Creates a new instance of the GPU General Purpose FIFO command processor.
  33. /// </summary>
  34. /// <param name="context">GPU context</param>
  35. /// <param name="channel">Channel that the GPFIFO processor belongs to</param>
  36. public GPFifoProcessor(GpuContext context, GpuChannel channel)
  37. {
  38. _context = context;
  39. _channel = channel;
  40. _fifoClass = new GPFifoClass(context, this);
  41. _subChannels = new GpuState[8];
  42. for (int index = 0; index < _subChannels.Length; index++)
  43. {
  44. _subChannels[index] = new GpuState(channel);
  45. _context.Methods.RegisterCallbacks(_subChannels[index]);
  46. }
  47. }
  48. /// <summary>
  49. /// Processes a command buffer.
  50. /// </summary>
  51. /// <param name="commandBuffer">Command buffer</param>
  52. public void Process(ReadOnlySpan<int> commandBuffer)
  53. {
  54. for (int index = 0; index < commandBuffer.Length; index++)
  55. {
  56. int command = commandBuffer[index];
  57. if (_state.MethodCount != 0)
  58. {
  59. Send(new MethodParams(_state.Method, command, _state.SubChannel, _state.MethodCount));
  60. if (!_state.NonIncrementing)
  61. {
  62. _state.Method++;
  63. }
  64. if (_state.IncrementOnce)
  65. {
  66. _state.NonIncrementing = true;
  67. }
  68. _state.MethodCount--;
  69. }
  70. else
  71. {
  72. CompressedMethod meth = Unsafe.As<int, CompressedMethod>(ref command);
  73. if (TryFastUniformBufferUpdate(meth, commandBuffer, index))
  74. {
  75. index += meth.MethodCount;
  76. continue;
  77. }
  78. switch (meth.SecOp)
  79. {
  80. case SecOp.IncMethod:
  81. case SecOp.NonIncMethod:
  82. case SecOp.OneInc:
  83. _state.Method = meth.MethodAddress;
  84. _state.SubChannel = meth.MethodSubchannel;
  85. _state.MethodCount = meth.MethodCount;
  86. _state.IncrementOnce = meth.SecOp == SecOp.OneInc;
  87. _state.NonIncrementing = meth.SecOp == SecOp.NonIncMethod;
  88. break;
  89. case SecOp.ImmdDataMethod:
  90. Send(new MethodParams(meth.MethodAddress, meth.ImmdData, meth.MethodSubchannel, 1));
  91. break;
  92. }
  93. }
  94. }
  95. }
  96. /// <summary>
  97. /// Tries to perform a fast constant buffer data update.
  98. /// If successful, all data will be copied at once, and <see cref="CompressedMethod.MethodCount"/> + 1
  99. /// command buffer entries will be consumed.
  100. /// </summary>
  101. /// <param name="meth">Compressed method to be checked</param>
  102. /// <param name="commandBuffer">Command buffer where <paramref name="meth"/> is contained</param>
  103. /// <param name="offset">Offset at <paramref name="commandBuffer"/> where <paramref name="meth"/> is located</param>
  104. /// <returns>True if the fast copy was successful, false otherwise</returns>
  105. private bool TryFastUniformBufferUpdate(CompressedMethod meth, ReadOnlySpan<int> commandBuffer, int offset)
  106. {
  107. int availableCount = commandBuffer.Length - offset;
  108. if (meth.MethodCount < availableCount &&
  109. meth.SecOp == SecOp.NonIncMethod &&
  110. meth.MethodAddress == (int)MethodOffset.UniformBufferUpdateData)
  111. {
  112. GpuState state = _subChannels[meth.MethodSubchannel];
  113. _context.Methods.UniformBufferUpdate(state, commandBuffer.Slice(offset + 1, meth.MethodCount));
  114. return true;
  115. }
  116. return false;
  117. }
  118. /// <summary>
  119. /// Sends a uncompressed method for processing by the graphics pipeline.
  120. /// </summary>
  121. /// <param name="meth">Method to be processed</param>
  122. private void Send(MethodParams meth)
  123. {
  124. if ((MethodOffset)meth.Method == MethodOffset.BindChannel)
  125. {
  126. _subChannels[meth.SubChannel].ClearCallbacks();
  127. _context.Methods.RegisterCallbacks(_subChannels[meth.SubChannel]);
  128. }
  129. else if (meth.Method < 0x60)
  130. {
  131. // TODO: check if macros are shared between subchannels or not. For now let's assume they are.
  132. _fifoClass.Write(meth.Method * 4, meth.Argument);
  133. }
  134. else if (meth.Method < 0xe00)
  135. {
  136. _subChannels[meth.SubChannel].CallMethod(meth);
  137. }
  138. else
  139. {
  140. int macroIndex = (meth.Method >> 1) & MacroIndexMask;
  141. if ((meth.Method & 1) != 0)
  142. {
  143. _fifoClass.MmePushArgument(macroIndex, meth.Argument);
  144. }
  145. else
  146. {
  147. _fifoClass.MmeStart(macroIndex, meth.Argument);
  148. }
  149. if (meth.IsLastCall)
  150. {
  151. _fifoClass.CallMme(macroIndex, _subChannels[meth.SubChannel]);
  152. _context.Methods.PerformDeferredDraws();
  153. }
  154. }
  155. }
  156. /// <summary>
  157. /// Sets the shadow ram control value of all sub-channels.
  158. /// </summary>
  159. /// <param name="control">New shadow ram control value</param>
  160. public void SetShadowRamControl(ShadowRamControl control)
  161. {
  162. for (int i = 0; i < _subChannels.Length; i++)
  163. {
  164. _subChannels[i].ShadowRamControl = control;
  165. }
  166. }
  167. /// <summary>
  168. /// Forces a full host state update by marking all state as modified,
  169. /// and also requests all GPU resources in use to be rebound.
  170. /// </summary>
  171. public void ForceAllDirty()
  172. {
  173. for (int index = 0; index < _subChannels.Length; index++)
  174. {
  175. _subChannels[index].ForceAllDirty();
  176. }
  177. }
  178. }
  179. }