ICycleTiming for PSX (Nymashock), actually use ICycleTiming for bk2s, general cleanup, retire VBlankCount in favor of ICycleTiming, make SubNES/GBHawk use actual lag frames instead of lag is vblank

This commit is contained in:
CasualPokePlayer 2022-02-02 22:52:09 -08:00
parent 3f7c80a950
commit 9a8be9d727
22 changed files with 52 additions and 104 deletions

View File

@ -19,8 +19,8 @@ namespace BizHawk.Client.Common
public const string Pal = "PAL";
public const string BoardName = "BoardName";
public const string SyncSettings = "SyncSettings";
public const string VBlankCount = "VBlankCount";
public const string CycleCount = "CycleCount";
public const string ClockRate = "ClockRate";
public const string Core = "Core";
public static bool Contains(string val) =>

View File

@ -257,8 +257,6 @@ namespace BizHawk.Client.Common
{
movie.HeaderEntries.Add(gb.IsCGBDMGMode() ? "IsCGBDMGMode" : "IsCGBMode", "1");
}
movie.HeaderEntries.Add(HeaderKeys.CycleCount, "0");
}
if (emulator is SMS sms)
@ -284,9 +282,10 @@ namespace BizHawk.Client.Common
movie.HeaderEntries.Add("Is32X", "1");
}
if (emulator is SubNESHawk)
if (emulator is ICycleTiming)
{
movie.HeaderEntries.Add(HeaderKeys.VBlankCount, "0");
movie.HeaderEntries.Add(HeaderKeys.CycleCount, "0");
movie.HeaderEntries.Add(HeaderKeys.ClockRate, "0");
}
movie.Core = ((CoreAttribute)Attribute

View File

@ -3,11 +3,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores;
using BizHawk.Emulation.Cores.Nintendo.Gameboy;
using BizHawk.Emulation.Cores.Nintendo.Sameboy;
using BizHawk.Emulation.Cores.Nintendo.SubNESHawk;
using BizHawk.Emulation.Cores.Nintendo.SubGBHawk;
namespace BizHawk.Client.Common
{
@ -347,52 +342,21 @@ namespace BizHawk.Client.Common
private void HandlePlaybackEnd()
{
if (Movie.IsAtEnd() && (
Movie.Core == CoreNames.Gambatte ||
Movie.Core == CoreNames.SubNesHawk ||
Movie.Core == CoreNames.SubGbHawk))
if (Movie.IsAtEnd() && (Movie.Emulator is ICycleTiming cycleCore))
{
long movieValue;
long coreValue = 0;
bool movieHasValue = true;
string movieValueStr = "";
string valueName = "";
long coreValue = cycleCore.CycleCount;
bool movieHasValue = Movie.HeaderEntries.TryGetValue(HeaderKeys.CycleCount, out string movieValueStr);
if (Movie.Core == CoreNames.Gambatte)
{
valueName = "cycle";
coreValue = ((Gameboy)Movie.Emulator).CycleCount;
movieHasValue = Movie.HeaderEntries.TryGetValue(HeaderKeys.CycleCount, out movieValueStr);
}
else if (Movie.Core == CoreNames.Sameboy)
{
valueName = "cycle";
coreValue = ((Sameboy)Movie.Emulator).CycleCount;
movieHasValue = Movie.HeaderEntries.TryGetValue(HeaderKeys.CycleCount, out movieValueStr);
}
else if (Movie.Core == CoreNames.SubGbHawk)
{
valueName = "cycle";
coreValue = ((SubGBHawk)Movie.Emulator).CycleCount;
movieHasValue = Movie.HeaderEntries.TryGetValue(HeaderKeys.CycleCount, out movieValueStr);
}
else if (Movie.Core == CoreNames.SubNesHawk)
{
valueName = "VBlank";
coreValue = ((SubNESHawk)Movie.Emulator).VblankCount;
movieHasValue = Movie.HeaderEntries.TryGetValue(HeaderKeys.VBlankCount, out movieValueStr);
}
movieValue = movieHasValue ? Convert.ToInt64(movieValueStr) : 0;
long movieValue = movieHasValue ? Convert.ToInt64(movieValueStr) : 0;
var valuesMatch = movieValue == coreValue;
if (!movieHasValue || !valuesMatch)
{
var previousState = !movieHasValue
? $"The movie is currently missing a {valueName} count."
: $"The {valueName} count in the movie ({movieValue}) doesn't match the current value.";
? $"The movie is currently missing a cycle count."
: $"The cycle count in the movie ({movieValue}) doesn't match the current value.";
// TODO: Ideally, this would be a Yes/No MessageBox that saves when "Yes" is pressed.
PopupMessage($"The end of the movie has been reached.\n\n{previousState}\n\nSave the movie to update to the current {valueName} count ({coreValue}).");
PopupMessage($"The end of the movie has been reached.\n\n{previousState}\n\nSave the movie to update to the current cycle count ({coreValue}).");
}
}

View File

@ -38,9 +38,6 @@ namespace BizHawk.Client.Common
["GB"] = 262144.0 / 4389.0, // 59.7275005696
["GBC"] = 262144.0 / 4389.0, // 59.7275005696
// RetroEdit: I don't like how this is cycles per second instead of FPS.
// It probably should be moved to a separate place.
["GB_Clock"] = 2097152.0,
["GBA"] = 262144.0 / 4389.0, // 59.7275005696
["NDS"] = 33513982.0 / 560190.0, // 59.8260982881
["GEN"] = 53693175 / (3420.0 * 262),

View File

@ -3,6 +3,7 @@ using System.IO;
using BizHawk.Common;
using BizHawk.Common.IOExtensions;
using BizHawk.Emulation.Common;
namespace BizHawk.Client.Common
{
@ -75,27 +76,16 @@ namespace BizHawk.Client.Common
// The saved cycle value will only be valid if the end of the movie has been emulated.
if (this.IsAtEnd())
{
if (Emulator is Emulation.Cores.Nintendo.SubNESHawk.SubNESHawk subNes)
if (Emulator is ICycleTiming cycleCore)
{
Header[HeaderKeys.VBlankCount] = subNes.VblankCount.ToString();
}
else if (Emulator is Emulation.Cores.Nintendo.Gameboy.Gameboy gameboy)
{
Header[HeaderKeys.CycleCount] = gameboy.CycleCount.ToString();
}
else if (Emulator is Emulation.Cores.Nintendo.Sameboy.Sameboy sameboy)
{
Header[HeaderKeys.CycleCount] = sameboy.CycleCount.ToString();
}
else if (Emulator is Emulation.Cores.Nintendo.SubGBHawk.SubGBHawk subGb)
{
Header[HeaderKeys.CycleCount] = subGb.CycleCount.ToString();
Header[HeaderKeys.CycleCount] = cycleCore.CycleCount.ToString();
Header[HeaderKeys.ClockRate] = cycleCore.ClockRate.ToString();
}
}
else
{
Header.Remove(HeaderKeys.CycleCount);
Header.Remove(HeaderKeys.VBlankCount);
Header.Remove(HeaderKeys.ClockRate);
}
}

View File

@ -68,19 +68,16 @@ namespace BizHawk.Client.Common
get
{
double dblSeconds;
var core = Header[HeaderKeys.Core];
if (Header.TryGetValue(HeaderKeys.CycleCount, out var numCyclesStr) && (core == CoreNames.Gambatte || core == CoreNames.SubGbHawk))
if (Header.TryGetValue(HeaderKeys.CycleCount, out var numCyclesStr) && Header.TryGetValue(HeaderKeys.ClockRate, out var clockRateStr))
{
var numCycles = Convert.ToUInt64(numCyclesStr);
double cyclesPerSecond = PlatformFrameRates.GetFrameRate("GB_Clock", IsPal);
dblSeconds = numCycles / cyclesPerSecond;
var clockRate = Convert.ToDouble(clockRateStr);
dblSeconds = numCycles / clockRate;
}
else
{
var numFrames = Header.TryGetValue(HeaderKeys.VBlankCount, out var numFramesStr)
? Convert.ToUInt64(numFramesStr)
: (ulong) FrameCount;
var numFrames = (ulong)FrameCount;
dblSeconds = numFrames / FrameRate;
}

View File

@ -1,6 +1,6 @@
namespace BizHawk.Emulation.Common
{
public interface ICycleTiming
public interface ICycleTiming : ISpecializedEmulatorService
{
/// <summary>
/// Total elapsed emulation time relative to <see cref="ClockRate"/>

View File

@ -18,7 +18,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem();
public bool _islag = true;
internal bool _islag = true;
private int _lagcount;
}
}

View File

@ -397,7 +397,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
public bool frame_is_done;
public bool current_strobe;
public bool new_strobe;
public bool alt_lag;
// this function will run one step of the ppu
// it will return whether the controller is read or not.
@ -850,7 +849,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
if (current_strobe && !new_strobe)
{
controller_was_latched = true;
alt_lag = false;
lagged = false;
InputCallbacks.Call();
}

View File

@ -19,7 +19,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
public IInputCallbackSystem InputCallbacks => _inputCallbacks;
private int _lagcount;
private bool lagged = true;
internal bool lagged = true;
private bool islag = false;
private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem();

View File

@ -263,7 +263,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
public ControllerDefinition ControllerDefinition { get; private set; }
private int _frame;
public int Frame { get => _frame;
public int Frame
{
get => _frame;
set => _frame = value;
}

View File

@ -51,6 +51,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubGBHawk
}
pass_a_frame = false;
_GBCore._islag = false;
InputCallbacks.Call();
@ -71,7 +72,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubGBHawk
}
current_cycle = 0;
_isLag = pass_a_frame;
_isLag = _GBCore._islag;
if (_isLag)
{
@ -113,7 +114,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubGBHawk
current_cycle++;
frame_cycle++;
CycleCount++;
_cycleCount++;
if (frame_cycle == 70224)
{

View File

@ -16,7 +16,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubGBHawk
set => _isLag = value;
}
public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem();
public IInputCallbackSystem InputCallbacks => _GBCore.InputCallbacks;
public bool _isLag = true;
private int _lagCount;

View File

@ -35,7 +35,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubGBHawk
ser.Sync(nameof(frame_cycle), ref frame_cycle);
ser.Sync(nameof(input_frame_length), ref input_frame_length);
ser.Sync(nameof(input_frame_length_int), ref input_frame_length_int);
ser.Sync(nameof(CycleCount), ref CycleCount);
ser.Sync(nameof(_cycleCount), ref _cycleCount);
ser.Sync(nameof(_GBCore.audio.master_audio_clock), ref _GBCore.audio.master_audio_clock);
}
}

View File

@ -9,7 +9,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubGBHawk
[Core(CoreNames.SubGbHawk, "")]
[ServiceNotApplicable(new[] { typeof(IDriveLight) })]
public partial class SubGBHawk : IEmulator, IStatable, IInputPollable,
ISettable<GBHawk.GBHawk.GBSettings, GBHawk.GBHawk.GBSyncSettings>, IDebuggable
ISettable<GBHawk.GBHawk.GBSettings, GBHawk.GBHawk.GBSyncSettings>, IDebuggable, ICycleTiming
{
[CoreConstructor(VSystemID.Raw.GB, Priority = CorePriority.SuperLow)]
[CoreConstructor(VSystemID.Raw.GBC, Priority = CorePriority.SuperLow)]
@ -23,7 +23,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubGBHawk
HardReset();
current_cycle = 0;
CycleCount = 0;
_cycleCount = 0;
_GBStatable = _GBCore.ServiceProvider.GetService<IStatable>();
@ -43,10 +43,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubGBHawk
ser.Register(_tracer);
}
public GBHawk.GBHawk _GBCore;
public GBHawk.GBHawk _GBCore;
// needed for movies to accurately calculate timing
private long _cycleCount;
// needed for movies to accurately calculate timing
public long CycleCount;
public long CycleCount => _cycleCount;
public double ClockRate => 4194304;
public void HardReset() => _GBCore.HardReset();
@ -74,6 +78,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubGBHawk
[FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException();
public long TotalExecutedCycles => CycleCount;
public long TotalExecutedCycles => _cycleCount;
}
}

View File

@ -35,10 +35,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk
reset_cycle = controller.AxisValue("Reset Cycle");
reset_cycle_int = (int)Math.Floor(reset_cycle);
_isLag = true;
_nesCore.alt_lag = true;
InputCallbacks.Call();
_nesCore.lagged = true;
DoFrame(controller);
@ -51,12 +48,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk
_nesCore.cpu.ext_ppu_cycle = current_cycle;
}
_isLag = _nesCore.alt_lag;
_isLag = _nesCore.lagged;
if (_isLag)
{
_lagCount++;
VblankCount++;
}
reset_frame = false;

