diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2020-03-12 22:30:26 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-03-13 12:30:26 +1100 |
| commit | ff2bac9c9042ef23437b19a32f3f2b6869cc1274 (patch) | |
| tree | f27bb1565759c0f818a56e63be3306d46c36d3ea | |
| parent | d904706fc0a14d17072f7235d73c80c4f01b1041 (diff) | |
Implement MME shadow RAM (#987)
| -rw-r--r-- | Ryujinx.Graphics.Gpu/MacroInterpreter.cs | 39 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/NvGpuFifo.cs | 30 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/NvGpuFifoMeth.cs | 13 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/ShadowRamControl.cs | 28 |
4 files changed, 90 insertions, 20 deletions
diff --git a/Ryujinx.Graphics.Gpu/MacroInterpreter.cs b/Ryujinx.Graphics.Gpu/MacroInterpreter.cs index 4287f055..fa8a4a48 100644 --- a/Ryujinx.Graphics.Gpu/MacroInterpreter.cs +++ b/Ryujinx.Graphics.Gpu/MacroInterpreter.cs @@ -45,7 +45,7 @@ namespace Ryujinx.Graphics.Gpu BitwiseNotAnd = 12 } - public Queue<int> Fifo { get; private set; } + public Queue<int> Fifo { get; } private int[] _gprs; @@ -62,6 +62,8 @@ namespace Ryujinx.Graphics.Gpu private int _pc; + private ShadowRamControl _shadowCtrl; + /// <summary> /// Creates a new instance of the macro code interpreter. /// </summary> @@ -78,8 +80,10 @@ namespace Ryujinx.Graphics.Gpu /// <param name="mme">Code of the program to execute</param> /// <param name="position">Start position to execute</param> /// <param name="param">Optional argument passed to the program, 0 if not used</param> + /// <param name="shadowCtrl">Shadow RAM control register value</param> /// <param name="state">Current GPU state</param> - public void Execute(int[] mme, int position, int param, GpuState state) + /// <param name="shadowState">Shadow GPU state</param> + public void Execute(int[] mme, int position, int param, ShadowRamControl shadowCtrl, GpuState state, GpuState shadowState) { Reset(); @@ -87,13 +91,15 @@ namespace Ryujinx.Graphics.Gpu _pc = position; + _shadowCtrl = shadowCtrl; + FetchOpCode(mme); - while (Step(mme, state)); + while (Step(mme, state, shadowState)); // Due to the delay slot, we still need to execute // one more instruction before we actually exit. - Step(mme, state); + Step(mme, state, shadowState); } /// <summary> @@ -118,8 +124,9 @@ namespace Ryujinx.Graphics.Gpu /// </summary> /// <param name="mme">Program code to execute</param> /// <param name="state">Current GPU state</param> + /// <param name="shadowState">Shadow GPU state</param> /// <returns>True to continue execution, false if the program exited</returns> - private bool Step(int[] mme, GpuState state) + private bool Step(int[] mme, GpuState state, GpuState shadowState) { int baseAddr = _pc - 1; @@ -165,7 +172,7 @@ namespace Ryujinx.Graphics.Gpu { SetDstGpr(FetchParam()); - Send(state, result); + Send(state, shadowState, result); break; } @@ -175,7 +182,7 @@ namespace Ryujinx.Graphics.Gpu { SetDstGpr(result); - Send(state, result); + Send(state, shadowState, result); break; } @@ -197,7 +204,7 @@ namespace Ryujinx.Graphics.Gpu SetMethAddr(result); - Send(state, FetchParam()); + Send(state, shadowState, FetchParam()); break; } @@ -209,7 +216,7 @@ namespace Ryujinx.Graphics.Gpu SetMethAddr(result); - Send(state, (result >> 12) & 0x3f); + Send(state, shadowState,(result >> 12) & 0x3f); break; } @@ -482,9 +489,21 @@ namespace Ryujinx.Graphics.Gpu /// Performs a GPU method call. /// </summary> /// <param name="state">Current GPU state</param> + /// <param name="shadowState">Shadow GPU state</param> /// <param name="value">Call argument</param> - private void Send(GpuState state, int value) + private void Send(GpuState state, GpuState shadowState, int value) { + // TODO: Figure out what TrackWithFilter does, compared to Track. + if (_shadowCtrl == ShadowRamControl.Track || + _shadowCtrl == ShadowRamControl.TrackWithFilter) + { + shadowState.Write(_methAddr, value); + } + else if (_shadowCtrl == ShadowRamControl.Replay) + { + value = shadowState.Read(_methAddr); + } + MethodParams meth = new MethodParams(_methAddr, value); state.CallMethod(meth); diff --git a/Ryujinx.Graphics.Gpu/NvGpuFifo.cs b/Ryujinx.Graphics.Gpu/NvGpuFifo.cs index 11a9e3fb..2056b3d4 100644 --- a/Ryujinx.Graphics.Gpu/NvGpuFifo.cs +++ b/Ryujinx.Graphics.Gpu/NvGpuFifo.cs @@ -1,4 +1,5 @@ using Ryujinx.Graphics.Gpu.State; +using System.IO; namespace Ryujinx.Graphics.Gpu { @@ -61,13 +62,13 @@ namespace Ryujinx.Graphics.Gpu /// </summary> /// <param name="mme">Program code</param> /// <param name="state">Current GPU state</param> - public void Execute(int[] mme, GpuState state) + public void Execute(int[] mme, ShadowRamControl shadowCtrl, GpuState state, GpuState shadowState) { if (_executionPending) { _executionPending = false; - _interpreter?.Execute(mme, Position, _argument, state); + _interpreter?.Execute(mme, Position, _argument, shadowCtrl, state, shadowState); } } @@ -84,6 +85,8 @@ namespace Ryujinx.Graphics.Gpu private int _currMacroPosition; private int _currMacroBindIndex; + private ShadowRamControl _shadowCtrl; + private CachedMacro[] _macros; private int[] _mme; @@ -99,6 +102,11 @@ namespace Ryujinx.Graphics.Gpu public GpuState State { get; } /// <summary> + /// Sub-channel shadow GPU state (used as backup storage to restore MME changes). + /// </summary> + public GpuState ShadowState { get; } + + /// <summary> /// Engine bound to the sub-channel. /// </summary> public ClassId Class { get; set; } @@ -109,6 +117,7 @@ namespace Ryujinx.Graphics.Gpu public SubChannel() { State = new GpuState(); + ShadowState = new GpuState(); } } @@ -188,11 +197,22 @@ namespace Ryujinx.Graphics.Gpu break; } + + case NvGpuFifoMeth.SetMmeShadowRamControl: + { + _shadowCtrl = (ShadowRamControl)meth.Argument; + + break; + } } } else if (meth.Method < 0xe00) { - _subChannels[meth.SubChannel].State.CallMethod(meth); + SubChannel sc = _subChannels[meth.SubChannel]; + + sc.ShadowState.Write(meth.Method, meth.Argument); + + sc.State.CallMethod(meth); } else { @@ -209,7 +229,9 @@ namespace Ryujinx.Graphics.Gpu if (meth.IsLastCall) { - _macros[macroIndex].Execute(_mme, _subChannels[meth.SubChannel].State); + SubChannel sc = _subChannels[meth.SubChannel]; + + _macros[macroIndex].Execute(_mme, _shadowCtrl, sc.State, sc.ShadowState); _context.Methods.PerformDeferredDraws(); } diff --git a/Ryujinx.Graphics.Gpu/NvGpuFifoMeth.cs b/Ryujinx.Graphics.Gpu/NvGpuFifoMeth.cs index 89023407..288c97d7 100644 --- a/Ryujinx.Graphics.Gpu/NvGpuFifoMeth.cs +++ b/Ryujinx.Graphics.Gpu/NvGpuFifoMeth.cs @@ -5,11 +5,12 @@ namespace Ryujinx.Graphics.Gpu /// </summary> enum NvGpuFifoMeth { - BindChannel = 0, - WaitForIdle = 0x44, - SetMacroUploadAddress = 0x45, - SendMacroCodeData = 0x46, - SetMacroBindingIndex = 0x47, - BindMacro = 0x48 + BindChannel = 0, + WaitForIdle = 0x44, + SetMacroUploadAddress = 0x45, + SendMacroCodeData = 0x46, + SetMacroBindingIndex = 0x47, + BindMacro = 0x48, + SetMmeShadowRamControl = 0x49 } }
\ No newline at end of file diff --git a/Ryujinx.Graphics.Gpu/ShadowRamControl.cs b/Ryujinx.Graphics.Gpu/ShadowRamControl.cs new file mode 100644 index 00000000..10dd39bc --- /dev/null +++ b/Ryujinx.Graphics.Gpu/ShadowRamControl.cs @@ -0,0 +1,28 @@ +namespace Ryujinx.Graphics.Gpu +{ + /// <summary> + /// Shadow RAM Control setting. + /// </summary> + enum ShadowRamControl + { + /// <summary> + /// Track data writes and store them on shadow RAM. + /// </summary> + Track = 0, + + /// <summary> + /// Track data writes and store them on shadow RAM, with filtering. + /// </summary> + TrackWithFilter = 1, + + /// <summary> + /// Writes data directly without storing on shadow RAM. + /// </summary> + Passthrough = 2, + + /// <summary> + /// Ignore data being written and replace with data on shadow RAM instead. + /// </summary> + Replay = 3 + } +} |
