Core: Added runahead support (1 to 10 frames)

This commit is contained in:
Sour 2019-12-24 13:46:10 -05:00
parent fd02e406b0
commit c7675bcd49
24 changed files with 1143 additions and 964 deletions

View file

@ -720,6 +720,17 @@ void Console::RunSlaveCpu()
} }
} }
void Console::RunFrame()
{
uint32_t frameCount = _ppu->GetFrameCount();
while(_ppu->GetFrameCount() == frameCount) {
_cpu->Exec();
if(_slave) {
RunSlaveCpu();
}
}
}
void Console::Run() void Console::Run()
{ {
Timer clockTimer; Timer clockTimer;
@ -729,7 +740,6 @@ void Console::Run()
double targetTime; double targetTime;
double lastFrameMin = 9999; double lastFrameMin = 9999;
double lastFrameMax = 0; double lastFrameMax = 0;
uint32_t lastFrameNumber = -1;
double lastDelay = GetFrameDelay(); double lastDelay = GetFrameDelay();
_runLock.Acquire(); _runLock.Acquire();
@ -753,13 +763,14 @@ void Console::Run()
bool crashed = false; bool crashed = false;
try { try {
while(true) { while(true) {
_cpu->Exec(); stringstream runAheadState;
bool useRunAhead = _settings->GetRunAheadFrames() > 0 && !_debugger && !_rewindManager->IsRewinding();
if(_slave) { if(useRunAhead) {
RunSlaveCpu(); RunFrameWithRunAhead(runAheadState);
} else {
RunFrame();
} }
if(_ppu->GetFrameCount() != lastFrameNumber) {
_soundMixer->ProcessEndOfFrame(); _soundMixer->ProcessEndOfFrame();
if(_slave) { if(_slave) {
_slave->_soundMixer->ProcessEndOfFrame(); _slave->_soundMixer->ProcessEndOfFrame();
@ -816,6 +827,12 @@ void Console::Run()
//Sleep until we're ready to start the next frame //Sleep until we're ready to start the next frame
clockTimer.WaitUntil(targetTime); clockTimer.WaitUntil(targetTime);
if(useRunAhead) {
_settings->SetRunAheadFrameFlag(true);
LoadState(runAheadState);
_settings->SetRunAheadFrameFlag(false);
}
if(_pauseCounter > 0) { if(_pauseCounter > 0) {
//Need to temporarely pause the emu (to save/load a state, etc.) //Need to temporarely pause the emu (to save/load a state, etc.)
_runLock.Release(); _runLock.Release();
@ -871,14 +888,11 @@ void Console::Run()
_systemActionManager->ProcessSystemActions(); _systemActionManager->ProcessSystemActions();
lastFrameNumber = _ppu->GetFrameCount();
if(_stop) { if(_stop) {
_stop = false; _stop = false;
break; break;
} }
} }
}
} catch(const std::runtime_error &ex) { } catch(const std::runtime_error &ex) {
crashed = true; crashed = true;
_stopCode = -1; _stopCode = -1;
@ -926,6 +940,26 @@ void Console::Run()
_notificationManager->SendNotification(ConsoleNotificationType::EmulationStopped); _notificationManager->SendNotification(ConsoleNotificationType::EmulationStopped);
} }
void Console::RunFrameWithRunAhead(std::stringstream& runAheadState)
{
uint32_t runAheadFrames = _settings->GetRunAheadFrames();
_settings->SetRunAheadFrameFlag(true);
//Run a single frame and save the state (no audio/video)
RunFrame();
SaveState(runAheadState);
while(runAheadFrames > 1) {
//Run extra frames if the requested run ahead frame count is higher than 1
runAheadFrames--;
RunFrame();
}
_apu->EndFrame();
_settings->SetRunAheadFrameFlag(false);
//Run one frame normally (with audio/video output)
RunFrame();
_apu->EndFrame();
}
void Console::ResetRunTimers() void Console::ResetRunTimers()
{ {
_resetRunTimers = true; _resetRunTimers = true;
@ -1023,6 +1057,9 @@ double Console::GetFrameDelay()
void Console::SaveState(ostream &saveStream) void Console::SaveState(ostream &saveStream)
{ {
if(_initialized) { if(_initialized) {
//Send any unprocessed sound to the SoundMixer - needed for rewind
_apu->EndFrame();
_cpu->SaveSnapshot(&saveStream); _cpu->SaveSnapshot(&saveStream);
_ppu->SaveSnapshot(&saveStream); _ppu->SaveSnapshot(&saveStream);
_memoryManager->SaveSnapshot(&saveStream); _memoryManager->SaveSnapshot(&saveStream);
@ -1050,6 +1087,9 @@ void Console::LoadState(istream &loadStream)
void Console::LoadState(istream &loadStream, uint32_t stateVersion) void Console::LoadState(istream &loadStream, uint32_t stateVersion)
{ {
if(_initialized) { if(_initialized) {
//Send any unprocessed sound to the SoundMixer - needed for rewind
_apu->EndFrame();
_cpu->LoadSnapshot(&loadStream, stateVersion); _cpu->LoadSnapshot(&loadStream, stateVersion);
_ppu->LoadSnapshot(&loadStream, stateVersion); _ppu->LoadSnapshot(&loadStream, stateVersion);
_memoryManager->LoadSnapshot(&loadStream, stateVersion); _memoryManager->LoadSnapshot(&loadStream, stateVersion);
@ -1080,9 +1120,6 @@ void Console::LoadState(istream &loadStream, uint32_t stateVersion)
void Console::LoadState(uint8_t *buffer, uint32_t bufferSize) void Console::LoadState(uint8_t *buffer, uint32_t bufferSize)
{ {
//Send any unprocessed sound to the SoundMixer - needed for rewind
_apu->EndFrame();
stringstream stream; stringstream stream;
stream.write((char*)buffer, bufferSize); stream.write((char*)buffer, bufferSize);
stream.seekg(0, ios::beg); stream.seekg(0, ios::beg);

View file

@ -100,6 +100,8 @@ private:
bool _initialized = false; bool _initialized = false;
std::thread::id _emulationThreadId; std::thread::id _emulationThreadId;
void RunFrameWithRunAhead(std::stringstream& runAheadState);
void LoadHdPack(VirtualFile &romFile, VirtualFile &patchFile); void LoadHdPack(VirtualFile &romFile, VirtualFile &patchFile);
void UpdateNesModel(bool sendNotification); void UpdateNesModel(bool sendNotification);
@ -156,6 +158,7 @@ public:
void RunSingleFrame(); void RunSingleFrame();
void RunSlaveCpu(); void RunSlaveCpu();
void RunFrame();
bool UpdateHdPackMode(); bool UpdateHdPackMode();
shared_ptr<SystemActionManager> GetSystemActionManager(); shared_ptr<SystemActionManager> GetSystemActionManager();

View file

@ -293,9 +293,11 @@ void ControlManager::UpdateInputState()
debugger->ProcessEvent(EventType::InputPolled); debugger->ProcessEvent(EventType::InputPolled);
} }
if(!_console->GetSettings()->IsRunAheadFrame()) {
for(IInputRecorder* recorder : _inputRecorders) { for(IInputRecorder* recorder : _inputRecorders) {
recorder->RecordInput(_controlDevices); recorder->RecordInput(_controlDevices);
} }
}
//Used by VS System games //Used by VS System games
RemapControllerButtons(); RemapControllerButtons();

View file

@ -655,6 +655,9 @@ private:
uint32_t _sampleRate = 48000; uint32_t _sampleRate = 48000;
AudioFilterSettings _audioFilterSettings; AudioFilterSettings _audioFilterSettings;
uint32_t _runAheadFrames = 0;
bool _isRunAheadFrame = false;
NesModel _model = NesModel::Auto; NesModel _model = NesModel::Auto;
PpuModel _ppuModel = PpuModel::Ppu2C02; PpuModel _ppuModel = PpuModel::Ppu2C02;
@ -992,6 +995,26 @@ public:
return value; return value;
} }
void SetRunAheadFrames(uint32_t frameCount)
{
_runAheadFrames = frameCount;
}
uint32_t GetRunAheadFrames()
{
return _runAheadFrames;
}
void SetRunAheadFrameFlag(bool disabled)
{
_isRunAheadFrame = disabled;
}
bool IsRunAheadFrame()
{
return _isRunAheadFrame;
}
//0: No limit, Number: % of default speed (50/60fps) //0: No limit, Number: % of default speed (50/60fps)
void SetEmulationSpeed(uint32_t emulationSpeed, bool displaySpeed = false) void SetEmulationSpeed(uint32_t emulationSpeed, bool displaySpeed = false)
{ {

View file

@ -48,6 +48,10 @@ void RewindManager::ClearBuffer()
void RewindManager::ProcessNotification(ConsoleNotificationType type, void * parameter) void RewindManager::ProcessNotification(ConsoleNotificationType type, void * parameter)
{ {
if(_settings->IsRunAheadFrame()) {
return;
}
if(type == ConsoleNotificationType::PpuFrameDone) { if(type == ConsoleNotificationType::PpuFrameDone) {
_hasHistory = _history.size() >= 2; _hasHistory = _history.size() >= 2;
if(_settings->GetRewindBufferSize() > 0) { if(_settings->GetRewindBufferSize() > 0) {

View file

@ -164,7 +164,7 @@ void SoundMixer::PlayAudioBuffer(uint32_t time)
_crossFeedFilter.ApplyFilter(_outputBuffer, sampleCount, filterSettings.CrossFadeRatio); _crossFeedFilter.ApplyFilter(_outputBuffer, sampleCount, filterSettings.CrossFadeRatio);
} }
if(rewindManager && rewindManager->SendAudio(_outputBuffer, (uint32_t)sampleCount, _sampleRate)) { if(!_settings->IsRunAheadFrame() && rewindManager && rewindManager->SendAudio(_outputBuffer, (uint32_t)sampleCount, _sampleRate)) {
bool isRecording = _waveRecorder || _console->GetVideoRenderer()->IsRecording(); bool isRecording = _waveRecorder || _console->GetVideoRenderer()->IsRecording();
if(isRecording) { if(isRecording) {
shared_ptr<WaveRecorder> recorder = _waveRecorder; shared_ptr<WaveRecorder> recorder = _waveRecorder;

View file

@ -41,11 +41,9 @@ public:
{ {
if(_needReset) { if(_needReset) {
SetBit(SystemActionManager::Buttons::ResetButton); SetBit(SystemActionManager::Buttons::ResetButton);
_needReset = false;
} }
if(_needPowerCycle) { if(_needPowerCycle) {
SetBit(SystemActionManager::Buttons::PowerButton); SetBit(SystemActionManager::Buttons::PowerButton);
_needPowerCycle = false;
} }
} }
@ -72,6 +70,7 @@ public:
shared_ptr<Console> console = _console; shared_ptr<Console> console = _console;
if(console) { if(console) {
if(IsPressed(SystemActionManager::Buttons::ResetButton)) { if(IsPressed(SystemActionManager::Buttons::ResetButton)) {
_needReset = false;
console->ResetComponents(true); console->ResetComponents(true);
console->GetControlManager()->UpdateInputState(); console->GetControlManager()->UpdateInputState();
} }

View file

@ -21,6 +21,7 @@
VideoDecoder::VideoDecoder(shared_ptr<Console> console) VideoDecoder::VideoDecoder(shared_ptr<Console> console)
{ {
_console = console; _console = console;
_settings = _console->GetSettings();
_frameChanged = false; _frameChanged = false;
_stopFlag = false; _stopFlag = false;
UpdateVideoFilter(); UpdateVideoFilter();
@ -158,6 +159,10 @@ uint32_t VideoDecoder::GetFrameCount()
void VideoDecoder::UpdateFrameSync(void *ppuOutputBuffer, HdScreenInfo *hdScreenInfo) void VideoDecoder::UpdateFrameSync(void *ppuOutputBuffer, HdScreenInfo *hdScreenInfo)
{ {
if(_settings->IsRunAheadFrame()) {
return;
}
_frameNumber = _console->GetFrameCount(); _frameNumber = _console->GetFrameCount();
_hdScreenInfo = hdScreenInfo; _hdScreenInfo = hdScreenInfo;
_ppuOutputBuffer = (uint16_t*)ppuOutputBuffer; _ppuOutputBuffer = (uint16_t*)ppuOutputBuffer;
@ -167,6 +172,10 @@ void VideoDecoder::UpdateFrameSync(void *ppuOutputBuffer, HdScreenInfo *hdScreen
void VideoDecoder::UpdateFrame(void *ppuOutputBuffer, HdScreenInfo *hdScreenInfo) void VideoDecoder::UpdateFrame(void *ppuOutputBuffer, HdScreenInfo *hdScreenInfo)
{ {
if(_settings->IsRunAheadFrame()) {
return;
}
if(_frameChanged) { if(_frameChanged) {
//Last frame isn't done decoding yet - sometimes Signal() introduces a 25-30ms delay //Last frame isn't done decoding yet - sometimes Signal() introduces a 25-30ms delay
while(_frameChanged) { while(_frameChanged) {

View file

@ -27,7 +27,7 @@ class VideoDecoder
{ {
private: private:
shared_ptr<Console> _console; shared_ptr<Console> _console;
EmulationSettings* _settings;
uint16_t *_ppuOutputBuffer = nullptr; uint16_t *_ppuOutputBuffer = nullptr;
HdScreenInfo *_hdScreenInfo = nullptr; HdScreenInfo *_hdScreenInfo = nullptr;
bool _hdFilterEnabled = false; bool _hdFilterEnabled = false;

View file

@ -38,6 +38,7 @@ namespace Mesen.GUI.Config
[MinMax(0, 5000)] public UInt32 EmulationSpeed = 100; [MinMax(0, 5000)] public UInt32 EmulationSpeed = 100;
[MinMax(0, 5000)] public UInt32 TurboSpeed = 300; [MinMax(0, 5000)] public UInt32 TurboSpeed = 300;
[MinMax(0, 5000)] public UInt32 RewindSpeed = 100; [MinMax(0, 5000)] public UInt32 RewindSpeed = 100;
[MinMax(0, 10)] public UInt32 RunAheadFrames = 0;
public EmulationInfo() public EmulationInfo()
{ {
@ -49,6 +50,7 @@ namespace Mesen.GUI.Config
InteropEmu.SetEmulationSpeed(emulationInfo.EmulationSpeed); InteropEmu.SetEmulationSpeed(emulationInfo.EmulationSpeed);
InteropEmu.SetTurboRewindSpeed(emulationInfo.TurboSpeed, emulationInfo.RewindSpeed); InteropEmu.SetTurboRewindSpeed(emulationInfo.TurboSpeed, emulationInfo.RewindSpeed);
InteropEmu.SetRunAheadFrames(emulationInfo.RunAheadFrames);
InteropEmu.SetFlag(EmulationFlags.Mmc3IrqAltBehavior, emulationInfo.UseAlternativeMmc3Irq); InteropEmu.SetFlag(EmulationFlags.Mmc3IrqAltBehavior, emulationInfo.UseAlternativeMmc3Irq);
InteropEmu.SetFlag(EmulationFlags.AllowInvalidInput, emulationInfo.AllowInvalidInput); InteropEmu.SetFlag(EmulationFlags.AllowInvalidInput, emulationInfo.AllowInvalidInput);

View file

@ -308,6 +308,8 @@
<Control ID="lblEmulationSpeed">Velocitat d'emulació:</Control> <Control ID="lblEmulationSpeed">Velocitat d'emulació:</Control>
<Control ID="lblRewindSpeedHint">% (0 = Velocitat màxima)</Control> <Control ID="lblRewindSpeedHint">% (0 = Velocitat màxima)</Control>
<Control ID="lblRewindSpeed">Velocitat del rebobinat:</Control> <Control ID="lblRewindSpeed">Velocitat del rebobinat:</Control>
<Control ID="lblRunAhead">Run Ahead:</Control>
<Control ID="lblRunAheadFrames">frames (reduces input lag, increases CPU usage)</Control>
<Control ID="tpgAdvanced">Avançat</Control> <Control ID="tpgAdvanced">Avançat</Control>
<Control ID="lblDeveloperSettings">Recommended settings for developers (homebrew / ROM hacking)</Control> <Control ID="lblDeveloperSettings">Recommended settings for developers (homebrew / ROM hacking)</Control>

View file

@ -308,6 +308,8 @@
<Control ID="lblTurboSpeed">Fast Forward Speed:</Control> <Control ID="lblTurboSpeed">Fast Forward Speed:</Control>
<Control ID="lblRewindSpeedHint">% (0 = Maximum speed)</Control> <Control ID="lblRewindSpeedHint">% (0 = Maximum speed)</Control>
<Control ID="lblRewindSpeed">Rewind Speed:</Control> <Control ID="lblRewindSpeed">Rewind Speed:</Control>
<Control ID="lblRunAhead">Run Ahead:</Control>
<Control ID="lblRunAheadFrames">frames (reduces input lag, increases CPU usage)</Control>
<Control ID="tpgAdvanced">Advanced</Control> <Control ID="tpgAdvanced">Advanced</Control>
<Control ID="lblDeveloperSettings">Recommended settings for developers (homebrew / ROM hacking)</Control> <Control ID="lblDeveloperSettings">Recommended settings for developers (homebrew / ROM hacking)</Control>

View file

@ -307,6 +307,8 @@
<Control ID="lblEmulationSpeed">Velocidad de emulación:</Control> <Control ID="lblEmulationSpeed">Velocidad de emulación:</Control>
<Control ID="lblRewindSpeedHint">% (0 = Velocidad máxima)</Control> <Control ID="lblRewindSpeedHint">% (0 = Velocidad máxima)</Control>
<Control ID="lblRewindSpeed">Velocidad de rebobinado:</Control> <Control ID="lblRewindSpeed">Velocidad de rebobinado:</Control>
<Control ID="lblRunAhead">Run Ahead:</Control>
<Control ID="lblRunAheadFrames">frames (reduces input lag, increases CPU usage)</Control>
<Control ID="tpgAdvanced">Avanzado</Control> <Control ID="tpgAdvanced">Avanzado</Control>
<Control ID="lblDeveloperSettings">Configuración recomendada para desarrolladores (homebrew / ROM hacking)</Control> <Control ID="lblDeveloperSettings">Configuración recomendada para desarrolladores (homebrew / ROM hacking)</Control>

View file

@ -308,6 +308,8 @@
<Control ID="lblTurboSpeed">Vitesse d'avance rapide :</Control> <Control ID="lblTurboSpeed">Vitesse d'avance rapide :</Control>
<Control ID="lblRewindSpeedHint">% (0 = Vitesse maximale)</Control> <Control ID="lblRewindSpeedHint">% (0 = Vitesse maximale)</Control>
<Control ID="lblRewindSpeed">Vitesse du rembobinage :</Control> <Control ID="lblRewindSpeed">Vitesse du rembobinage :</Control>
<Control ID="lblRunAhead">Run Ahead:</Control>
<Control ID="lblRunAheadFrames">images (réduit l'input lag, au coût de la performance)</Control>
<Control ID="tpgAdvanced">Avancé</Control> <Control ID="tpgAdvanced">Avancé</Control>
<Control ID="lblDeveloperSettings">Options recommandées pour les développeurs (homebrew / ROM hacking)</Control> <Control ID="lblDeveloperSettings">Options recommandées pour les développeurs (homebrew / ROM hacking)</Control>

View file

@ -308,6 +308,8 @@
<Control ID="lblTurboSpeed">Velocità avanti veloce:</Control> <Control ID="lblTurboSpeed">Velocità avanti veloce:</Control>
<Control ID="lblRewindSpeedHint">% (0 = Velocità massima)</Control> <Control ID="lblRewindSpeedHint">% (0 = Velocità massima)</Control>
<Control ID="lblRewindSpeed">Velocità Riavvolgimento:</Control> <Control ID="lblRewindSpeed">Velocità Riavvolgimento:</Control>
<Control ID="lblRunAhead">Run Ahead:</Control>
<Control ID="lblRunAheadFrames">frames (reduces input lag, increases CPU usage)</Control>
<Control ID="tpgAdvanced">Avanzato</Control> <Control ID="tpgAdvanced">Avanzato</Control>
<Control ID="lblDeveloperSettings">Opzioni raccomandate per sviluppatori (homebrew / ROM hacking)</Control> <Control ID="lblDeveloperSettings">Opzioni raccomandate per sviluppatori (homebrew / ROM hacking)</Control>

View file

@ -307,6 +307,8 @@
<Control ID="lblTurboSpeed">早送りの速度:</Control> <Control ID="lblTurboSpeed">早送りの速度:</Control>
<Control ID="lblRewindSpeedHint">% (0 = 最高速度)</Control> <Control ID="lblRewindSpeedHint">% (0 = 最高速度)</Control>
<Control ID="lblRewindSpeed">巻き戻しの速度:</Control> <Control ID="lblRewindSpeed">巻き戻しの速度:</Control>
<Control ID="lblRunAhead">Run Ahead:</Control>
<Control ID="lblRunAheadFrames">フレーム (入力遅延低下)</Control>
<Control ID="tpgAdvanced">詳細設定</Control> <Control ID="tpgAdvanced">詳細設定</Control>
<Control ID="lblDeveloperSettings">開発者向け設定 (自作ソフト / ROM hacking)</Control> <Control ID="lblDeveloperSettings">開発者向け設定 (自作ソフト / ROM hacking)</Control>

View file

@ -308,6 +308,8 @@
<Control ID="lblTurboSpeed">Velocidade de avanço rápido:</Control> <Control ID="lblTurboSpeed">Velocidade de avanço rápido:</Control>
<Control ID="lblRewindSpeedHint">% (0 = Velocidade máxima)</Control> <Control ID="lblRewindSpeedHint">% (0 = Velocidade máxima)</Control>
<Control ID="lblRewindSpeed">Velocidade de rebobinamento:</Control> <Control ID="lblRewindSpeed">Velocidade de rebobinamento:</Control>
<Control ID="lblRunAhead">Run Ahead:</Control>
<Control ID="lblRunAheadFrames">frames (reduces input lag, increases CPU usage)</Control>
<Control ID="tpgAdvanced">Avançado</Control> <Control ID="tpgAdvanced">Avançado</Control>
<Control ID="lblDeveloperSettings">Configurações recomendadas para programadores (homebrew / ROM hacking)</Control> <Control ID="lblDeveloperSettings">Configurações recomendadas para programadores (homebrew / ROM hacking)</Control>

View file

@ -307,6 +307,8 @@
<Control ID="lblTurboSpeed">Перемотка:</Control> <Control ID="lblTurboSpeed">Перемотка:</Control>
<Control ID="lblRewindSpeedHint">% (0 = Максимальная скорость)</Control> <Control ID="lblRewindSpeedHint">% (0 = Максимальная скорость)</Control>
<Control ID="lblRewindSpeed">Скорость перемотки:</Control> <Control ID="lblRewindSpeed">Скорость перемотки:</Control>
<Control ID="lblRunAhead">Run Ahead:</Control>
<Control ID="lblRunAheadFrames">frames (reduces input lag, increases CPU usage)</Control>
<Control ID="tpgAdvanced">Расширенные</Control> <Control ID="tpgAdvanced">Расширенные</Control>
<Control ID="lblDeveloperSettings">Рекомендованные настройки для разработчиков (homebrew / ROM hacking)</Control> <Control ID="lblDeveloperSettings">Рекомендованные настройки для разработчиков (homebrew / ROM hacking)</Control>

View file

@ -307,6 +307,8 @@
<Control ID="lblTurboSpeed">Перемотка:</Control> <Control ID="lblTurboSpeed">Перемотка:</Control>
<Control ID="lblRewindSpeedHint">% (0 = Максимальна швидкiсть)</Control> <Control ID="lblRewindSpeedHint">% (0 = Максимальна швидкiсть)</Control>
<Control ID="lblRewindSpeed">Швидкість перемотування:</Control> <Control ID="lblRewindSpeed">Швидкість перемотування:</Control>
<Control ID="lblRunAhead">Run Ahead:</Control>
<Control ID="lblRunAheadFrames">frames (reduces input lag, increases CPU usage)</Control>
<Control ID="tpgAdvanced">Розширені</Control> <Control ID="tpgAdvanced">Розширені</Control>
<Control ID="lblDeveloperSettings">Recommended settings for developers (homebrew / ROM hacking)</Control> <Control ID="lblDeveloperSettings">Recommended settings for developers (homebrew / ROM hacking)</Control>

View file

@ -334,6 +334,8 @@
<Control ID="lblTurboSpeed">快进速度:</Control> <Control ID="lblTurboSpeed">快进速度:</Control>
<Control ID="lblRewindSpeedHint">% (0 = 最快)</Control> <Control ID="lblRewindSpeedHint">% (0 = 最快)</Control>
<Control ID="lblRewindSpeed">快退速度:</Control> <Control ID="lblRewindSpeed">快退速度:</Control>
<Control ID="lblRunAhead">Run Ahead:</Control>
<Control ID="lblRunAheadFrames">frames (reduces input lag, increases CPU usage)</Control>
<Control ID="tpgAdvanced">高级</Control> <Control ID="tpgAdvanced">高级</Control>
<Control ID="lblDeveloperSettings">开发者推荐设置 (自作/修改 ROM)</Control> <Control ID="lblDeveloperSettings">开发者推荐设置 (自作/修改 ROM)</Control>

View file

@ -34,6 +34,10 @@ namespace Mesen.GUI.Forms.Config
this.tabMain = new System.Windows.Forms.TabControl(); this.tabMain = new System.Windows.Forms.TabControl();
this.tpgGeneral = new System.Windows.Forms.TabPage(); this.tpgGeneral = new System.Windows.Forms.TabPage();
this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel(); this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel();
this.flowLayoutPanel5 = new System.Windows.Forms.FlowLayoutPanel();
this.nudRunAheadFrames = new Mesen.GUI.Controls.MesenNumericUpDown();
this.lblRunAheadFrames = new System.Windows.Forms.Label();
this.lblRunAhead = new System.Windows.Forms.Label();
this.flowLayoutPanel9 = new System.Windows.Forms.FlowLayoutPanel(); this.flowLayoutPanel9 = new System.Windows.Forms.FlowLayoutPanel();
this.nudTurboSpeed = new Mesen.GUI.Controls.MesenNumericUpDown(); this.nudTurboSpeed = new Mesen.GUI.Controls.MesenNumericUpDown();
this.lblTurboSpeedHint = new System.Windows.Forms.Label(); this.lblTurboSpeedHint = new System.Windows.Forms.Label();
@ -91,6 +95,7 @@ namespace Mesen.GUI.Forms.Config
this.tabMain.SuspendLayout(); this.tabMain.SuspendLayout();
this.tpgGeneral.SuspendLayout(); this.tpgGeneral.SuspendLayout();
this.tableLayoutPanel4.SuspendLayout(); this.tableLayoutPanel4.SuspendLayout();
this.flowLayoutPanel5.SuspendLayout();
this.flowLayoutPanel9.SuspendLayout(); this.flowLayoutPanel9.SuspendLayout();
this.flowLayoutPanel6.SuspendLayout(); this.flowLayoutPanel6.SuspendLayout();
this.flowLayoutPanel10.SuspendLayout(); this.flowLayoutPanel10.SuspendLayout();
@ -142,6 +147,8 @@ namespace Mesen.GUI.Forms.Config
this.tableLayoutPanel4.ColumnCount = 2; this.tableLayoutPanel4.ColumnCount = 2;
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel4.Controls.Add(this.flowLayoutPanel5, 1, 3);
this.tableLayoutPanel4.Controls.Add(this.lblRunAhead, 0, 3);
this.tableLayoutPanel4.Controls.Add(this.flowLayoutPanel9, 1, 1); this.tableLayoutPanel4.Controls.Add(this.flowLayoutPanel9, 1, 1);
this.tableLayoutPanel4.Controls.Add(this.lblTurboSpeed, 0, 1); this.tableLayoutPanel4.Controls.Add(this.lblTurboSpeed, 0, 1);
this.tableLayoutPanel4.Controls.Add(this.flowLayoutPanel6, 1, 0); this.tableLayoutPanel4.Controls.Add(this.flowLayoutPanel6, 1, 0);
@ -151,7 +158,8 @@ namespace Mesen.GUI.Forms.Config
this.tableLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Fill; this.tableLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel4.Location = new System.Drawing.Point(3, 3); this.tableLayoutPanel4.Location = new System.Drawing.Point(3, 3);
this.tableLayoutPanel4.Name = "tableLayoutPanel4"; this.tableLayoutPanel4.Name = "tableLayoutPanel4";
this.tableLayoutPanel4.RowCount = 4; this.tableLayoutPanel4.RowCount = 5;
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
@ -159,6 +167,68 @@ namespace Mesen.GUI.Forms.Config
this.tableLayoutPanel4.Size = new System.Drawing.Size(519, 354); this.tableLayoutPanel4.Size = new System.Drawing.Size(519, 354);
this.tableLayoutPanel4.TabIndex = 0; this.tableLayoutPanel4.TabIndex = 0;
// //
// flowLayoutPanel5
//
this.flowLayoutPanel5.AutoSize = true;
this.flowLayoutPanel5.Controls.Add(this.nudRunAheadFrames);
this.flowLayoutPanel5.Controls.Add(this.lblRunAheadFrames);
this.flowLayoutPanel5.Dock = System.Windows.Forms.DockStyle.Fill;
this.flowLayoutPanel5.Location = new System.Drawing.Point(111, 81);
this.flowLayoutPanel5.Margin = new System.Windows.Forms.Padding(0);
this.flowLayoutPanel5.Name = "flowLayoutPanel5";
this.flowLayoutPanel5.Size = new System.Drawing.Size(408, 27);
this.flowLayoutPanel5.TabIndex = 18;
//
// nudRunAheadFrames
//
this.nudRunAheadFrames.DecimalPlaces = 0;
this.nudRunAheadFrames.Increment = new decimal(new int[] {
1,
0,
0,
0});
this.nudRunAheadFrames.Location = new System.Drawing.Point(3, 3);
this.nudRunAheadFrames.Maximum = new decimal(new int[] {
10,
0,
0,
0});
this.nudRunAheadFrames.MaximumSize = new System.Drawing.Size(10000, 20);
this.nudRunAheadFrames.Minimum = new decimal(new int[] {
0,
0,
0,
0});
this.nudRunAheadFrames.MinimumSize = new System.Drawing.Size(0, 21);
this.nudRunAheadFrames.Name = "nudRunAheadFrames";
this.nudRunAheadFrames.Size = new System.Drawing.Size(48, 21);
this.nudRunAheadFrames.TabIndex = 1;
this.nudRunAheadFrames.Value = new decimal(new int[] {
0,
0,
0,
0});
//
// lblRunAheadFrames
//
this.lblRunAheadFrames.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblRunAheadFrames.AutoSize = true;
this.lblRunAheadFrames.Location = new System.Drawing.Point(57, 7);
this.lblRunAheadFrames.Name = "lblRunAheadFrames";
this.lblRunAheadFrames.Size = new System.Drawing.Size(277, 13);
this.lblRunAheadFrames.TabIndex = 2;
this.lblRunAheadFrames.Text = "frames (reduces input lag, increases system requirements)";
//
// lblRunAhead
//
this.lblRunAhead.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblRunAhead.AutoSize = true;
this.lblRunAhead.Location = new System.Drawing.Point(3, 88);
this.lblRunAhead.Name = "lblRunAhead";
this.lblRunAhead.Size = new System.Drawing.Size(64, 13);
this.lblRunAhead.TabIndex = 17;
this.lblRunAhead.Text = "Run Ahead:";
//
// flowLayoutPanel9 // flowLayoutPanel9
// //
this.flowLayoutPanel9.AutoSize = true; this.flowLayoutPanel9.AutoSize = true;
@ -922,6 +992,8 @@ namespace Mesen.GUI.Forms.Config
this.tpgGeneral.PerformLayout(); this.tpgGeneral.PerformLayout();
this.tableLayoutPanel4.ResumeLayout(false); this.tableLayoutPanel4.ResumeLayout(false);
this.tableLayoutPanel4.PerformLayout(); this.tableLayoutPanel4.PerformLayout();
this.flowLayoutPanel5.ResumeLayout(false);
this.flowLayoutPanel5.PerformLayout();
this.flowLayoutPanel9.ResumeLayout(false); this.flowLayoutPanel9.ResumeLayout(false);
this.flowLayoutPanel9.PerformLayout(); this.flowLayoutPanel9.PerformLayout();
this.flowLayoutPanel6.ResumeLayout(false); this.flowLayoutPanel6.ResumeLayout(false);
@ -1010,5 +1082,9 @@ namespace Mesen.GUI.Forms.Config
private ctrlRiskyOption chkRandomizeCpuPpuAlignment; private ctrlRiskyOption chkRandomizeCpuPpuAlignment;
private ctrlRiskyOption chkEnablePpu2000ScrollGlitch; private ctrlRiskyOption chkEnablePpu2000ScrollGlitch;
private ctrlRiskyOption chkEnablePpu2006ScrollGlitch; private ctrlRiskyOption chkEnablePpu2006ScrollGlitch;
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel5;
private MesenNumericUpDown nudRunAheadFrames;
private System.Windows.Forms.Label lblRunAheadFrames;
private System.Windows.Forms.Label lblRunAhead;
} }
} }

View file

@ -27,6 +27,7 @@ namespace Mesen.GUI.Forms.Config
AddBinding("EmulationSpeed", nudEmulationSpeed); AddBinding("EmulationSpeed", nudEmulationSpeed);
AddBinding("TurboSpeed", nudTurboSpeed); AddBinding("TurboSpeed", nudTurboSpeed);
AddBinding("RewindSpeed", nudRewindSpeed); AddBinding("RewindSpeed", nudRewindSpeed);
AddBinding("RunAheadFrames", nudRunAheadFrames);
AddBinding("UseAlternativeMmc3Irq", chkUseAlternativeMmc3Irq); AddBinding("UseAlternativeMmc3Irq", chkUseAlternativeMmc3Irq);
AddBinding("AllowInvalidInput", chkAllowInvalidInput); AddBinding("AllowInvalidInput", chkAllowInvalidInput);

View file

@ -31,6 +31,7 @@ namespace Mesen.GUI
[DllImport(DLLPath)] public static extern void HistoryViewerRelease(); [DllImport(DLLPath)] public static extern void HistoryViewerRelease();
[DllImport(DLLPath)] public static extern void HistoryViewerRun(); [DllImport(DLLPath)] public static extern void HistoryViewerRun();
[DllImport(DLLPath)] public static extern void HistoryViewerStop(); [DllImport(DLLPath)] public static extern void HistoryViewerStop();
[DllImport(DLLPath)] public static extern UInt32 HistoryViewerGetHistoryLength(); [DllImport(DLLPath)] public static extern UInt32 HistoryViewerGetHistoryLength();
[DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool HistoryViewerSaveMovie([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string movieFile, UInt32 startPosition, UInt32 endPosition); [DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool HistoryViewerSaveMovie([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string movieFile, UInt32 startPosition, UInt32 endPosition);
[DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool HistoryViewerCreateSaveState([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string outfileFile, UInt32 position); [DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool HistoryViewerCreateSaveState([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string outfileFile, UInt32 position);
@ -192,6 +193,7 @@ namespace Mesen.GUI
[DllImport(DLLPath)] public static extern void SetSampleRate(UInt32 sampleRate); [DllImport(DLLPath)] public static extern void SetSampleRate(UInt32 sampleRate);
[DllImport(DLLPath)] public static extern void SetAudioLatency(UInt32 msLatency); [DllImport(DLLPath)] public static extern void SetAudioLatency(UInt32 msLatency);
[DllImport(DLLPath)] public static extern void SetAudioFilterSettings(AudioFilterSettings settings); [DllImport(DLLPath)] public static extern void SetAudioFilterSettings(AudioFilterSettings settings);
[DllImport(DLLPath)] public static extern void SetRunAheadFrames(UInt32 frameCount);
[DllImport(DLLPath)] public static extern NesModel GetNesModel(); [DllImport(DLLPath)] public static extern NesModel GetNesModel();
[DllImport(DLLPath)] public static extern void SetNesModel(NesModel model); [DllImport(DLLPath)] public static extern void SetNesModel(NesModel model);

View file

@ -627,6 +627,7 @@ namespace InteropEmu {
DllExport void __stdcall SetSampleRate(uint32_t sampleRate) { _settings->SetSampleRate(sampleRate); } DllExport void __stdcall SetSampleRate(uint32_t sampleRate) { _settings->SetSampleRate(sampleRate); }
DllExport void __stdcall SetAudioLatency(uint32_t msLatency) { _settings->SetAudioLatency(msLatency); } DllExport void __stdcall SetAudioLatency(uint32_t msLatency) { _settings->SetAudioLatency(msLatency); }
DllExport void __stdcall SetAudioFilterSettings(AudioFilterSettings settings) { _settings->SetAudioFilterSettings(settings); } DllExport void __stdcall SetAudioFilterSettings(AudioFilterSettings settings) { _settings->SetAudioFilterSettings(settings); }
DllExport void __stdcall SetRunAheadFrames(uint32_t frameCount) { _settings->SetRunAheadFrames(frameCount); }
DllExport NesModel __stdcall GetNesModel() { return _console->GetModel(); } DllExport NesModel __stdcall GetNesModel() { return _console->GetModel(); }
DllExport void __stdcall SetNesModel(uint32_t model) { _settings->SetNesModel((NesModel)model); } DllExport void __stdcall SetNesModel(uint32_t model) { _settings->SetNesModel((NesModel)model); }