View File

@ -16,9 +16,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk
set => _isLag = value;
}
public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem();
public IInputCallbackSystem InputCallbacks => _nesCore.InputCallbacks;
public bool _isLag = true;
private bool _isLag = true;
private int _lagCount;
}
}

View File

@ -34,7 +34,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk
ser.Sync(nameof(current_cycle), ref current_cycle);
ser.Sync(nameof(reset_cycle), ref reset_cycle);
ser.Sync(nameof(reset_cycle_int), ref reset_cycle_int);
ser.Sync(nameof(VblankCount), ref VblankCount);
}
}
}

View File

@ -19,7 +19,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk
HardReset();
current_cycle = 0;
_nesCore.cpu.ext_ppu_cycle = current_cycle;
VblankCount = 0;
_nesStatable = _nesCore.ServiceProvider.GetService<IStatable>();
@ -37,6 +36,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk
ser.Register(_nesCore.ServiceProvider.GetService<IDebuggable>());
ser.Register(_nesCore.ServiceProvider.GetService<IRegionable>());
ser.Register(_nesCore.ServiceProvider.GetService<ICodeDataLogger>());
ser.Register(_nesCore.ServiceProvider.GetService<ICycleTiming>());
const string TRACE_HEADER = "6502: PC, machine code, mnemonic, operands, registers (A, X, Y, P, SP), flags (NVTBDIZCR), CPU Cycle, PPU Cycle";
_tracer = new TraceBuffer(TRACE_HEADER);
@ -52,9 +52,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk
private readonly NES.NES _nesCore;
// needed for movies to accurately calculate timing
public int VblankCount;
public void HardReset() => _nesCore.HardReset();
private void SoftReset()

