diff --git a/src/font.c b/src/font.c index f8dc5a03..bbc3ba9d 100644 --- a/src/font.c +++ b/src/font.c @@ -102,7 +102,7 @@ INTERNAL WORK_TASK_FUNC_DEF(font_load_asset_task, vparams) struct asset *asset = params->asset; logf_info("Loading font \"%F\" (point size %F)", FMT_STR(path), FMT_FLOAT((f64)point_size)); - sys_timestamp_t start_ts = sys_timestamp(); + struct sys_timestamp start_ts = sys_timestamp_prog(); ASSERT(string_ends_with(path, STR(".ttf"))); if (!resource_exists(path)) { @@ -157,7 +157,8 @@ INTERNAL WORK_TASK_FUNC_DEF(font_load_asset_task, vparams) font_task_params_release(params); - logf_info("Finished loading font \"%F\" (point size %F) in %F seconds", FMT_STR(path), FMT_FLOAT((f64)point_size), FMT_FLOAT(sys_timestamp_seconds(sys_timestamp() - start_ts))); + f64 elapsed = sys_timestamp_to_seconds(sys_timestamp_sub(sys_timestamp_prog(), start_ts)); + logf_info("Finished loading font \"%F\" (point size %F) in %F seconds", FMT_STR(path), FMT_FLOAT((f64)point_size), FMT_FLOAT(elapsed)); asset_cache_mark_ready(asset, font); scratch_end(scratch); diff --git a/src/game.c b/src/game.c index 8b5b5fd0..5082cee5 100644 --- a/src/game.c +++ b/src/game.c @@ -504,7 +504,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) * ========================== */ ++G.tick.tick_id; - G.tick.tick_ts = sys_timestamp(); + G.tick.tick_ts = sys_timestamp_prog(); G.tick.dt = max_f64(0.0, (1.0 / GAME_FPS) * G.tick.timescale); G.tick.time += G.tick.dt; @@ -1347,13 +1347,13 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(game_thread_entry_point, arg) struct temp_arena scratch = scratch_begin_no_conflict(); (UNUSED)arg; - sys_timestamp_t last_frame_ts = 0; + struct sys_timestamp last_frame_ts = ZI; f64 target_dt = GAME_FPS > (0) ? (1.0 / GAME_FPS) : 0; while (!atomic_i32_eval(&G.game_thread_shutdown)) { __profscope(game_update_w_sleep); struct temp_arena temp = arena_temp_begin(scratch.arena); sleep_frame(last_frame_ts, target_dt); - last_frame_ts = sys_timestamp(); + last_frame_ts = sys_timestamp_prog(); { struct game_cmd_array game_cmds = pop_cmds(temp.arena); if (!G.paused) { diff --git a/src/game.h b/src/game.h index 11369b03..fca9f68b 100644 --- a/src/game.h +++ b/src/game.h @@ -7,6 +7,10 @@ struct sprite_startup_receipt; struct sound_startup_receipt; struct phys_startup_receipt; +/* ========================== * + * Game cmd + * ========================== */ + enum game_cmd_state { GAME_CMD_STATE_STOP = -1, GAME_CMD_STATE_NO_CHANGE = 0, @@ -30,16 +34,6 @@ enum game_cmd_kind { GAME_CMD_KIND_COUNT }; -/* Absolute layers */ -#define GAME_LAYER_FLOOR_DECALS -300 -#define GAME_LAYER_BULLETS -200 -#define GAME_LAYER_TRACERS -100 -#define GAME_LAYER_SHOULDERS 0 - -/* Relative layers */ -#define GAME_LAYER_RELATIVE_DEFAULT 0 -#define GAME_LAYER_RELATIVE_WEAPON 1 - struct game_cmd { enum game_cmd_kind kind; enum game_cmd_state state; @@ -61,6 +55,16 @@ struct game_cmd_array { u64 count; }; +/* Absolute layers */ +#define GAME_LAYER_FLOOR_DECALS -300 +#define GAME_LAYER_BULLETS -200 +#define GAME_LAYER_TRACERS -100 +#define GAME_LAYER_SHOULDERS 0 + +/* Relative layers */ +#define GAME_LAYER_RELATIVE_DEFAULT 0 +#define GAME_LAYER_RELATIVE_WEAPON 1 + struct game_startup_receipt { i32 _; }; struct game_startup_receipt game_startup(struct mixer_startup_receipt *mixer_sr, struct sprite_startup_receipt *sheet_sr, diff --git a/src/intrinsics.h b/src/intrinsics.h index 3dc45654..fd4c8c01 100644 --- a/src/intrinsics.h +++ b/src/intrinsics.h @@ -115,7 +115,7 @@ INLINE void ix_pause(void) _mm_pause(); } -INLINE u64 ix_clock(void) +INLINE i64 ix_clock(void) { return __rdtsc(); } diff --git a/src/sound.c b/src/sound.c index 1a08b194..99d2e058 100644 --- a/src/sound.c +++ b/src/sound.c @@ -91,7 +91,7 @@ INTERNAL WORK_TASK_FUNC_DEF(sound_load_asset_task, vparams) u32 flags = params->flags; logf_info("Loading sound \"%F\"", FMT_STR(path)); - sys_timestamp_t start_ts = sys_timestamp(); + struct sys_timestamp start_ts = sys_timestamp_prog(); b32 success = true; struct string error_msg = STR("Unknown error"); @@ -132,9 +132,8 @@ INTERNAL WORK_TASK_FUNC_DEF(sound_load_asset_task, vparams) }; MEMCPY(sound->pcm.samples, decoded.pcm.samples, decoded.pcm.count * sizeof(*decoded.pcm.samples)); - logf_info("Finished loading sound \"%F\" in %F seconds", - FMT_STR(path), - FMT_FLOAT(sys_timestamp_seconds(sys_timestamp() - start_ts))); + f64 elapsed = sys_timestamp_to_seconds(sys_timestamp_sub(sys_timestamp_prog(), start_ts)); + logf_info("Finished loading sound \"%F\" in %F seconds", FMT_STR(path), FMT_FLOAT(elapsed)); asset_cache_mark_ready(asset, sound); } else { diff --git a/src/sprite.c b/src/sprite.c index 22d590ef..bcbd22c0 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -342,7 +342,7 @@ INTERNAL void cache_node_load_texture(struct cache_node *n, struct sprite_tag ta struct string path = tag.path; logf_info("Loading sprite texture \"%F\"", FMT_STR(path)); - sys_timestamp_t start_ts = sys_timestamp(); + struct sys_timestamp start_ts = sys_timestamp_prog(); ASSERT(string_ends_with(path, STR(".ase"))); ASSERT(n->kind == CACHE_NODE_KIND_TEXTURE); @@ -383,9 +383,10 @@ INTERNAL void cache_node_load_texture(struct cache_node *n, struct sprite_tag ta n->memory_usage = n->arena.committed + memory_size; atomic_u64_eval_add(&G.cache.memory_usage, n->memory_usage); + f64 elapsed = sys_timestamp_to_seconds(sys_timestamp_sub(sys_timestamp_prog(), start_ts)); logf_info("Finished loading sprite texture \"%F\" in %F seconds (cache size: %F bytes).", FMT_STR(path), - FMT_FLOAT(sys_timestamp_seconds(sys_timestamp() - start_ts)), + FMT_FLOAT(elapsed), FMT_UINT(n->memory_usage)); atomic_u32_eval_exchange(&n->state, CACHE_NODE_STATE_LOADED); @@ -647,7 +648,7 @@ INTERNAL void cache_node_load_sheet(struct cache_node *n, struct sprite_tag tag) struct string path = tag.path; logf_info("Loading sprite sheet \"%F\"", FMT_STR(path)); - sys_timestamp_t start_ts = sys_timestamp(); + struct sys_timestamp start_ts = sys_timestamp_prog(); //ASSERT(string_ends_with(path, STR(".ase"))); ASSERT(n->kind == CACHE_NODE_KIND_SHEET); @@ -682,9 +683,10 @@ INTERNAL void cache_node_load_sheet(struct cache_node *n, struct sprite_tag tag) n->memory_usage = n->arena.committed; atomic_u64_eval_add(&G.cache.memory_usage, n->memory_usage); + f64 elapsed = sys_timestamp_to_seconds(sys_timestamp_sub(sys_timestamp_prog(), start_ts)); logf_info("Finished loading sprite sheet \"%F\" in %F seconds (cache size: %F bytes).", FMT_STR(path), - FMT_FLOAT(sys_timestamp_seconds(sys_timestamp() - start_ts)), + FMT_FLOAT(elapsed), FMT_UINT(n->memory_usage)); diff --git a/src/sys.h b/src/sys.h index bc05f5fb..5217114c 100644 --- a/src/sys.h +++ b/src/sys.h @@ -174,25 +174,50 @@ void sys_memory_set_committed_readonly(void *address, u64 size); void sys_memory_set_committed_readwrite(void *address, u64 size); /* ========================== * - * Time + * Timestamp + * ========================== */ + +struct sys_timestamp { + u64 v; +}; + +/* Returns timestamp representing time since program start */ +struct sys_timestamp sys_timestamp_prog(void); + +/* NOTE: Conversion between timestamp & seconds should only happen with small + * timestamp values (like relative timestamps) to avoid precision loss */ +struct sys_timestamp sys_timestamp_from_seconds(f64 s); +f64 sys_timestamp_to_seconds(struct sys_timestamp ts); + +INLINE struct sys_timestamp sys_timestamp_add(struct sys_timestamp a, struct sys_timestamp b) +{ + struct sys_timestamp res; + res.v = a.v + b.v; + return res; +} + +INLINE struct sys_timestamp sys_timestamp_sub(struct sys_timestamp a, struct sys_timestamp b) +{ + struct sys_timestamp res; + res.v = a.v - b.v; + return res; +} + +/* ========================== * + * Datetime * ========================== */ struct sys_datetime { - u32 year; - u32 month; - u32 day_of_week; - u32 day; - u32 hour; - u32 minute; - u32 second; - u32 milliseconds; + u32 year; + u32 month; + u32 day_of_week; + u32 day; + u32 hour; + u32 minute; + u32 second; + u32 milliseconds; }; -typedef u64 sys_timestamp_t; - -sys_timestamp_t sys_timestamp(void); -f64 sys_timestamp_seconds(sys_timestamp_t ts); - struct sys_datetime sys_local_time(void); /* ========================== * diff --git a/src/sys_win32.c b/src/sys_win32.c index ee58f879..d1fe06b3 100644 --- a/src/sys_win32.c +++ b/src/sys_win32.c @@ -244,16 +244,25 @@ INTERNAL i64 _win32_i64_muldiv(i64 value, i64 numer, i64 denom) { return q * numer + r * numer / denom; } -sys_timestamp_t sys_timestamp(void) +struct sys_timestamp sys_timestamp_prog(void) { + struct sys_timestamp ts; LARGE_INTEGER time; QueryPerformanceCounter(&time); - return (u64)_win32_i64_muldiv(time.QuadPart - G.timer_start.QuadPart, 1000000000, G.timer_frequency.QuadPart); + ts.v = (u64)_win32_i64_muldiv(time.QuadPart - G.timer_start.QuadPart, 1000000000, G.timer_frequency.QuadPart); + return ts; } -f64 sys_timestamp_seconds(sys_timestamp_t ts) +struct sys_timestamp sys_timestamp_from_seconds(f64 s) { - return (f64)ts / 1000000000.0; + struct sys_timestamp ts; + ts.v = (u64)(s * 1000000000.0); + return ts; +} + +f64 sys_timestamp_to_seconds(struct sys_timestamp ts) +{ + return (f64)(ts.v) / 1000000000.0; } struct sys_datetime sys_local_time(void) diff --git a/src/user.c b/src/user.c index 097c4d1b..ac01851e 100644 --- a/src/user.c +++ b/src/user.c @@ -291,13 +291,13 @@ INTERNAL struct interp_ticks pull_ticks(f64 blend_time) from_tick = oldest_tick; to_tick = newest_tick; for (struct blend_tick *bt = G.head_blend_tick; bt; bt = bt->next) { - f64 bt_time = sys_timestamp_seconds(bt->world.tick_ts); + f64 bt_time = sys_timestamp_to_seconds(bt->world.tick_ts); - if (bt_time < blend_time && bt_time > sys_timestamp_seconds(from_tick->tick_ts)) { + if (bt_time < blend_time && bt_time > sys_timestamp_to_seconds(from_tick->tick_ts)) { from_tick = &bt->world; } - if (bt_time > blend_time && bt_time < sys_timestamp_seconds(to_tick->tick_ts)) { + if (bt_time > blend_time && bt_time < sys_timestamp_to_seconds(to_tick->tick_ts)) { to_tick = &bt->world; } } @@ -309,8 +309,8 @@ INTERNAL struct interp_ticks pull_ticks(f64 blend_time) u64 bts_to_free_count = 0; for (struct blend_tick *bt = G.head_blend_tick; bt; bt = bt->next) { - f64 bt_time = sys_timestamp_seconds(bt->world.tick_ts); - if (bt_time < sys_timestamp_seconds(from_tick->tick_ts)) { + f64 bt_time = sys_timestamp_to_seconds(bt->world.tick_ts); + if (bt_time < sys_timestamp_to_seconds(from_tick->tick_ts)) { *arena_push(scratch.arena, struct blend_tick *) = bt; ++bts_to_free_count; } @@ -490,7 +490,7 @@ INTERNAL void user_update(void) * Begin frame * ========================== */ - f64 cur_time = sys_timestamp_seconds(sys_timestamp()); + f64 cur_time = sys_timestamp_to_seconds(sys_timestamp_prog()); G.dt = max_f64(0.0, cur_time - G.time); G.time += G.dt; G.screen_size = sys_window_get_size(G.window); @@ -500,11 +500,11 @@ INTERNAL void user_update(void) struct game_cmd_list cmd_list = ZI; /* ========================== * - * Produce interpolated tick + * Interpolate between game ticks * ========================== */ { - __profscope(produce_interpolated_tick); + __profscope(interpolate_ticks); #if USER_INTERP_ENABLED /* TODO: Use actual fps of game thread (will differ from GAME_FPS if game thread is lagging) to hide lag with slow-motion? */ @@ -518,8 +518,8 @@ INTERNAL void user_update(void) f32 tick_blend = 0; { - f64 t0_time = sys_timestamp_seconds(t0->tick_ts); - f64 t1_time = sys_timestamp_seconds(t1->tick_ts); + f64 t0_time = sys_timestamp_to_seconds(t0->tick_ts); + f64 t1_time = sys_timestamp_to_seconds(t1->tick_ts); if (t1_time > t0_time) { tick_blend = (f32)((blend_time - t0_time) / (t1_time - t0_time)); } @@ -1717,13 +1717,13 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_thread_entry_point, arg) { (UNUSED)arg; - sys_timestamp_t last_frame_ts = 0; + struct sys_timestamp last_frame_ts = ZI; f64 target_dt = USER_FRAME_LIMIT > (0) ? (1.0 / USER_FRAME_LIMIT) : 0; while (!atomic_i32_eval(&G.user_thread_shutdown)) { __profscope(user_update_w_sleep); sleep_frame(last_frame_ts, target_dt); - last_frame_ts = sys_timestamp(); + last_frame_ts = sys_timestamp_prog(); user_update(); } } diff --git a/src/util.h b/src/util.h index d026d783..16717ff1 100644 --- a/src/util.h +++ b/src/util.h @@ -239,11 +239,11 @@ INLINE void sync_flag_wait(struct sync_flag *sf) * Sleep frame * ========================== */ -INLINE void sleep_frame(sys_timestamp_t last_frame_time, f64 target_dt) +INLINE void sleep_frame(struct sys_timestamp last_frame_time, f64 target_dt) { __prof; - if (last_frame_time != 0 && target_dt > 0) { - f64 last_frame_dt = sys_timestamp_seconds(sys_timestamp() - last_frame_time); + if (last_frame_time.v != 0 && target_dt > 0) { + f64 last_frame_dt = sys_timestamp_to_seconds(sys_timestamp_sub(sys_timestamp_prog(), last_frame_time)); f64 sleep_time = target_dt - last_frame_dt; if (sleep_time > 0) { sys_sleep_precise(sleep_time); diff --git a/src/world.h b/src/world.h index a7c870e8..d2f8e6c0 100644 --- a/src/world.h +++ b/src/world.h @@ -4,9 +4,9 @@ #include "entity.h" struct world { - u64 continuity_gen; /* Starts at 1 */ - u64 tick_id; /* Starts at 1 */ - u64 tick_ts; /* When was this tick simulated in program time */ + u64 continuity_gen; /* Starts at 1 */ + u64 tick_id; /* Starts at 1 */ + struct sys_timestamp tick_ts; /* When was this tick simulated in program time */ /* World time */ f64 timescale;