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 Pal = "PAL";
public const string BoardName = "BoardName"; public const string BoardName = "BoardName";
public const string SyncSettings = "SyncSettings"; public const string SyncSettings = "SyncSettings";
public const string VBlankCount = "VBlankCount";
public const string CycleCount = "CycleCount"; public const string CycleCount = "CycleCount";
public const string ClockRate = "ClockRate";
public const string Core = "Core"; public const string Core = "Core";
public static bool Contains(string val) => 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(gb.IsCGBDMGMode() ? "IsCGBDMGMode" : "IsCGBMode", "1");
} }
movie.HeaderEntries.Add(HeaderKeys.CycleCount, "0");
} }
if (emulator is SMS sms) if (emulator is SMS sms)
@ -284,9 +282,10 @@ namespace BizHawk.Client.Common
movie.HeaderEntries.Add("Is32X", "1"); 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 movie.Core = ((CoreAttribute)Attribute

View File

@ -3,11 +3,6 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using BizHawk.Emulation.Common; 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 namespace BizHawk.Client.Common
{ {
@ -347,52 +342,21 @@ namespace BizHawk.Client.Common
private void HandlePlaybackEnd() private void HandlePlaybackEnd()
{ {
if (Movie.IsAtEnd() && ( if (Movie.IsAtEnd() && (Movie.Emulator is ICycleTiming cycleCore))
Movie.Core == CoreNames.Gambatte ||
Movie.Core == CoreNames.SubNesHawk ||
Movie.Core == CoreNames.SubGbHawk))
{ {
long movieValue; long coreValue = cycleCore.CycleCount;
long coreValue = 0; bool movieHasValue = Movie.HeaderEntries.TryGetValue(HeaderKeys.CycleCount, out string movieValueStr);
bool movieHasValue = true;
string movieValueStr = "";
string valueName = "";
if (Movie.Core == CoreNames.Gambatte) long movieValue = movieHasValue ? Convert.ToInt64(movieValueStr) : 0;
{
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;
var valuesMatch = movieValue == coreValue; var valuesMatch = movieValue == coreValue;
if (!movieHasValue || !valuesMatch) if (!movieHasValue || !valuesMatch)
{ {
var previousState = !movieHasValue var previousState = !movieHasValue
? $"The movie is currently missing a {valueName} count." ? $"The movie is currently missing a cycle count."
: $"The {valueName} count in the movie ({movieValue}) doesn't match the current value."; : $"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. // 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 ["GB"] = 262144.0 / 4389.0, // 59.7275005696
["GBC"] = 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 ["GBA"] = 262144.0 / 4389.0, // 59.7275005696
["NDS"] = 33513982.0 / 560190.0, // 59.8260982881 ["NDS"] = 33513982.0 / 560190.0, // 59.8260982881
["GEN"] = 53693175 / (3420.0 * 262), ["GEN"] = 53693175 / (3420.0 * 262),

View File

@ -3,6 +3,7 @@ using System.IO;
using BizHawk.Common; using BizHawk.Common;
using BizHawk.Common.IOExtensions; using BizHawk.Common.IOExtensions;
using BizHawk.Emulation.Common;
namespace BizHawk.Client.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. // The saved cycle value will only be valid if the end of the movie has been emulated.
if (this.IsAtEnd()) if (this.IsAtEnd())
{ {
if (Emulator is Emulation.Cores.Nintendo.SubNESHawk.SubNESHawk subNes) if (Emulator is ICycleTiming cycleCore)
{ {
Header[HeaderKeys.VBlankCount] = subNes.VblankCount.ToString(); Header[HeaderKeys.CycleCount] = cycleCore.CycleCount.ToString();
} Header[HeaderKeys.ClockRate] = cycleCore.ClockRate.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();
} }
} }
else else
{ {
Header.Remove(HeaderKeys.CycleCount); Header.Remove(HeaderKeys.CycleCount);
Header.Remove(HeaderKeys.VBlankCount); Header.Remove(HeaderKeys.ClockRate);
} }
} }

View File

@ -68,19 +68,16 @@ namespace BizHawk.Client.Common
get get
{ {
double dblSeconds; 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); var numCycles = Convert.ToUInt64(numCyclesStr);
double cyclesPerSecond = PlatformFrameRates.GetFrameRate("GB_Clock", IsPal); var clockRate = Convert.ToDouble(clockRateStr);
dblSeconds = numCycles / cyclesPerSecond; dblSeconds = numCycles / clockRate;
} }
else else
{ {
var numFrames = Header.TryGetValue(HeaderKeys.VBlankCount, out var numFramesStr) var numFrames = (ulong)FrameCount;
? Convert.ToUInt64(numFramesStr)
: (ulong) FrameCount;
dblSeconds = numFrames / FrameRate; dblSeconds = numFrames / FrameRate;
} }

View File

@ -1,6 +1,6 @@
namespace BizHawk.Emulation.Common namespace BizHawk.Emulation.Common
{ {
public interface ICycleTiming public interface ICycleTiming : ISpecializedEmulatorService
{ {
/// <summary> /// <summary>
/// Total elapsed emulation time relative to <see cref="ClockRate"/> /// 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 IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem();
public bool _islag = true; internal bool _islag = true;
private int _lagcount; private int _lagcount;
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -16,7 +16,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubGBHawk
set => _isLag = value; set => _isLag = value;
} }
public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem(); public IInputCallbackSystem InputCallbacks => _GBCore.InputCallbacks;
public bool _isLag = true; public bool _isLag = true;
private int _lagCount; 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(frame_cycle), ref frame_cycle);
ser.Sync(nameof(input_frame_length), ref input_frame_length); 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(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); 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, "")] [Core(CoreNames.SubGbHawk, "")]
[ServiceNotApplicable(new[] { typeof(IDriveLight) })] [ServiceNotApplicable(new[] { typeof(IDriveLight) })]
public partial class SubGBHawk : IEmulator, IStatable, IInputPollable, 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.GB, Priority = CorePriority.SuperLow)]
[CoreConstructor(VSystemID.Raw.GBC, Priority = CorePriority.SuperLow)] [CoreConstructor(VSystemID.Raw.GBC, Priority = CorePriority.SuperLow)]
@ -23,7 +23,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubGBHawk
HardReset(); HardReset();
current_cycle = 0; current_cycle = 0;
CycleCount = 0; _cycleCount = 0;
_GBStatable = _GBCore.ServiceProvider.GetService<IStatable>(); _GBStatable = _GBCore.ServiceProvider.GetService<IStatable>();
@ -43,10 +43,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubGBHawk
ser.Register(_tracer); 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 => _cycleCount;
public long CycleCount;
public double ClockRate => 4194304;
public void HardReset() => _GBCore.HardReset(); public void HardReset() => _GBCore.HardReset();
@ -74,6 +78,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubGBHawk
[FeatureNotImplemented] [FeatureNotImplemented]
public void Step(StepType type) => throw new NotImplementedException(); 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 = controller.AxisValue("Reset Cycle");
reset_cycle_int = (int)Math.Floor(reset_cycle); reset_cycle_int = (int)Math.Floor(reset_cycle);
_isLag = true; _nesCore.lagged = true;
_nesCore.alt_lag = true;
InputCallbacks.Call();
DoFrame(controller); DoFrame(controller);
@ -51,12 +48,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk
_nesCore.cpu.ext_ppu_cycle = current_cycle; _nesCore.cpu.ext_ppu_cycle = current_cycle;
} }
_isLag = _nesCore.alt_lag; _isLag = _nesCore.lagged;
if (_isLag) if (_isLag)
{ {
_lagCount++; _lagCount++;
VblankCount++;
} }
reset_frame = false; reset_frame = false;

View File

@ -16,9 +16,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk
set => _isLag = value; 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; 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(current_cycle), ref current_cycle);
ser.Sync(nameof(reset_cycle), ref reset_cycle); ser.Sync(nameof(reset_cycle), ref reset_cycle);
ser.Sync(nameof(reset_cycle_int), ref reset_cycle_int); 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(); HardReset();
current_cycle = 0; current_cycle = 0;
_nesCore.cpu.ext_ppu_cycle = current_cycle; _nesCore.cpu.ext_ppu_cycle = current_cycle;
VblankCount = 0;
_nesStatable = _nesCore.ServiceProvider.GetService<IStatable>(); _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<IDebuggable>());
ser.Register(_nesCore.ServiceProvider.GetService<IRegionable>()); ser.Register(_nesCore.ServiceProvider.GetService<IRegionable>());
ser.Register(_nesCore.ServiceProvider.GetService<ICodeDataLogger>()); 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"; 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); _tracer = new TraceBuffer(TRACE_HEADER);
@ -52,9 +52,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk
private readonly NES.NES _nesCore; private readonly NES.NES _nesCore;
// needed for movies to accurately calculate timing
public int VblankCount;
public void HardReset() => _nesCore.HardReset(); public void HardReset() => _nesCore.HardReset();
private void SoftReset() private void SoftReset()

View File

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

View File

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

View File

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