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

Most upvoted comments

I am also dealing with this problem. @OmegaJak , @emilk any temporal workarounds?

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.rs

I don’t know how I miss-typed “0.24” as “0.18”, but I did 🤦

If you run with RUST_LOG=eframe=trace you 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 the run_and_return function) and in struct Repaint in crates/egui/src/context.rs