diff --git a/src/pc/pc_main.c b/src/pc/pc_main.c index aec1288f2..b0818773f 100644 --- a/src/pc/pc_main.c +++ b/src/pc/pc_main.c @@ -89,9 +89,9 @@ f32 gRenderingDelta = 0; #define FRAMERATE 30 static const f64 sFrameTime = (1.0 / ((double)FRAMERATE)); -static f64 sFrameTargetTime = 0; +static f64 sPeriodTimeStart = 0; static f64 sFrameTimeStart = 0; -static f64 sFrameLastClock = 0; +static u32 sDrawnFrames = 0; bool gGameInited = false; bool gGfxInited = false; @@ -177,24 +177,41 @@ static inline void patch_interpolations(f32 delta) { patch_scroll_targets_interpolated(delta); } +static void compute_fps(f64 start, f64 end) { + u32 fps = round((f64) sDrawnFrames / MAX(0.001, end - start)); + djui_fps_display_update(fps); + sDrawnFrames = 0; +} + void produce_interpolation_frames_and_delay(void) { - u64 frames = 0; - f64 curTime = clock_elapsed_f64(); - f64 timeStart = curTime; + bool is30Fps = (!configUncappedFramerate && configFrameLimit == FRAMERATE); gRenderingInterpolated = true; - // sanity check target time to deal with hangs and such - if (curTime >= sFrameTargetTime) { sFrameTargetTime = curTime - 0.01; } + // Delta time is based on the remaining number of frames we need to draw during the current second + f64 curTime = clock_elapsed_f64(); + f64 remainingTime = sPeriodTimeStart + 1.0 - curTime; + f64 targetTime = sFrameTimeStart + sFrameTime; + f64 targetDelta = ( + is30Fps ? + targetTime - curTime : + remainingTime / (f64) MAX(1, configFrameLimit - sDrawnFrames) + ); - // Account for the actual start of the frame and the time elapsed during the game logic - f64 targetDelta = ((sFrameTargetTime - curTime + (sFrameLastClock - sFrameTimeStart)) * FRAMERATE) / (f64) configFrameLimit; + if (!configUncappedFramerate && (remainingTime < 0.0 || sDrawnFrames >= configFrameLimit)) { + compute_fps(sPeriodTimeStart, curTime); + sPeriodTimeStart = curTime; + sFrameTimeStart = curTime; + targetTime = curTime + sFrameTime; + targetDelta = 1.0 / (f64) configFrameLimit; + } // interpolate and render - while ((curTime = clock_elapsed_f64()) < sFrameTargetTime) { - f32 delta = ((!configUncappedFramerate && configFrameLimit == FRAMERATE) - ? 1.0f - : MAX(MIN((curTime - timeStart) / (sFrameTargetTime - timeStart), 1.0f), 0.0f) + while ((curTime = clock_elapsed_f64()) < targetTime) { + f32 delta = ( + is30Fps ? + 1.0f : + MAX(MIN((curTime - sFrameTimeStart) / (targetTime - sFrameTimeStart), 1.0f), 0.0f) ); gRenderingDelta = delta; @@ -203,7 +220,7 @@ void produce_interpolation_frames_and_delay(void) { send_display_list(gGfxSPTask); gfx_end_frame(); - frames++; + sDrawnFrames++; if (configUncappedFramerate) { continue; } @@ -215,25 +232,18 @@ void produce_interpolation_frames_and_delay(void) { if (delay > 0.0f) { WAPI.delay((u32)delay); } + + if (is30Fps) { break; } } - static u64 sFramesSinceFpsUpdate = 0; - static u64 sLastFpsUpdateTime = 0; - - sFramesSinceFpsUpdate += frames; - - u64 sCurrentFpsUpdateTime = (u64)clock_elapsed_f64(); - if (sLastFpsUpdateTime != sCurrentFpsUpdateTime) { - u32 fps = sFramesSinceFpsUpdate / (sCurrentFpsUpdateTime - sLastFpsUpdateTime); - sLastFpsUpdateTime = sCurrentFpsUpdateTime; - sFramesSinceFpsUpdate = 0; - - djui_fps_display_update(fps); + if ((curTime = clock_elapsed_f64()) >= sPeriodTimeStart + 1.0) { + compute_fps(sPeriodTimeStart, curTime); + sPeriodTimeStart += 1.0; + sFrameTimeStart = sPeriodTimeStart; + } else { + sFrameTimeStart += sFrameTime; } - sFrameTimeStart = sFrameTargetTime; - sFrameLastClock = clock_elapsed_f64(); - sFrameTargetTime += sFrameTime; gRenderingInterpolated = false; }