DmaPusher.cs 4.9 KB

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