From b1e7fafe703498dd86a67774ae7e8b015ba73b19 Mon Sep 17 00:00:00 2001 From: Konkitoman Date: Wed, 18 Oct 2023 18:47:16 +0300 Subject: [PATCH] egui: * now every viewport has his own frame_nr eframe: * some refactoring * now on Windows spinner will make the async viewport refresh, this problem was only for async viewport in Windows * problem found there are two redraw systems, one was broken now is fixed, the one that was broken on Linux X11 was not needed, but for Windows both are needed! 1: The egui repaint_callback system 2: The egui repaint_after from FullOutput --- crates/eframe/src/native/run.rs | 67 +++++++++++---------------------- crates/egui/src/context.rs | 35 ++++++++++++----- 2 files changed, 48 insertions(+), 54 deletions(-) diff --git a/crates/eframe/src/native/run.rs b/crates/eframe/src/native/run.rs index 3313aed13..0f516db78 100644 --- a/crates/eframe/src/native/run.rs +++ b/crates/eframe/src/native/run.rs @@ -42,7 +42,7 @@ pub enum UserEvent { /// A repaint is requested. RequestRepaint { /// What to repaint. - id: ViewportId, + viewport_id: ViewportId, /// When to repaint. when: Instant, @@ -91,7 +91,7 @@ enum EventResult { trait WinitApp { /// The current frame number, as reported by egui. - fn frame_nr(&self) -> u64; + fn frame_nr(&self, viewport_id: ViewportId) -> u64; fn is_focused(&self, window_id: winit::window::WindowId) -> bool; @@ -187,16 +187,6 @@ fn run_and_return( return; } - // Platform-dependent event handlers to workaround a winit bug - // See: https://github.com/rust-windowing/winit/issues/987 - // See: https://github.com/rust-windowing/winit/issues/1619 - // #[cfg(target_os = "windows")] - // winit::event::Event::RedrawEventsCleared => { - // windows_next_repaint_times.clear(); - // winit_app.run_ui_and_paint(None) - // vec![EventResult::Wait] - // } - // #[cfg(not(target_os = "windows"))] winit::event::Event::RedrawRequested(window_id) => { windows_next_repaint_times.remove(window_id); winit_app.run_ui_and_paint(*window_id) @@ -205,11 +195,11 @@ fn run_and_return( winit::event::Event::UserEvent(UserEvent::RequestRepaint { when, frame_nr, - id: window_id, + viewport_id, }) => { - if winit_app.frame_nr() == *frame_nr { + if winit_app.frame_nr(*viewport_id) == *frame_nr + 1 { log::trace!("UserEvent::RequestRepaint scheduling repaint at {when:?}"); - if let Some(window_id) = winit_app.get_window_winit_id(*window_id) { + if let Some(window_id) = winit_app.get_window_winit_id(*viewport_id) { vec![EventResult::RepaintAt(window_id, *when)] } else { vec![EventResult::Wait] @@ -287,13 +277,11 @@ fn run_and_return( for (window_id, repaint_time) in &windows_next_repaint_times.clone() { if *repaint_time <= Instant::now() { if let Some(window) = winit_app.window(*window_id) { + log::trace!("request_redraw"); window.read().request_redraw(); - windows_next_repaint_times.remove(window_id); - control_flow.set_poll(); - } else { - windows_next_repaint_times.remove(window_id); - control_flow.set_wait(); } + windows_next_repaint_times.remove(window_id); + control_flow.set_poll(); } else { next_repaint_time = Some(next_repaint_time.map_or(*repaint_time, |last| last.min(*repaint_time))); @@ -344,15 +332,7 @@ fn run_and_exit(event_loop: EventLoop, mut winit_app: impl WinitApp + vec![EventResult::Exit] } - // Platform-dependent event handlers to workaround a winit bug - // See: https://github.com/rust-windowing/winit/issues/987 - // See: https://github.com/rust-windowing/winit/issues/1619 - winit::event::Event::RedrawEventsCleared if cfg!(target_os = "windows") => { - // windows_next_repaint_times.clear(); - // winit_app.run_ui_and_paint(None) - vec![] - } - winit::event::Event::RedrawRequested(window_id) if !cfg!(target_os = "windows") => { + winit::event::Event::RedrawRequested(window_id) => { windows_next_repaint_times.remove(&window_id); winit_app.run_ui_and_paint(window_id) } @@ -360,10 +340,10 @@ fn run_and_exit(event_loop: EventLoop, mut winit_app: impl WinitApp + winit::event::Event::UserEvent(UserEvent::RequestRepaint { when, frame_nr, - id: window_id, + viewport_id, }) => { - if winit_app.frame_nr() == frame_nr { - if let Some(window_id) = winit_app.get_window_winit_id(window_id) { + if winit_app.frame_nr(viewport_id) == frame_nr + 1 { + if let Some(window_id) = winit_app.get_window_winit_id(viewport_id) { vec![EventResult::RepaintAt(window_id, when)] } else { vec![EventResult::Wait] @@ -425,8 +405,8 @@ fn run_and_exit(event_loop: EventLoop, mut winit_app: impl WinitApp + if let Some(window) = winit_app.window(*window_id) { log::trace!("request_redraw"); window.read().request_redraw(); - windows_next_repaint_times.remove(window_id); } + windows_next_repaint_times.remove(window_id); control_flow.set_poll(); } else { next_repaint_time = @@ -1030,7 +1010,7 @@ mod glow_integration { event_loop_proxy .lock() .send_event(UserEvent::RequestRepaint { - id: info.viewport_id, + viewport_id: info.viewport_id, when, frame_nr, }) @@ -1303,11 +1283,10 @@ mod glow_integration { } impl WinitApp for GlowWinitApp { - fn frame_nr(&self) -> u64 { - self.running - .read() - .as_ref() - .map_or(0, |r| r.integration.read().egui_ctx.frame_nr()) + fn frame_nr(&self, viewport_id: ViewportId) -> u64 { + self.running.read().as_ref().map_or(0, |r| { + r.integration.read().egui_ctx.frame_nr_for(viewport_id) + }) } fn is_focused(&self, window_id: winit::window::WindowId) -> bool { @@ -2073,7 +2052,7 @@ mod wgpu_integration { .send_event(UserEvent::RequestRepaint { when, frame_nr, - id: info.viewport_id, + viewport_id: info.viewport_id, }) .ok(); }); @@ -2249,10 +2228,10 @@ mod wgpu_integration { } impl WinitApp for WgpuWinitApp { - fn frame_nr(&self) -> u64 { - self.running - .as_ref() - .map_or(0, |r| r.integration.read().egui_ctx.frame_nr()) + fn frame_nr(&self, viewport_id: ViewportId) -> u64 { + self.running.as_ref().map_or(0, |r| { + r.integration.read().egui_ctx.frame_nr_for(viewport_id) + }) } fn is_focused(&self, window_id: winit::window::WindowId) -> bool { diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index 6c4150481..a35159a78 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -58,7 +58,7 @@ struct Repaint { /// The current frame number. /// /// Incremented at the end of each frame. - frame_nr: u64, + viewports_frame_nr: HashMap, /// The duration backend will poll for new events, before forcing another egui update /// even if there's no new events. @@ -83,7 +83,7 @@ impl Default for Repaint { let mut repaint_requests = HashMap::default(); repaint_requests.insert(ViewportId::MAIN, 1); Self { - frame_nr: 0, + viewports_frame_nr: HashMap::default(), repaint_after, repaint_requests, request_repaint_callback: None, @@ -118,7 +118,7 @@ impl Repaint { if let Some(callback) = &self.request_repaint_callback { let info = RequestRepaintInfo { after, - current_frame_nr: self.frame_nr, + current_frame_nr: *self.viewports_frame_nr.entry(viewport_id).or_default(), viewport_id, }; (callback)(info); @@ -160,9 +160,11 @@ impl Repaint { self.repaint_after.insert(viewport_id, repaint_after); self.requested_repaint_last_frame = repaint_after.is_zero(); - self.frame_nr += 1; + *self.viewports_frame_nr.entry(viewport_id).or_default() += 1; self.repaint_after.retain(|id, _| viewports.contains(id)); + self.viewports_frame_nr + .retain(|id, _| viewports.contains(id)); self.repaint_requests .retain(|id, repaints| viewports.contains(id) && *repaints != 0); @@ -1150,13 +1152,28 @@ impl Context { } } - /// The current frame number. + /// The current frame number for the current viewport. /// /// Starts at zero, and is incremented at the end of [`Self::run`] or by [`Self::end_frame`]. /// /// Between calls to [`Self::run`], this is the frame number of the coming frame. pub fn frame_nr(&self) -> u64 { - self.read(|ctx| ctx.repaint.frame_nr) + self.frame_nr_for(self.viewport_id()) + } + + /// The current frame number. + /// + /// Starts at zero, and is incremented at the end of [`Self::run`] or by [`Self::end_frame`]. + /// + /// Between calls to [`Self::run`], this is the frame number of the coming frame. + pub fn frame_nr_for(&self, id: ViewportId) -> u64 { + self.read(|ctx| { + ctx.repaint + .viewports_frame_nr + .get(&id) + .copied() + .unwrap_or_default() + }) } /// Call this if there is need to repaint the UI, i.e. if you are showing an animation. @@ -1648,10 +1665,8 @@ impl Context { }); } - let repaint_after = self.write(|ctx| { - ctx.repaint - .end_frame(ctx.viewport_id(), &avalibile_viewports) - }); + let repaint_after = + self.write(|ctx| ctx.repaint.end_frame(viewport_id, &avalibile_viewports)); FullOutput { platform_output,