From 896a6ef5959043db5463637d84ed524ae7bade1e Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sat, 11 Apr 2026 16:35:25 -0700 Subject: Render only if there was an update --- simloop/include/simloop.h | 1 + simloop/src/simloop.c | 17 +++++++++++++---- simloop/test/simloop_test.c | 14 ++++++++------ 3 files changed, 22 insertions(+), 10 deletions(-) (limited to 'simloop') diff --git a/simloop/include/simloop.h b/simloop/include/simloop.h index 6ee3b98..1e5b4e0 100644 --- a/simloop/include/simloop.h +++ b/simloop/include/simloop.h @@ -67,6 +67,7 @@ typedef struct Simloop { uint64_t frame; ///< Frame counter. Timer* timer; bool first_iter; + bool updates_since_last_render; } Simloop; /// Create a simulation loop. diff --git a/simloop/src/simloop.c b/simloop/src/simloop.c index aa2b6b7..606f5ed 100644 --- a/simloop/src/simloop.c +++ b/simloop/src/simloop.c @@ -19,6 +19,7 @@ Simloop simloop_make(const SimloopArgs* args) { .last_step = args->timer->start_time}, .timer = args->timer, .first_iter = true, + .updates_since_last_render = false, }; } @@ -57,11 +58,19 @@ void simloop_update(Simloop* sim, SimloopOut* out) { assert(sim); assert(out); - out->should_update = step_update(sim, &sim->update); - out->should_render = - step_render(sim, &sim->render) || + // Simulation update. + const bool updated = step_update(sim, &sim->update); + out->should_update = updated; + sim->updates_since_last_render = sim->updates_since_last_render || updated; + // Simulation render. + const bool rendered = + (sim->updates_since_last_render && step_render(sim, &sim->render)) || (sim->first_iter); // Trigger an initial render on the first frame. - sim->frame += (out->should_update ? 1 : 0); + out->should_render = rendered; + sim->updates_since_last_render = + sim->updates_since_last_render && !out->should_render; + // Loop state update. + sim->frame += (updated ? 1 : 0); sim->first_iter = false; out->frame = sim->frame; out->render_elapsed = time_elapsed(sim, sim->render.last_step); diff --git a/simloop/test/simloop_test.c b/simloop/test/simloop_test.c index c79ee32..9f11e86 100644 --- a/simloop/test/simloop_test.c +++ b/simloop/test/simloop_test.c @@ -44,7 +44,7 @@ TEST_CASE(simloop_initial_render_not_retriggered) { /// A simulation loop with no render frame cap: /// 1. Updates based on the desired update frame rate. -/// 2. Renders at every loop. +/// 2. Renders at every loop (provided there are updates). TEST_CASE(simloop_no_render_frame_cap) { constexpr int UPDATE_FPS = 10; const time_delta EXPECT_UPDATE = sec_to_time_delta(1.0 / (double)UPDATE_FPS); @@ -59,8 +59,10 @@ TEST_CASE(simloop_no_render_frame_cap) { for (time_delta t = 0; t < SIM_TIME_SEC; t += STEP) { timer_advance(&timer, t); simloop_update(&simloop, &simout); - TEST_TRUE(simout.should_render); - TEST_EQUAL((t > 0) && ((t % EXPECT_UPDATE) == 0), simout.should_update); + const bool expect_update = (t > 0) && ((t % EXPECT_UPDATE) == 0); + // A render is still expected at time 0. + TEST_EQUAL(simout.should_render, (t == 0) || expect_update); + TEST_EQUAL(simout.should_update, expect_update); } } @@ -83,9 +85,9 @@ TEST_CASE(simloop_with_render_frame_cap) { for (time_delta t = 0; t < SIM_TIME_SEC; t += STEP) { timer_advance(&timer, t); simloop_update(&simloop, &simout); - // Also expecting initial render at t=0. - TEST_EQUAL((t % EXPECT_RENDER) == 0, simout.should_render); - TEST_EQUAL((t > 0) && ((t % EXPECT_UPDATE) == 0), simout.should_update); + // A render is still expected at time 0. + TEST_EQUAL(simout.should_render, (t % EXPECT_RENDER) == 0); + TEST_EQUAL(simout.should_update, (t > 0) && ((t % EXPECT_UPDATE) == 0)); } } -- cgit v1.2.3