/ src / Ryujinx.Graphics.Gpu / Engine / DeviceStateWithShadow.cs
DeviceStateWithShadow.cs
  1  using Ryujinx.Graphics.Device;
  2  using System;
  3  using System.Collections.Generic;
  4  using System.Diagnostics;
  5  using System.Diagnostics.CodeAnalysis;
  6  using System.Runtime.CompilerServices;
  7  
  8  namespace Ryujinx.Graphics.Gpu.Engine
  9  {
 10      /// <summary>
 11      /// State interface with a shadow memory control register.
 12      /// </summary>
 13      interface IShadowState
 14      {
 15          /// <summary>
 16          /// MME shadow ram control mode.
 17          /// </summary>
 18          SetMmeShadowRamControlMode SetMmeShadowRamControlMode { get; }
 19      }
 20  
 21      /// <summary>
 22      /// Represents a device's state, with a additional shadow state.
 23      /// </summary>
 24      /// <typeparam name="TState">Type of the state</typeparam>
 25      class DeviceStateWithShadow<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TState> : IDeviceState where TState : unmanaged, IShadowState
 26      {
 27          private readonly DeviceState<TState> _state;
 28          private readonly DeviceState<TState> _shadowState;
 29  
 30          /// <summary>
 31          /// Current device state.
 32          /// </summary>
 33          public ref TState State => ref _state.State;
 34  
 35          /// <summary>
 36          /// Current shadow state.
 37          /// </summary>
 38          public ref TState ShadowState => ref _shadowState.State;
 39  
 40          /// <summary>
 41          /// Creates a new instance of the device state, with shadow state.
 42          /// </summary>
 43          /// <param name="callbacks">Optional that will be called if a register specified by name is read or written</param>
 44          /// <param name="debugLogCallback">Optional callback to be used for debug log messages</param>
 45          public DeviceStateWithShadow(IReadOnlyDictionary<string, RwCallback> callbacks = null, Action<string> debugLogCallback = null)
 46          {
 47              _state = new DeviceState<TState>(callbacks, debugLogCallback);
 48              _shadowState = new DeviceState<TState>();
 49          }
 50  
 51          /// <summary>
 52          /// Reads a value from a register.
 53          /// </summary>
 54          /// <param name="offset">Register offset in bytes</param>
 55          /// <returns>Value stored on the register</returns>
 56          [MethodImpl(MethodImplOptions.AggressiveInlining)]
 57          public int Read(int offset)
 58          {
 59              return _state.Read(offset);
 60          }
 61  
 62          /// <summary>
 63          /// Writes a value to a register.
 64          /// </summary>
 65          /// <param name="offset">Register offset in bytes</param>
 66          /// <param name="value">Value to be written</param>
 67          [MethodImpl(MethodImplOptions.AggressiveInlining)]
 68          public void Write(int offset, int value)
 69          {
 70              WriteWithRedundancyCheck(offset, value, out _);
 71          }
 72  
 73          /// <summary>
 74          /// Writes a value to a register, returning a value indicating if <paramref name="value"/>
 75          /// is different from the current value on the register.
 76          /// </summary>
 77          /// <param name="offset">Register offset in bytes</param>
 78          /// <param name="value">Value to be written</param>
 79          /// <param name="changed">True if the value was changed, false otherwise</param>
 80          [MethodImpl(MethodImplOptions.AggressiveInlining)]
 81          public void WriteWithRedundancyCheck(int offset, int value, out bool changed)
 82          {
 83              var shadowRamControl = _state.State.SetMmeShadowRamControlMode;
 84              if (shadowRamControl == SetMmeShadowRamControlMode.MethodPassthrough || offset < 0x200)
 85              {
 86                  _state.WriteWithRedundancyCheck(offset, value, out changed);
 87              }
 88              else if (shadowRamControl == SetMmeShadowRamControlMode.MethodTrack ||
 89                       shadowRamControl == SetMmeShadowRamControlMode.MethodTrackWithFilter)
 90              {
 91                  _shadowState.Write(offset, value);
 92                  _state.WriteWithRedundancyCheck(offset, value, out changed);
 93              }
 94              else /* if (shadowRamControl == SetMmeShadowRamControlMode.MethodReplay) */
 95              {
 96                  Debug.Assert(shadowRamControl == SetMmeShadowRamControlMode.MethodReplay);
 97                  _state.WriteWithRedundancyCheck(offset, _shadowState.Read(offset), out changed);
 98              }
 99          }
100      }
101  }