diff --git a/crates/host_desktop/src/main.rs b/crates/host_desktop/src/main.rs index 5d33fe14..9d5db4f0 100644 --- a/crates/host_desktop/src/main.rs +++ b/crates/host_desktop/src/main.rs @@ -30,7 +30,8 @@ struct PrometeuApp { input_signals: InputSignals, frame_target_dt: Duration, - next_frame: Instant, + last_frame_time: Instant, + accumulator: Duration, last_stats_update: Instant, frames_since_last_update: u64, @@ -38,6 +39,8 @@ struct PrometeuApp { impl PrometeuApp { fn new() -> Self { + let target_fps = 60; + Self { window: None, pixels: None, @@ -46,8 +49,9 @@ impl PrometeuApp { input_signals: InputSignals::default(), - frame_target_dt: Duration::from_nanos(1_000_000_000 / 60), - next_frame: Instant::now(), + frame_target_dt: Duration::from_nanos(1_000_000_000 / target_fps), + last_frame_time: Instant::now(), + accumulator: Duration::ZERO, last_stats_update: Instant::now(), frames_since_last_update: 0, @@ -98,7 +102,6 @@ impl ApplicationHandler for PrometeuApp { self.pixels = Some(pixels); - self.next_frame = Instant::now(); event_loop.set_control_flow(ControlFlow::Poll); } @@ -185,43 +188,43 @@ impl ApplicationHandler for PrometeuApp { } fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) { - // Pacing simples a ~60Hz let now = Instant::now(); + let mut frame_delta = now.duration_since(self.last_frame_time); - if now >= self.next_frame { - self.next_frame += self.frame_target_dt; + // Limitador para evitar a "espiral da morte" se o SO travar (máximo de 100ms por volta) + if frame_delta > Duration::from_millis(100) { + frame_delta = Duration::from_millis(100); + } - // executa 1 frame do PROMETEU + self.last_frame_time = now; + self.accumulator += frame_delta; + + // 🔥 O coração do determinismo: consome o tempo em fatias exatas de 60Hz + while self.accumulator >= self.frame_target_dt { self.machine.step_frame(&self.input_signals); - + self.accumulator -= self.frame_target_dt; self.frames_since_last_update += 1; + } - let elapsed = now.duration_since(self.last_stats_update); - if elapsed >= Duration::from_secs(1) { - if let Some(window) = self.window { - let fps = self.frames_since_last_update as f64 / elapsed.as_secs_f64(); - let usage_bytes = self.machine.gfx.memory_usage_bytes(); - let kb = usage_bytes as f64 / 1024.0; + // Atualiza estatísticas a cada 1 segundo real + let stats_elapsed = now.duration_since(self.last_stats_update); + if stats_elapsed >= Duration::from_secs(1) { + if let Some(window) = self.window { + let fps = self.frames_since_last_update as f64 / stats_elapsed.as_secs_f64(); + let kb = self.machine.gfx.memory_usage_bytes() as f64 / 1024.0; - let title = format!( - "PROMETEU | GFX: {:.1} KB | FPS: {:.1} | Frame: {}", - kb, - fps, - self.machine.frame_index); - window.set_title(&title); - } - - self.last_stats_update = now; - self.frames_since_last_update = 0; + let title = format!( + "PROMETEU | GFX: {:.1} KB | FPS: {:.1} | Frame: {}", + kb, fps, self.machine.frame_index + ); + window.set_title(&title); } - // pede redraw - self.request_redraw(); - } else { - // dorme pouco para não fritar CPU - let sleep_for = self.next_frame - now; - std::thread::sleep(sleep_for.min(Duration::from_millis(2))); + self.last_stats_update = now; + self.frames_since_last_update = 0; } + + self.request_redraw(); } }