1
0
mirror of https://github.com/emilk/egui.git synced 2026-06-27 15:13:12 -04:00

Output the repaint delay for integrations that don't install a callback

This commit is contained in:
Emil Ernerfeldt
2023-11-15 20:41:53 +01:00
parent 09b639e586
commit e222247ee1
3 changed files with 73 additions and 36 deletions

View File

@@ -1169,6 +1169,7 @@ mod glow_integration {
builder,
viewport_ui_cb,
commands,
repaint_delay: _, // ignored - we listend to the repaint callback instead
},
) in viewport_output
{
@@ -1386,7 +1387,7 @@ mod glow_integration {
.egui_ctx
.set_request_repaint_callback(move |info| {
log::trace!("request_repaint_callback: {info:?}");
let when = Instant::now() + info.after;
let when = Instant::now() + info.delay;
let frame_nr = info.current_frame_nr;
event_loop_proxy
.lock()
@@ -1989,7 +1990,7 @@ mod wgpu_integration {
.egui_ctx
.set_request_repaint_callback(move |info| {
log::trace!("request_repaint_callback: {info:?}");
let when = Instant::now() + info.after;
let when = Instant::now() + info.delay;
let frame_nr = info.current_frame_nr;
event_loop_proxy
@@ -2676,6 +2677,7 @@ mod wgpu_integration {
builder,
viewport_ui_cb,
commands,
repaint_delay: _, // ignored - we listend to the repaint callback instead
},
) in viewport_output
{

View File

@@ -28,7 +28,7 @@ pub struct RequestRepaintInfo {
pub viewport_id: ViewportId,
/// Repaint after this duration. If zero, repaint as soon as possible.
pub after: Duration,
pub delay: Duration,
/// The current frame number.
///
@@ -71,30 +71,26 @@ impl ContextImpl {
self.request_repaint_after(Duration::ZERO, viewport_id);
}
fn request_repaint_after(&mut self, after: Duration, viewport_id: ViewportId) {
fn request_repaint_after(&mut self, delay: Duration, viewport_id: ViewportId) {
let mut viewport = self.viewports.entry(viewport_id).or_default();
// Each request results in two repaints, just to give some things time to settle.
// This solves some corner-cases of missing repaints on frame-delayed responses.
viewport.repaint.outstanding = 1;
let current_frame_nr = viewport.repaint.frame_nr;
self.call_repaint_callback(RequestRepaintInfo {
viewport_id,
after,
current_frame_nr,
});
}
fn call_repaint_callback(&mut self, info: RequestRepaintInfo) {
if let Some(callback) = &self.request_repaint_callback {
(callback)(info);
} else {
eprintln!(
"request_repaint_callback is not implemented by egui integration!
If is your integration you need to call `Context::set_request_repaint_callback`"
);
// We save some CPU time by only calling the callback if we need to.
// If the new delay is greater or equal to the previous lowest,
// it means we have already called the callback, and don't need to do it again.
if delay < viewport.repaint.repaint_delay {
viewport.repaint.repaint_delay = delay;
(callback)(RequestRepaintInfo {
viewport_id,
delay,
current_frame_nr: viewport.repaint.frame_nr,
});
}
}
}
@@ -106,10 +102,10 @@ impl ContextImpl {
}
#[must_use]
fn requested_repaint(&self, viewport_id: &ViewportId) -> bool {
self.viewports
.get(viewport_id)
.map_or(false, |v| 0 < v.repaint.outstanding)
fn has_requested_repaint(&self, viewport_id: &ViewportId) -> bool {
self.viewports.get(viewport_id).map_or(false, |v| {
0 < v.repaint.outstanding || v.repaint.repaint_delay < Duration::MAX
})
}
}
@@ -152,11 +148,18 @@ struct ViewportState {
}
/// Per-viewport state related to repaint scheduling.
#[derive(Default)]
struct ViewportRepaintInfo {
/// Monotonically increasing counter.
frame_nr: u64,
/// The duration which the 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.
///
/// This is also returned in [`crate::ViewportOutput`].
repaint_delay: Duration,
/// While positive, keep requesting repaints. Decrement at the start of each frame.
outstanding: u8,
@@ -164,6 +167,22 @@ struct ViewportRepaintInfo {
requested_last_frame: bool,
}
impl Default for ViewportRepaintInfo {
fn default() -> Self {
Self {
frame_nr: 0,
// We haven't scheduled a repaint yet.
repaint_delay: Duration::MAX,
// Let's run a couple of frames at the start, because why not.
outstanding: 1,
requested_last_frame: false,
}
}
}
// ----------------------------------------------------------------------------
#[derive(Default)]
@@ -206,14 +225,19 @@ impl ContextImpl {
self.viewport_stack.push(ids);
let viewport = self.viewports.entry(viewport_id).or_default();
if 0 < viewport.repaint.outstanding {
if viewport.repaint.outstanding == 0 {
// We are repainting now, so we can wait a while for the next repaint.
viewport.repaint.repaint_delay = Duration::MAX;
} else {
viewport.repaint.repaint_delay = Duration::ZERO;
viewport.repaint.outstanding -= 1;
let current_frame_nr = viewport.repaint.frame_nr;
self.call_repaint_callback(RequestRepaintInfo {
viewport_id,
after: Duration::ZERO,
current_frame_nr,
});
if let Some(callback) = &self.request_repaint_callback {
(callback)(RequestRepaintInfo {
viewport_id,
delay: Duration::ZERO,
current_frame_nr: viewport.repaint.frame_nr,
});
}
}
if let Some(new_pixels_per_point) = self.memory.override_pixels_per_point {
@@ -1222,14 +1246,14 @@ impl Context {
/// Has a repaint been requested for the current viewport?
#[must_use]
pub fn requested_repaint(&self) -> bool {
self.requested_repaint_for(&self.viewport_id())
pub fn has_requested_repaint(&self) -> bool {
self.has_requested_repaint_for(&self.viewport_id())
}
/// Has a repaint been requested for the given viewport?
#[must_use]
pub fn requested_repaint_for(&self, viewport_id: &ViewportId) -> bool {
self.read(|ctx| ctx.requested_repaint(viewport_id))
pub fn has_requested_repaint_for(&self, viewport_id: &ViewportId) -> bool {
self.read(|ctx| ctx.has_requested_repaint(viewport_id))
}
/// For integrations: this callback will be called when an egui user calls [`Self::request_repaint`] or [`Self::request_repaint_after`].
@@ -1590,6 +1614,7 @@ impl ContextImpl {
builder: viewport.builder.clone(),
viewport_ui_cb: viewport.viewport_ui_cb.clone(),
commands,
repaint_delay: viewport.repaint.repaint_delay,
},
)
})

View File

@@ -677,6 +677,14 @@ pub struct ViewportOutput {
/// Commands to change the viewport, e.g. window title and size.
pub commands: Vec<ViewportCommand>,
/// Schedulare a repaint of this viewport after this delay.
///
/// It is preferably to instead install a [`Context::set_request_repaint_callback`],
/// but if you haven't, you can use this instead.
///
/// If the duration is zero, schedule a repaint immediately.
pub repaint_delay: std::time::Duration,
}
impl ViewportOutput {
@@ -691,12 +699,14 @@ impl ViewportOutput {
builder,
viewport_ui_cb,
mut commands,
repaint_delay,
} = newer;
self.ids = ids;
self.builder.patch(&builder);
self.viewport_ui_cb = viewport_ui_cb;
self.commands.append(&mut commands);
self.repaint_delay = self.repaint_delay.min(repaint_delay);
}
}