| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- using Ryujinx.Graphics.Memory;
- using System.Collections.Concurrent;
- using System.Threading;
- namespace Ryujinx.Graphics
- {
- public class DmaPusher
- {
- private ConcurrentQueue<(NvGpuVmm, long)> _ibBuffer;
- private long _dmaPut;
- private long _dmaGet;
- private struct DmaState
- {
- public int Method;
- public int SubChannel;
- public int MethodCount;
- public bool NonIncrementing;
- public bool IncrementOnce;
- public int LengthPending;
- }
- private DmaState _state;
- private bool _sliEnable;
- private bool _sliActive;
- private bool _ibEnable;
- private bool _nonMain;
- private long _dmaMGet;
- private NvGpuVmm _vmm;
- private NvGpu _gpu;
- private AutoResetEvent _event;
- public DmaPusher(NvGpu gpu)
- {
- _gpu = gpu;
- _ibBuffer = new ConcurrentQueue<(NvGpuVmm, long)>();
- _ibEnable = true;
- _event = new AutoResetEvent(false);
- }
- public void Push(NvGpuVmm vmm, long entry)
- {
- _ibBuffer.Enqueue((vmm, entry));
- _event.Set();
- }
- public bool WaitForCommands()
- {
- return _event.WaitOne(8);
- }
- public void DispatchCalls()
- {
- while (Step());
- }
- private bool Step()
- {
- if (_dmaGet != _dmaPut)
- {
- int word = _vmm.ReadInt32(_dmaGet);
- _dmaGet += 4;
- if (!_nonMain)
- {
- _dmaMGet = _dmaGet;
- }
- if (_state.LengthPending != 0)
- {
- _state.LengthPending = 0;
- _state.MethodCount = word & 0xffffff;
- }
- else if (_state.MethodCount != 0)
- {
- if (!_sliEnable || _sliActive)
- {
- CallMethod(word);
- }
- if (!_state.NonIncrementing)
- {
- _state.Method++;
- }
- if (_state.IncrementOnce)
- {
- _state.NonIncrementing = true;
- }
- _state.MethodCount--;
- }
- else
- {
- int submissionMode = (word >> 29) & 7;
- switch (submissionMode)
- {
- case 1:
- // Incrementing.
- SetNonImmediateState(word);
- _state.NonIncrementing = false;
- _state.IncrementOnce = false;
- break;
- case 3:
- // Non-incrementing.
- SetNonImmediateState(word);
- _state.NonIncrementing = true;
- _state.IncrementOnce = false;
- break;
- case 4:
- // Immediate.
- _state.Method = (word >> 0) & 0x1fff;
- _state.SubChannel = (word >> 13) & 7;
- _state.NonIncrementing = true;
- _state.IncrementOnce = false;
- CallMethod((word >> 16) & 0x1fff);
- break;
- case 5:
- // Increment-once.
- SetNonImmediateState(word);
- _state.NonIncrementing = false;
- _state.IncrementOnce = true;
- break;
- }
- }
- }
- else if (_ibEnable && _ibBuffer.TryDequeue(out (NvGpuVmm Vmm, long Entry) tuple))
- {
- _vmm = tuple.Vmm;
- long entry = tuple.Entry;
- int length = (int)(entry >> 42) & 0x1fffff;
- _dmaGet = entry & 0xfffffffffc;
- _dmaPut = _dmaGet + length * 4;
- _nonMain = (entry & (1L << 41)) != 0;
- _gpu.ResourceManager.ClearPbCache();
- }
- else
- {
- return false;
- }
- return true;
- }
- private void SetNonImmediateState(int word)
- {
- _state.Method = (word >> 0) & 0x1fff;
- _state.SubChannel = (word >> 13) & 7;
- _state.MethodCount = (word >> 16) & 0x1fff;
- }
- private void CallMethod(int argument)
- {
- _gpu.Fifo.CallMethod(_vmm, new GpuMethodCall(
- _state.Method,
- argument,
- _state.SubChannel,
- _state.MethodCount));
- }
- }
- }
|