egui: Duration passed to `request_repaint_after` is ignored if called each frame
Describe the bug
Using egui 0.22.0, calling request_repaint_after() causes the application to redraw the UI with a high refresh rate, regardless of the duration passed into request_repaint_after(). It behaves (mostly) as if calling request_repaint().
The bug was not there in version 0.21.0.
Steps to reproduce the behavior: The following code was adapted from the hello world example. I replaced the controls with a fps (frames per second) and counter label. Rust file:
use eframe::egui;
use std::time::{Duration, Instant};
fn main() -> Result<(), eframe::Error> {
let options = eframe::NativeOptions {
initial_window_size: Some(egui::vec2(320.0, 240.0)),
..Default::default()
};
eframe::run_native(
"My egui App",
options,
Box::new(|_cc| Box::<MyApp>::default()),
)
}
struct MyApp {
previous_instant: Instant,
previous_count: u64,
}
impl Default for MyApp {
fn default() -> Self {
Self {
previous_instant: Instant::now(),
previous_count: 0,
}
}
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("My egui Application");
let fps = 1.0 / self.previous_instant.elapsed().as_secs_f64();
self.previous_instant = Instant::now();
self.previous_count += 1;
ui.label(format!("fps: {:.2}, counter: {}", fps, self.previous_count));
});
ctx.request_repaint_after(Duration::from_secs(1));
}
}
toml:
[package]
name = "egui_request_repaint_bug"
version = "0.1.0"
edition = "2021"
[dependencies]
egui = "0.22.0"
eframe = { version = "0.22.0", default-features = false, features = [
"default_fonts", # Embed the default egui fonts.
"glow", # Use the glow rendering backend. Alternative: "wgpu".
] }
[patch.crates-io]
egui = { git = "https://github.com/emilk/egui", branch = "master" }
eframe = { git = "https://github.com/emilk/egui", branch = "master" }
Build and run on Windows 10.
When the application has focus, the “fps” labels shows approximately a value of 144 on my monitor (which has a refresh rate of 144 Hz), regardless of where the mouse is. When the application does not have focus, the “fps” label continues updating with a high frequency and shows approximately 90. (I have no idea where the 90 is coming from.)
If I remove the call to request_repaint_after(), the application no longer updates with a high rate.
Keeping the request_repaint_after() call and going back to egui 0.21.0, I get the expected behavior. Considering the release notes, I guess this is related to #2939.
Expected behavior
When the application does NOT have focus, the “fps” label should show a value of approximately 1. In other words, the GUI should update only once a second because I passed 1s as duration to request_repaint_after().
When the application does have focus, the “fps” label should show a value of 144 only while moving around the mouse.
Desktop:
- OS: Windows 10
- Browser: Not applicable; running on native
- Version of egui: 0.22.0 (version 0.21.0 is not affected)
About this issue
- Original URL
- State: closed
- Created a year ago
- Reactions: 3
- Comments: 20 (10 by maintainers)
Commits related to this issue
- Update eframe/egui to 0.25 On a new branch because of https://github.com/emilk/egui/issues/3109 — committed to dimtpap/coppwr by dimtpap 5 months ago
- Fix calling request_repaint_after every frame causing immediate repaint (#3978) * Closes https://github.com/emilk/egui/pull/3925 * Closes #3109 — committed to emilk/egui by emilk 5 months ago
Here’s my clunky temporary solution - just spin up another thread that sleeps and occasionally calls
request_repaint: https://github.com/OmegaJak/gwaihir/blob/f132180306bfeca47321f14d5d881d8742d920d5/crates/gwaihir-client/src/periodic_repaint_thread.rsI don’t know how I miss-typed “0.24” as “0.18”, but I did 🤦
If you run with
RUST_LOG=eframe=traceyou should get some log output that explains why eframe is repainting; maybe that can help you find the bug. I would appreciate help here since I’m way too busy right now to take a proper look at it.Most of the logic can be found in
crates/eframe/src/native/run.rs(in therun_and_returnfunction) and instruct Repaintincrates/egui/src/context.rs