From 4d3bd808d3a1dc4035644ea975bd39824e090ab7 Mon Sep 17 00:00:00 2001 From: SakiiCode <13037299+SakiiCode@users.noreply.github.com> Date: Sat, 18 Apr 2026 18:09:07 +0200 Subject: [PATCH 1/5] move fps check to FpsLimiter --- src/window/mod.rs | 24 +++++++++++++++--------- src/window/multi_window.rs | 4 ++-- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/window/mod.rs b/src/window/mod.rs index 6d35aec..3b8976d 100644 --- a/src/window/mod.rs +++ b/src/window/mod.rs @@ -2,6 +2,7 @@ use std::{ env, fs::File, io::BufReader, + num::NonZeroU32, ops::Deref, process, thread, time::{Duration, Instant}, @@ -26,28 +27,33 @@ mod multi_window; pub use multi_window::MultiWindow; pub(crate) struct FpsLimiter { - max_fps: u32, + max_fps: Option, frame_start: Instant, } impl FpsLimiter { pub(crate) fn new() -> Self { Self { - max_fps: 60, + max_fps: NonZeroU32::new(60), frame_start: Instant::now(), } } - fn desired_loop_duration(&self) -> Duration { - Duration::from_secs_f32(1.0 / self.max_fps as f32) + fn desired_loop_duration(max_fps: NonZeroU32) -> Duration { + Duration::from_secs_f32(1.0 / max_fps.get() as f32) } fn sleep(&mut self) { - let sleep_duration = (self.frame_start + self.desired_loop_duration()) - .saturating_duration_since(Instant::now()); - thread::sleep(sleep_duration); + match self.max_fps { + Some(max_fps) => { + let sleep_duration = (self.frame_start + Self::desired_loop_duration(max_fps)) + .saturating_duration_since(Instant::now()); + thread::sleep(sleep_duration); - self.frame_start = Instant::now(); + self.frame_start = Instant::now(); + } + None => {} + } } } @@ -204,6 +210,6 @@ impl Window { /// Sets the FPS limit of the window. pub fn set_max_fps(&mut self, max_fps: u32) { - self.fps_limiter.max_fps = max_fps; + self.fps_limiter.max_fps = NonZeroU32::new(max_fps); } } diff --git a/src/window/multi_window.rs b/src/window/multi_window.rs index 45b6b7f..a263987 100644 --- a/src/window/multi_window.rs +++ b/src/window/multi_window.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::{collections::HashMap, num::NonZeroU32}; use embedded_graphics::{pixelcolor::Rgb888, prelude::*}; @@ -127,7 +127,7 @@ impl MultiWindow { /// Sets the FPS limit of the window. pub fn set_max_fps(&mut self, max_fps: u32) { - self.fps_limiter.max_fps = max_fps; + self.fps_limiter.max_fps = NonZeroU32::new(max_fps); } } From a1ffee37b7923418581b3edf2461fa1a751f83dd Mon Sep 17 00:00:00 2001 From: SakiiCode <13037299+SakiiCode@users.noreply.github.com> Date: Sat, 18 Apr 2026 18:27:38 +0200 Subject: [PATCH 2/5] update docs and changelog --- CHANGELOG.md | 4 ++++ src/window/mod.rs | 2 +- src/window/multi_window.rs | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68a0102..5a5aa17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ - **(breaking)** [#71](https://github.com/embedded-graphics/simulator/pull/71) Added support for non-square pixels. +### Changed + +- [#72](https://github.com/embedded-graphics/simulator/pull/72) `set_max_fps` now accepts `0` to disable the FPS limiter. + ### Fixed - [#71](https://github.com/embedded-graphics/simulator/pull/71) Fixed pixel spacing for unscaled outputs. diff --git a/src/window/mod.rs b/src/window/mod.rs index 3b8976d..dc140bd 100644 --- a/src/window/mod.rs +++ b/src/window/mod.rs @@ -208,7 +208,7 @@ impl Window { .events(&self.output_settings) } - /// Sets the FPS limit of the window. + /// Changes the FPS limit of the window. Set to `0` to disable the FPS limiter. pub fn set_max_fps(&mut self, max_fps: u32) { self.fps_limiter.max_fps = NonZeroU32::new(max_fps); } diff --git a/src/window/multi_window.rs b/src/window/multi_window.rs index a263987..a6586ef 100644 --- a/src/window/multi_window.rs +++ b/src/window/multi_window.rs @@ -125,7 +125,7 @@ impl MultiWindow { display.bounding_box().contains(p).then_some(p) } - /// Sets the FPS limit of the window. + /// Changes the FPS limit of the window. Set to `0` to disable the FPS limiter. pub fn set_max_fps(&mut self, max_fps: u32) { self.fps_limiter.max_fps = NonZeroU32::new(max_fps); } From 18e398f66fb67a5834acb0c83b260a303f0ea930 Mon Sep 17 00:00:00 2001 From: Sakii <13037299+SakiiCode@users.noreply.github.com> Date: Sat, 18 Apr 2026 16:29:22 +0000 Subject: [PATCH 3/5] check for duration Co-authored-by: Ralf Fuest --- src/window/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/window/mod.rs b/src/window/mod.rs index dc140bd..c15042f 100644 --- a/src/window/mod.rs +++ b/src/window/mod.rs @@ -44,7 +44,9 @@ impl FpsLimiter { } fn sleep(&mut self) { - match self.max_fps { + let Some(duration) = self.desired_loop_duration() else { + return; + }; Some(max_fps) => { let sleep_duration = (self.frame_start + Self::desired_loop_duration(max_fps)) .saturating_duration_since(Instant::now()); From 4b2b083f98c26e1f09888cb2c50d7e3ebaea5c63 Mon Sep 17 00:00:00 2001 From: Sakii <13037299+SakiiCode@users.noreply.github.com> Date: Sat, 18 Apr 2026 16:30:15 +0000 Subject: [PATCH 4/5] change desired_loop_duration signature Co-authored-by: Ralf Fuest --- src/window/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/window/mod.rs b/src/window/mod.rs index c15042f..04bb4f8 100644 --- a/src/window/mod.rs +++ b/src/window/mod.rs @@ -39,7 +39,7 @@ impl FpsLimiter { } } - fn desired_loop_duration(max_fps: NonZeroU32) -> Duration { + fn desired_loop_duration(&self) -> Option { Duration::from_secs_f32(1.0 / max_fps.get() as f32) } From b0f77cff4077d48ad9fe401878532260897cee6e Mon Sep 17 00:00:00 2001 From: SakiiCode <13037299+SakiiCode@users.noreply.github.com> Date: Sat, 18 Apr 2026 18:32:41 +0200 Subject: [PATCH 5/5] fix option --- src/window/mod.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/window/mod.rs b/src/window/mod.rs index 04bb4f8..fa9c695 100644 --- a/src/window/mod.rs +++ b/src/window/mod.rs @@ -40,22 +40,19 @@ impl FpsLimiter { } fn desired_loop_duration(&self) -> Option { - Duration::from_secs_f32(1.0 / max_fps.get() as f32) + Some(Duration::from_secs_f32(1.0 / self.max_fps?.get() as f32)) } fn sleep(&mut self) { let Some(duration) = self.desired_loop_duration() else { - return; + return; }; - Some(max_fps) => { - let sleep_duration = (self.frame_start + Self::desired_loop_duration(max_fps)) - .saturating_duration_since(Instant::now()); - thread::sleep(sleep_duration); - self.frame_start = Instant::now(); - } - None => {} - } + let sleep_duration = + (self.frame_start + duration).saturating_duration_since(Instant::now()); + thread::sleep(sleep_duration); + + self.frame_start = Instant::now(); } }