[Impeller] improved glyph hashing performance (#44502)
This change makes the glyph hash 39% faster (66ms vs 107ms). The glyph hash function occupies the most CPU time on the raster thread when scrolling around the main screen for the Flutter Gallery
## before
<img width="1101" alt="Screenshot 2023-08-08 at 10 53 06 AM" src="https://github.com/flutter/engine/assets/30870216/2332323e-80cd-4f39-9ec1-95cb5662be7b">
## after
<img width="1097" alt="Screenshot 2023-08-08 at 10 52 51 AM" src="https://github.com/flutter/engine/assets/30870216/13bbc07b-7f56-40e8-ada5-32de77ddf614">
[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
diff --git a/impeller/typographer/font_glyph_pair.h b/impeller/typographer/font_glyph_pair.h
index 0b89c80..16eaecd 100644
--- a/impeller/typographer/font_glyph_pair.h
+++ b/impeller/typographer/font_glyph_pair.h
@@ -31,8 +31,20 @@
struct Hash {
std::size_t operator()(const FontGlyphPair& p) const {
- return fml::HashCombine(p.font.GetHash(), p.glyph.index, p.glyph.type,
- p.scale);
+ static_assert(sizeof(p.glyph.index) == 2);
+ static_assert(sizeof(p.glyph.type) == 1);
+ size_t index = p.glyph.index;
+ size_t type = static_cast<size_t>(p.glyph.type);
+ // By packaging multiple values in a single size_t the hash function is
+ // more efficient without losing entropy.
+ if (sizeof(size_t) == 8 && sizeof(Scalar) == 4) {
+ const float* fScale = &p.scale;
+ size_t nScale = *reinterpret_cast<const uint32_t*>(fScale);
+ size_t index_type_scale = nScale << 32 | index << 16 | type;
+ return fml::HashCombine(p.font.GetHash(), index_type_scale);
+ }
+ size_t index_type = index << 16 | type;
+ return fml::HashCombine(p.font.GetHash(), index_type, p.scale);
}
};
struct Equal {