commit 9cbba37507b60ffc6a57098fcafdf76272330034
parent b94e715539b2251626d568f518a62e7ec355d811
Author: William Casarin <jb55@jb55.com>
Date: Mon, 4 Aug 2025 11:29:54 -0700
debug: add repaint causes debug tool
enable with --debug, click on fps/frame time counter
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
6 files changed, 83 insertions(+), 21 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -3622,6 +3622,7 @@ dependencies = [
"eframe",
"egui",
"egui-wgpu",
+ "egui_extras",
"enostr",
"futures",
"hex",
diff --git a/crates/notedeck/src/media/gif.rs b/crates/notedeck/src/media/gif.rs
@@ -151,12 +151,11 @@ pub fn ensure_latest_texture(
gifs.insert(url.to_owned(), new_state);
}
- if let Some(req) = next_state.repaint_at {
- // TODO(jb55): make a continuous gif rendering setting
- // 24fps for gif is fine
- tracing::trace!("requesting repaint for {url} after {req:?}");
- ui.ctx()
- .request_repaint_after(std::time::Duration::from_millis(41));
+ if let Some(repaint) = next_state.repaint_at {
+ tracing::trace!("requesting repaint for {url} after {repaint:?}");
+ if let Ok(dur) = repaint.duration_since(SystemTime::now()) {
+ ui.ctx().request_repaint_after(dur);
+ }
}
next_state.texture
diff --git a/crates/notedeck_chrome/src/chrome.rs b/crates/notedeck_chrome/src/chrome.rs
@@ -19,6 +19,7 @@ use notedeck_columns::{
use notedeck_dave::{Dave, DaveAvatar};
use notedeck_notebook::Notebook;
use notedeck_ui::{app_images, AnimationHelper, ProfilePic};
+use std::collections::HashMap;
static ICON_WIDTH: f32 = 40.0;
pub static ICON_EXPANSION_MULTIPLE: f32 = 1.2;
@@ -28,15 +29,18 @@ pub struct Chrome {
open: bool,
tab_selected: i32,
apps: Vec<NotedeckApp>,
+ pub repaint_causes: HashMap<egui::RepaintCause, u64>,
#[cfg(feature = "memory")]
show_memory_debug: bool,
+ show_repaint_debug: bool,
}
impl Default for Chrome {
fn default() -> Self {
Self {
active: 0,
+ repaint_causes: Default::default(),
tab_selected: 0,
// sidemenu is not open by default on mobile/narrow uis
open: !notedeck::ui::is_compiled_as_mobile(),
@@ -44,6 +48,7 @@ impl Default for Chrome {
#[cfg(feature = "memory")]
show_memory_debug: false,
+ show_repaint_debug: false,
}
}
}
@@ -959,7 +964,7 @@ fn pfp_button(ctx: &mut AppContext, ui: &mut egui::Ui) -> egui::Response {
/// The section of the chrome sidebar that starts at the
/// bottom and goes up
fn bottomup_sidebar(
- _chrome: &mut Chrome,
+ chrome: &mut Chrome,
ctx: &mut AppContext,
ui: &mut egui::Ui,
) -> Option<ChromePanelAction> {
@@ -1009,11 +1014,30 @@ fn bottomup_sidebar(
.on_hover_cursor(egui::CursorIcon::PointingHand);
if ctx.args.options.contains(NotedeckOptions::Debug) {
- ui.weak(format!("{}", ctx.frame_history.fps() as i32));
- ui.weak(format!(
- "{:10.1}",
- ctx.frame_history.mean_frame_time() * 1e3
- ));
+ let r = ui
+ .weak(format!("{}", ctx.frame_history.fps() as i32))
+ .union(ui.weak(format!(
+ "{:10.1}",
+ ctx.frame_history.mean_frame_time() * 1e3
+ )))
+ .on_hover_cursor(egui::CursorIcon::PointingHand);
+
+ if r.clicked() {
+ chrome.show_repaint_debug = !chrome.show_repaint_debug;
+ }
+
+ if chrome.show_repaint_debug {
+ for cause in ui.ctx().repaint_causes() {
+ chrome
+ .repaint_causes
+ .entry(cause)
+ .and_modify(|rc| {
+ *rc += 1;
+ })
+ .or_insert(1);
+ }
+ repaint_causes_window(ui, &chrome.repaint_causes)
+ }
#[cfg(feature = "memory")]
{
@@ -1024,14 +1048,14 @@ fn bottomup_sidebar(
.on_hover_cursor(egui::CursorIcon::PointingHand)
.clicked()
{
- _chrome.show_memory_debug = !_chrome.show_memory_debug;
+ chrome.show_memory_debug = !chrome.show_memory_debug;
}
}
if let Some(resident) = mem_use.resident {
ui.weak(format!("{}", format_bytes(resident as f64)));
}
- if _chrome.show_memory_debug {
+ if chrome.show_memory_debug {
egui::Window::new("Memory Debug").show(ui.ctx(), memory_debug_ui);
}
}
@@ -1151,3 +1175,46 @@ pub fn format_bytes(number_of_bytes: f64) -> String {
format!("{:.*} GiB", decimals, number_of_bytes / 30.0_f64.exp2())
}
}
+
+fn repaint_causes_window(ui: &mut egui::Ui, causes: &HashMap<egui::RepaintCause, u64>) {
+ egui::Window::new("Repaint Causes").show(ui.ctx(), |ui| {
+ use egui_extras::{Column, TableBuilder};
+ TableBuilder::new(ui)
+ .column(Column::auto().at_least(600.0).resizable(true))
+ .column(Column::auto().at_least(50.0).resizable(true))
+ .column(Column::auto().at_least(50.0).resizable(true))
+ .column(Column::remainder())
+ .header(20.0, |mut header| {
+ header.col(|ui| {
+ ui.heading("file");
+ });
+ header.col(|ui| {
+ ui.heading("line");
+ });
+ header.col(|ui| {
+ ui.heading("count");
+ });
+ header.col(|ui| {
+ ui.heading("reason");
+ });
+ })
+ .body(|mut body| {
+ for (cause, hits) in causes.iter() {
+ body.row(30.0, |mut row| {
+ row.col(|ui| {
+ ui.label(cause.file.to_string());
+ });
+ row.col(|ui| {
+ ui.label(format!("{}", cause.line));
+ });
+ row.col(|ui| {
+ ui.label(format!("{hits}"));
+ });
+ row.col(|ui| {
+ ui.label(format!("{}", &cause.reason));
+ });
+ });
+ }
+ });
+ });
+}
diff --git a/crates/notedeck_columns/src/app.rs b/crates/notedeck_columns/src/app.rs
@@ -27,7 +27,6 @@ use notedeck_ui::{
};
use std::collections::{BTreeSet, HashMap};
use std::path::Path;
-use std::time::Duration;
use tracing::{debug, error, info, trace, warn};
use uuid::Uuid;
@@ -374,7 +373,7 @@ fn render_damus(
fullscreen_media_viewer_ui(ui, &mut damus.view_state.media_viewer, app_ctx.img_cache);
// We use this for keeping timestamps and things up to date
- ui.ctx().request_repaint_after(Duration::from_secs(5));
+ //ui.ctx().request_repaint_after(Duration::from_secs(5));
app_action
}
diff --git a/crates/notedeck_dave/Cargo.toml b/crates/notedeck_dave/Cargo.toml
@@ -23,3 +23,4 @@ rand = "0.9.0"
bytemuck = "1.22.0"
futures = "0.3.31"
#reqwest = "0.12.15"
+egui_extras = { workspace = true }
diff --git a/crates/notedeck_dave/src/lib.rs b/crates/notedeck_dave/src/lib.rs
@@ -344,11 +344,6 @@ You are an AI agent for the nostr protocol called Dave, created by Damus. nostr
impl notedeck::App for Dave {
fn update(&mut self, ctx: &mut AppContext<'_>, ui: &mut egui::Ui) -> Option<AppAction> {
- /*
- self.app
- .frame_history
- .on_new_frame(ctx.input(|i| i.time), frame.info().cpu_usage);
- */
let mut app_action: Option<AppAction> = None;
// always insert system prompt if we have no context