diff options
Diffstat (limited to 'source/nds/entry.cpp')
-rw-r--r-- | source/nds/entry.cpp | 244 |
1 files changed, 145 insertions, 99 deletions
diff --git a/source/nds/entry.cpp b/source/nds/entry.cpp index 6cbf3ef..08e95cb 100644 --- a/source/nds/entry.cpp +++ b/source/nds/entry.cpp @@ -642,10 +642,19 @@ static unsigned int sync_next = 0; static unsigned int skip_rate= 0; +#define CPU_DOWNCLOCK_EARLY_TIME 293 /* 1 = 42.667 us. 391 = 16.67 ms */ +#define CPU_DOWNCLOCK_DETERMINATION_INTERVAL 46874 /* 23437 = 1 s */ + +static unsigned int LastAutoCPUTime = 0; +unsigned int AutoCPUFrequency = 5; +static bool8 ConsistentlyEarly = FALSE; +static bool8 FastForwardLastFrame = FALSE; + void S9xSyncSpeed () { uint32 syncnow; int32 syncdif; + unsigned int LastAutoCPUFrequency = AutoCPUFrequency; #if 0 if (Settings.SoundSync == 2) @@ -657,8 +666,19 @@ void S9xSyncSpeed () #endif syncnow = getSysTime(); - if (game_fast_forward || temporary_fast_forward /* hotkey is held */) + bool8 FastForward = game_fast_forward || temporary_fast_forward /* hotkey is held */; + + if (game_config.clock_speed_number == 0) + if (FastForward && !FastForwardLastFrame) + HighFrequencyCPU (); + else if (!FastForward && FastForwardLastFrame) + GameFrequencyCPU (); + + FastForwardLastFrame = FastForward; + + if (FastForward) { + ConsistentlyEarly = FALSE; // don't use fast-forward to lower CPU sync_last = syncnow; sync_next = syncnow; @@ -670,137 +690,149 @@ void S9xSyncSpeed () IPPU.RenderThisFrame = true; } } - else if (Settings.SkipFrames == AUTO_FRAMERATE /* && !game_fast_forward && !temporary_fast_forward */) + else { - // frame_time is in getSysTime units: 42.667 microseconds. - int32 frame_time = Settings.PAL ? 468 /* = 20.0 ms */ : 391 /* = 16.67 ms */; - if (sync_last > syncnow) // Overflow occurred! (every 50 hrs) + // Manual or automatic frame skipping, no fast-forward. + if (Settings.SkipFrames == AUTO_FRAMERATE) { - // Render this frame regardless, set the - // sync_next, and get the hell out. - IPPU.RenderThisFrame = TRUE; + // frame_time is in getSysTime units: 42.667 microseconds. + int32 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. + ConsistentlyEarly = FALSE; + AutoCPUFrequency = 5; + LastAutoCPUTime = syncnow; + + IPPU.RenderThisFrame = TRUE; + sync_last = syncnow; + sync_next = syncnow + frame_time; + goto finalise; + } 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(skip_rate < 2 /* did not skip 2 frames yet */) - { - // Skip a minimum of 2 frames between rendered frames. - // This prevents the DSTwo-DS link from being too busy - // to return button statuses. - ++skip_rate; - IPPU.RenderThisFrame = FALSE; - sync_next += frame_time; - } - else 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 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(skip_rate < 2 /* did not skip 2 frames yet */) { - if(syncdif >= -11719 /* not more than 500.0 ms late */) + // Skip a minimum of 2 frames between rendered frames. + // This prevents the DSTwo-DS link from being too busy + // to return button statuses. + ++skip_rate; + IPPU.RenderThisFrame = FALSE; + sync_next += frame_time; + } + else if(syncdif < 0) + { + ConsistentlyEarly = FALSE; + AutoCPUFrequency = 5; + LastAutoCPUTime = syncnow; + + /* + * 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) { - IPPU.RenderThisFrame = FALSE; - sync_next += frame_time; + 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; + } } else - { //lag more than 0.5s, maybe paused + { + skip_rate = 0; IPPU.RenderThisFrame = TRUE; sync_next = syncnow + frame_time; } } - else + else // Early { + ConsistentlyEarly = ConsistentlyEarly && syncdif >= CPU_DOWNCLOCK_EARLY_TIME; skip_rate = 0; - IPPU.RenderThisFrame = TRUE; - sync_next = syncnow + frame_time; - } - } - else // Early - { - skip_rate = 0; - if (syncdif > 0) - { - do { - S9xProcessSound (0); + if (syncdif > 0) + { + do { + S9xProcessSound (0); #ifdef ACCUMULATE_JOYPAD /* * This call allows NDSSFC to synchronise the DS controller more often. * If porting a later version of Snes9x into NDSSFC, it is essential to * preserve it. */ - NDSSFCAccumulateJoypad (); + NDSSFCAccumulateJoypad (); #endif - syncdif = sync_next - getSysTime(); - } while (syncdif > 0); - } + syncdif = sync_next - getSysTime(); + } while (syncdif > 0); + } - IPPU.RenderThisFrame = TRUE; - sync_next += frame_time; - } + IPPU.RenderThisFrame = TRUE; + sync_next += frame_time; + } #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; - } + 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 && !temporary_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) + } + else /* if (Settings.SkipFrames != AUTO_FRAMERATE) */ { - skip_rate = 0; - IPPU.RenderThisFrame = TRUE; - // Are we early? - syncdif = sync_next - syncnow; - if (syncdif > 0) + // 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) { - do { - S9xProcessSound (0); + skip_rate = 0; + IPPU.RenderThisFrame = TRUE; + // Are we early? + syncdif = sync_next - syncnow; + if (syncdif > 0) + { + ConsistentlyEarly = ConsistentlyEarly && syncdif >= CPU_DOWNCLOCK_EARLY_TIME; + do { + S9xProcessSound (0); #ifdef ACCUMULATE_JOYPAD /* * This call allows NDSSFC to synchronise the DS controller more often. * If porting a later version of Snes9x into NDSSFC, it is essential to * preserve it. */ - NDSSFCAccumulateJoypad (); + NDSSFCAccumulateJoypad (); #endif - syncdif = sync_next - getSysTime(); - } while (syncdif > 0); - // After that little delay, what time is it? - syncnow = getSysTime(); + syncdif = sync_next - getSysTime(); + } while (syncdif > 0); + // After that little delay, what time is it? + syncnow = getSysTime(); + } + else + { + // Nope, we're late. + ConsistentlyEarly = FALSE; + AutoCPUFrequency = 5; + LastAutoCPUTime = syncnow; + } + sync_next = syncnow + frame_time * (Settings.SkipFrames + 1); + } + else + { + IPPU.RenderThisFrame = FALSE; } - sync_next = syncnow + frame_time * (Settings.SkipFrames + 1); - } - else - { - IPPU.RenderThisFrame = FALSE; } } @@ -887,6 +919,20 @@ void S9xSyncSpeed () next1.tv_usec %= 1000000; } #endif + +finalise: ; + + if (syncnow - LastAutoCPUTime >= CPU_DOWNCLOCK_DETERMINATION_INTERVAL) { + if (ConsistentlyEarly && AutoCPUFrequency > 0) + AutoCPUFrequency--; + + LastAutoCPUTime = syncnow; + ConsistentlyEarly = TRUE; + // will get unset if the CPU should stay the same at next check + } + + if (game_config.clock_speed_number == 0 && LastAutoCPUFrequency != AutoCPUFrequency) + GameFrequencyCPU (); } bool8 S9xOpenSoundDevice (int mode, bool8 stereo, int buffer_size) |