| @@ -74,8 +74,7 @@ int main(int argc, char* argv[]) { | |||||
| nes_render(rend, &sys.ppu); | nes_render(rend, &sys.ppu); | ||||
| struct timespec t_target = {0}; | |||||
| time_get(&t_target); | |||||
| time_us t_target = time_now(); | |||||
| uint64_t cycle_last_frame = 0; | uint64_t cycle_last_frame = 0; | ||||
| uint64_t total_cycles = 0; | uint64_t total_cycles = 0; | ||||
| @@ -92,14 +91,20 @@ int main(int argc, char* argv[]) { | |||||
| // Sleep to catch up to master clock | // Sleep to catch up to master clock | ||||
| uint64_t elapsed_cycles = total_cycles - | uint64_t elapsed_cycles = total_cycles - | ||||
| cycle_last_frame; | cycle_last_frame; | ||||
| int elapsed_ns = ( elapsed_cycles * | |||||
| int elapsed_us = ( elapsed_cycles * | |||||
| nes_clock_master_den * | nes_clock_master_den * | ||||
| NS_PER_S ) / | |||||
| US_PER_S ) / | |||||
| nes_clock_master_num; | nes_clock_master_num; | ||||
| t_add_ns(&t_target, &t_target, elapsed_ns); | |||||
| t_target += elapsed_us; | |||||
| time_sleep_until(&t_target); | |||||
| time_us slept_us = time_sleep_until(t_target); | |||||
| (void)slept_us; | |||||
| if (slept_us <= -elapsed_us) { | |||||
| // We're way out of sync. | |||||
| t_target = time_now(); | |||||
| } | |||||
| cycle_last_frame = total_cycles; | cycle_last_frame = total_cycles; | ||||
| @@ -1,21 +1,21 @@ | |||||
| #include <time.h> | |||||
| #include "time.h" | |||||
| #include "timer.h" | |||||
| #include <SDL2/SDL.h> | #include <SDL2/SDL.h> | ||||
| void time_get(struct timespec* ts) { | |||||
| uint64_t time = SDL_GetTicks64(); | |||||
| ts->tv_sec = time / 1000U; | |||||
| ts->tv_nsec = (time % 1000U) * 1000U * 1000U; | |||||
| time_us time_now(void) { | |||||
| return (SDL_GetTicks64() * 1000U); | |||||
| } | |||||
| void time_sleep(time_us sleep_us) { | |||||
| SDL_Delay(sleep_us / 1000U); | |||||
| } | } | ||||
| void time_sleep_until(const struct timespec* ts) { | |||||
| uint64_t t_target = ( (ts->tv_sec * 1000ULL) + | |||||
| (ts->tv_nsec / (1000U * 1000U))); | |||||
| uint64_t t_now = SDL_GetTicks64(); | |||||
| if (t_target > t_now) { | |||||
| SDL_Delay(t_target - t_now); | |||||
| time_us time_sleep_until(time_us t_target) { | |||||
| time_us t_now = time_now(); | |||||
| time_us t_diff = t_target - t_now; | |||||
| if (t_diff > 0) { | |||||
| time_sleep(t_diff); | |||||
| } | } | ||||
| return t_diff; | |||||
| } | } | ||||
| @@ -1,31 +1,20 @@ | |||||
| #ifndef NESE_TIMER_H_ | #ifndef NESE_TIMER_H_ | ||||
| #define NESE_TIMER_H_ | #define NESE_TIMER_H_ | ||||
| #include <time.h> | |||||
| #include <stdint.h> | |||||
| #define NS_PER_S (1000U * 1000U * 1000U) | |||||
| #define US_PER_S (1000U * 1000U) | |||||
| static inline int t_diff_ns(const struct timespec* b, | |||||
| const struct timespec* a) { | |||||
| int sec = (b->tv_sec - a->tv_sec); | |||||
| int nsec = (b->tv_nsec - a->tv_nsec); | |||||
| return ((sec * NS_PER_S) + nsec); | |||||
| } | |||||
| typedef int64_t time_us; | |||||
| static inline void t_add_ns(struct timespec* s, | |||||
| const struct timespec* a, | |||||
| int b) { | |||||
| int nsec = a->tv_nsec + b; | |||||
| s->tv_sec = a->tv_sec + (nsec / NS_PER_S); | |||||
| s->tv_nsec = nsec % NS_PER_S; | |||||
| } | |||||
| time_us time_now(void); | |||||
| void time_get(struct timespec*); | |||||
| void time_sleep(time_us); | |||||
| void time_sleep_until(const struct timespec*); | |||||
| time_us time_sleep_until(time_us); | |||||
| #endif // NESE_TIME_H_ | #endif // NESE_TIME_H_ | ||||