Skip to content

Commit 6b7a36c

Browse files
committed
Improve FPS limit on Linux.
1 parent 256d3f7 commit 6b7a36c

1 file changed

Lines changed: 37 additions & 9 deletions

File tree

src/engine_lib/src/render/renderer.c

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
#define NOMINMAX
55
#include <Windows.h>
66
#elif defined(__linux__)
7-
#include "time.h"
7+
#include <time.h>
8+
#include <errno.h>
89
#endif
910
#include <stdio.h>
1011
#include <stdlib.h>
@@ -52,6 +53,10 @@ struct te_renderer {
5253

5354
unsigned int fps_limit;
5455

56+
#if defined(__linux__)
57+
struct timespec frame_end_time;
58+
#endif
59+
5560
#if defined(ENGINE_DEBUG_TOOLS)
5661
// GPU time query IDs.
5762
unsigned int gl_timestamp_frame_start;
@@ -107,6 +112,10 @@ renderer_create(struct te_window* window) {
107112

108113
renderer->fps_limit = 0;
109114

115+
#if defined(__linux__)
116+
clock_gettime(CLOCK_MONOTONIC, &renderer->frame_end_time);
117+
#endif
118+
110119
// Create GL context.
111120
renderer->gl_context = SDL_GL_CreateContext(prv_window_get_sdl_window(window));
112121
if (renderer->gl_context == NULL) {
@@ -267,24 +276,43 @@ prv_renderer_calc_frame_stats(te_renderer* renderer, float delta_time_sec) {
267276

268277
// FPS limit.
269278
if (renderer->fps_limit > 0) {
270-
// Should use perf counters and high precision timers here but this already works fine.
279+
#if defined(WIN32)
271280
const float target_time_ms = 1000.0f / (float)renderer->fps_limit;
272281
const float time_to_sleep_ms = target_time_ms - delta_time_sec;
273282
if (time_to_sleep_ms >= 1.0) {
274-
#if defined(WIN32)
275283
timeBeginPeriod(1);
276284
Sleep((unsigned long)time_to_sleep_ms);
277285
timeEndPeriod(1);
286+
}
278287
#elif defined(__linux__)
279-
struct timespec tim;
280-
struct timespec tim2;
281-
tim.tv_sec = 0;
282-
tim.tv_nsec = (long)floor(time_to_sleep_ms * 1000000.0f * 0.965f);
283-
nanosleep(&tim, &tim2);
288+
const long target_time_ns = (long)(1000000000.0 / (double)renderer->fps_limit);
289+
290+
struct timespec now;
291+
clock_gettime(CLOCK_MONOTONIC, &now);
292+
long delta_ns = now.tv_nsec - renderer->frame_end_time.tv_nsec;
293+
if (delta_ns < 0) {
294+
delta_ns += 1000000000;
295+
}
296+
297+
const long time_to_sleep_ns = target_time_ns - delta_ns;
298+
if (time_to_sleep_ns > 0) {
299+
struct timespec requested;
300+
struct timespec remaining;
301+
requested.tv_sec = 0;
302+
requested.tv_nsec = time_to_sleep_ns;
303+
while (nanosleep(&requested, &remaining) == -1) {
304+
if (errno == EINTR) {
305+
requested = remaining;
306+
} else {
307+
break;
308+
}
309+
}
310+
}
311+
312+
clock_gettime(CLOCK_MONOTONIC, &renderer->frame_end_time);
284313
#else
285314
#error "unsupported OS"
286315
#endif
287-
}
288316
}
289317
}
290318

0 commit comments

Comments
 (0)