Skip to content

Commit

Permalink
Fix automatic dynamic frame skipping
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Steelskin authored and rkitover committed Feb 15, 2023
1 parent d1733c4 commit f1d3f63
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 27 deletions.
2 changes: 1 addition & 1 deletion src/System.h
Expand Up @@ -76,7 +76,7 @@ extern void systemPossibleCartridgeRumble(bool);
extern void updateRumbleFrame();
extern bool systemCanChangeSoundQuality();
extern void systemShowSpeed(int);
extern void system10Frames(int);
extern void system10Frames();
extern void systemFrame();
extern void systemGbBorderOn();
extern void Sm60FPS_Init();
Expand Down
4 changes: 2 additions & 2 deletions src/gb/GB.cpp
Expand Up @@ -5016,7 +5016,7 @@ void gbEmulate(int ticksToStop)
gbSoundTick(soundTicks);

if ((gbFrameCount % 10) == 0)
system10Frames(60);
system10Frames();

if (gbFrameCount >= 60) {
uint32_t currentTime = systemGetClock();
Expand Down Expand Up @@ -5224,7 +5224,7 @@ void gbEmulate(int ticksToStop)
gbSoundTick(soundTicks);

if ((gbFrameCount % 10) == 0)
system10Frames(60);
system10Frames();

if (gbFrameCount >= 60) {
uint32_t currentTime = systemGetClock();
Expand Down
2 changes: 1 addition & 1 deletion src/gba/GBA.cpp
Expand Up @@ -3859,7 +3859,7 @@ void CPULoop(int ticks)
systemFrame();

if ((count % 10) == 0) {
system10Frames(60);
system10Frames();
}
if (count == 60) {
uint32_t time = systemGetClock();
Expand Down
2 changes: 1 addition & 1 deletion src/libretro/libretro.cpp
Expand Up @@ -1896,7 +1896,7 @@ void systemShowSpeed(int)
{
}

void system10Frames(int)
void system10Frames()
{
}

Expand Down
4 changes: 2 additions & 2 deletions src/sdl/SDL.cpp
Expand Up @@ -2091,15 +2091,15 @@ void systemFrame()
{
}

void system10Frames(int rate)
void system10Frames()
{
uint32_t time = systemGetClock();
if (!wasPaused && autoFrameSkip) {
uint32_t diff = time - autoFrameSkipLastTime;
int speed = 100;

if (diff)
speed = (1000000 / rate) / diff;
speed = (1000000 / 60) / diff;

if (speed >= 98) {
frameskipadjust++;
Expand Down
55 changes: 35 additions & 20 deletions src/wx/sys.cpp
@@ -1,12 +1,15 @@
#include "../common/SoundSDL.h"
#include "config/game-control.h"
#include "config/option-proxy.h"
#include "wxvbam.h"
#include "SDL.h"
#include <algorithm>

#include <wx/ffile.h>
#include <wx/generic/prntdlgg.h>
#include <wx/print.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
int systemVerbose;
Expand Down Expand Up @@ -469,43 +472,55 @@ void systemShowSpeed(int speed)

int systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;

void system10Frames(int rate)
{
void system10Frames() {
GameArea* panel = wxGetApp().frame->GetPanel();
int fs = frameSkip;

if (fs < 0) {
// I don't know why this algorithm isn't in common somewhere
// as is, I copied it from SDL
// We keep a rolling mean of the last second and use this value to
// 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 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)) {
int speed = t == prevclock ? 100 * 10000 / rate - (t - prevclock) : 100;
const uint32_t timestamp = systemGetClock();

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??
if (speed >= 98)
speedadj++;
else if (speed < 80)
speedadj -= (90 - speed) / 5;
speedadj -= (90 - speed) / 10;
else
speedadj--;

if (speedadj >= 3) {
speedadj = 0;

if (systemFrameSkip > 0)
systemFrameSkip--;
systemFrameSkip = std::max(systemFrameSkip - 1, 0);
} else if (speedadj <= -2) {
speedadj += 2;

if (systemFrameSkip < 9)
systemFrameSkip++;
systemFrameSkip = std::min(systemFrameSkip + 1, 9);
}
}

prevclock = t;
prevclock = timestamp;
panel->was_paused = false;
}

Expand Down

0 comments on commit f1d3f63

Please sign in to comment.