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",
|
"../renderer",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if (!is_fuchsia) {
|
||||||
|
public_deps +=
|
||||||
|
[ "//flutter/third_party/abseil-cpp/absl/container:flat_hash_map" ]
|
||||||
|
}
|
||||||
|
|
||||||
deps = [ "//flutter/fml" ]
|
deps = [ "//flutter/fml" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,11 +41,10 @@ struct ScaledFont {
|
|||||||
Font font;
|
Font font;
|
||||||
Scalar scale;
|
Scalar scale;
|
||||||
|
|
||||||
struct Hash {
|
template <typename H>
|
||||||
constexpr std::size_t operator()(const impeller::ScaledFont& sf) const {
|
friend H AbslHashValue(H h, const ScaledFont& sf) {
|
||||||
return fml::HashCombine(sf.font.GetHash(), sf.scale);
|
return H::combine(std::move(h), sf.font.GetHash(), sf.scale);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
struct Equal {
|
struct Equal {
|
||||||
constexpr bool operator()(const impeller::ScaledFont& lhs,
|
constexpr bool operator()(const impeller::ScaledFont& lhs,
|
||||||
@ -70,19 +69,18 @@ struct SubpixelGlyph {
|
|||||||
subpixel_offset(p_subpixel_offset),
|
subpixel_offset(p_subpixel_offset),
|
||||||
properties(p_properties) {}
|
properties(p_properties) {}
|
||||||
|
|
||||||
struct Hash {
|
template <typename H>
|
||||||
constexpr std::size_t operator()(const impeller::SubpixelGlyph& sg) const {
|
friend H AbslHashValue(H h, const SubpixelGlyph& sg) {
|
||||||
if (!sg.properties.has_value()) {
|
if (!sg.properties.has_value()) {
|
||||||
return fml::HashCombine(sg.glyph.index, sg.subpixel_offset.x,
|
return H::combine(std::move(h), sg.glyph.index, sg.subpixel_offset.x,
|
||||||
sg.subpixel_offset.y);
|
sg.subpixel_offset.y);
|
||||||
}
|
}
|
||||||
return fml::HashCombine(
|
return H::combine(std::move(h), sg.glyph.index, sg.subpixel_offset.x,
|
||||||
sg.glyph.index, sg.subpixel_offset.x, sg.subpixel_offset.y,
|
sg.subpixel_offset.y, sg.properties->color.ToARGB(),
|
||||||
sg.properties->color.ToARGB(), sg.properties->stroke,
|
sg.properties->stroke, sg.properties->stroke_cap,
|
||||||
sg.properties->stroke_cap, sg.properties->stroke_join,
|
sg.properties->stroke_join, sg.properties->stroke_miter,
|
||||||
sg.properties->stroke_miter, sg.properties->stroke_width);
|
sg.properties->stroke_width);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
struct Equal {
|
struct Equal {
|
||||||
constexpr bool operator()(const impeller::SubpixelGlyph& lhs,
|
constexpr bool operator()(const impeller::SubpixelGlyph& lhs,
|
||||||
|
@ -78,7 +78,9 @@ void GlyphAtlas::SetAtlasGeneration(size_t generation) {
|
|||||||
void GlyphAtlas::AddTypefaceGlyphPositionAndBounds(const FontGlyphPair& pair,
|
void GlyphAtlas::AddTypefaceGlyphPositionAndBounds(const FontGlyphPair& pair,
|
||||||
Rect position,
|
Rect position,
|
||||||
Rect bounds) {
|
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};
|
FrameBounds{position, bounds, /*is_placeholder=*/false};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,12 +95,9 @@ std::optional<FrameBounds> GlyphAtlas::FindFontGlyphBounds(
|
|||||||
|
|
||||||
FontGlyphAtlas* GlyphAtlas::GetOrCreateFontGlyphAtlas(
|
FontGlyphAtlas* GlyphAtlas::GetOrCreateFontGlyphAtlas(
|
||||||
const ScaledFont& scaled_font) {
|
const ScaledFont& scaled_font) {
|
||||||
const auto& found = font_atlas_map_.find(scaled_font);
|
auto [iter, inserted] =
|
||||||
if (found != font_atlas_map_.end()) {
|
font_atlas_map_.try_emplace(scaled_font, FontGlyphAtlas());
|
||||||
return &found->second;
|
return &iter->second;
|
||||||
}
|
|
||||||
font_atlas_map_[scaled_font] = FontGlyphAtlas();
|
|
||||||
return &font_atlas_map_[scaled_font];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t GlyphAtlas::GetGlyphCount() const {
|
size_t GlyphAtlas::GetGlyphCount() const {
|
||||||
|
@ -8,7 +8,16 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#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/core/texture.h"
|
||||||
#include "impeller/geometry/rect.h"
|
#include "impeller/geometry/rect.h"
|
||||||
@ -19,6 +28,30 @@ namespace impeller {
|
|||||||
|
|
||||||
class FontGlyphAtlas;
|
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 {
|
struct FrameBounds {
|
||||||
/// The bounds of the glyph within the glyph atlas.
|
/// The bounds of the glyph within the glyph atlas.
|
||||||
Rect atlas_bounds;
|
Rect atlas_bounds;
|
||||||
@ -160,11 +193,19 @@ class GlyphAtlas {
|
|||||||
std::shared_ptr<Texture> texture_;
|
std::shared_ptr<Texture> texture_;
|
||||||
size_t generation_ = 0;
|
size_t generation_ = 0;
|
||||||
|
|
||||||
std::unordered_map<ScaledFont,
|
#if defined(IMPELLER_TYPOGRAPHER_USE_STD_HASH)
|
||||||
|
using FontAtlasMap = std::unordered_map<ScaledFont,
|
||||||
FontGlyphAtlas,
|
FontGlyphAtlas,
|
||||||
ScaledFont::Hash,
|
AbslHashAdapter<ScaledFont>,
|
||||||
ScaledFont::Equal>
|
ScaledFont::Equal>;
|
||||||
font_atlas_map_;
|
#else
|
||||||
|
using FontAtlasMap = absl::flat_hash_map<ScaledFont,
|
||||||
|
FontGlyphAtlas,
|
||||||
|
absl::Hash<ScaledFont>,
|
||||||
|
ScaledFont::Equal>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FontAtlasMap font_atlas_map_;
|
||||||
|
|
||||||
GlyphAtlas(const GlyphAtlas&) = delete;
|
GlyphAtlas(const GlyphAtlas&) = delete;
|
||||||
|
|
||||||
@ -228,6 +269,7 @@ class GlyphAtlasContext {
|
|||||||
class FontGlyphAtlas {
|
class FontGlyphAtlas {
|
||||||
public:
|
public:
|
||||||
FontGlyphAtlas() = default;
|
FontGlyphAtlas() = default;
|
||||||
|
FontGlyphAtlas(FontGlyphAtlas&&) = default;
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
/// @brief Find the location of a glyph in the atlas.
|
/// @brief Find the location of a glyph in the atlas.
|
||||||
@ -249,12 +291,19 @@ class FontGlyphAtlas {
|
|||||||
private:
|
private:
|
||||||
friend class GlyphAtlas;
|
friend class GlyphAtlas;
|
||||||
|
|
||||||
std::unordered_map<SubpixelGlyph,
|
#if defined(IMPELLER_TYPOGRAPHER_USE_STD_HASH)
|
||||||
|
using PositionsMap = std::unordered_map<SubpixelGlyph,
|
||||||
FrameBounds,
|
FrameBounds,
|
||||||
SubpixelGlyph::Hash,
|
AbslHashAdapter<SubpixelGlyph>,
|
||||||
SubpixelGlyph::Equal>
|
SubpixelGlyph::Equal>;
|
||||||
positions_;
|
#else
|
||||||
|
using PositionsMap = absl::flat_hash_map<SubpixelGlyph,
|
||||||
|
FrameBounds,
|
||||||
|
absl::Hash<SubpixelGlyph>,
|
||||||
|
SubpixelGlyph::Equal>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PositionsMap positions_;
|
||||||
FontGlyphAtlas(const FontGlyphAtlas&) = delete;
|
FontGlyphAtlas(const FontGlyphAtlas&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user