use std::sync::OnceLock;
use std::time::Instant;
pub(crate) fn enabled() -> bool {
static ENABLED: OnceLock<bool> = OnceLock::new();
*ENABLED.get_or_init(|| std::env::var_os("AGG_PAINT_TIMING").is_some())
}
pub(crate) fn start() -> Option<Instant> {
enabled().then(Instant::now)
}
pub(crate) fn ms(t: &Option<Instant>) -> f64 {
t.as_ref()
.map_or(0.0, |t| t.elapsed().as_secs_f64() * 1000.0)
}
#[derive(Default)]
pub(crate) struct PaintTiming {
pub widget_paint_ms: f64,
pub lcd_ctx_setup_ms: f64,
pub plane_update_ms: f64,
pub make_mut_ms: f64,
pub rowcopy_ms: f64,
pub blit_ms: f64,
pub overlay_ms: f64,
pub did_raster: bool,
pub is_strip: bool,
pub strip_rows: Option<(u32, u32)>,
pub h_phys: u32,
}
#[derive(Default)]
pub(crate) struct TextAreaPaintTiming {
pub head_ms: f64,
pub bg_fill_ms: f64,
pub clip_ms: f64,
pub state_clone_ms: f64,
pub sel_loop_ms: f64,
pub text_loop_ms: f64,
pub tail_ms: f64,
pub painted_lines: u32,
pub hl_ms: f64,
}
impl TextAreaPaintTiming {
pub fn emit(&self) {
eprintln!(
"[ta paint strip] head={:.3} bg_fill={:.3} clip={:.3} state_clone={:.3} \
sel_loop={:.3} text_loop={:.3} (painted_lines={} hl={:.3}) tail={:.3}",
self.head_ms,
self.bg_fill_ms,
self.clip_ms,
self.state_clone_ms,
self.sel_loop_ms,
self.text_loop_ms,
self.painted_lines,
self.hl_ms,
self.tail_ms,
);
}
}
impl PaintTiming {
pub fn emit(&self) {
let kind = if !self.did_raster {
"blit-only"
} else if self.is_strip {
"strip"
} else {
"full"
};
let rows = match self.strip_rows {
Some((s, e)) => format!("{s}..{e} of {} ({} rows)", self.h_phys, e.saturating_sub(s)),
None => format!("(full {} rows)", self.h_phys),
};
eprintln!(
"[paint {kind}] widget_paint={:.3} lcd_ctx_setup={:.3} plane_update={:.3} \
(make_mut={:.3} rowcopy={:.3}) blit={:.3} overlay={:.3} rows={rows}",
self.widget_paint_ms,
self.lcd_ctx_setup_ms,
self.plane_update_ms,
self.make_mut_ms,
self.rowcopy_ms,
self.blit_ms,
self.overlay_ms,
);
}
}