2017-10-04 07:07:04 +02:00
/*
2019-08-03 19:43:48 +02:00
* This software is licensed under the terms of the MIT License .
2017-10-04 07:07:04 +02:00
* See COPYING for further information .
* - - -
2019-01-23 21:10:43 +01:00
* Copyright ( c ) 2011 - 2019 , Lukas Weber < laochailan @ web . de > .
2019-07-03 20:00:56 +02:00
* Copyright ( c ) 2012 - 2019 , Andrei Alexeyev < akari @ taisei - project . org > .
2017-10-04 07:07:04 +02:00
*/
2017-11-25 20:45:11 +01:00
# include "taisei.h"
2017-10-04 07:07:04 +02:00
# include "util.h"
2017-11-11 19:47:15 +01:00
# include "hirestime.h"
2023-03-28 22:53:56 +02:00
# include "thread.h"
2017-10-04 07:07:04 +02:00
static bool use_hires ;
2017-11-11 19:47:15 +01:00
static hrtime_t time_current ;
static hrtime_t time_offset ;
2017-10-04 07:07:04 +02:00
static uint64_t prev_hires_time ;
static uint64_t prev_hires_freq ;
2019-01-09 04:25:10 +01:00
static uint64_t fast_path_mul ;
2019-08-03 18:47:21 +02:00
INLINE void set_freq ( uint64_t freq ) {
2019-01-09 04:25:10 +01:00
prev_hires_freq = freq ;
lldiv_t d = lldiv ( HRTIME_RESOLUTION , freq ) ;
fast_path_mul = d . quot * ( d . rem = = 0 ) ;
}
2017-10-04 07:07:04 +02:00
static void time_update ( void ) {
2018-01-12 19:26:07 +01:00
bool retry ;
2017-10-04 07:07:04 +02:00
2018-01-12 19:26:07 +01:00
do {
retry = false ;
2017-10-04 07:07:04 +02:00
2018-01-12 19:26:07 +01:00
uint64_t freq = SDL_GetPerformanceFrequency ( ) ;
uint64_t cntr = SDL_GetPerformanceCounter ( ) ;
2017-10-04 07:07:04 +02:00
2018-01-12 19:26:07 +01:00
if ( freq ! = prev_hires_freq ) {
2019-01-09 04:25:10 +01:00
log_debug ( " High resolution timer frequency changed: was % " PRIu64 " , now % " PRIu64 " . Saved time offset: % " PRIuTIME " " , prev_hires_freq , freq , time_offset ) ;
2018-01-12 19:26:07 +01:00
time_offset = time_current ;
2019-01-09 04:25:10 +01:00
set_freq ( freq ) ;
2018-01-12 19:26:07 +01:00
prev_hires_time = SDL_GetPerformanceCounter ( ) ;
retry = true ;
continue ;
}
2017-10-04 07:07:04 +02:00
2019-01-09 04:25:10 +01:00
hrtime_t time_new ;
if ( fast_path_mul ) {
time_new = time_offset + ( cntr - prev_hires_time ) * fast_path_mul ;
} else {
time_new = time_offset + umuldiv64 ( cntr - prev_hires_time , HRTIME_RESOLUTION , freq ) ;
}
2017-10-04 07:07:04 +02:00
2018-01-12 19:26:07 +01:00
if ( time_new < time_current ) {
2019-01-09 04:25:10 +01:00
log_warn ( " BUG: time went backwards. Was % " PRIuTIME " , now % " PRIuTIME " . Possible cause: your OS sucks spherical objects. Attempting to correct this... " , time_current , time_new ) ;
2018-01-12 19:26:07 +01:00
time_offset = time_current ;
time_current = 0 ;
prev_hires_time = SDL_GetPerformanceCounter ( ) ;
retry = true ;
} else {
time_current = time_new ;
}
} while ( retry ) ;
2017-10-04 07:07:04 +02:00
}
void time_init ( void ) {
2018-04-18 00:34:41 +02:00
use_hires = env_get ( " TAISEI_HIRES_TIMER " , 1 ) ;
2017-10-04 07:07:04 +02:00
2018-01-12 19:26:07 +01:00
if ( use_hires ) {
log_info ( " Using the system high resolution timer " ) ;
prev_hires_time = SDL_GetPerformanceCounter ( ) ;
2019-01-09 04:25:10 +01:00
set_freq ( SDL_GetPerformanceFrequency ( ) ) ;
2018-01-12 19:26:07 +01:00
} else {
log_info ( " Not using the system high resolution timer: disabled by environment " ) ;
return ;
}
2017-10-04 07:07:04 +02:00
}
void time_shutdown ( void ) {
2019-01-09 04:25:10 +01:00
2017-10-04 07:07:04 +02:00
}
2017-11-11 19:47:15 +01:00
hrtime_t time_get ( void ) {
2018-01-12 19:26:07 +01:00
if ( use_hires ) {
2023-03-28 22:53:56 +02:00
assert ( thread_current_is_main ( ) ) ;
2018-01-12 19:26:07 +01:00
time_update ( ) ;
2019-01-09 04:25:10 +01:00
return time_current ;
2018-01-12 19:26:07 +01:00
}
2017-10-04 07:07:04 +02:00
2019-01-09 04:25:10 +01:00
return SDL_GetTicks ( ) * ( HRTIME_RESOLUTION / 1000 ) ;
2017-10-04 07:07:04 +02:00
}