From 4f1696cf9cb65ce84a6abc6905d18d7e3c1fd67b Mon Sep 17 00:00:00 2001 From: Konkitoman Date: Thu, 19 Oct 2023 15:53:38 +0300 Subject: [PATCH] big refractor egui: * removed FullOutput::repaint_after * now for redraw only request_repaint_callback is used! * now on every Context::request_repaint() will repaint only once * exposed Context::requested_repaint and Context::requested_repaint_last_frame eframe: * now event result is returned as EventResult insted of Vec * fix to many redraw requests ----: * fix egui not waking when a repaint was from other thread * now every thing feels more responsive! --- crates/eframe/src/native/run.rs | 328 ++++++++++++++------------------ crates/egui/src/context.rs | 154 ++++++--------- crates/egui/src/data/output.rs | 14 -- 3 files changed, 204 insertions(+), 292 deletions(-) diff --git a/crates/eframe/src/native/run.rs b/crates/eframe/src/native/run.rs index 0f516db78..ab07f54b4 100644 --- a/crates/eframe/src/native/run.rs +++ b/crates/eframe/src/native/run.rs @@ -108,7 +108,7 @@ trait WinitApp { fn save_and_destroy(&mut self); - fn run_ui_and_paint(&mut self, window_id: winit::window::WindowId) -> Vec; + fn run_ui_and_paint(&mut self, window_id: winit::window::WindowId) -> EventResult; fn on_event( &mut self, @@ -169,6 +169,7 @@ fn run_and_return( log::debug!("Entering the winit event loop (run_return)…"); let mut windows_next_repaint_times = HashMap::default(); + let mut next_repaint_time = Option::::None; let mut returned_result = Ok(()); @@ -177,7 +178,7 @@ fn run_and_return( WINIT_EVENT_LOOP.with(|row_event_loop| *row_event_loop.write() = event_loop); - let event_results = match &event { + let event_result = match &event { winit::event::Event::LoopDestroyed => { // On Mac, Cmd-Q we get here and then `run_return` doesn't return (despite its name), // so we need to save state now: @@ -197,16 +198,17 @@ fn run_and_return( frame_nr, viewport_id, }) => { - if winit_app.frame_nr(*viewport_id) == *frame_nr + 1 { + let current_frame_nr = winit_app.frame_nr(*viewport_id); + if current_frame_nr == *frame_nr || current_frame_nr == *frame_nr + 1 { log::trace!("UserEvent::RequestRepaint scheduling repaint at {when:?}"); if let Some(window_id) = winit_app.get_window_winit_id(*viewport_id) { - vec![EventResult::RepaintAt(window_id, *when)] + EventResult::RepaintAt(window_id, *when) } else { - vec![EventResult::Wait] + EventResult::Wait } } else { log::trace!("Got outdated UserEvent::RequestRepaint"); - vec![EventResult::Wait] // old request - we've already repainted + EventResult::Wait // old request - we've already repainted } } @@ -214,7 +216,7 @@ fn run_and_return( .. }) => { log::trace!("Woke up to check next_repaint_time"); - vec![EventResult::Wait] + EventResult::Wait } winit::event::Event::WindowEvent { window_id, .. } @@ -222,69 +224,74 @@ fn run_and_return( { // This can happen if we close a window, and then reopen a new one, // or if we have multiple windows open. - vec![EventResult::RepaintNext(*window_id)] + EventResult::RepaintNext(*window_id) } event => match winit_app.on_event(event_loop, event) { - Ok(event_result) => vec![event_result], + Ok(event_result) => event_result, Err(err) => { log::error!("Exiting because of error: {err:?} on event {event:?}"); returned_result = Err(err); - vec![EventResult::Exit] + EventResult::Exit } }, }; - for event_result in event_results { - match event_result { - EventResult::Wait => { - control_flow.set_wait(); - } - EventResult::RepaintNow(window_id) => { - log::trace!("Repaint caused by winit::Event: {:?}", event_result); - if cfg!(target_os = "windows") { - // Fix flickering on Windows, see https://github.com/emilk/egui/pull/2280 - windows_next_repaint_times.remove(&window_id); + match event_result { + EventResult::Wait => { + control_flow.set_wait(); + } + EventResult::RepaintNow(window_id) => { + log::trace!("Repaint caused by winit::Event: {:?}", event_result); + if cfg!(target_os = "windows") { + // Fix flickering on Windows, see https://github.com/emilk/egui/pull/2280 + windows_next_repaint_times.remove(&window_id); - winit_app.run_ui_and_paint(window_id); - } else { - // Fix for https://github.com/emilk/egui/issues/2425 - windows_next_repaint_times.insert(window_id, Instant::now()); - } - } - EventResult::RepaintNext(window_id) => { - log::trace!("Repaint caused by winit::Event: {:?}", event_result); + winit_app.run_ui_and_paint(window_id); + } else { + // Fix for https://github.com/emilk/egui/issues/2425 windows_next_repaint_times.insert(window_id, Instant::now()); } - EventResult::RepaintAt(window_id, repaint_time) => { - windows_next_repaint_times.insert( - window_id, - windows_next_repaint_times - .get(&window_id) - .map_or(repaint_time, |last| (*last).min(repaint_time)), - ); - } - EventResult::Exit => { - log::debug!("Asking to exit event loop…"); - winit_app.save_and_destroy(); - *control_flow = ControlFlow::Exit; - return; - } + } + EventResult::RepaintNext(window_id) => { + log::trace!("Repaint caused by winit::Event: {:?}", event_result); + windows_next_repaint_times.insert(window_id, Instant::now()); + } + EventResult::RepaintAt(window_id, repaint_time) => { + windows_next_repaint_times.insert( + window_id, + windows_next_repaint_times + .get(&window_id) + .map_or(repaint_time, |last| (*last).min(repaint_time)), + ); + } + EventResult::Exit => { + log::debug!("Asking to exit event loop…"); + winit_app.save_and_destroy(); + *control_flow = ControlFlow::Exit; + return; } } - let mut next_repaint_time = Option::::None; - 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(); + // This is for not duplicating redraw requests + + use winit::event::Event; + if matches!( + event, + Event::RedrawEventsCleared | Event::RedrawRequested(_) | Event::Resumed + ) { + 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(); + } + control_flow.set_poll(); + } else { + next_repaint_time = Some( + next_repaint_time.map_or(*repaint_time, |last| last.min(*repaint_time)), + ); } - 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))); } } @@ -320,21 +327,22 @@ fn run_and_exit(event_loop: EventLoop, mut winit_app: impl WinitApp + log::debug!("Entering the winit event loop (run)…"); let mut windows_next_repaint_times = HashMap::default(); + let mut next_repaint_time = Option::::None; event_loop.run(move |event, event_loop, control_flow| { crate::profile_scope!("winit_event", short_event_description(&event)); WINIT_EVENT_LOOP.with(|row_event_loop| *row_event_loop.write() = event_loop); - let event_results = match event { + let event_result = match &event { winit::event::Event::LoopDestroyed => { log::debug!("Received Event::LoopDestroyed"); - vec![EventResult::Exit] + EventResult::Exit } winit::event::Event::RedrawRequested(window_id) => { - windows_next_repaint_times.remove(&window_id); - winit_app.run_ui_and_paint(window_id) + windows_next_repaint_times.remove(window_id); + winit_app.run_ui_and_paint(*window_id) } winit::event::Event::UserEvent(UserEvent::RequestRepaint { @@ -342,75 +350,81 @@ fn run_and_exit(event_loop: EventLoop, mut winit_app: impl WinitApp + frame_nr, viewport_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)] + let current_frame_nr = winit_app.frame_nr(*viewport_id); + if current_frame_nr == *frame_nr || current_frame_nr == *frame_nr + 1 { + if let Some(window_id) = winit_app.get_window_winit_id(*viewport_id) { + EventResult::RepaintAt(window_id, *when) } else { - vec![EventResult::Wait] + EventResult::Wait } } else { - vec![EventResult::Wait] // old request - we've already repainted + EventResult::Wait // old request - we've already repainted } } winit::event::Event::NewEvents(winit::event::StartCause::ResumeTimeReached { .. - }) => vec![EventResult::Wait], // We just woke up to check next_repaint_time + }) => EventResult::Wait, // We just woke up to check next_repaint_time - event => match winit_app.on_event(event_loop, &event) { - Ok(event_result) => vec![event_result], + event => match winit_app.on_event(event_loop, event) { + Ok(event_result) => event_result, Err(err) => { panic!("eframe encountered a fatal error: {err}"); } }, }; - for event_result in event_results { - match event_result { - EventResult::Wait => {} - EventResult::RepaintNow(window_id) => { - if cfg!(target_os = "windows") { - // Fix flickering on Windows, see https://github.com/emilk/egui/pull/2280 - windows_next_repaint_times.remove(&window_id); + match event_result { + EventResult::Wait => {} + EventResult::RepaintNow(window_id) => { + if cfg!(target_os = "windows") { + // Fix flickering on Windows, see https://github.com/emilk/egui/pull/2280 + windows_next_repaint_times.remove(&window_id); - winit_app.run_ui_and_paint(window_id); - } else { - // Fix for https://github.com/emilk/egui/issues/2425 - windows_next_repaint_times.insert(window_id, Instant::now()); - } - } - EventResult::RepaintNext(window_id) => { + winit_app.run_ui_and_paint(window_id); + } else { + // Fix for https://github.com/emilk/egui/issues/2425 windows_next_repaint_times.insert(window_id, Instant::now()); } - EventResult::RepaintAt(window_id, repaint_time) => { - windows_next_repaint_times.insert( - window_id, - windows_next_repaint_times - .get(&window_id) - .map_or(repaint_time, |last| (*last).min(repaint_time)), - ); - } - EventResult::Exit => { - log::debug!("Quitting - saving app state…"); - winit_app.save_and_destroy(); - #[allow(clippy::exit)] - std::process::exit(0); - } + } + EventResult::RepaintNext(window_id) => { + windows_next_repaint_times.insert(window_id, Instant::now()); + } + EventResult::RepaintAt(window_id, repaint_time) => { + windows_next_repaint_times.insert( + window_id, + windows_next_repaint_times + .get(&window_id) + .map_or(repaint_time, |last| (*last).min(repaint_time)), + ); + } + EventResult::Exit => { + log::debug!("Quitting - saving app state…"); + winit_app.save_and_destroy(); + #[allow(clippy::exit)] + std::process::exit(0); } } - let mut next_repaint_time = Option::::None; - 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(); + // This is for not duplicating redraw requests + + use winit::event::Event; + if matches!( + event, + Event::RedrawEventsCleared | Event::RedrawRequested(_) | Event::Resumed + ) { + 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(); + } + control_flow.set_poll(); + } else { + next_repaint_time = Some( + next_repaint_time.map_or(*repaint_time, |last| last.min(*repaint_time)), + ); } - 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))); } } @@ -1356,9 +1370,9 @@ mod glow_integration { } } - fn run_ui_and_paint(&mut self, window_id: winit::window::WindowId) -> Vec { + fn run_ui_and_paint(&mut self, window_id: winit::window::WindowId) -> EventResult { if self.running.read().is_none() { - return vec![EventResult::Wait]; + return EventResult::Wait; } if let Some(viewport_id) = self.get_window_id(&window_id) { @@ -1387,16 +1401,15 @@ mod glow_integration { glutin.viewports.get(&viewport.read().pair.parent) { if let Some(window) = parent_viewport.read().window.as_ref() { - return vec![EventResult::RepaintNext(window.read().id())]; + return EventResult::RepaintNext(window.read().id()); } } - return vec![]; + return EventResult::Wait; } } let egui::FullOutput { platform_output, - repaint_after, textures_delta, shapes, viewports, @@ -1422,7 +1435,6 @@ mod glow_integration { let win = &mut *win.write(); egui::FullOutput { platform_output, - repaint_after, textures_delta, shapes, viewports, @@ -1535,37 +1547,12 @@ mod glow_integration { } } - { - let glutin = glutin.read(); - let window_maps = &glutin.window_maps; + control_flow = if integration.should_close() { + EventResult::Exit + } else { + EventResult::Wait + }; - control_flow = if integration.should_close() { - vec![EventResult::Exit] - } else { - repaint_after - .into_iter() - .filter_map(|(id, time)| { - if time.is_zero() { - window_maps.get(&id).map(|id| EventResult::RepaintNext(*id)) - } else if let Some(repaint_after_instant) = - std::time::Instant::now().checked_add(time) - { - // if repaint_after is something huge and can't be added to Instant, - // we will use `ControlFlow::Wait` instead. - // technically, this might lead to some weird corner cases where the user *WANTS* - // winit to use `WaitUntil(MAX_INSTANT)` explicitly. they can roll their own - // egui backend impl i guess. - - window_maps.get(&id).map(|id| { - EventResult::RepaintAt(*id, repaint_after_instant) - }) - } else { - None - } - }) - .collect::>() - }; - } integration .maybe_autosave(app.write().as_mut(), win.read().window.clone().unwrap()); @@ -1593,7 +1580,7 @@ mod glow_integration { control_flow } else { - vec![EventResult::Wait] + EventResult::Wait } } @@ -2291,7 +2278,7 @@ mod wgpu_integration { } } - fn run_ui_and_paint(&mut self, window_id: winit::window::WindowId) -> Vec { + fn run_ui_and_paint(&mut self, window_id: winit::window::WindowId) -> EventResult { if let Some(running) = &mut self.running { #[cfg(feature = "puffin")] puffin::GlobalProfiler::lock().new_frame(); @@ -2308,22 +2295,24 @@ mod wgpu_integration { let egui::FullOutput { platform_output, - repaint_after, textures_delta, shapes, mut viewports, viewport_commands, }; { - let Some((viewport_id, Window{window: Some(window), state, render, parent_id })) = windows_id.read().get(&window_id).and_then(|id|(windows.read().get(id).map(|w|(*id, w.clone())))) else{return vec![]}; + let Some((viewport_id, Window{window: Some(window), state, render, parent_id })) = windows_id.read() + .get(&window_id) + .and_then(|id|(windows.read().get(id).map(|w|(*id, w.clone())))) + else{ return EventResult::Wait }; // This is used to not render a viewport if is sync if viewport_id != ViewportId::MAIN && render.is_none() { if let Some(window) = running.viewports.read().get(&parent_id) { if let Some(w) = window.window.as_ref() { - return vec![EventResult::RepaintNext(w.read().id())]; + return EventResult::RepaintNext(w.read().id()); } } - return vec![]; + return EventResult::Wait; } let _ = pollster::block_on( @@ -2334,7 +2323,6 @@ mod wgpu_integration { egui::FullOutput { platform_output, - repaint_after, textures_delta, shapes, viewports, @@ -2444,46 +2432,10 @@ mod wgpu_integration { .retain(|_, id| active_viewports_ids.contains(id)); painter.write().clean_surfaces(&active_viewports_ids); - let mut control_flow = vec![EventResult::Wait]; - for repaint_after in repaint_after { - control_flow.push(if integration.read().should_close() { - EventResult::Exit - } else if repaint_after.1.is_zero() { - if let Some(Window { - window: Some(window), - .. - }) = windows.read().get(&repaint_after.0) - { - EventResult::RepaintNext(window.read().id()) - } else { - EventResult::Wait - } - } else if let Some(repaint_after_instant) = - std::time::Instant::now().checked_add(repaint_after.1) - { - // if repaint_after is something huge and can't be added to Instant, - // we will use `ControlFlow::Wait` instead. - // technically, this might lead to some weird corner cases where the user *WANTS* - // winit to use `WaitUntil(MAX_INSTANT)` explicitly. they can roll their own - // egui backend impl i guess. - if let Some(Window { - window: Some(window), - .. - }) = windows.read().get(&repaint_after.0) - { - EventResult::RepaintAt(window.read().id(), repaint_after_instant) - } else { - EventResult::Wait - } - } else { - EventResult::Wait - }); - } - let Some((_, Window{window: Some(window), ..})) = windows_id.read().get(&window_id) .and_then(|id|windows.read().get(id) .map(|w|(*id, w.clone())) - ) else{return vec![]}; + ) else{return EventResult::Wait}; integration .write() .maybe_autosave(app.as_mut(), window.clone()); @@ -2495,9 +2447,13 @@ mod wgpu_integration { std::thread::sleep(std::time::Duration::from_millis(10)); } - control_flow + if integration.read().should_close() { + EventResult::Exit + } else { + EventResult::Wait + } } else { - vec![EventResult::Wait] + EventResult::Wait } } diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index a35159a78..56d046826 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -54,42 +54,18 @@ impl Default for WrappedTextureManager { // ---------------------------------------------------------------------------- /// Logic related to repainting the ui. +#[derive(Default)] struct Repaint { /// The current frame number. /// /// Incremented at the end of each frame. viewports_frame_nr: HashMap, - /// The duration backend will poll for new events, before forcing another egui update - /// even if there's no new events. - /// - /// Also used to suppress multiple calls to the repaint callback during the same frame. - pub repaint_after: HashMap, - /// While positive, keep requesting repaints. Decrement at the end of each frame. - repaint_requests: HashMap, + repaint_request: HashMap, request_repaint_callback: Option>, - requested_repaint_last_frame: bool, -} - -impl Default for Repaint { - fn default() -> Self { - let mut repaint_after = HashMap::default(); - - // Start with painting an extra frame to compensate for some widgets - // that take two frames before they "settle": - repaint_after.insert(ViewportId::MAIN, std::time::Duration::from_millis(100)); - let mut repaint_requests = HashMap::default(); - repaint_requests.insert(ViewportId::MAIN, 1); - Self { - viewports_frame_nr: HashMap::default(), - repaint_after, - repaint_requests, - request_repaint_callback: None, - requested_repaint_last_frame: false, - } - } + requested_repaint_last_frame: HashMap, } impl Repaint { @@ -99,76 +75,53 @@ impl Repaint { fn request_repaint_after(&mut self, after: std::time::Duration, viewport_id: ViewportId) { if after == std::time::Duration::ZERO { - // Do a few extra frames to let things settle. - // This is a bit of a hack, and we don't support it for `repaint_after` callbacks yet. - self.repaint_requests.insert(viewport_id, 2); + // This will only work if the current viewport is drawing + self.repaint_request.insert(viewport_id, true); } - // We only re-call the callback if we get a lower duration, - // otherwise it's already been covered by the previous callback. - if after - < self - .repaint_after - .get(&viewport_id) - .copied() - .unwrap_or(std::time::Duration::MAX) - { - self.repaint_after.insert(viewport_id, after); - - if let Some(callback) = &self.request_repaint_callback { - let info = RequestRepaintInfo { - after, - current_frame_nr: *self.viewports_frame_nr.entry(viewport_id).or_default(), - viewport_id, - }; - (callback)(info); - } + // This will work always + if let Some(callback) = &self.request_repaint_callback { + let info = RequestRepaintInfo { + after, + current_frame_nr: *self.viewports_frame_nr.entry(viewport_id).or_default(), + viewport_id, + }; + (callback)(info); + } else { + log::warn!("request_repaint_callback is not implemented by egui integration!\nIf is your integration you need to call `Context::set_request_repaint_callback`"); } } fn start_frame(&mut self, viewport_id: ViewportId) { - // We are repainting; no need to reschedule a repaint unless the user asks for it again. - self.repaint_after.remove(&viewport_id); + let request = self.repaint_request.entry(viewport_id).or_default(); + self.requested_repaint_last_frame + .insert(viewport_id, *request); + *request = false; } - // returns how long to wait until repaint - fn end_frame( - &mut self, - viewport_id: ViewportId, - viewports: &[ViewportId], - ) -> HashMap { - // if repaint_requests is greater than zero. just set the duration to zero for immediate - // repaint. if there's no repaint requests, then we can use the actual repaint_after instead. - let repaint_after = if self - .repaint_requests - .get(&viewport_id) - .copied() - .unwrap_or(0) - > 0 - { - if let Some(requests) = self.repaint_requests.get_mut(&viewport_id) { - *requests -= 1; - } - - std::time::Duration::ZERO - } else { - self.repaint_after - .get(&viewport_id) - .copied() - .unwrap_or(std::time::Duration::MAX) - }; - self.repaint_after.insert(viewport_id, repaint_after); - - self.requested_repaint_last_frame = repaint_after.is_zero(); + // returns what is needed to be repainted + fn end_frame(&mut self, viewport_id: ViewportId, viewports: &[ViewportId]) { *self.viewports_frame_nr.entry(viewport_id).or_default() += 1; - self.repaint_after.retain(|id, _| viewports.contains(id)); + self.requested_repaint_last_frame + .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); + self.repaint_request.retain(|id, _| viewports.contains(id)); + } - self.repaint_after.clone() + fn requested_repaint_last_frame(&self, viewport_id: &ViewportId) -> bool { + self.requested_repaint_last_frame + .get(viewport_id) + .copied() + .unwrap_or_default() + } + + fn requested_repaint(&self, viewport_id: &ViewportId) -> bool { + self.repaint_request + .get(viewport_id) + .copied() + .unwrap_or_default() } } @@ -283,11 +236,10 @@ impl ContextImpl { pair.this, ); - let input = self - .input - .remove(&pair) - .unwrap_or_default() - .begin_frame(new_raw_input, self.repaint.requested_repaint_last_frame); + let input = self.input.remove(&pair).unwrap_or_default().begin_frame( + new_raw_input, + self.repaint.requested_repaint_last_frame(&pair), + ); self.input.insert(pair.this, input); self.frame_state @@ -1279,6 +1231,26 @@ impl Context { self.write(|ctx| ctx.repaint.request_repaint_after(duration, id)); } + /// With this you can know if the application stal before + pub fn requested_repaint_last_frame(&self) -> bool { + self.requested_repaint_last_frame_for(&self.viewport_id()) + } + + /// With this you can know if the viewport stal before + pub fn requested_repaint_last_frame_for(&self, viewport_id: &ViewportId) -> bool { + self.read(|ctx| ctx.repaint.requested_repaint_last_frame(viewport_id)) + } + + /// With this you will know if the application will redraw + pub fn requested_repaint(&self) -> bool { + self.requested_repaint_for(&self.viewport_id()) + } + + /// With this you will know if the viewport will redraw + pub fn requested_repaint_for(&self, viewport_id: &ViewportId) -> bool { + self.read(|ctx| ctx.repaint.requested_repaint(viewport_id)) + } + /// For integrations: this callback will be called when an egui user calls [`Self::request_repaint`]. /// /// This lets you wake up a sleeping UI thread. @@ -1665,12 +1637,10 @@ impl Context { }); } - let repaint_after = - self.write(|ctx| ctx.repaint.end_frame(viewport_id, &avalibile_viewports)); + self.write(|ctx| ctx.repaint.end_frame(viewport_id, &avalibile_viewports)); FullOutput { platform_output, - repaint_after, textures_delta, shapes, viewports, diff --git a/crates/egui/src/data/output.rs b/crates/egui/src/data/output.rs index 9c2f0d770..fb7d970c0 100644 --- a/crates/egui/src/data/output.rs +++ b/crates/egui/src/data/output.rs @@ -1,7 +1,5 @@ //! All the data egui returns to the backend at the end of each frame. -use ahash::HashMap; - use crate::ViewportId; use crate::{ViewportCommand, ViewportOutput, WidgetType}; @@ -13,16 +11,6 @@ pub struct FullOutput { /// Non-rendering related output. pub platform_output: PlatformOutput, - /// If `Duration::is_zero()`, egui is requesting immediate repaint (i.e. on the next frame). - /// - /// This happens for instance when there is an animation, or if a user has called `Context::request_repaint()`. - /// - /// If `Duration` is greater than zero, egui wants to be repainted at or before the specified - /// duration elapses. when in reactive mode, egui spends forever waiting for input and only then, - /// will it repaint itself. this can be used to make sure that backend will only wait for a - /// specified amount of time, and repaint egui without any new input. - pub repaint_after: HashMap, - /// Texture changes since last frame (including the font texture). /// /// The backend needs to apply [`crate::TexturesDelta::set`] _before_ painting, @@ -44,7 +32,6 @@ impl FullOutput { pub fn append(&mut self, newer: Self) { let Self { platform_output, - repaint_after, textures_delta, shapes, mut viewports, @@ -52,7 +39,6 @@ impl FullOutput { } = newer; self.platform_output.append(platform_output); - self.repaint_after = repaint_after; // if the last frame doesn't need a repaint, then we don't need to repaint self.textures_delta.append(textures_delta); self.shapes = shapes; // Only paint the latest self.viewports.append(&mut viewports);