From 9261ec6bc858948c7ba73e1ff1301e19623be933 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sat, 25 Apr 2020 10:56:56 -0300 Subject: [PATCH] Fix MME shadow RAM implementation (#1051) --- Ryujinx.Graphics.Gpu/MacroInterpreter.cs | 34 +++++---------- Ryujinx.Graphics.Gpu/NvGpuFifo.cs | 20 ++------- Ryujinx.Graphics.Gpu/State/GpuState.cs | 55 ++++++++++++++++-------- 3 files changed, 50 insertions(+), 59 deletions(-) diff --git a/Ryujinx.Graphics.Gpu/MacroInterpreter.cs b/Ryujinx.Graphics.Gpu/MacroInterpreter.cs index fa8a4a48..8d2d6202 100644 --- a/Ryujinx.Graphics.Gpu/MacroInterpreter.cs +++ b/Ryujinx.Graphics.Gpu/MacroInterpreter.cs @@ -82,8 +82,7 @@ namespace Ryujinx.Graphics.Gpu /// Optional argument passed to the program, 0 if not used /// Shadow RAM control register value /// Current GPU state - /// Shadow GPU state - public void Execute(int[] mme, int position, int param, ShadowRamControl shadowCtrl, GpuState state, GpuState shadowState) + public void Execute(int[] mme, int position, int param, ShadowRamControl shadowCtrl, GpuState state) { Reset(); @@ -95,11 +94,11 @@ namespace Ryujinx.Graphics.Gpu FetchOpCode(mme); - while (Step(mme, state, shadowState)); + while (Step(mme, state)); // Due to the delay slot, we still need to execute // one more instruction before we actually exit. - Step(mme, state, shadowState); + Step(mme, state); } /// @@ -124,9 +123,8 @@ namespace Ryujinx.Graphics.Gpu /// /// Program code to execute /// Current GPU state - /// Shadow GPU state /// True to continue execution, false if the program exited - private bool Step(int[] mme, GpuState state, GpuState shadowState) + private bool Step(int[] mme, GpuState state) { int baseAddr = _pc - 1; @@ -172,7 +170,7 @@ namespace Ryujinx.Graphics.Gpu { SetDstGpr(FetchParam()); - Send(state, shadowState, result); + Send(state, result); break; } @@ -182,7 +180,7 @@ namespace Ryujinx.Graphics.Gpu { SetDstGpr(result); - Send(state, shadowState, result); + Send(state, result); break; } @@ -204,7 +202,7 @@ namespace Ryujinx.Graphics.Gpu SetMethAddr(result); - Send(state, shadowState, FetchParam()); + Send(state, FetchParam()); break; } @@ -216,7 +214,7 @@ namespace Ryujinx.Graphics.Gpu SetMethAddr(result); - Send(state, shadowState,(result >> 12) & 0x3f); + Send(state, (result >> 12) & 0x3f); break; } @@ -489,24 +487,12 @@ namespace Ryujinx.Graphics.Gpu /// Performs a GPU method call. /// /// Current GPU state - /// Shadow GPU state /// Call argument - private void Send(GpuState state, GpuState shadowState, int value) + private void Send(GpuState state, 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); + state.CallMethod(meth, _shadowCtrl); _methAddr += _methIncr; } diff --git a/Ryujinx.Graphics.Gpu/NvGpuFifo.cs b/Ryujinx.Graphics.Gpu/NvGpuFifo.cs index 5936fa53..7628fe6b 100644 --- a/Ryujinx.Graphics.Gpu/NvGpuFifo.cs +++ b/Ryujinx.Graphics.Gpu/NvGpuFifo.cs @@ -62,13 +62,13 @@ namespace Ryujinx.Graphics.Gpu /// /// Program code /// Current GPU state - public void Execute(int[] mme, ShadowRamControl shadowCtrl, GpuState state, GpuState shadowState) + public void Execute(int[] mme, ShadowRamControl shadowCtrl, GpuState state) { if (_executionPending) { _executionPending = false; - _interpreter?.Execute(mme, Position, _argument, shadowCtrl, state, shadowState); + _interpreter?.Execute(mme, Position, _argument, shadowCtrl, state); } } @@ -101,11 +101,6 @@ namespace Ryujinx.Graphics.Gpu /// public GpuState State { get; } - /// - /// Sub-channel shadow GPU state (used as backup storage to restore MME changes). - /// - public GpuState ShadowState { get; } - /// /// Engine bound to the sub-channel. /// @@ -117,7 +112,6 @@ namespace Ryujinx.Graphics.Gpu public SubChannel() { State = new GpuState(); - ShadowState = new GpuState(); } } @@ -202,11 +196,7 @@ namespace Ryujinx.Graphics.Gpu } else if (meth.Method < 0xe00) { - SubChannel sc = _subChannels[meth.SubChannel]; - - sc.ShadowState.Write(meth.Method, meth.Argument); - - sc.State.CallMethod(meth); + _subChannels[meth.SubChannel].State.CallMethod(meth, _shadowCtrl); } else { @@ -223,9 +213,7 @@ namespace Ryujinx.Graphics.Gpu if (meth.IsLastCall) { - SubChannel sc = _subChannels[meth.SubChannel]; - - _macros[macroIndex].Execute(_mme, _shadowCtrl, sc.State, sc.ShadowState); + _macros[macroIndex].Execute(_mme, _shadowCtrl, _subChannels[meth.SubChannel].State); _context.Methods.PerformDeferredDraws(); } diff --git a/Ryujinx.Graphics.Gpu/State/GpuState.cs b/Ryujinx.Graphics.Gpu/State/GpuState.cs index a6671fe8..fb495eff 100644 --- a/Ryujinx.Graphics.Gpu/State/GpuState.cs +++ b/Ryujinx.Graphics.Gpu/State/GpuState.cs @@ -12,7 +12,8 @@ namespace Ryujinx.Graphics.Gpu.State public delegate void MethodCallback(GpuState state, int argument); - private int[] _backingMemory; + private readonly int[] _memory; + private readonly int[] _shadow; /// /// GPU register information. @@ -29,14 +30,15 @@ namespace Ryujinx.Graphics.Gpu.State public bool Modified; } - private Register[] _registers; + private readonly Register[] _registers; /// /// Creates a new instance of the GPU state. /// public GpuState() { - _backingMemory = new int[RegistersCount]; + _memory = new int[RegistersCount]; + _shadow = new int[RegistersCount]; _registers = new Register[RegistersCount]; @@ -62,25 +64,40 @@ namespace Ryujinx.Graphics.Gpu.State } } - InitializeDefaultState(); + InitializeDefaultState(_memory); + InitializeDefaultState(_shadow); } /// /// Calls a GPU method, using this state. /// /// The GPU method to be called - public void CallMethod(MethodParams meth) + /// Shadow RAM control register value + public void CallMethod(MethodParams meth, ShadowRamControl shadowCtrl) { + int value = meth.Argument; + + // TODO: Figure out what TrackWithFilter does, compared to Track. + if (shadowCtrl == ShadowRamControl.Track || + shadowCtrl == ShadowRamControl.TrackWithFilter) + { + _shadow[meth.Method] = value; + } + else if (shadowCtrl == ShadowRamControl.Replay) + { + value = _shadow[meth.Method]; + } + Register register = _registers[meth.Method]; - if (_backingMemory[meth.Method] != meth.Argument) + if (_memory[meth.Method] != value) { _registers[(int)register.BaseOffset].Modified = true; } - _backingMemory[meth.Method] = meth.Argument; + _memory[meth.Method] = value; - register.Callback?.Invoke(this, meth.Argument); + register.Callback?.Invoke(this, value); } /// @@ -90,7 +107,7 @@ namespace Ryujinx.Graphics.Gpu.State /// Data at the register public int Read(int offset) { - return _backingMemory[offset]; + return _memory[offset]; } /// @@ -100,7 +117,7 @@ namespace Ryujinx.Graphics.Gpu.State /// Value to be written public void Write(int offset, int value) { - _backingMemory[offset] = value; + _memory[offset] = value; } /// @@ -109,29 +126,29 @@ namespace Ryujinx.Graphics.Gpu.State /// The offset to be written public void SetUniformBufferOffset(int offset) { - _backingMemory[(int)MethodOffset.UniformBufferState + 3] = offset; + _memory[(int)MethodOffset.UniformBufferState + 3] = offset; } /// /// Initializes registers with the default state. /// - private void InitializeDefaultState() + private static void InitializeDefaultState(int[] memory) { // Enable Rasterizer - _backingMemory[(int)MethodOffset.RasterizeEnable] = 1; + memory[(int)MethodOffset.RasterizeEnable] = 1; // Depth ranges. for (int index = 0; index < Constants.TotalViewports; index++) { - _backingMemory[(int)MethodOffset.ViewportExtents + index * 4 + 2] = 0; - _backingMemory[(int)MethodOffset.ViewportExtents + index * 4 + 3] = 0x3F800000; + memory[(int)MethodOffset.ViewportExtents + index * 4 + 2] = 0; + memory[(int)MethodOffset.ViewportExtents + index * 4 + 3] = 0x3F800000; } // Viewport transform enable. - _backingMemory[(int)MethodOffset.ViewportTransformEnable] = 1; + memory[(int)MethodOffset.ViewportTransformEnable] = 1; // Default front stencil mask. - _backingMemory[0x4e7] = 0xff; + memory[0x4e7] = 0xff; // Conditional rendering condition. _backingMemory[0x556] = (int)Condition.Always; @@ -139,7 +156,7 @@ namespace Ryujinx.Graphics.Gpu.State // Default color mask. for (int index = 0; index < Constants.TotalRenderTargets; index++) { - _backingMemory[(int)MethodOffset.RtColorMask + index] = 0x1111; + memory[(int)MethodOffset.RtColorMask + index] = 0x1111; } // Default blend states @@ -342,7 +359,7 @@ namespace Ryujinx.Graphics.Gpu.State /// The data at the specified location public T Get(MethodOffset offset) where T : struct { - return MemoryMarshal.Cast(_backingMemory.AsSpan().Slice((int)offset))[0]; + return MemoryMarshal.Cast(_memory.AsSpan().Slice((int)offset))[0]; } ///