fix(launcher): continuous vsync-paced present for stable VRR

The 60fps cap still left 16ms gaps with no present; on windowed G-Sync/FreeSync
DWM keeps moving the window in and out of the VRR path across those gaps and the
refresh rate swings, which the panel shows as flicker. Render continuously
(request_repaint every frame) with vsync on so the window stays continuously in
VRR at the display's own variable refresh.
This commit is contained in:
funman300
2026-08-20 19:38:42 +00:00
parent 6be75f5452
commit cf515f5584
2 changed files with 12 additions and 9 deletions
+9 -9
View File
@@ -1804,15 +1804,15 @@ impl LauncherApp {
impl eframe::App for LauncherApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
// Present at a steady ~60 FPS while the window is open. egui is normally
// reactive and would idle at ~2 FPS (a 500 ms repaint), but on a G-Sync /
// FreeSync (VRR) display that sits below the VRR floor: the panel engages
// low-framerate compensation, and every hover/animation briefly spikes the
// rate and drops back, so the refresh rate keeps swinging and the panel
// visibly flickers. A constant, in-range cadence gives VRR a single rate to
// lock onto and removes the flicker. 16 ms is monitor-independent and cheap
// for a UI this small; vsync (on by default) keeps present times regular.
ctx.request_repaint_after(std::time::Duration::from_millis(16));
// Render continuously (present every vsync) instead of reactively. egui
// normally idles at a low, bursty repaint rate; on a G-Sync / FreeSync
// (VRR) display a windowed app that presents in bursts with idle gaps
// makes DWM keep moving the window in and out of the VRR path and the
// refresh rate swing — which the panel shows as flicker. Presenting on
// every frame keeps the window continuously in VRR at the display's own
// (variable) refresh, which is stable. vsync (on by default) paces this to
// the monitor rather than spinning uncapped.
ctx.request_repaint();
self.drive_restart_queue();
egui::TopBottomPanel::top("header")
+3
View File
@@ -22,6 +22,9 @@ fn main() -> eframe::Result<()> {
.with_icon(app_icon())
.with_inner_size([1040.0, 720.0])
.with_min_inner_size([880.0, 600.0]),
// Pair vsync with the display's VRR (G-Sync + Vsync is the recommended
// combination): frames present on the monitor's own variable refresh.
vsync: true,
..Default::default()
};