remove sys_timestamp, refactor into generalized i64 holding nanoseconds

This commit is contained in:
jacob 2025-01-29 11:29:31 -06:00
parent a20e8eced5
commit f0a25248c3
12 changed files with 109 additions and 134 deletions

View File

@ -231,6 +231,10 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t);
#define GIGABYTE(n) (n*MEGABYTE(1024ULL))
#define TERABYTE(n) (n*GIGABYTE(1024ULL))
/* Time */
#define NS_FROM_SECONDS(s) ((i64)((s) * 1000000000.0))
#define SECONDS_FROM_NS(ns) ((f64)(ns) / 1000000000.0)
/* typeof */
#if COMPILER_MSVC
/* Typeof not supported in MSVC */

View File

@ -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));
struct sys_timestamp start_ts = sys_timestamp_prog();
i64 start_ns = sys_time_ns();
ASSERT(string_ends_with(path, STR(".ttf")));
if (!resource_exists(path)) {
@ -157,7 +157,7 @@ INTERNAL WORK_TASK_FUNC_DEF(font_load_asset_task, vparams)
font_task_params_release(params);
f64 elapsed = sys_timestamp_to_seconds(sys_timestamp_sub(sys_timestamp_prog(), start_ts));
f64 elapsed = SECONDS_FROM_NS(sys_time_ns() - start_ns);
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);

View File

