Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

eframe: Repaint immediately on RepaintAsap, fixes #903 #2280

Merged
merged 6 commits into from
Nov 13, 2022
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 69 additions & 6 deletions crates/eframe/src/native/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,17 @@ pub use epi::NativeOptions;
#[derive(Debug)]
enum EventResult {
Wait,
/// Causes a synchronous repaint inside the event handler. This should only
/// be used in special situations if the window must be repainted while
/// handling a specific event. This occurs on Windows when handling resizes.
///
/// `RepaintAsap` introduces a one-frame delay, and should therefore only be
/// used for extremely urgent repaints.
RepaintAsap,
/// Queues a repaint for once the event loop handles its next redraw. Exists
/// so that multiple input events can be handled in one frame. Does not
/// cause any delay like `RepaintAsap`.
RepaintNext,
RepaintAt(Instant),
Exit,
}
Expand Down Expand Up @@ -103,7 +113,7 @@ fn run_and_return(event_loop: &mut EventLoop<RequestRepaintEvent>, mut winit_app
winit::event::Event::UserEvent(RequestRepaintEvent)
| winit::event::Event::NewEvents(winit::event::StartCause::ResumeTimeReached {
..
}) => EventResult::RepaintAsap,
}) => EventResult::RepaintNext,

winit::event::Event::WindowEvent { window_id, .. }
if winit_app.window().is_none()
Expand All @@ -120,6 +130,11 @@ fn run_and_return(event_loop: &mut EventLoop<RequestRepaintEvent>, mut winit_app
match event_result {
EventResult::Wait => {}
EventResult::RepaintAsap => {
tracing::trace!("Repaint caused by winit::Event: {:?}", event);
next_repaint_time = Instant::now() + Duration::from_secs(1_000_000_000);
winit_app.paint();
}
EventResult::RepaintNext => {
tracing::trace!("Repaint caused by winit::Event: {:?}", event);
next_repaint_time = Instant::now();
}
Expand Down Expand Up @@ -188,14 +203,18 @@ fn run_and_exit(
winit::event::Event::UserEvent(RequestRepaintEvent)
| winit::event::Event::NewEvents(winit::event::StartCause::ResumeTimeReached {
..
}) => EventResult::RepaintAsap,
}) => EventResult::RepaintNext,

event => winit_app.on_event(event_loop, &event),
};

match event_result {
EventResult::Wait => {}
EventResult::RepaintAsap => {
next_repaint_time = Instant::now() + Duration::from_secs(1_000_000_000);
winit_app.paint();
}
EventResult::RepaintNext => {
next_repaint_time = Instant::now();
}
EventResult::RepaintAt(repaint_time) => {
Expand Down Expand Up @@ -496,7 +515,7 @@ mod glow_integration {
let control_flow = if integration.should_close() {
EventResult::Exit
} else if repaint_after.is_zero() {
EventResult::RepaintAsap
EventResult::RepaintNext
} else if let Some(repaint_after_instant) =
std::time::Instant::now().checked_add(repaint_after)
{
Expand Down Expand Up @@ -560,11 +579,28 @@ mod glow_integration {

winit::event::Event::WindowEvent { event, .. } => {
if let Some(running) = &mut self.running {
// On Windows, if a window is resized by the user, it should repaint synchronously, inside the
// event handler.
//
// If this is not done, the compositor will assume that the window does not want to redraw,
// and continue ahead.
//
// In eframe's case, that causes the window to rapidly flicker, as it struggles to deliver
// new frames to the compositor in time.
//
// The flickering is technically glutin or glow's fault, but we should be responding properly
// to resizes anyway, as doing so avoids dropping frames.
//
// See: https://github.com/emilk/egui/issues/903
let mut repaint_asap = false;

match &event {
winit::event::WindowEvent::Focused(new_focused) => {
self.is_focused = *new_focused;
}
winit::event::WindowEvent::Resized(physical_size) => {
repaint_asap = true;

// Resize with 0 width and height is used by winit to signal a minimize event on Windows.
// See: https://github.com/rust-windowing/winit/issues/208
// This solves an issue where the app would panic when minimizing on Windows.
Expand All @@ -576,6 +612,7 @@ mod glow_integration {
new_inner_size,
..
} => {
repaint_asap = true;
running.gl_window.resize(**new_inner_size);
}
winit::event::WindowEvent::CloseRequested
Expand All @@ -592,7 +629,11 @@ mod glow_integration {
if running.integration.should_close() {
EventResult::Exit
} else if event_response.repaint {
EventResult::RepaintAsap
if repaint_asap {
EventResult::RepaintAsap
} else {
EventResult::RepaintNext
}
} else {
EventResult::Wait
}
Expand Down Expand Up @@ -854,7 +895,7 @@ mod wgpu_integration {
let control_flow = if integration.should_close() {
EventResult::Exit
} else if repaint_after.is_zero() {
EventResult::RepaintAsap
EventResult::RepaintNext
} else if let Some(repaint_after_instant) =
std::time::Instant::now().checked_add(repaint_after)
{
Expand Down Expand Up @@ -923,11 +964,28 @@ mod wgpu_integration {

winit::event::Event::WindowEvent { event, .. } => {
if let Some(running) = &mut self.running {
// On Windows, if a window is resized by the user, it should repaint synchronously, inside the
// event handler.
//
// If this is not done, the compositor will assume that the window does not want to redraw,
// and continue ahead.
//
// In eframe's case, that causes the window to rapidly flicker, as it struggles to deliver
// new frames to the compositor in time.
//
// The flickering is technically glutin or glow's fault, but we should be responding properly
// to resizes anyway, as doing so avoids dropping frames.
//
// See: https://github.com/emilk/egui/issues/903
let mut repaint_asap = false;

match &event {
winit::event::WindowEvent::Focused(new_focused) => {
self.is_focused = *new_focused;
}
winit::event::WindowEvent::Resized(physical_size) => {
repaint_asap = true;

// Resize with 0 width and height is used by winit to signal a minimize event on Windows.
// See: https://github.com/rust-windowing/winit/issues/208
// This solves an issue where the app would panic when minimizing on Windows.
Expand All @@ -942,6 +1000,7 @@ mod wgpu_integration {
new_inner_size,
..
} => {
repaint_asap = true;
running
.painter
.on_window_resized(new_inner_size.width, new_inner_size.height);
Expand All @@ -959,7 +1018,11 @@ mod wgpu_integration {
if running.integration.should_close() {
EventResult::Exit
} else if event_response.repaint {
EventResult::RepaintAsap
if repaint_asap {
EventResult::RepaintAsap
} else {
EventResult::RepaintNext
}
} else {
EventResult::Wait
}
Expand Down