using Ryujinx.Graphics.Device; using System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; namespace Ryujinx.Graphics.Gpu.Engine { /// /// State interface with a shadow memory control register. /// interface IShadowState { /// /// MME shadow ram control mode. /// SetMmeShadowRamControlMode SetMmeShadowRamControlMode { get; } } /// /// Represents a device's state, with a additional shadow state. /// /// Type of the state class DeviceStateWithShadow<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TState> : IDeviceState where TState : unmanaged, IShadowState { private readonly DeviceState _state; private readonly DeviceState _shadowState; /// /// Current device state. /// public ref TState State => ref _state.State; /// /// Creates a new instance of the device state, with shadow state. /// /// Optional that will be called if a register specified by name is read or written /// Optional callback to be used for debug log messages public DeviceStateWithShadow(IReadOnlyDictionary callbacks = null, Action debugLogCallback = null) { _state = new DeviceState(callbacks, debugLogCallback); _shadowState = new DeviceState(); } /// /// Reads a value from a register. /// /// Register offset in bytes /// Value stored on the register [MethodImpl(MethodImplOptions.AggressiveInlining)] public int Read(int offset) { return _state.Read(offset); } /// /// Writes a value to a register. /// /// Register offset in bytes /// Value to be written [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Write(int offset, int value) { WriteWithRedundancyCheck(offset, value, out _); } /// /// Writes a value to a register, returning a value indicating if /// is different from the current value on the register. /// /// Register offset in bytes /// Value to be written /// True if the value was changed, false otherwise [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteWithRedundancyCheck(int offset, int value, out bool changed) { var shadowRamControl = _state.State.SetMmeShadowRamControlMode; if (shadowRamControl == SetMmeShadowRamControlMode.MethodPassthrough || offset < 0x200) { _state.WriteWithRedundancyCheck(offset, value, out changed); } else if (shadowRamControl == SetMmeShadowRamControlMode.MethodTrack || shadowRamControl == SetMmeShadowRamControlMode.MethodTrackWithFilter) { _shadowState.Write(offset, value); _state.WriteWithRedundancyCheck(offset, value, out changed); } else /* if (shadowRamControl == SetMmeShadowRamControlMode.MethodReplay) */ { Debug.Assert(shadowRamControl == SetMmeShadowRamControlMode.MethodReplay); _state.WriteWithRedundancyCheck(offset, _shadowState.Read(offset), out changed); } } } }