mirror of
https://github.com/open-goal/jak-project
synced 2026-09-11 04:33:32 -04:00
smoother timing in frame limiter
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
#include "FrameLimiter.h"
|
||||
#include "common/common_types.h"
|
||||
#include <thread>
|
||||
#include <stdio.h>
|
||||
|
||||
double FrameLimiter::round_to_nearest_60fps(double current) {
|
||||
double one_frame = 1.f / 60.f;
|
||||
@@ -16,31 +18,16 @@ FrameLimiter::FrameLimiter() {}
|
||||
|
||||
FrameLimiter::~FrameLimiter() {}
|
||||
|
||||
void FrameLimiter::run(double target_fps,
|
||||
bool experimental_accurate_lag,
|
||||
bool do_sleeps,
|
||||
double engine_time) {
|
||||
double target_seconds;
|
||||
if (experimental_accurate_lag) {
|
||||
target_seconds = round_to_nearest_60fps(engine_time);
|
||||
} else {
|
||||
target_seconds = 1.f / target_fps;
|
||||
}
|
||||
double remaining_time = target_seconds - m_timer.getSeconds();
|
||||
|
||||
if (do_sleeps && remaining_time > 0.001) {
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(int((remaining_time - 0.001) * 1e6)));
|
||||
}
|
||||
|
||||
while (remaining_time > 0) {
|
||||
remaining_time = target_seconds - m_timer.getSeconds();
|
||||
}
|
||||
|
||||
m_timer.start();
|
||||
void sleep_us(u64 us) {
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(us));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void sleep_us(u64 us) {
|
||||
Sleep(us);
|
||||
}
|
||||
|
||||
#define NOMINMAX
|
||||
#include <Windows.h>
|
||||
|
||||
@@ -52,27 +39,34 @@ FrameLimiter::~FrameLimiter() {
|
||||
timeEndPeriod(0);
|
||||
}
|
||||
|
||||
void FrameLimiter::run(double target_fps,
|
||||
bool experimental_accurate_lag,
|
||||
bool do_sleeps,
|
||||
double engine_time) {
|
||||
double target_seconds;
|
||||
if (experimental_accurate_lag) {
|
||||
target_seconds = round_to_nearest_60fps(engine_time);
|
||||
} else {
|
||||
target_seconds = 1.f / target_fps;
|
||||
}
|
||||
double remaining_time = target_seconds - m_timer.getSeconds();
|
||||
|
||||
if (do_sleeps && remaining_time > 0.001) {
|
||||
Sleep((remaining_time * 1000) - 1);
|
||||
}
|
||||
|
||||
while (remaining_time > 0) {
|
||||
remaining_time = target_seconds - m_timer.getSeconds();
|
||||
}
|
||||
|
||||
m_timer.start();
|
||||
}
|
||||
|
||||
#endif
|
||||
void FrameLimiter::run(double target_fps, bool do_sleeps, double engine_time) {
|
||||
// we want to exit this function when the current time reaches m_us_target.
|
||||
// and update m_us_target for the next frame.
|
||||
constexpr s64 max_lag_us = 20000;
|
||||
constexpr s64 max_ahead_us = 50000;
|
||||
|
||||
s64 entry_time = m_timer.getUs();
|
||||
|
||||
// first, see if we're lagging too far behind:
|
||||
if (entry_time > m_us_target + max_lag_us) {
|
||||
m_us_target = entry_time - max_lag_us;
|
||||
}
|
||||
|
||||
// see if we're too far ahead
|
||||
if (m_us_target > entry_time + max_ahead_us) {
|
||||
m_us_target = entry_time + max_ahead_us;
|
||||
}
|
||||
|
||||
// sleep!
|
||||
s64 remaining = m_us_target - entry_time;
|
||||
if (do_sleeps && remaining > 1000) {
|
||||
sleep_us(remaining - 1000);
|
||||
}
|
||||
while (m_timer.getUs() < m_us_target) {
|
||||
// wait....
|
||||
}
|
||||
|
||||
// now update the next target...
|
||||
m_us_target += 1e6 * round_to_nearest_60fps(engine_time) * 60 / target_fps;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/util/Timer.h"
|
||||
|
||||
class FrameLimiter {
|
||||
@@ -7,10 +8,12 @@ class FrameLimiter {
|
||||
FrameLimiter();
|
||||
~FrameLimiter();
|
||||
|
||||
void run(double target_fps, bool experimental_accurate_lag, bool do_sleeps, double engine_time);
|
||||
void run(double target_fps, bool do_sleeps, double engine_time);
|
||||
|
||||
private:
|
||||
double round_to_nearest_60fps(double current);
|
||||
|
||||
Timer m_timer;
|
||||
|
||||
s64 m_us_target = 0;
|
||||
};
|
||||
@@ -112,7 +112,6 @@ void OpenGlDebugGui::draw(const DmaStats& dma_stats) {
|
||||
target_fps = m_target_fps_text;
|
||||
}
|
||||
ImGui::Separator();
|
||||
ImGui::Checkbox("Accurate Lag Mode", &experimental_accurate_lag);
|
||||
ImGui::Checkbox("Sleep in Frame Limiter", &sleep_in_frame_limiter);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
@@ -59,9 +59,8 @@ class OpenGlDebugGui {
|
||||
|
||||
bool get_vsync_flag() { return m_vsync; }
|
||||
|
||||
bool framelimiter = false;
|
||||
bool framelimiter = true;
|
||||
float target_fps = 60.f;
|
||||
bool experimental_accurate_lag = false;
|
||||
bool sleep_in_frame_limiter = true;
|
||||
bool small_profiler = false;
|
||||
bool record_events = false;
|
||||
@@ -75,6 +74,6 @@ class OpenGlDebugGui {
|
||||
bool m_draw_debug = false;
|
||||
bool m_want_screenshot = false;
|
||||
char m_screenshot_save_name[256] = "screenshot.png";
|
||||
bool m_vsync = true;
|
||||
bool m_vsync = false;
|
||||
float m_target_fps_text = 60.0;
|
||||
};
|
||||
|
||||
@@ -120,7 +120,7 @@ static int gl_init(GfxSettings& settings) {
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); // 4.3
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // core profile, not compat
|
||||
// debug check
|
||||
glfwWindowHint(GLFW_REFRESH_RATE, 60);
|
||||
if (settings.debug) {
|
||||
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);
|
||||
} else {
|
||||
@@ -262,7 +262,6 @@ void render_game_frame(int width, int height, int lbox_width, int lbox_height) {
|
||||
// should be fine to remove this mutex if the game actually waits for vsync to call
|
||||
// send_chain again. but let's be safe for now.
|
||||
std::unique_lock<std::mutex> lock(g_gfx_data->dma_mutex);
|
||||
g_gfx_data->engine_timer.start();
|
||||
g_gfx_data->has_data_to_render = false;
|
||||
g_gfx_data->sync_cv.notify_all();
|
||||
}
|
||||
@@ -436,18 +435,23 @@ static void gl_render_display(GfxDisplay* display) {
|
||||
glfwSwapInterval(req_vsync);
|
||||
}
|
||||
|
||||
g_gfx_data->last_engine_time = g_gfx_data->engine_timer.getSeconds();
|
||||
|
||||
// actual vsync
|
||||
g_gfx_data->debug_gui.finish_frame();
|
||||
{
|
||||
auto p = scoped_prof("swap-buffers");
|
||||
glfwSwapBuffers(window);
|
||||
}
|
||||
|
||||
if (g_gfx_data->debug_gui.framelimiter) {
|
||||
auto p = scoped_prof("frame-limiter");
|
||||
g_gfx_data->frame_limiter.run(
|
||||
g_gfx_data->debug_gui.target_fps, g_gfx_data->debug_gui.experimental_accurate_lag,
|
||||
g_gfx_data->debug_gui.sleep_in_frame_limiter, g_gfx_data->last_engine_time);
|
||||
g_gfx_data->frame_limiter.run(g_gfx_data->debug_gui.target_fps,
|
||||
g_gfx_data->debug_gui.sleep_in_frame_limiter,
|
||||
g_gfx_data->last_engine_time);
|
||||
}
|
||||
g_gfx_data->engine_timer.start();
|
||||
|
||||
g_gfx_data->debug_gui.start_frame();
|
||||
prof().instant_event("ROOT");
|
||||
update_global_profiler();
|
||||
@@ -498,7 +502,6 @@ u32 gl_sync_path() {
|
||||
return 0;
|
||||
}
|
||||
std::unique_lock<std::mutex> lock(g_gfx_data->sync_mutex);
|
||||
g_gfx_data->last_engine_time = g_gfx_data->engine_timer.getSeconds();
|
||||
if (!g_gfx_data->has_data_to_render) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1276,8 +1276,8 @@
|
||||
(define *screen-shot* #f)
|
||||
(defun display-frame-start ((disp display) (new-frame-idx int) (odd-even int))
|
||||
"Set up a new frame. Call this before drawing anything.
|
||||
new-frame-idx is the display frame that will be set up.
|
||||
odd-even is the odd-even of the new frame"
|
||||
new-frame-idx is the display frame that will be set up.
|
||||
odd-even is the odd-even of the new frame"
|
||||
|
||||
|
||||
;; due to a HW bug in the PS2, you must set this.
|
||||
@@ -1292,7 +1292,7 @@
|
||||
)
|
||||
)
|
||||
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(let ((float-time-ratio (/ (the float (timer-count (the-as timer-bank #x10000800))) (the float *ticks-per-frame*))))
|
||||
@@ -1304,18 +1304,29 @@
|
||||
;; if we actually do miss a frame, the time ratio will be around 2.
|
||||
|
||||
(#when PC_PORT
|
||||
(if (< float-time-ratio 3.3)
|
||||
(set! time-ratio 3.0)
|
||||
)
|
||||
(if (< float-time-ratio 2.3)
|
||||
(set! time-ratio 2.0)
|
||||
)
|
||||
(if (< float-time-ratio 1.3)
|
||||
(set! time-ratio 1.0)
|
||||
)
|
||||
|
||||
|
||||
#|
|
||||
(if (> time-ratio 1.)
|
||||
(format #t "LAG ~f frames~%" (- time-ratio 1.))
|
||||
)
|
||||
|#
|
||||
)
|
||||
;; (format *stdcon* "time: ~f and ~f~%" time-ratio float-time-ratio)
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
;; inform display system of our speed. This will adjust the scaling used in all physics calculations
|
||||
(set-time-ratios *display* time-ratio)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user