aboutsummaryrefslogtreecommitdiff
path: root/source
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
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')
-rw-r--r--source/cheats.h2
-rw-r--r--source/cpuexec.cpp75
-rw-r--r--source/nds/entry.cpp195
-rw-r--r--source/nds/gui.c21
-rw-r--r--source/nds/gui.h62
-rw-r--r--source/nds/message.h17
-rw-r--r--source/snes9x.h4
7 files changed, 227 insertions, 149 deletions
diff --git a/source/cheats.h b/source/cheats.h
index bb2646f..2f3252e 100644
--- a/source/cheats.h
+++ b/source/cheats.h
@@ -102,7 +102,7 @@ struct SCheat
uint8 byte;
uint8 saved_byte;
// bool8 enabled;
- uint32 enabled; // THIS IS A TOTAL HACK FOR THE NDSSFC GUI, YOU HAVE BEEN WARNED [Neb]
+ u32 enabled; // THIS IS A TOTAL HACK FOR THE NDSSFC GUI, YOU HAVE BEEN WARNED [Neb]
bool8 saved;
char name[MAX_SFCCHEAT_NAME];
};
diff --git a/source/cpuexec.cpp b/source/cpuexec.cpp
index 66bb8da..b90da6d 100644
--- a/source/cpuexec.cpp
+++ b/source/cpuexec.cpp
@@ -330,81 +330,6 @@ void S9xDoHBlankProcessing ()
Snapshot (NULL);
}
#endif
- if(!game_fast_forward)
- {
- syncnow = getSysTime();
- if(syncnow > sync_next)
- {
- /*
- * Little bit of a hack here:
- * If we get behind and stay behind for a certain number
- * of frames, we automatically enable fast forward.
- * That really helps with certain games, such as
- * Super Mario RPG and Yoshi's Island.
- */
- if(skip_rate++ < 10)
- {
- syncdif = syncnow - sync_next;
- if(syncdif < 11718)
- {
- IPPU.RenderThisFrame = false;
- sync_next += 391;
- }
- else
- { //lag more than 0.5s, maybe paused
- IPPU.RenderThisFrame = true;
- sync_next = syncnow;
- framenum = 0;
- sync_last = syncnow;
- realframe = 1;
- }
- }
- else
- {
- skip_rate = 0;
- IPPU.RenderThisFrame = true;
- sync_last= syncnow;
- sync_next = syncnow+391;
- }
- }
- else
- {
- skip_rate = 0;
- syncdif = sync_next - syncnow;
- if(syncdif > 391)
- {
- udelay(syncdif*22);
- S9xProcessSound (0);
- }
-
- IPPU.RenderThisFrame = true;
- sync_next += 391; //16.7ms
- realframe += 1;
- }
-#if 0
- 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
- {
- sync_last= 0;
- sync_next = 0;
-
- if(skip_rate++ < 10)
- IPPU.RenderThisFrame = false;
- else
- {
- skip_rate = 0;
- IPPU.RenderThisFrame = true;
- }
- }
}
if (CPU.V_Counter == PPU.ScreenHeight + 3)
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};
diff --git a/source/nds/gui.c b/source/nds/gui.c
index 4ebb224..d198166 100644
--- a/source/nds/gui.c
+++ b/source/nds/gui.c
@@ -17,8 +17,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "snes9x.h"
-
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
@@ -78,7 +78,7 @@ GAME_CONFIG game_config;
//save state file map
char savestate_map[SAVE_STATE_SLOT_NUM];
-static unsigned int savestate_index;
+static u32 savestate_index;
#define MAKE_MENU(name, init_function, passive_function, key_function, end_function, \
focus_option, screen_focus) \
@@ -2776,7 +2776,7 @@ u32 menu(u16 *screen)
(char*)&msg[MSG_VIDEO_ASPECT_RATIO_3],
(char*)&msg[MSG_VIDEO_ASPECT_RATIO_4]};
- char *frameskip_options[] = { (char*)&msg[MSG_FRAMESKIP_0], (char*)&msg[MSG_FRAMESKIP_1] };
+ char *frameskip_options[] = { (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_AUTOMATIC], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_0], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_1], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_2], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_3], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_4], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_5], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_6], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_7], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_8], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_9], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_10] };
char *on_off_options[] = { (char*)&msg[MSG_GENERAL_OFF], (char*)&msg[MSG_GENERAL_ON] };
@@ -2800,7 +2800,10 @@ u32 menu(u16 *screen)
&game_fast_forward, 2, NULL, ACTION_TYPE, 2),
/* 03 */ STRING_SELECTION_OPTION(game_disableAudio, NULL, &msg[FMT_AUDIO_SOUND], sound_seletion,
- &game_enable_audio, 2, NULL, ACTION_TYPE, 3)
+ &game_enable_audio, 2, NULL, ACTION_TYPE, 3),
+
+ /* 04 */ STRING_SELECTION_OPTION(game_set_frameskip, NULL, &msg[FMT_VIDEO_FRAME_SKIPPING], frameskip_options,
+ &game_config.frameskip_value, 12 /* auto (0) and 0..10 (1..11) make 12 option values */, NULL, ACTION_TYPE, 4)
};
MAKE_MENU(graphics, NULL, NULL, NULL, NULL, 0, 0);
@@ -4004,9 +4007,7 @@ void init_game_config(void)
game_config.clock_speed_number = 5; // 396 MHz by default
clock_speed_number = 5;
game_config.graphic = 3; // By default, have a good-looking aspect ratio
-
- game_config.gamepad_config_menu = BUTTON_ID_TOUCH;
- memcpy(game_config.gamepad_config_map, gamepad_config_map_init, sizeof(gamepad_config_map_init));
+ game_config.frameskip_value = 0; // Automatic frame skipping
game_config.backward = 0; //time backward disable
game_config.backward_time = 2; //time backward granularity 1s
@@ -4063,9 +4064,8 @@ void load_game_config_file(void)
{
fread(&game_config, 1, sizeof(GAME_CONFIG), fp);
- memcpy(gamepad_config_map, game_config.gamepad_config_map, sizeof(game_config.gamepad_config_map));
- gamepad_config_menu = game_config.gamepad_config_menu;
clock_speed_number = game_config.clock_speed_number;
+ Settings.SkipFrames = (game_config.frameskip_value == 0 ? AUTO_FRAMERATE : game_config.frameskip_value - 1 /* 1 -> 0 and so on */);
}
fclose(fp);
@@ -4113,9 +4113,6 @@ int save_game_config_file(void)
if(gamepak_name[0] == 0) return -1;
- memcpy(game_config.gamepad_config_map, gamepad_config_map, sizeof(game_config.gamepad_config_map));
- game_config.gamepad_config_menu = gamepad_config_menu;
-
sprintf(game_config_filename, "%s/%s", DEFAULT_CFG_DIR, gamepak_name);
pt = strrchr(game_config_filename, '.');
if(NULL == pt)
diff --git a/source/nds/gui.h b/source/nds/gui.h
index 5a40979..ec0dd1a 100644
--- a/source/nds/gui.h
+++ b/source/nds/gui.h
@@ -44,16 +44,63 @@ struct _EMU_CONFIG
struct _GAME_CONFIG
{
- u32 clock_speed_number;
- u32 frameskip_type;
+ u32 clock_speed_number;
+ u32 Reserved0;
u32 frameskip_value;
- u32 graphic;
- u32 enable_audio;
- u32 gamepad_config_menu;
+ u32 graphic;
+ u32 enable_audio;
+ u32 Reserved1;
u32 backward;
u32 backward_time;
- u32 reserve[32];
- u32 gamepad_config_map[MAX_GAMEPAD_MAP];
+ u32 Reserved2;
+ u32 Reserved3;
+ u32 Reserved4;
+ u32 Reserved5;
+ u32 Reserved6;
+ u32 Reserved7;
+ u32 Reserved8;
+ u32 Reserved9;
+ u32 Reserved10;
+ u32 Reserved11;
+ u32 Reserved12;
+ u32 Reserved13;
+ u32 Reserved14;
+ u32 Reserved15;
+ u32 Reserved16;
+ u32 Reserved17;
+ u32 Reserved18;
+ u32 Reserved19;
+ u32 Reserved20;
+ u32 Reserved21;
+ u32 Reserved22;
+ u32 Reserved23;
+ u32 Reserved24;
+ u32 Reserved25;
+ u32 Reserved26;
+ u32 Reserved27;
+ u32 Reserved28;
+ u32 Reserved29;
+ u32 Reserved30;
+ u32 Reserved31;
+ u32 Reserved32;
+
+ u32 Reserved33;
+ u32 Reserved34;
+ u32 Reserved35;
+ u32 Reserved36;
+ u32 Reserved37;
+ u32 Reserved38;
+ u32 Reserved39;
+ u32 Reserved40;
+ u32 Reserved41;
+ u32 Reserved42;
+ u32 Reserved43;
+ u32 Reserved44;
+ u32 Reserved45;
+ u32 Reserved46;
+ u32 Reserved47;
+ u32 Reserved48;
+ u32 Reserved49;
};
typedef enum
@@ -118,6 +165,7 @@ extern GAME_CONFIG game_config;
extern void gui_init(u32 lang_id);
extern u32 menu(u16 *original_screen);
extern void game_disableAudio();
+extern void game_set_frameskip();
extern void set_cpu_clock(u32 num);
#ifdef __cplusplus
diff --git a/source/nds/message.h b/source/nds/message.h
index ee89acd..09332bc 100644
--- a/source/nds/message.h
+++ b/source/nds/message.h
@@ -30,8 +30,7 @@ enum MSG
MSG_MAIN_MENU_EXIT,
FMT_VIDEO_ASPECT_RATIO,
FMT_VIDEO_FAST_FORWARD,
- FMT_VIDEO_FRAME_SKIP_AUTOMATIC,
- FMT_VIDEO_FRAME_SKIP_MANUAL,
+ FMT_VIDEO_FRAME_SKIPPING,
FMT_AUDIO_SOUND,
MSG_SAVED_STATE_CREATE,
FMT_SAVED_STATE_LOAD,
@@ -56,8 +55,18 @@ enum MSG
MSG_VIDEO_ASPECT_RATIO_3,
MSG_VIDEO_ASPECT_RATIO_4,
- MSG_FRAMESKIP_0, // currently unused
- MSG_FRAMESKIP_1, // currently unused
+ MSG_VIDEO_FRAME_SKIPPING_AUTOMATIC,
+ MSG_VIDEO_FRAME_SKIPPING_0,
+ MSG_VIDEO_FRAME_SKIPPING_1,
+ MSG_VIDEO_FRAME_SKIPPING_2,
+ MSG_VIDEO_FRAME_SKIPPING_3,
+ MSG_VIDEO_FRAME_SKIPPING_4,
+ MSG_VIDEO_FRAME_SKIPPING_5,
+ MSG_VIDEO_FRAME_SKIPPING_6,
+ MSG_VIDEO_FRAME_SKIPPING_7,
+ MSG_VIDEO_FRAME_SKIPPING_8,
+ MSG_VIDEO_FRAME_SKIPPING_9,
+ MSG_VIDEO_FRAME_SKIPPING_10,
MSG_GENERAL_OFF,
MSG_GENERAL_ON,
diff --git a/source/snes9x.h b/source/snes9x.h
index e9ed479..e9e29b8 100644
--- a/source/snes9x.h
+++ b/source/snes9x.h
@@ -97,9 +97,13 @@
#include "fs_api.h"
#include "ds2_malloc.h"
+#ifdef __cplusplus
extern "C" {
+#endif
extern int cprintf(const char *fmt, ...);
+#ifdef __cplusplus
}
+#endif
#ifdef __WIN32__
#include "..\wsnes9x.h"