diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index 099f8009..de0a7e2e 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -339,6 +339,15 @@ impl RepaintCause { /// Per-viewport state related to repaint scheduling. struct ViewportRepaintInfo { /// Monotonically increasing counter. + /// + /// Incremented at the end of [`Context::run`]. + /// This can be smaller than [`Self::cumulative_pass_nr`], + /// but never larger. + cumulative_frame_nr: u64, + + /// Monotonically increasing counter, counting the number of passes. + /// This can be larger than [`Self::cumulative_frame_nr`], + /// but never smaller. cumulative_pass_nr: u64, /// The duration which the backend will poll for new events @@ -369,6 +378,7 @@ struct ViewportRepaintInfo { impl Default for ViewportRepaintInfo { fn default() -> Self { Self { + cumulative_frame_nr: 0, cumulative_pass_nr: 0, // We haven't scheduled a repaint yet. @@ -864,6 +874,7 @@ impl Context { } else { viewport.num_multipass_in_row = 0; } + viewport.repaint.cumulative_frame_nr += 1; }); output @@ -1536,6 +1547,28 @@ impl Context { } } + /// The total number of completed frames. + /// + /// Starts at zero, and is incremented once at the end of each call to [`Self::run`]. + /// + /// This is always smaller or equal to [`Self::cumulative_pass_nr`]. + pub fn cumulative_frame_nr(&self) -> u64 { + self.cumulative_frame_nr_for(self.viewport_id()) + } + + /// The total number of completed frames. + /// + /// Starts at zero, and is incremented once at the end of each call to [`Self::run`]. + /// + /// This is always smaller or equal to [`Self::cumulative_pass_nr_for`]. + pub fn cumulative_frame_nr_for(&self, id: ViewportId) -> u64 { + self.read(|ctx| { + ctx.viewports + .get(&id) + .map_or(0, |v| v.repaint.cumulative_frame_nr) + }) + } + /// The total number of completed passes (usually there is one pass per rendered frame). /// /// Starts at zero, and is incremented for each completed pass inside of [`Self::run`] (usually once). @@ -2998,36 +3031,54 @@ impl Context { pub fn inspection_ui(&self, ui: &mut Ui) { use crate::containers::CollapsingHeader; - ui.label(format!("Is using pointer: {}", self.is_using_pointer())) - .on_hover_text( - "Is egui currently using the pointer actively (e.g. dragging a slider)?", - ); - ui.label(format!("Wants pointer input: {}", self.wants_pointer_input())) - .on_hover_text("Is egui currently interested in the location of the pointer (either because it is in use, or because it is hovering over a window)."); - ui.label(format!( - "Wants keyboard input: {}", - self.wants_keyboard_input() - )) - .on_hover_text("Is egui currently listening for text input?"); - ui.label(format!( - "Keyboard focus widget: {}", - self.memory(|m| m.focused()) - .as_ref() - .map(Id::short_debug_format) - .unwrap_or_default() - )) - .on_hover_text("Is egui currently listening for text input?"); + crate::Grid::new("egui-inspection-grid") + .num_columns(2) + .striped(true) + .show(ui, |ui| { + ui.label("Total ui frames:"); + ui.monospace(ui.ctx().cumulative_frame_nr().to_string()); + ui.end_row(); - let pointer_pos = self - .pointer_hover_pos() - .map_or_else(String::new, |pos| format!("{pos:?}")); - ui.label(format!("Pointer pos: {pointer_pos}")); + ui.label("Total ui passes:"); + ui.monospace(ui.ctx().cumulative_pass_nr().to_string()); + ui.end_row(); - let top_layer = self - .pointer_hover_pos() - .and_then(|pos| self.layer_id_at(pos)) - .map_or_else(String::new, |layer| layer.short_debug_format()); - ui.label(format!("Top layer under mouse: {top_layer}")); + ui.label("Is using pointer") + .on_hover_text("Is egui currently using the pointer actively (e.g. dragging a slider)?"); + ui.monospace(self.is_using_pointer().to_string()); + ui.end_row(); + + ui.label("Wants pointer input") + .on_hover_text("Is egui currently interested in the location of the pointer (either because it is in use, or because it is hovering over a window)."); + ui.monospace(self.wants_pointer_input().to_string()); + ui.end_row(); + + ui.label("Wants keyboard input").on_hover_text("Is egui currently listening for text input?"); + ui.monospace(self.wants_keyboard_input().to_string()); + ui.end_row(); + + ui.label("Keyboard focus widget").on_hover_text("Is egui currently listening for text input?"); + ui.monospace(self.memory(|m| m.focused()) + .as_ref() + .map(Id::short_debug_format) + .unwrap_or_default()); + ui.end_row(); + + let pointer_pos = self + .pointer_hover_pos() + .map_or_else(String::new, |pos| format!("{pos:?}")); + ui.label("Pointer pos"); + ui.monospace(pointer_pos); + ui.end_row(); + + let top_layer = self + .pointer_hover_pos() + .and_then(|pos| self.layer_id_at(pos)) + .map_or_else(String::new, |layer| layer.short_debug_format()); + ui.label("Top layer under mouse"); + ui.monospace(top_layer); + ui.end_row(); + }); ui.add_space(16.0); diff --git a/crates/egui_demo_app/src/backend_panel.rs b/crates/egui_demo_app/src/backend_panel.rs index 1fb0c655..e98d5179 100644 --- a/crates/egui_demo_app/src/backend_panel.rs +++ b/crates/egui_demo_app/src/backend_panel.rs @@ -146,6 +146,10 @@ impl BackendPanel { // builds to keep the noise down in the official demo. if cfg!(debug_assertions) { ui.collapsing("More…", |ui| { + ui.horizontal(|ui| { + ui.label("Total ui frames:"); + ui.monospace(ui.ctx().cumulative_frame_nr().to_string()); + }); ui.horizontal(|ui| { ui.label("Total ui passes:"); ui.monospace(ui.ctx().cumulative_pass_nr().to_string());