Fix automatic dynamic frame skipping

The previously used algorithm was too aggressive. This fixes the issue
by using the last second data and using a more gentle adjustment curve
to prevent huge changes in frame skipping.
This commit is contained in:
Fabrice de Gans 2023-02-15 00:15:38 -08:00 committed by Rafael Kitover
parent d1733c4505
commit f1d3f631d2
6 changed files with 42 additions and 27 deletions

View File

@ -76,7 +76,7 @@ extern void systemPossibleCartridgeRumble(bool);
extern void updateRumbleFrame(); extern void updateRumbleFrame();
extern bool systemCanChangeSoundQuality(); extern bool systemCanChangeSoundQuality();
extern void systemShowSpeed(int); extern void systemShowSpeed(int);
extern void system10Frames(int); extern void system10Frames();
extern void systemFrame(); extern void systemFrame();
extern void systemGbBorderOn(); extern void systemGbBorderOn();
extern void Sm60FPS_Init(); extern void Sm60FPS_Init();

View File

@ -5016,7 +5016,7 @@ void gbEmulate(int ticksToStop)
gbSoundTick(soundTicks); gbSoundTick(soundTicks);
if ((gbFrameCount % 10) == 0) if ((gbFrameCount % 10) == 0)
system10Frames(60); system10Frames();
if (gbFrameCount >= 60) { if (gbFrameCount >= 60) {
uint32_t currentTime = systemGetClock(); uint32_t currentTime = systemGetClock();
@ -5224,7 +5224,7 @@ void gbEmulate(int ticksToStop)
gbSoundTick(soundTicks); gbSoundTick(soundTicks);
if ((gbFrameCount % 10) == 0) if ((gbFrameCount % 10) == 0)
system10Frames(60); system10Frames();
if (gbFrameCount >= 60) { if (gbFrameCount >= 60) {
uint32_t currentTime = systemGetClock(); uint32_t currentTime = systemGetClock();

View File

@ -3859,7 +3859,7 @@ void CPULoop(int ticks)
systemFrame(); systemFrame();
if ((count % 10) == 0) { if ((count % 10) == 0) {
system10Frames(60); system10Frames();
} }
if (count == 60) { if (count == 60) {
uint32_t time = systemGetClock(); uint32_t time = systemGetClock();

View File

@ -1896,7 +1896,7 @@ void systemShowSpeed(int)
{ {
} }
void system10Frames(int) void system10Frames()
{ {
} }

View File

@ -2091,7 +2091,7 @@ void systemFrame()
{ {
} }
void system10Frames(int rate) void system10Frames()
{ {
uint32_t time = systemGetClock(); uint32_t time = systemGetClock();
if (!wasPaused && autoFrameSkip) { if (!wasPaused && autoFrameSkip) {
@ -2099,7 +2099,7 @@ void system10Frames(int rate)
int speed = 100; int speed = 100;
if (diff) if (diff)
speed = (1000000 / rate) / diff; speed = (1000000 / 60) / diff;
if (speed >= 98) { if (speed >= 98) {
frameskipadjust++; frameskipadjust++;

View File

@ -1,12 +1,15 @@
#include "../common/SoundSDL.h" #include <algorithm>
#include "config/game-control.h"
#include "config/option-proxy.h"
#include "wxvbam.h"
#include "SDL.h"
#include <wx/ffile.h> #include <wx/ffile.h>
#include <wx/generic/prntdlgg.h> #include <wx/generic/prntdlgg.h>
#include <wx/print.h> #include <wx/print.h>
#include <wx/printdlg.h> #include <wx/printdlg.h>
#include <SDL.h>
#include "../common/SoundSDL.h"
#include "config/game-control.h"
#include "config/option-proxy.h"
#include "wxvbam.h"
// These should probably be in vbamcore // These should probably be in vbamcore
int systemVerbose; int systemVerbose;
@ -469,43 +472,55 @@ void systemShowSpeed(int speed)
int systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; int systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
void system10Frames(int rate) void system10Frames() {
{
GameArea* panel = wxGetApp().frame->GetPanel(); GameArea* panel = wxGetApp().frame->GetPanel();
int fs = frameSkip; int fs = frameSkip;
if (fs < 0) { if (fs < 0) {
// I don't know why this algorithm isn't in common somewhere // We keep a rolling mean of the last second and use this value to
// as is, I copied it from SDL // adjust the systemFrameSkip value dynamically.
// Target time in ms for 10 frames at 60 FPS.
constexpr int kTarget = 10 * 1000 / 60;
static uint32_t prevclock = 0; static uint32_t prevclock = 0;
static int speedadj = 0; static int speedadj = 0;
uint32_t t = systemGetClock(); static int last_second[6] = {kTarget, kTarget, kTarget,
kTarget, kTarget, kTarget};
static size_t last_index = 0;
if (!panel->was_paused && prevclock && (t - prevclock) != (uint32_t)(10000 / rate)) { const uint32_t timestamp = systemGetClock();
int speed = t == prevclock ? 100 * 10000 / rate - (t - prevclock) : 100;
if (!panel->was_paused && prevclock) {
last_second[last_index] = systemGetClock() - prevclock;
last_index = (last_index + 1) % 6;
int average = 0;
for (size_t i = 0; i < 6; i++) {
average += last_second[i];
}
average /= 6;
const int speed = (kTarget * 100) / average;
// why 98?? // why 98??
if (speed >= 98) if (speed >= 98)
speedadj++; speedadj++;
else if (speed < 80) else if (speed < 80)
speedadj -= (90 - speed) / 5; speedadj -= (90 - speed) / 10;
else else
speedadj--; speedadj--;
if (speedadj >= 3) { if (speedadj >= 3) {
speedadj = 0; speedadj = 0;
systemFrameSkip = std::max(systemFrameSkip - 1, 0);
if (systemFrameSkip > 0)
systemFrameSkip--;
} else if (speedadj <= -2) { } else if (speedadj <= -2) {
speedadj += 2; speedadj += 2;
systemFrameSkip = std::min(systemFrameSkip + 1, 9);
if (systemFrameSkip < 9)
systemFrameSkip++;
} }
} }
prevclock = t; prevclock = timestamp;
panel->was_paused = false; panel->was_paused = false;
} }