GPFifoProcessor.cs 8.0 KB

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