Macro.cs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. using Ryujinx.Graphics.Device;
  2. using Ryujinx.Graphics.Gpu.Engine.GPFifo;
  3. using System;
  4. namespace Ryujinx.Graphics.Gpu.Engine.MME
  5. {
  6. /// <summary>
  7. /// GPU macro program.
  8. /// </summary>
  9. struct Macro
  10. {
  11. /// <summary>
  12. /// Word offset of the code on the code memory.
  13. /// </summary>
  14. public int Position { get; }
  15. private IMacroEE _executionEngine;
  16. private bool _executionPending;
  17. private int _argument;
  18. private MacroHLEFunctionName _hleFunction;
  19. /// <summary>
  20. /// Creates a new instance of the GPU cached macro program.
  21. /// </summary>
  22. /// <param name="position">Macro code start position</param>
  23. public Macro(int position)
  24. {
  25. Position = position;
  26. _executionEngine = null;
  27. _executionPending = false;
  28. _argument = 0;
  29. _hleFunction = MacroHLEFunctionName.None;
  30. }
  31. /// <summary>
  32. /// Sets the first argument for the macro call.
  33. /// </summary>
  34. /// <param name="context">GPU context where the macro code is being executed</param>
  35. /// <param name="processor">GPU GP FIFO command processor</param>
  36. /// <param name="code">Code to be executed</param>
  37. /// <param name="argument">First argument</param>
  38. public void StartExecution(GpuContext context, GPFifoProcessor processor, ReadOnlySpan<int> code, int argument)
  39. {
  40. _argument = argument;
  41. _executionPending = true;
  42. if (_executionEngine == null)
  43. {
  44. if (GraphicsConfig.EnableMacroHLE && MacroHLETable.TryGetMacroHLEFunction(code.Slice(Position), context.Capabilities, out _hleFunction))
  45. {
  46. _executionEngine = new MacroHLE(processor, _hleFunction);
  47. }
  48. else if (GraphicsConfig.EnableMacroJit)
  49. {
  50. _executionEngine = new MacroJit();
  51. }
  52. else
  53. {
  54. _executionEngine = new MacroInterpreter();
  55. }
  56. }
  57. // We don't consume the parameter buffer value, so we don't need to flush it.
  58. // Doing so improves performance if the value was written by a GPU shader.
  59. if (_hleFunction == MacroHLEFunctionName.DrawElementsIndirect)
  60. {
  61. context.GPFifo.SetFlushSkips(1);
  62. }
  63. else if (_hleFunction == MacroHLEFunctionName.MultiDrawElementsIndirectCount)
  64. {
  65. context.GPFifo.SetFlushSkips(2);
  66. }
  67. }
  68. /// <summary>
  69. /// Starts executing the macro program code.
  70. /// </summary>
  71. /// <param name="code">Program code</param>
  72. /// <param name="state">Current GPU state</param>
  73. public void Execute(ReadOnlySpan<int> code, IDeviceState state)
  74. {
  75. if (_executionPending)
  76. {
  77. _executionPending = false;
  78. _executionEngine?.Execute(code.Slice(Position), state, _argument);
  79. }
  80. }
  81. /// <summary>
  82. /// Pushes an argument to the macro call argument FIFO.
  83. /// </summary>
  84. /// <param name="gpuVa">GPU virtual address where the command word is located</param>
  85. /// <param name="argument">Argument to be pushed</param>
  86. public void PushArgument(ulong gpuVa, int argument)
  87. {
  88. _executionEngine?.Fifo.Enqueue(new FifoWord(gpuVa, argument));
  89. }
  90. }
  91. }