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 }