View File

@ -7,7 +7,7 @@ using BizHawk.Emulation.Cores.Waterbox;
namespace BizHawk.Emulation.Cores.Sony.PSX
{
[PortedCore(CoreNames.Nymashock, "Mednafen Team", "1.27.1", "https://mednafen.github.io/releases/")]
public class Nymashock : NymaCore, IRegionable
public class Nymashock : NymaCore, IRegionable, ICycleTiming
{
[CoreConstructor(VSystemID.Raw.PSX)]
public Nymashock(CoreLoadParameters<NymaSettings, NymaSyncSettings> lp)

View File

@ -141,6 +141,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
public int NominalHeight;
public VideoSystem VideoSystem;
public int FpsFixed;
public long MasterClock;
public int LcmWidth;
public int LcmHeight;
public int PointerScaleX;

View File

@ -147,6 +147,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
}
VsyncNumerator = info.FpsFixed;
VsyncDenominator = 1 << 24;
ClockRate = info.MasterClock / (double)0x100000000;
_soundBuffer = new short[22050 * 2];
InitControls(portData, discs?.Length > 0, ref info);
@ -256,10 +257,12 @@ namespace BizHawk.Emulation.Cores.Waterbox
private int _mdfnNominalWidth;
private int _mdfnNominalHeight;
public override int VirtualWidth => _mdfnNominalWidth;
public override int VirtualHeight =>_mdfnNominalHeight;
public override int VirtualHeight => _mdfnNominalHeight;
public DisplayType Region { get; protected set; }
public double ClockRate { get; private set; }
/// <summary>
/// Gets a string array of valid layers to pass to SetLayers, or an empty list if that method should not be called
/// </summary>