Moved font glyph atlas to flat_hash_map (flutter/engine#56847)
In https://github.com/flutter/engine/pull/56844 we saw a 15% increase in performance by switching to absl::flat_hash_map. I suspect we say see even better results ([source](https://martin.ankerl.com/2022/08/27/hashmap-bench-01)). The absl guidance is to default to using this. test exempt: no intentional functional change, just performance [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
This commit is contained in:
parent
52504d1d77
commit
6d390bfaed
@ -34,6 +34,11 @@ impeller_component("typographer") {
|
||||
"../renderer",
|
||||
]
|
||||
|
||||
if (!is_fuchsia) {
|
||||
public_deps +=
|
||||
[ "//flutter/third_party/abseil-cpp/absl/container:flat_hash_map" ]
|
||||
}
|
||||
|
||||
deps = [ "//flutter/fml" ]
|
||||
}
|
||||
|
||||
|
@ -41,11 +41,10 @@ struct ScaledFont {
|
||||
Font font;
|
||||
Scalar scale;
|
||||
|
||||
struct Hash {
|
||||
constexpr std::size_t operator()(const impeller::ScaledFont& sf) const {
|
||||
return fml::HashCombine(sf.font.GetHash(), sf.scale);
|
||||
}
|
||||
};
|
||||
template <typename H>
|
||||
friend H AbslHashValue(H h, const ScaledFont& sf) {
|
||||
return H::combine(std::move(h), sf.font.GetHash(), sf.scale);
|
||||
}
|
||||
|
||||
struct Equal {
|
||||
constexpr bool operator()(const impeller::ScaledFont& lhs,
|
||||
@ -70,19 +69,18 @@ struct SubpixelGlyph {
|
||||
subpixel_offset(p_subpixel_offset),
|
||||
properties(p_properties) {}
|
||||
|
||||
struct Hash {
|
||||
constexpr std::size_t operator()(const impeller::SubpixelGlyph& sg) const {
|
||||
if (!sg.properties.has_value()) {
|
||||
return fml::HashCombine(sg.glyph.index, sg.subpixel_offset.x,
|
||||
sg.subpixel_offset.y);
|
||||
}
|
||||
return fml::HashCombine(
|
||||
sg.glyph.index, sg.subpixel_offset.x, sg.subpixel_offset.y,
|
||||
sg.properties->color.ToARGB(), sg.properties->stroke,
|
||||
sg.properties->stroke_cap, sg.properties->stroke_join,
|
||||
sg.properties->stroke_miter, sg.properties->stroke_width);
|
||||
template <typename H>
|
||||
friend H AbslHashValue(H h, const SubpixelGlyph& sg) {
|
||||
if (!sg.properties.has_value()) {
|
||||
return H::combine(std::move(h), sg.glyph.index, sg.subpixel_offset.x,
|
||||
sg.subpixel_offset.y);
|
||||
}
|
||||
};
|
||||
return H::combine(std::move(h), sg.glyph.index, sg.subpixel_offset.x,
|
||||
sg.subpixel_offset.y, sg.properties->color.ToARGB(),
|
||||
sg.properties->stroke, sg.properties->stroke_cap,
|
||||
sg.properties->stroke_join, sg.properties->stroke_miter,
|
||||
sg.properties->stroke_width);
|
||||
}
|
||||
|
||||
struct Equal {
|
||||
constexpr bool operator()(const impeller::SubpixelGlyph& lhs,
|
||||
|
@ -78,7 +78,9 @@ void GlyphAtlas::SetAtlasGeneration(size_t generation) {
|
||||
void GlyphAtlas::AddTypefaceGlyphPositionAndBounds(const FontGlyphPair& pair,
|
||||
Rect position,
|
||||
Rect bounds) {
|
||||
font_atlas_map_[pair.scaled_font].positions_[pair.glyph] =
|
||||
FontAtlasMap::iterator it = font_atlas_map_.find(pair.scaled_font);
|
||||
FML_DCHECK(it != font_atlas_map_.end());
|
||||
it->second.positions_[pair.glyph] =
|
||||
FrameBounds{position, bounds, /*is_placeholder=*/false};
|
||||
}
|
||||
|
||||
@ -93,12 +95,9 @@ std::optional<FrameBounds> GlyphAtlas::FindFontGlyphBounds(
|
||||
|
||||
FontGlyphAtlas* GlyphAtlas::GetOrCreateFontGlyphAtlas(
|
||||
const ScaledFont& scaled_font) {
|
||||
const auto& found = font_atlas_map_.find(scaled_font);
|
||||
if (found != font_atlas_map_.end()) {
|
||||
return &found->second;
|
||||
}
|
||||
font_atlas_map_[scaled_font] = FontGlyphAtlas();
|
||||
return &font_atlas_map_[scaled_font];
|
||||
auto [iter, inserted] =
|
||||
font_atlas_map_.try_emplace(scaled_font, FontGlyphAtlas());
|
||||
return &iter->second;
|
||||
}
|
||||
|
||||
size_t GlyphAtlas::GetGlyphCount() const {
|
||||
|
@ -8,7 +8,16 @@
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "flutter/fml/build_config.h"
|
||||
|
||||
#if defined(OS_FUCHSIA)
|
||||
// TODO(gaaclarke): Migrate to use absl. I couldn't get it working since absl
|
||||
// has special logic in its GN files for Fuchsia that I couldn't sort out.
|
||||
#define IMPELLER_TYPOGRAPHER_USE_STD_HASH
|
||||
#else
|
||||
#include "flutter/third_party/abseil-cpp/absl/container/flat_hash_map.h"
|
||||
#endif
|
||||
|
||||
#include "impeller/core/texture.h"
|
||||
#include "impeller/geometry/rect.h"
|
||||
@ -19,6 +28,30 @@ namespace impeller {
|
||||
|
||||
class FontGlyphAtlas;
|
||||
|
||||
/// Helper for AbslHashAdapter. Tallies a hash value with fml::HashCombine.
|
||||
template <typename T>
|
||||
struct AbslHashAdapterCombiner {
|
||||
std::size_t value = 0;
|
||||
|
||||
template <typename... Args>
|
||||
static AbslHashAdapterCombiner combine(AbslHashAdapterCombiner combiner,
|
||||
const Args&... args) {
|
||||
combiner.value = fml::HashCombine(combiner.value, args...);
|
||||
return combiner;
|
||||
}
|
||||
};
|
||||
|
||||
/// Adapts AbslHashValue functions to be used with std::unordered_map and the
|
||||
/// fml hash functions.
|
||||
template <typename T>
|
||||
struct AbslHashAdapter {
|
||||
constexpr std::size_t operator()(const T& element) const {
|
||||
AbslHashAdapterCombiner<T> combiner;
|
||||
combiner = AbslHashValue(std::move(combiner), element);
|
||||
return combiner.value;
|
||||
}
|
||||
};
|
||||
|
||||
struct FrameBounds {
|
||||
/// The bounds of the glyph within the glyph atlas.
|
||||
Rect atlas_bounds;
|
||||
@ -160,11 +193,19 @@ class GlyphAtlas {
|
||||
std::shared_ptr<Texture> texture_;
|
||||
size_t generation_ = 0;
|
||||
|
||||
std::unordered_map<ScaledFont,
|
||||
FontGlyphAtlas,
|
||||
ScaledFont::Hash,
|
||||
ScaledFont::Equal>
|
||||
font_atlas_map_;
|
||||
#if defined(IMPELLER_TYPOGRAPHER_USE_STD_HASH)
|
||||
using FontAtlasMap = std::unordered_map<ScaledFont,
|
||||
FontGlyphAtlas,
|
||||
AbslHashAdapter<ScaledFont>,
|
||||
ScaledFont::Equal>;
|
||||
#else
|
||||
using FontAtlasMap = absl::flat_hash_map<ScaledFont,
|
||||
FontGlyphAtlas,
|
||||
absl::Hash<ScaledFont>,
|
||||
ScaledFont::Equal>;
|
||||
#endif
|
||||
|
||||
FontAtlasMap font_atlas_map_;
|
||||
|
||||
GlyphAtlas(const GlyphAtlas&) = delete;
|
||||
|
||||
@ -228,6 +269,7 @@ class GlyphAtlasContext {
|
||||
class FontGlyphAtlas {
|
||||
public:
|
||||
FontGlyphAtlas() = default;
|
||||
FontGlyphAtlas(FontGlyphAtlas&&) = default;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Find the location of a glyph in the atlas.
|
||||
@ -249,12 +291,19 @@ class FontGlyphAtlas {
|
||||
private:
|
||||
friend class GlyphAtlas;
|
||||
|
||||
std::unordered_map<SubpixelGlyph,
|
||||
FrameBounds,
|
||||
SubpixelGlyph::Hash,
|
||||
SubpixelGlyph::Equal>
|
||||
positions_;
|
||||
#if defined(IMPELLER_TYPOGRAPHER_USE_STD_HASH)
|
||||
using PositionsMap = std::unordered_map<SubpixelGlyph,
|
||||
FrameBounds,
|
||||
AbslHashAdapter<SubpixelGlyph>,
|
||||
SubpixelGlyph::Equal>;
|
||||
#else
|
||||
using PositionsMap = absl::flat_hash_map<SubpixelGlyph,
|
||||
FrameBounds,
|
||||
absl::Hash<SubpixelGlyph>,
|
||||
SubpixelGlyph::Equal>;
|
||||
#endif
|
||||
|
||||
PositionsMap positions_;
|
||||
FontGlyphAtlas(const FontGlyphAtlas&) = delete;
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user