DmaPusher.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. using System.Collections.Concurrent;
  2. using System.Threading;
  3. namespace Ryujinx.Graphics.Gpu
  4. {
  5. public class DmaPusher
  6. {
  7. private ConcurrentQueue<ulong> _ibBuffer;
  8. private ulong _dmaPut;
  9. private ulong _dmaGet;
  10. private struct DmaState
  11. {
  12. public int Method;
  13. public int SubChannel;
  14. public int MethodCount;
  15. public bool NonIncrementing;
  16. public bool IncrementOnce;
  17. public int LengthPending;
  18. }
  19. private DmaState _state;
  20. private bool _sliEnable;
  21. private bool _sliActive;
  22. private bool _ibEnable;
  23. private bool _nonMain;
  24. private ulong _dmaMGet;
  25. private GpuContext _context;
  26. private AutoResetEvent _event;
  27. internal DmaPusher(GpuContext context)
  28. {
  29. _context = context;
  30. _ibBuffer = new ConcurrentQueue<ulong>();
  31. _ibEnable = true;
  32. _event = new AutoResetEvent(false);
  33. }
  34. public void Push(ulong entry)
  35. {
  36. _ibBuffer.Enqueue(entry);
  37. _event.Set();
  38. }
  39. public bool WaitForCommands()
  40. {
  41. return _event.WaitOne(8);
  42. }
  43. public void DispatchCalls()
  44. {
  45. while (Step());
  46. }
  47. private bool Step()
  48. {
  49. if (_dmaGet != _dmaPut)
  50. {
  51. int word = _context.MemoryAccessor.ReadInt32(_dmaGet);
  52. _dmaGet += 4;
  53. if (!_nonMain)
  54. {
  55. _dmaMGet = _dmaGet;
  56. }
  57. if (_state.LengthPending != 0)
  58. {
  59. _state.LengthPending = 0;
  60. _state.MethodCount = word & 0xffffff;
  61. }
  62. else if (_state.MethodCount != 0)
  63. {
  64. if (!_sliEnable || _sliActive)
  65. {
  66. CallMethod(word);
  67. }
  68. if (!_state.NonIncrementing)
  69. {
  70. _state.Method++;
  71. }
  72. if (_state.IncrementOnce)
  73. {
  74. _state.NonIncrementing = true;
  75. }
  76. _state.MethodCount--;
  77. }
  78. else
  79. {
  80. int submissionMode = (word >> 29) & 7;
  81. switch (submissionMode)
  82. {
  83. case 1:
  84. // Incrementing.
  85. SetNonImmediateState(word);
  86. _state.NonIncrementing = false;
  87. _state.IncrementOnce = false;
  88. break;
  89. case 3:
  90. // Non-incrementing.
  91. SetNonImmediateState(word);
  92. _state.NonIncrementing = true;
  93. _state.IncrementOnce = false;
  94. break;
  95. case 4:
  96. // Immediate.
  97. _state.Method = (word >> 0) & 0x1fff;
  98. _state.SubChannel = (word >> 13) & 7;
  99. _state.NonIncrementing = true;
  100. _state.IncrementOnce = false;
  101. CallMethod((word >> 16) & 0x1fff);
  102. break;
  103. case 5:
  104. // Increment-once.
  105. SetNonImmediateState(word);
  106. _state.NonIncrementing = false;
  107. _state.IncrementOnce = true;
  108. break;
  109. }
  110. }
  111. }
  112. else if (_ibEnable && _ibBuffer.TryDequeue(out ulong entry))
  113. {
  114. ulong length = (entry >> 42) & 0x1fffff;
  115. _dmaGet = entry & 0xfffffffffc;
  116. _dmaPut = _dmaGet + length * 4;
  117. _nonMain = (entry & (1UL << 41)) != 0;
  118. }
  119. else
  120. {
  121. return false;
  122. }
  123. return true;
  124. }
  125. private void SetNonImmediateState(int word)
  126. {
  127. _state.Method = (word >> 0) & 0x1fff;
  128. _state.SubChannel = (word >> 13) & 7;
  129. _state.MethodCount = (word >> 16) & 0x1fff;
  130. }
  131. private void CallMethod(int argument)
  132. {
  133. _context.Fifo.CallMethod(new MethodParams(
  134. _state.Method,
  135. argument,
  136. _state.SubChannel,
  137. _state.MethodCount));
  138. }
  139. }
  140. }