From 4325c8f3c836697d90815ac86e17561c899bae36 Mon Sep 17 00:00:00 2001 From: valadaptive Date: Sun, 7 Sep 2025 21:33:49 -0400 Subject: [PATCH] Optimize glyph allocation cache lookups --- crates/epaint/src/text/font.rs | 38 +++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/crates/epaint/src/text/font.rs b/crates/epaint/src/text/font.rs index 51cd88024..767c22fd7 100644 --- a/crates/epaint/src/text/font.rs +++ b/crates/epaint/src/text/font.rs @@ -81,8 +81,7 @@ pub struct FontImpl { ab_glyph_font: ab_glyph::FontArc, tweak: FontTweak, glyph_info_cache: ahash::HashMap, - glyph_alloc_cache: - ahash::HashMap<(ab_glyph::GlyphId, OrderedFloat, OrderedFloat), GlyphAllocation>, + glyph_alloc_cache: ahash::HashMap<(ab_glyph::GlyphId, u64), GlyphAllocation>, } trait FontExt { @@ -262,11 +261,10 @@ impl FontImpl { return GlyphAllocation::default(); }; - let entry = match self.glyph_alloc_cache.entry(( - glyph_id, - metrics.px_scale_factor.into(), - metrics.pixels_per_point.into(), - )) { + let entry = match self + .glyph_alloc_cache + .entry((glyph_id, metrics.glyph_cache_key())) + { std::collections::hash_map::Entry::Occupied(glyph_alloc) => { return *glyph_alloc.get(); } @@ -441,6 +439,32 @@ pub struct ScaledMetrics { pub row_height: f32, } +impl ScaledMetrics { + fn glyph_cache_key(&self) -> u64 { + // This is faster than hashing two `OrderedFloat`s. Neither scale factor should ever be negative-zero or NaN. + debug_assert!( + self.pixels_per_point.is_finite() && self.pixels_per_point.is_sign_positive(), + "pixels_per_point can be safely hashed as raw bits" + ); + debug_assert!( + self.px_scale_factor.is_finite() && self.px_scale_factor.is_sign_positive(), + "px_scale_factor can be safely hashed as raw bits" + ); + let dpi_bits = self.pixels_per_point.to_le_bytes(); + let scale_bits = self.px_scale_factor.to_le_bytes(); + u64::from_le_bytes([ + dpi_bits[0], + dpi_bits[1], + dpi_bits[2], + dpi_bits[3], + scale_bits[0], + scale_bits[1], + scale_bits[2], + scale_bits[3], + ]) + } +} + /// Code points that will always be invisible (zero width). /// /// See also [`FontImpl::ignore_character`].