Perf profiling and some low hanging perf improvements in text rendering

This commit is contained in:
Will Temple
2026-05-16 19:07:44 -04:00
parent 4347232b98
commit e5ae067bc2
13 changed files with 1010 additions and 117 deletions

View File

@@ -36,6 +36,35 @@ pub struct LayoutSnapshot {
pub root_min_size: UiSize,
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct LayoutFrameStats {
pub total_ms: f64,
pub nodes: usize,
pub text_nodes: usize,
pub container_nodes: usize,
pub background_quads: usize,
pub intrinsic_calls: usize,
pub intrinsic_size_calls: usize,
pub intrinsic_text_calls: usize,
pub intrinsic_container_calls: usize,
pub intrinsic_ms: f64,
pub text_prepare_calls: usize,
pub text_prepare_ms: f64,
pub viewport_culled: usize,
pub layout_cache_hits: usize,
pub layout_cache_misses: usize,
pub intrinsic_cache_hits: usize,
pub text_requests: u32,
pub text_cache_hits: u32,
pub text_cache_misses: u32,
pub text_output_glyphs: u32,
pub text_family_resolve_ms: f64,
pub text_buffer_build_ms: f64,
pub text_glyph_collect_ms: f64,
pub text_miss_ms: f64,
pub scene_items: usize,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct LayoutPath(Vec<u32>);
@@ -194,6 +223,16 @@ pub fn layout_snapshot_with_cache(
text_system: &mut TextSystem,
layout_cache: &mut LayoutCache,
) -> LayoutSnapshot {
layout_snapshot_with_cache_and_stats(version, logical_size, root, text_system, layout_cache).0
}
pub fn layout_snapshot_with_cache_and_stats(
version: u64,
logical_size: UiSize,
root: &Element,
text_system: &mut TextSystem,
layout_cache: &mut LayoutCache,
) -> (LayoutSnapshot, LayoutFrameStats) {
let layout_started = Instant::now();
let perf_enabled = tracing::enabled!(target: "ruin_ui::layout_perf", tracing::Level::DEBUG);
let mut perf_stats = LayoutPerfStats::new(perf_enabled);
@@ -215,48 +254,78 @@ pub fn layout_snapshot_with_cache(
None,
);
let text_stats = text_system.take_frame_stats();
let stats = LayoutFrameStats {
total_ms: layout_started.elapsed().as_secs_f64() * 1_000.0,
nodes: perf_stats.nodes,
text_nodes: perf_stats.text_nodes,
container_nodes: perf_stats.container_nodes,
background_quads: perf_stats.background_quads,
intrinsic_calls: perf_stats.intrinsic_calls,
intrinsic_size_calls: perf_stats.intrinsic_size_calls,
intrinsic_text_calls: perf_stats.intrinsic_text_calls,
intrinsic_container_calls: perf_stats.intrinsic_container_calls,
intrinsic_ms: perf_stats.intrinsic_ms,
text_prepare_calls: perf_stats.text_prepare_calls,
text_prepare_ms: perf_stats.text_prepare_ms,
viewport_culled: perf_stats.viewport_culled,
layout_cache_hits: perf_stats.layout_cache_hits,
layout_cache_misses: perf_stats.layout_cache_misses,
intrinsic_cache_hits: perf_stats.intrinsic_cache_hits,
text_requests: text_stats.requests,
text_cache_hits: text_stats.cache_hits,
text_cache_misses: text_stats.cache_misses,
text_output_glyphs: text_stats.output_glyphs,
text_family_resolve_ms: text_stats.family_resolve_ms,
text_buffer_build_ms: text_stats.buffer_build_ms,
text_glyph_collect_ms: text_stats.glyph_collect_ms,
text_miss_ms: text_stats.miss_ms,
scene_items: scene.items.len(),
};
if perf_stats.enabled {
tracing::debug!(
target: "ruin_ui::layout_perf",
scene_version = version,
width = logical_size.width,
height = logical_size.height,
total_ms = layout_started.elapsed().as_secs_f64() * 1_000.0,
nodes = perf_stats.nodes,
text_nodes = perf_stats.text_nodes,
container_nodes = perf_stats.container_nodes,
background_quads = perf_stats.background_quads,
intrinsic_calls = perf_stats.intrinsic_calls,
intrinsic_size_calls = perf_stats.intrinsic_size_calls,
intrinsic_text_calls = perf_stats.intrinsic_text_calls,
intrinsic_container_calls = perf_stats.intrinsic_container_calls,
intrinsic_ms = perf_stats.intrinsic_ms,
text_prepare_calls = perf_stats.text_prepare_calls,
text_prepare_ms = perf_stats.text_prepare_ms,
viewport_culled = perf_stats.viewport_culled,
layout_cache_hits = perf_stats.layout_cache_hits,
layout_cache_misses = perf_stats.layout_cache_misses,
intrinsic_cache_hits = perf_stats.intrinsic_cache_hits,
text_requests = text_stats.requests,
text_cache_hits = text_stats.cache_hits,
text_cache_misses = text_stats.cache_misses,
text_output_glyphs = text_stats.output_glyphs,
text_family_resolve_ms = text_stats.family_resolve_ms,
text_buffer_build_ms = text_stats.buffer_build_ms,
text_glyph_collect_ms = text_stats.glyph_collect_ms,
text_miss_ms = text_stats.miss_ms,
scene_items = scene.items.len(),
total_ms = stats.total_ms,
nodes = stats.nodes,
text_nodes = stats.text_nodes,
container_nodes = stats.container_nodes,
background_quads = stats.background_quads,
intrinsic_calls = stats.intrinsic_calls,
intrinsic_size_calls = stats.intrinsic_size_calls,
intrinsic_text_calls = stats.intrinsic_text_calls,
intrinsic_container_calls = stats.intrinsic_container_calls,
intrinsic_ms = stats.intrinsic_ms,
text_prepare_calls = stats.text_prepare_calls,
text_prepare_ms = stats.text_prepare_ms,
viewport_culled = stats.viewport_culled,
layout_cache_hits = stats.layout_cache_hits,
layout_cache_misses = stats.layout_cache_misses,
intrinsic_cache_hits = stats.intrinsic_cache_hits,
text_requests = stats.text_requests,
text_cache_hits = stats.text_cache_hits,
text_cache_misses = stats.text_cache_misses,
text_output_glyphs = stats.text_output_glyphs,
text_family_resolve_ms = stats.text_family_resolve_ms,
text_buffer_build_ms = stats.text_buffer_build_ms,
text_glyph_collect_ms = stats.text_glyph_collect_ms,
text_miss_ms = stats.text_miss_ms,
scene_items = stats.scene_items,
"layout snapshot perf"
);
}
let root_min_size = element_min_size(root);
LayoutSnapshot {
scene,
interaction_tree: InteractionTree {
root: interaction_root,
(
LayoutSnapshot {
scene,
interaction_tree: InteractionTree {
root: interaction_root,
},
root_min_size,
},
root_min_size,
}
stats,
)
}
#[allow(clippy::too_many_arguments)]
@@ -2903,7 +2972,7 @@ mod tests {
.items
.iter()
.filter_map(|item| match item {
DisplayItem::Text(text) => Some(text.text.as_str()),
DisplayItem::Text(text) => Some(text.text.as_ref()),
_ => None,
})
.collect()