aboutsummaryrefslogtreecommitdiff
path: root/source/nds/entry.cpp
diff options
context:
space:
mode:
authorNebuleon Fumika2013-01-07 02:16:34 -0500
committerNebuleon Fumika2013-01-07 02:16:34 -0500
commitc01c25febed921976e256d974bf97f948fe16753 (patch)
tree6cd8703c03ff4d2882ec12c1a79935b43340be46 /source/nds/entry.cpp
parent6c5bd7571644baa5693acef24d52c4fb08ed9ce3 (diff)
downloadsnes9x2005-c01c25febed921976e256d974bf97f948fe16753.tar.gz
snes9x2005-c01c25febed921976e256d974bf97f948fe16753.tar.bz2
snes9x2005-c01c25febed921976e256d974bf97f948fe16753.zip
Add support for user-selected and automatic frame skipping. Add support for PAL timings (20 ms per frame).
User-selected frameskip causes slowdowns if the game runs slower than the resulting frame rate, but synchronises correctly if the game runs faster. Automatic frame skipping is still the default. It now only skips up to 8 frames, but in some games still skips that entire 8 frames. What's needed is an algorithm that averages frame latencies over a few seconds and skips while the latency is LOWER than the average.
Diffstat (limited to 'source/nds/entry.cpp')
-rw-r--r--source/nds/entry.cpp195
1 files changed, 145 insertions, 50 deletions
diff --git a/source/nds/entry.cpp b/source/nds/entry.cpp
index 5573f47..58adf49 100644
--- a/source/nds/entry.cpp
+++ b/source/nds/entry.cpp
@@ -343,6 +343,18 @@ void game_disableAudio()
S9xSetSoundMute (TRUE);
}
}
+
+void game_set_frameskip()
+{
+ if( game_config.frameskip_value == 0)
+ {
+ Settings.SkipFrames = AUTO_FRAMERATE;
+ }
+ else
+ {
+ Settings.SkipFrames = game_config.frameskip_value - 1 /* 1 -> 0 and so on */;
+ }
+}
void init_sfc_setting(void)
{
@@ -368,7 +380,6 @@ void init_sfc_setting(void)
Settings.ShutdownMaster = TRUE;
Settings.FrameTimePAL = 20000;
Settings.FrameTimeNTSC = 16667;
- Settings.FrameTime = Settings.FrameTimeNTSC;
Settings.DisableSampleCaching = FALSE;
Settings.DisableMasterVolume = FALSE;
Settings.Mouse = TRUE;
@@ -449,10 +460,12 @@ int load_gamepak(char* file)
game_disableAudio();
CPU.Flags = 0;
- S9xReset ();
// mdelay(50); // Delete this delay
if (!Memory.LoadROM (file))
return -1;
+ S9xReset ();
+
+ Settings.FrameTime = (Settings.PAL ? Settings.FrameTimePAL : Settings.FrameTimeNTSC);
Memory.LoadSRAM (S9xGetFilename (".srm"));
// mdelay(50); // Delete this delay
@@ -611,41 +624,18 @@ int sfc_main (int argc, char **argv)
return (0);
}
+static unsigned int sync_last= 0;
+static unsigned int sync_next = 0;
+static unsigned int framenum = 0;
+
+extern "C" u32 game_fast_forward;
+
+static unsigned int skip_rate= 0;
+
void S9xSyncSpeed ()
{
-#if 0
-#ifdef _NETPLAY_SUPPORT
- if (Settings.NetPlay)
- {
- // XXX: Send joypad position update to server
- // XXX: Wait for heart beat from server
- S9xNetPlaySendJoypadUpdate (joypads [0]);
- if (!S9xNetPlayCheckForHeartBeat ())
- {
- do
- {
- CHECK_SOUND ();
-// S9xProcessEvents (FALSE);
- } while (!S9xNetPlayCheckForHeartBeat ());
- IPPU.RenderThisFrame = TRUE;
- IPPU.SkippedFrames = 0;
- }
- else
- {
- if (IPPU.SkippedFrames < 10)
- {
- IPPU.SkippedFrames++;
- IPPU.RenderThisFrame = FALSE;
- }
- else
- {
- IPPU.RenderThisFrame = TRUE;
- IPPU.SkippedFrames = 0;
- }
- }
- }
- else
-#endif
+ uint32 syncnow;
+ int32 syncdif;
#if 0
if (Settings.SoundSync == 2)
@@ -655,30 +645,135 @@ void S9xSyncSpeed ()
return;
}
#endif
+ syncnow = getSysTime();
+
+ if (game_fast_forward)
+ {
+ sync_last = syncnow;
+ sync_next = syncnow;
+ if(++skip_rate < 10)
+ IPPU.RenderThisFrame = false;
+ else
+ {
+ skip_rate = 0;
+ IPPU.RenderThisFrame = true;
+ }
+ }
+ else if (Settings.SkipFrames == AUTO_FRAMERATE /* && !game_fast_forward */)
+ {
+ // frame_time is in getSysTime units: 42.667 microseconds.
+ uint32 frame_time = Settings.PAL ? 468 /* = 20.0 ms */ : 391 /* = 16.67 ms */;
+ if (sync_last > syncnow) // Overflow occurred! (every 50 hrs)
+ {
+ // Render this frame regardless, set the
+ // sync_next, and get the hell out.
+ IPPU.RenderThisFrame = TRUE;
+ sync_last = syncnow;
+ sync_next = syncnow + frame_time;
+ return;
+ }
+ sync_last = syncnow;
+ // If this is positive, we have syncdif*42.66 microseconds to
+ // spare.
+ // If this is negative, we're late by syncdif*42.66
+ // microseconds.
+ syncdif = sync_next - syncnow;
+ if (syncdif < 0 && syncdif >= -(frame_time / 2))
+ {
+ // We're late, but by less than half a frame. Draw it
+ // anyway. If the next frame is too late, it'll be
+ // skipped.
+ skip_rate = 0;
+ IPPU.RenderThisFrame = true;
+ sync_next += frame_time;
+ }
+ else if(syncdif < 0)
+ {
+ /*
+ * If we're consistently late, delay up to 8 frames.
+ *
+ * That really helps with certain games, such as
+ * Super Mario RPG and Yoshi's Island.
+ */
+ if(++skip_rate < 10)
+ {
+ if(syncdif >= -11719 /* not more than 500.0 ms late */)
+ {
+ IPPU.RenderThisFrame = FALSE;
+ sync_next += frame_time;
+ }
+ else
+ { //lag more than 0.5s, maybe paused
+ IPPU.RenderThisFrame = TRUE;
+ sync_next = syncnow + frame_time;
+ framenum = 0;
+ }
+ }
+ else
+ {
+ skip_rate = 0;
+ IPPU.RenderThisFrame = TRUE;
+ sync_next = syncnow + frame_time;
+ }
+ }
+ else // Early
+ {
+ skip_rate = 0;
+ ds2_setCPUclocklevel(0);
+ if (syncdif > 0)
+ udelay(syncdif * 128 / 3 /* times 42 + 2/3 microseconds */);
+ set_cpu_clock(clock_speed_number);
+ S9xProcessSound (0);
+
+ IPPU.RenderThisFrame = TRUE;
+ sync_next += frame_time;
+ }
#if 0
- if (Settings.TurboMode)
- {
- if(++IPPU.FrameSkip >= Settings.TurboSkipFrames)
- {
- IPPU.FrameSkip = 0;
- IPPU.SkippedFrames = 0;
- IPPU.RenderThisFrame = TRUE;
- }
- else
- {
- ++IPPU.SkippedFrames;
- IPPU.RenderThisFrame = FALSE;
- }
- return;
- }
+ if(++framenum >= 60)
+ {
+ syncdif = syncnow - sync_last;
+ sync_last = syncnow;
+ framenum = 0;
+ //printf("T %d %d\n", syncdif*42667/1000, realframe);
+ realframe = 0;
+ }
#endif
+ }
+ else /* if (Settings.SkipFrames != AUTO_FRAMERATE && !game_fast_forward) */
+ {
+ // frame_time is in getSysTime units: 42.667 microseconds.
+ uint32 frame_time = Settings.PAL ? 468 /* = 20.0 ms */ : 391 /* = 16.67 ms */;
+ sync_last = syncnow;
+ if (++skip_rate > Settings.SkipFrames)
+ {
+ skip_rate = 0;
+ IPPU.RenderThisFrame = TRUE;
+ // Are we early?
+ syncdif = sync_next - syncnow;
+ if (syncdif > 0)
+ {
+ ds2_setCPUclocklevel(0);
+ udelay(syncdif * 128 / 3 /* times 42 + 2/3 microseconds */);
+ set_cpu_clock(clock_speed_number);
+ S9xProcessSound (0);
+ // After that little delay, what time is it?
+ syncnow = getSysTime();
+ }
+ sync_next = syncnow + frame_time * Settings.SkipFrames;
+ }
+ else
+ {
+ IPPU.RenderThisFrame = FALSE;
+ }
+ }
#ifdef __sgi
/* BS: saves on CPU usage */
sginap(1);
#endif
+#if 0
/* Check events */
static struct timeval next1 = {0, 0};