Remove test_vsync

Simplify sync_framerate_with_timer
This commit is contained in:
blackops7799 2021-11-25 03:05:58 -05:00
parent c4a55e351d
commit d1b787427c
1 changed files with 22 additions and 73 deletions

View File

@ -54,7 +54,9 @@ static void (*kb_all_keys_up)(void) = NULL;
// whether to use timer for frame control
static bool use_timer = true;
// time between consequtive game frames, in perf counter ticks
static double frame_time = 0.0; // set in init()
static double frame_rate = 0.0; // set in init()
// time in which a frame began, in perf counter ticks
static double frame_time = 0.0; // updated in start_frame()
// GetPerformanceFrequency
static double perf_freq = 0.0;
@ -115,54 +117,6 @@ static inline void sys_sleep(const uint64_t us) {
usleep(us);
}
static int test_vsync(void) {
// Even if SDL_GL_SetSwapInterval succeeds, it doesn't mean that VSync actually works.
// A 60 Hz monitor should have a swap interval of 16.67 milliseconds.
// Try to detect the length of a vsync by swapping buffers some times.
// Since the graphics card may enqueue a fixed number of frames,
// first send in four dummy frames to hopefully fill the queue.
// This method will fail if the refresh rate is changed, which, in
// combination with that we can't control the queue size (i.e. lag)
// is a reason this generic SDL2 backend should only be used as last resort.
for (int i = 0; i < 8; ++i)
SDL_GL_SwapWindow(wnd);
Uint32 start = SDL_GetTicks();
SDL_GL_SwapWindow(wnd);
SDL_GL_SwapWindow(wnd);
SDL_GL_SwapWindow(wnd);
SDL_GL_SwapWindow(wnd);
Uint32 end = SDL_GetTicks();
const float average = 4.0 * 1000.0 / (end - start);
if (average > 27.0f && average < 33.0f) return 1;
if (average > 57.0f && average < 63.0f) return 2;
if (average > 86.0f && average < 94.0f) return 3;
if (average > 115.0f && average < 125.0f) return 4;
if (average > 234.0f && average < 246.0f) return 8;
return 0;
}
static inline void gfx_sdl_set_vsync(const bool enabled) {
if (enabled) {
// try to detect refresh rate
SDL_GL_SetSwapInterval(1);
const int vblanks = gCLIOpts.SyncFrames ? (int)gCLIOpts.SyncFrames : test_vsync();
if (vblanks) {
printf("determined swap interval: %d\n", vblanks);
SDL_GL_SetSwapInterval(vblanks);
return;
} else {
printf("could not determine swap interval, falling back to timer sync\n");
}
}
SDL_GL_SetSwapInterval(0);
}
static void gfx_sdl_set_fullscreen(void) {
if (configWindow.reset)
configWindow.fullscreen = false;
@ -198,7 +152,7 @@ static void gfx_sdl_reset_dimension_and_pos(void) {
SDL_SetWindowSize(wnd, configWindow.w, configWindow.h);
SDL_SetWindowPosition(wnd, xpos, ypos);
// in case vsync changed
gfx_sdl_set_vsync(configWindow.vsync);
SDL_GL_SetSwapInterval(configWindow.vsync);
}
static void gfx_sdl_init(const char *window_title) {
@ -226,13 +180,13 @@ static void gfx_sdl_init(const char *window_title) {
);
ctx = SDL_GL_CreateContext(wnd);
gfx_sdl_set_vsync(configWindow.vsync);
SDL_GL_SetSwapInterval(configWindow.vsync);
gfx_sdl_set_fullscreen();
perf_freq = SDL_GetPerformanceFrequency();
frame_time = perf_freq / FRAMERATE;
frame_rate = perf_freq / FRAMERATE;
for (size_t i = 0; i < sizeof(windows_scancode_table) / sizeof(SDL_Scancode); i++) {
inverted_scancode_table[windows_scancode_table[i]] = i;
@ -333,39 +287,34 @@ static void gfx_sdl_set_keyboard_callbacks(kb_callback_t on_key_down, kb_callbac
}
static bool gfx_sdl_start_frame(void) {
frame_time = SDL_GetPerformanceCounter();
return true;
}
static inline void sync_framerate_with_timer(void) {
static double last_time;
static double last_sec;
static int frames_since_last_sec;
const double now = SDL_GetPerformanceCounter();
frames_since_last_sec += 1;
if (last_time) {
const double elapsed = last_sec ? (now - last_sec) : (now - last_time);
if ((elapsed < frame_time && !last_sec) || (elapsed < frames_since_last_sec * frame_time && last_sec)) {
const double delay = last_sec ? frames_since_last_sec * frame_time - elapsed : frame_time - elapsed;
sys_sleep(delay / perf_freq * 1000000.0);
last_time = now + delay;
} else {
last_time = now;
}
if ((int64_t)(now / perf_freq) > (int64_t)(last_sec / perf_freq)) {
last_sec = last_time;
frames_since_last_sec = 0;
}
} else {
last_time = now;
// calculate how long it took for the frame to render
const double frame_length = SDL_GetPerformanceCounter() - frame_time;
if (frame_length < frame_rate) {
// Only sleep if we have time to spare
const double remain = frame_rate - frame_length;
// Sleep remaining time away
sys_sleep(remain / perf_freq * 1000000.0);
}
}
static void gfx_sdl_swap_buffers_begin(void) {
sync_framerate_with_timer();
// Swap after we finished rendering, only if this frame wasn't dropped.
// This will wait for vblank if vsync is enabled and then update our window with our render.
SDL_GL_SwapWindow(wnd);
}
static void gfx_sdl_swap_buffers_end(void) {
// The game isn't always going to run at a consistent rate,
// with frame pacing going up and down depending on hardware performance.
// Sleep off any remaining time to make the main loop iteration be called at a consistent frane rate.
// We do this after our swap, because it actually will take the time to swap into account.
sync_framerate_with_timer();
}
static double gfx_sdl_get_time(void) {