GPFifoProcessor.cs 7.1 KB

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