@ -504,12 +504,13 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
* ========================== */
++G.tick.tick_id;
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;
G.tick.simtime_ns = sys_time_ns();
f64 dt = G.tick.dt;
f64 time = G.tick.time;
G.tick.dt_ns = NS_FROM_SECONDS(max_f64(0.0, (1.0 / GAME_FPS) * G.tick.timescale));
G.tick.time_ns += G.tick.dt_ns;
f64 dt = SECONDS_FROM_NS(G.tick.dt_ns);
f64 time = SECONDS_FROM_NS(G.tick.time_ns);
G.sprite_frame_scope = sprite_scope_begin();
G.root = entity_from_handle(G.tick.entity_store, G.tick.entity_store->root);
@ -1218,7 +1219,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
/* Lerp camera */
if (ent->camera_applied_lerp_continuity_gen_plus_one == ent->camera_lerp_continuity_gen + 1) {
f32 t = 1 - math_pow(2.f, -20.f * (f32)G.tick.dt);
f32 t = 1 - math_pow(2.f, -20.f * (f32)dt);
xf = xform_lerp(xf, ent->camera_xform_target, t);
} else {
/* Skip lerp */
@ -1347,13 +1348,13 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(game_thread_entry_point, arg)
struct temp_arena scratch = scratch_begin_no_conflict();
(UNUSED)arg;
struct sys_timestamp last_frame_ts = ZI;
f64 target_dt = GAME_FPS > (0) ? (1.0 / GAME_FPS) : 0;
i64 last_frame_ns = 0;
i64 target_dt_ns = NS_FROM_SECONDS(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_prog();
sleep_frame(last_frame_ns, target_dt_ns);
last_frame_ns = sys_time_ns();
{
struct game_cmd_array game_cmds = pop_cmds(temp.arena);
if (!G.paused) {

View File

@ -590,16 +590,26 @@ INLINE f32 math_unwind_angle(f32 a)
* Lerp
* ========================== */
INLINE f32 math_lerp(f32 val0, f32 val1, f32 t)
INLINE f32 math_lerp_f32(f32 val0, f32 val1, f32 t)
{
return val0 + ((val1 - val0) * t);
}
INLINE f64 math_lerp64(f64 val0, f64 val1, f64 t)
INLINE f64 math_lerp_f64(f64 val0, f64 val1, f64 t)
{
return val0 + ((val1 - val0) * t);
}
INLINE i32 math_lerp_i32(i32 val0, i32 val1, f32 t)
{
return val0 + math_round_to_int(((f32)(val1 - val0) * t));
}
INLINE i64 math_lerp_i64(i64 val0, i64 val1, f64 t)
{
return val0 + math_round_to_int64(((f64)(val1 - val0) * t));
}
INLINE f32 math_lerp_angle(f32 a, f32 b, f32 t) {
f32 diff = math_unwind_angle(b - a);
return a + diff * t;
@ -795,14 +805,14 @@ INLINE struct v2 v2_closest_point_ray(struct v2 ray_pos, struct v2 ray_dir_norm,
/* Interpolate position vectors */
INLINE struct v2 v2_lerp(struct v2 val0, struct v2 val1, f32 t)
{
return V2(math_lerp(val0.x, val1.x, t), math_lerp(val0.y, val1.y, t));
return V2(math_lerp_f32(val0.x, val1.x, t), math_lerp_f32(val0.y, val1.y, t));
}
/* Interpolate direction vectors (spherical lerp) */
INLINE struct v2 v2_slerp(struct v2 val0, struct v2 val1, f32 t)
{
f32 rot = math_lerp_angle(v2_angle(val0), v2_angle(val1), t);
f32 len = math_lerp(v2_len(val0), v2_len(val1), t);
f32 len = math_lerp_f32(v2_len(val0), v2_len(val1), t);
return v2_mul(v2_from_angle(rot), len);
}

View File

@ -376,8 +376,8 @@ struct mixed_pcm_f32 mixer_update(struct arena *arena, u64 frame_count)
/* Lerp */
f32 t = in_frame_pos_exact - (f32)in_frame_pos_prev;
f32 sample1 = math_lerp(sample1_prev, sample1_next, t);
f32 sample2 = math_lerp(sample2_prev, sample2_next, t);
f32 sample1 = math_lerp_f32(sample1_prev, sample1_next, t);
f32 sample2 = math_lerp_f32(sample2_prev, sample2_next, t);
out_samples[(out_frame_pos * 2) + 0] += sample1;
out_samples[(out_frame_pos * 2) + 1] += sample2;
@ -395,7 +395,7 @@ struct mixed_pcm_f32 mixer_update(struct arena *arena, u64 frame_count)
/* Lerp */
f32 t = (f32)in_frame_pos_exact - in_frame_pos_prev;
f32 sample = math_lerp(sample_prev, sample_next, t);
f32 sample = math_lerp_f32(sample_prev, sample_next, t);
out_samples[(out_frame_pos * 2) + 0] += sample;
out_samples[(out_frame_pos * 2) + 1] += sample;
@ -446,8 +446,8 @@ struct mixed_pcm_f32 mixer_update(struct arena *arena, u64 frame_count)
/* Spatialize samples */
for (u64 frame_pos = 0; frame_pos < frame_count; ++frame_pos) {
f32 t = (f32)frame_pos / (f32)(frame_count - 1);
f32 volume = math_lerp(volume_start, volume_end, t);
f32 pan = math_lerp(pan_start, pan_end, t);
f32 volume = math_lerp_f32(volume_start, volume_end, t);
f32 pan = math_lerp_f32(pan_start, pan_end, t);
u64 sample1_index = frame_pos * 2;
u64 sample2_index = sample1_index + 1;

View File

@ -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));
struct sys_timestamp start_ts = sys_timestamp_prog();
i64 start_ns = sys_time_ns();
b32 success = true;
struct string error_msg = STR("Unknown error");
@ -132,7 +132,7 @@ INTERNAL WORK_TASK_FUNC_DEF(sound_load_asset_task, vparams)
};
MEMCPY(sound->pcm.samples, decoded.pcm.samples, decoded.pcm.count * sizeof(*decoded.pcm.samples));
f64 elapsed = sys_timestamp_to_seconds(sys_timestamp_sub(sys_timestamp_prog(), start_ts));
f64 elapsed = SECONDS_FROM_NS(sys_time_ns() - start_ns);
logf_info("Finished loading sound \"%F\" in %F seconds", FMT_STR(path), FMT_FLOAT(elapsed));
asset_cache_mark_ready(asset, sound);

View File

@ -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));
struct sys_timestamp start_ts = sys_timestamp_prog();
i64 start_ns = sys_time_ns();
ASSERT(string_ends_with(path, STR(".ase")));
ASSERT(n->kind == CACHE_NODE_KIND_TEXTURE);
@ -383,7 +383,7 @@ 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));
f64 elapsed = SECONDS_FROM_NS(sys_time_ns() - start_ns);
logf_info("Finished loading sprite texture \"%F\" in %F seconds (cache size: %F bytes).",
FMT_STR(path),
FMT_FLOAT(elapsed),
@ -648,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));
struct sys_timestamp start_ts = sys_timestamp_prog();
i64 start_ns = sys_time_ns();
//ASSERT(string_ends_with(path, STR(".ase")));
ASSERT(n->kind == CACHE_NODE_KIND_SHEET);
@ -683,7 +683,7 @@ 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));
f64 elapsed = SECONDS_FROM_NS(sys_time_ns() - start_ns);
logf_info("Finished loading sprite sheet \"%F\" in %F seconds (cache size: %F bytes).",
FMT_STR(path),
FMT_FLOAT(elapsed),

View File

@ -174,37 +174,7 @@ void sys_memory_set_committed_readonly(void *address, u64 size);
void sys_memory_set_committed_readwrite(void *address, u64 size);
/* ========================== *
* 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
* Time
* ========================== */
struct sys_datetime {
@ -220,6 +190,8 @@ struct sys_datetime {
struct sys_datetime sys_local_time(void);
i64 sys_time_ns(void);
/* ========================== *
* File system
*

View File

@ -224,7 +224,8 @@ void sys_memory_set_committed_readwrite(void *address, u64 size)
INTERNAL struct sys_datetime win32_time_to_sys_time(SYSTEMTIME st)
{
return (struct sys_datetime) {
return (struct sys_datetime)
{
.year = st.wYear,
.month = st.wMonth,
.day_of_week = st.wDayOfWeek,
@ -236,27 +237,6 @@ INTERNAL struct sys_datetime win32_time_to_sys_time(SYSTEMTIME st)
};
}
struct sys_timestamp sys_timestamp_prog(void)
{
struct sys_timestamp ts;
LARGE_INTEGER qpc;
QueryPerformanceCounter(&qpc);
ts.v = (qpc.QuadPart * G.timer_frequency_ns) - G.timer_start_ns;
return ts;
}
struct sys_timestamp sys_timestamp_from_seconds(f64 s)
{
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)
{
SYSTEMTIME lt;
@ -264,6 +244,14 @@ struct sys_datetime sys_local_time(void)
return win32_time_to_sys_time(lt);
}
i64 sys_time_ns(void)
{
LARGE_INTEGER qpc;
QueryPerformanceCounter(&qpc);
i64 res = (qpc.QuadPart * G.timer_frequency_ns) - G.timer_start_ns;
return res;
}
/* ========================== *
* File system
* ========================== */

View File

@ -71,8 +71,8 @@ GLOBAL struct {
struct arena sys_events_arena;
/* Per-frame */
f64 time;
f64 dt;
i64 time_ns;
i64 dt_ns;
struct v2 screen_size;
struct v2 screen_cursor;
struct v2 ui_screen_offset;
@ -257,7 +257,7 @@ struct interp_ticks {
struct world *to_tick;
};
INTERNAL struct interp_ticks pull_ticks(f64 blend_time)
INTERNAL struct interp_ticks pull_ticks(i64 blend_time_ns)
{
__prof;
@ -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_to_seconds(bt->world.tick_ts);
i64 bt_time_ns = bt->world.simtime_ns;
if (bt_time < blend_time && bt_time > sys_timestamp_to_seconds(from_tick->tick_ts)) {
if (bt_time_ns < blend_time_ns && bt_time_ns > from_tick->simtime_ns) {
from_tick = &bt->world;
}
if (bt_time > blend_time && bt_time < sys_timestamp_to_seconds(to_tick->tick_ts)) {
if (bt_time_ns > blend_time_ns && bt_time_ns < to_tick->simtime_ns) {
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_to_seconds(bt->world.tick_ts);
if (bt_time < sys_timestamp_to_seconds(from_tick->tick_ts)) {
i64 bt_time_ns = bt->world.simtime_ns;
if (bt_time_ns < from_tick->simtime_ns) {
*arena_push(scratch.arena, struct blend_tick *) = bt;
++bts_to_free_count;
}
@ -490,9 +490,9 @@ INTERNAL void user_update(void)
* Begin frame
* ========================== */
f64 cur_time = sys_timestamp_to_seconds(sys_timestamp_prog());
G.dt = max_f64(0.0, cur_time - G.time);
G.time += G.dt;
i64 now_ns = sys_time_ns();
G.dt_ns = max_f64(0.0, now_ns - G.time_ns);
G.time_ns += G.dt_ns;
G.screen_size = sys_window_get_size(G.window);
struct entity_store *store = G.world.entity_store;
@ -508,20 +508,22 @@ INTERNAL void user_update(void)
#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? */
f64 blend_time_offset = (1.0 / GAME_FPS) * USER_INTERP_OFFSET_TICK_RATIO;
f64 blend_time = G.time > blend_time_offset ? G.time - blend_time_offset : 0;
i64 blend_time_offset_ns = NS_FROM_SECONDS((1.0 / GAME_FPS) * USER_INTERP_OFFSET_TICK_RATIO);
i64 blend_time_ns = G.time_ns > blend_time_offset_ns ? G.time_ns - blend_time_offset_ns : 0;
/* Pull ticks */
struct interp_ticks interp_ticks = pull_ticks(blend_time);
struct interp_ticks interp_ticks = pull_ticks(blend_time_ns);
struct world *t0 = interp_ticks.from_tick;
struct world *t1 = interp_ticks.to_tick;
f32 tick_blend = 0;
{
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));
i64 t0_time_ns = t0->simtime_ns;
i64 t1_time_ns = t1->simtime_ns;
if (t1_time_ns > t0_time_ns) {
f64 t0_t1_elapsed = SECONDS_FROM_NS(t1_time_ns - t0_time_ns);
f64 t0_blend_elapsed = SECONDS_FROM_NS(blend_time_ns - t0_time_ns);
tick_blend = t0_blend_elapsed / t0_t1_elapsed;
}
tick_blend = clamp_f32(tick_blend, 0.0f, 1.0f);
}
@ -529,8 +531,8 @@ INTERNAL void user_update(void)
world_copy_replace(&G.world, t0);
/* Blend world globals */
G.world.time = math_lerp64(t0->time, t1->time, (f64)tick_blend);
G.world.dt = math_lerp64(t0->dt, t1->dt, (f64)tick_blend);
G.world.time_ns = math_lerp_i64(t0->time_ns, t1->time_ns, (f64)tick_blend);
G.world.dt_ns = math_lerp_i64(t0->dt_ns, t1->dt_ns, (f64)tick_blend);
/* Blend entities */
u64 num_entities = min_u64(t0->entity_store->reserved, t1->entity_store->reserved);
@ -554,8 +556,8 @@ INTERNAL void user_update(void)
entity_set_xform(e, xform_lerp(e0_xf, e1_xf, tick_blend));
}
e->control_force = math_lerp(e0->control_force, e1->control_force, tick_blend);
e->control_torque = math_lerp(e0->control_torque, e1->control_torque, tick_blend);
e->control_force = math_lerp_f32(e0->control_force, e1->control_force, tick_blend);
e->control_torque = math_lerp_f32(e0->control_torque, e1->control_torque, tick_blend);
e->linear_velocity = v2_lerp(e0->linear_velocity, e1->linear_velocity, tick_blend);
e->angular_velocity = math_lerp_angle(e0->angular_velocity, e1->angular_velocity, tick_blend);
@ -564,12 +566,12 @@ INTERNAL void user_update(void)
e->control.focus = v2_lerp(e0->control.focus, e1->control.focus, tick_blend);
e->sprite_local_xform = xform_lerp(e0->sprite_local_xform, e1->sprite_local_xform, tick_blend);
e->animation_time_in_frame = math_lerp64(e0->animation_time_in_frame, e1->animation_time_in_frame, (f64)tick_blend);
e->animation_frame = (u32)math_round_to_int(math_lerp(e0->animation_frame, e1->animation_frame, tick_blend));
e->animation_time_in_frame = math_lerp_f64(e0->animation_time_in_frame, e1->animation_time_in_frame, (f64)tick_blend);
e->animation_frame = (u32)math_round_to_int(math_lerp_f32(e0->animation_frame, e1->animation_frame, tick_blend));
e->camera_quad_xform = xform_lerp(e0->camera_quad_xform, e1->camera_quad_xform, tick_blend);
e->camera_xform_target = xform_lerp(e0->camera_xform_target, e1->camera_xform_target, tick_blend);
e->shake = math_lerp(e0->shake, e1->shake, tick_blend);
e->shake = math_lerp_f32(e0->shake, e1->shake, tick_blend);
e->tracer_gradient_start = v2_lerp(e0->tracer_gradient_start, e1->tracer_gradient_start, tick_blend);
e->tracer_gradient_end = v2_lerp(e0->tracer_gradient_end, e1->tracer_gradient_end, tick_blend);
@ -735,12 +737,12 @@ INTERNAL void user_update(void)
if (!entity_is_valid_and_active(ent)) continue;
/* How much time between camera shakes */
const f32 frequency = 0.01f;
i64 frequency_ns = NS_FROM_SECONDS(0.01f);
f32 shake = ent->shake;
if (shake > 0) {
u64 basis = hash_fnv64(HASH_FNV64_BASIS, BUFFER_FROM_STRUCT(&ent->handle));
u32 angle_seed0 = basis + (u64)(G.world.time / frequency);
u32 angle_seed1 = angle_seed0 + 1;
u64 angle_seed0 = basis + (u64)(G.world.time_ns / frequency_ns);
u64 angle_seed1 = angle_seed0 + 1;
f32 angle0 = rng_noise_f32(angle_seed0, 0, TAU);
f32 angle1 = rng_noise_f32(angle_seed1, 0, TAU);
@ -749,7 +751,7 @@ INTERNAL void user_update(void)
struct v2 vec1 = v2_with_len(v2_from_angle(angle1), shake);
/* TODO: Cubic interp? */
f32 blend = math_fmod64(G.world.time, frequency) / frequency;
f32 blend = (f32)(G.world.time_ns % frequency_ns) / (f32)frequency_ns;
struct v2 vec = v2_lerp(vec0, vec1, blend);
struct xform xf = entity_get_xform(ent);
@ -1534,15 +1536,12 @@ INTERNAL void user_update(void)
if (font) {
struct temp_arena temp = arena_temp_begin(scratch.arena);
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, STR("time: %F"), FMT_FLOAT((f64)G.time)));
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, STR("time: %F"), FMT_FLOAT(SECONDS_FROM_NS(G.time_ns))));
pos.y += spacing;
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, STR("world time: %F"), FMT_FLOAT((f64)G.world.time)));
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, STR("world time: %F"), FMT_FLOAT(SECONDS_FROM_NS(G.world.time_ns))));
pos.y += spacing;
//draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, STR("time - world time: %F"), FMT_FLOAT((f64)G.time - (f64)G.world.time)));
//pos.y += spacing;
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, STR("entities: %F/%F"), FMT_UINT(G.world.entity_store->allocated), FMT_UINT(G.world.entity_store->reserved)));
pos.y += spacing;
@ -1717,13 +1716,13 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_thread_entry_point, arg)
{
(UNUSED)arg;
struct sys_timestamp last_frame_ts = ZI;
f64 target_dt = USER_FRAME_LIMIT > (0) ? (1.0 / USER_FRAME_LIMIT) : 0;
i64 last_frame_ns = 0;
i64 target_dt_ns = NS_FROM_SECONDS(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_prog();
sleep_frame(last_frame_ns, target_dt_ns);
last_frame_ns = sys_time_ns();
user_update();
}
}

View File

@ -239,14 +239,15 @@ INLINE void sync_flag_wait(struct sync_flag *sf)
* Sleep frame
* ========================== */
INLINE void sleep_frame(struct sys_timestamp last_frame_time, f64 target_dt)
INLINE void sleep_frame(i64 last_frame_time_ns, i64 target_dt_ns)
{
__prof;
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);
if (last_frame_time_ns != 0 && target_dt_ns > 0) {
i64 now_ns = sys_time_ns();
i64 last_frame_dt_ns = now_ns - last_frame_time_ns;
i64 sleep_time_ns = target_dt_ns - last_frame_dt_ns;
if (sleep_time_ns > 0) {
sys_sleep_precise(SECONDS_FROM_NS(sleep_time_ns));
}
}
}

View File

@ -6,12 +6,12 @@
struct world {
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 */
i64 simtime_ns; /* When was this tick simulated in program time */
/* World time */
f64 timescale;
f64 dt;
f64 time;
i64 dt_ns;
i64 time_ns;
struct entity_store *entity_store;
};