Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 38e37ce

Browse files
author
Jonah Williams
authored
[Impeller] hash less text stuff per frame for text rendering. (#55060)
The Glyph color and stroke property are only required for stroked text or COLR text, in all other cases its a no-op. We can do the text hashing faster if we let these properties be optional. ~Also as an experiment switches to absl containers which should be more reasonably performant than std containers.~ required more changes, will try again later
1 parent ade8ef2 commit 38e37ce

File tree

6 files changed

+90
-64
lines changed

6 files changed

+90
-64
lines changed

impeller/entity/contents/text_contents.cc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,11 @@ bool TextContents::Render(const ContentContext& renderer,
222222
Point subpixel = TextFrame::ComputeSubpixelPosition(
223223
glyph_position, font.GetAxisAlignment(), offset_, scale_);
224224
std::optional<std::pair<Rect, Rect>> maybe_atlas_glyph_bounds =
225-
font_atlas->FindGlyphBounds(
226-
SubpixelGlyph{glyph_position.glyph, subpixel, properties_});
225+
font_atlas->FindGlyphBounds(SubpixelGlyph{
226+
glyph_position.glyph, subpixel,
227+
(properties_.stroke || frame_->HasColor())
228+
? std::optional<GlyphProperties>(properties_)
229+
: std::nullopt});
227230
if (!maybe_atlas_glyph_bounds.has_value()) {
228231
VALIDATION_LOG << "Could not find glyph position in the atlas.";
229232
continue;

impeller/typographer/backends/skia/typographer_context_skia.cc

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ static void DrawGlyph(SkCanvas* canvas,
208208
const ScaledFont& scaled_font,
209209
const SubpixelGlyph& glyph,
210210
const Rect& scaled_bounds,
211-
const GlyphProperties& prop,
211+
const std::optional<GlyphProperties>& prop,
212212
bool has_color) {
213213
const auto& metrics = scaled_font.font.GetMetrics();
214214
SkGlyphID glyph_id = glyph.glyph.index;
@@ -222,18 +222,17 @@ static void DrawGlyph(SkCanvas* canvas,
222222
sk_font.setSubpixel(true);
223223
sk_font.setSize(sk_font.getSize() * scaled_font.scale);
224224

225-
auto glyph_color =
226-
has_color ? glyph.properties.color.ToARGB() : SK_ColorBLACK;
225+
auto glyph_color = prop.has_value() ? prop->color.ToARGB() : SK_ColorBLACK;
227226

228227
SkPaint glyph_paint;
229228
glyph_paint.setColor(glyph_color);
230229
glyph_paint.setBlendMode(SkBlendMode::kSrc);
231-
if (prop.stroke) {
230+
if (prop.has_value() && prop->stroke) {
232231
glyph_paint.setStroke(true);
233-
glyph_paint.setStrokeWidth(prop.stroke_width * scaled_font.scale);
234-
glyph_paint.setStrokeCap(ToSkiaCap(glyph.properties.stroke_cap));
235-
glyph_paint.setStrokeJoin(ToSkiaJoin(glyph.properties.stroke_join));
236-
glyph_paint.setStrokeMiter(prop.stroke_miter * scaled_font.scale);
232+
glyph_paint.setStrokeWidth(prop->stroke_width * scaled_font.scale);
233+
glyph_paint.setStrokeCap(ToSkiaCap(prop->stroke_cap));
234+
glyph_paint.setStrokeJoin(ToSkiaJoin(prop->stroke_join));
235+
glyph_paint.setStrokeMiter(prop->stroke_miter * scaled_font.scale);
237236
}
238237
canvas->save();
239238
canvas->translate(glyph.subpixel_offset.x, glyph.subpixel_offset.y);
@@ -384,12 +383,12 @@ static Rect ComputeGlyphSize(const SkFont& font,
384383
Scalar scale) {
385384
SkRect scaled_bounds;
386385
SkPaint glyph_paint;
387-
if (glyph.properties.stroke) {
386+
if (glyph.properties.has_value() && glyph.properties->stroke) {
388387
glyph_paint.setStroke(true);
389-
glyph_paint.setStrokeWidth(glyph.properties.stroke_width * scale);
390-
glyph_paint.setStrokeCap(ToSkiaCap(glyph.properties.stroke_cap));
391-
glyph_paint.setStrokeJoin(ToSkiaJoin(glyph.properties.stroke_join));
392-
glyph_paint.setStrokeMiter(glyph.properties.stroke_miter * scale);
388+
glyph_paint.setStrokeWidth(glyph.properties->stroke_width * scale);
389+
glyph_paint.setStrokeCap(ToSkiaCap(glyph.properties->stroke_cap));
390+
glyph_paint.setStrokeJoin(ToSkiaJoin(glyph.properties->stroke_join));
391+
glyph_paint.setStrokeMiter(glyph.properties->stroke_miter * scale);
393392
}
394393
font.getBounds(&glyph.glyph.index, 1, &scaled_bounds, &glyph_paint);
395394

impeller/typographer/font_glyph_pair.h

Lines changed: 57 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <unordered_map>
99
#include <unordered_set>
1010

11+
#include "fml/hash_combine.h"
1112
#include "impeller/geometry/color.h"
1213
#include "impeller/geometry/path.h"
1314
#include "impeller/geometry/point.h"
@@ -32,6 +33,19 @@ struct GlyphProperties {
3233
struct ScaledFont {
3334
Font font;
3435
Scalar scale;
36+
37+
struct Hash {
38+
constexpr std::size_t operator()(const impeller::ScaledFont& sf) const {
39+
return fml::HashCombine(sf.font.GetHash(), sf.scale);
40+
}
41+
};
42+
43+
struct Equal {
44+
constexpr bool operator()(const impeller::ScaledFont& lhs,
45+
const impeller::ScaledFont& rhs) const {
46+
return lhs.font.IsEqual(rhs.font) && lhs.scale == rhs.scale;
47+
}
48+
};
3549
};
3650

3751
//------------------------------------------------------------------------------
@@ -40,18 +54,58 @@ struct ScaledFont {
4054
struct SubpixelGlyph {
4155
Glyph glyph;
4256
Point subpixel_offset;
43-
GlyphProperties properties;
57+
std::optional<GlyphProperties> properties;
4458

4559
SubpixelGlyph(Glyph p_glyph,
4660
Point p_subpixel_offset,
47-
GlyphProperties p_properties)
61+
std::optional<GlyphProperties> p_properties)
4862
: glyph(p_glyph),
4963
subpixel_offset(p_subpixel_offset),
5064
properties(p_properties) {}
65+
66+
struct Hash {
67+
constexpr std::size_t operator()(const impeller::SubpixelGlyph& sg) const {
68+
if (!sg.properties.has_value()) {
69+
return fml::HashCombine(sg.glyph.index, sg.subpixel_offset.x,
70+
sg.subpixel_offset.y);
71+
}
72+
return fml::HashCombine(
73+
sg.glyph.index, sg.subpixel_offset.x, sg.subpixel_offset.y,
74+
sg.properties->color.ToARGB(), sg.properties->stroke,
75+
sg.properties->stroke_cap, sg.properties->stroke_join,
76+
sg.properties->stroke_miter, sg.properties->stroke_width);
77+
}
78+
};
79+
80+
struct Equal {
81+
constexpr bool operator()(const impeller::SubpixelGlyph& lhs,
82+
const impeller::SubpixelGlyph& rhs) const {
83+
if (!lhs.properties.has_value() && !rhs.properties.has_value()) {
84+
return lhs.glyph.index == rhs.glyph.index &&
85+
lhs.glyph.type == rhs.glyph.type &&
86+
lhs.subpixel_offset == rhs.subpixel_offset;
87+
}
88+
return lhs.glyph.index == rhs.glyph.index &&
89+
lhs.glyph.type == rhs.glyph.type &&
90+
lhs.subpixel_offset == rhs.subpixel_offset &&
91+
lhs.properties.has_value() && rhs.properties.has_value() &&
92+
lhs.properties->color.ToARGB() == rhs.properties->color.ToARGB() &&
93+
lhs.properties->stroke == rhs.properties->stroke &&
94+
lhs.properties->stroke_cap == rhs.properties->stroke_cap &&
95+
lhs.properties->stroke_join == rhs.properties->stroke_join &&
96+
lhs.properties->stroke_miter == rhs.properties->stroke_miter &&
97+
lhs.properties->stroke_width == rhs.properties->stroke_width;
98+
}
99+
};
51100
};
52101

53102
using FontGlyphMap =
54-
std::unordered_map<ScaledFont, std::unordered_set<SubpixelGlyph>>;
103+
std::unordered_map<ScaledFont,
104+
std::unordered_set<SubpixelGlyph,
105+
SubpixelGlyph::Hash,
106+
SubpixelGlyph::Equal>,
107+
ScaledFont::Hash,
108+
ScaledFont::Equal>;
55109

56110
//------------------------------------------------------------------------------
57111
/// @brief A font along with a glyph in that font rendered at a particular
@@ -66,46 +120,4 @@ struct FontGlyphPair {
66120

67121
} // namespace impeller
68122

69-
template <>
70-
struct std::hash<impeller::ScaledFont> {
71-
constexpr std::size_t operator()(const impeller::ScaledFont& sf) const {
72-
return fml::HashCombine(sf.font.GetHash(), sf.scale);
73-
}
74-
};
75-
76-
template <>
77-
struct std::equal_to<impeller::ScaledFont> {
78-
constexpr bool operator()(const impeller::ScaledFont& lhs,
79-
const impeller::ScaledFont& rhs) const {
80-
return lhs.font.IsEqual(rhs.font) && lhs.scale == rhs.scale;
81-
}
82-
};
83-
84-
template <>
85-
struct std::hash<impeller::SubpixelGlyph> {
86-
constexpr std::size_t operator()(const impeller::SubpixelGlyph& sg) const {
87-
return fml::HashCombine(
88-
sg.glyph.index, sg.subpixel_offset.x, sg.subpixel_offset.y,
89-
sg.properties.color.ToARGB(), sg.properties.stroke,
90-
sg.properties.stroke_cap, sg.properties.stroke_join,
91-
sg.properties.stroke_miter, sg.properties.stroke_width);
92-
}
93-
};
94-
95-
template <>
96-
struct std::equal_to<impeller::SubpixelGlyph> {
97-
constexpr bool operator()(const impeller::SubpixelGlyph& lhs,
98-
const impeller::SubpixelGlyph& rhs) const {
99-
return lhs.glyph.index == rhs.glyph.index &&
100-
lhs.glyph.type == rhs.glyph.type &&
101-
lhs.subpixel_offset == rhs.subpixel_offset &&
102-
lhs.properties.color.ToARGB() == rhs.properties.color.ToARGB() &&
103-
lhs.properties.stroke == rhs.properties.stroke &&
104-
lhs.properties.stroke_cap == rhs.properties.stroke_cap &&
105-
lhs.properties.stroke_join == rhs.properties.stroke_join &&
106-
lhs.properties.stroke_miter == rhs.properties.stroke_miter &&
107-
lhs.properties.stroke_width == rhs.properties.stroke_width;
108-
}
109-
};
110-
111123
#endif // FLUTTER_IMPELLER_TYPOGRAPHER_FONT_GLYPH_PAIR_H_

impeller/typographer/glyph_atlas.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,11 @@ class GlyphAtlas {
136136
const Type type_;
137137
std::shared_ptr<Texture> texture_;
138138

139-
std::unordered_map<ScaledFont, FontGlyphAtlas> font_atlas_map_;
139+
std::unordered_map<ScaledFont,
140+
FontGlyphAtlas,
141+
ScaledFont::Hash,
142+
ScaledFont::Equal>
143+
font_atlas_map_;
140144

141145
GlyphAtlas(const GlyphAtlas&) = delete;
142146

@@ -214,7 +218,11 @@ class FontGlyphAtlas {
214218

215219
private:
216220
friend class GlyphAtlas;
217-
std::unordered_map<SubpixelGlyph, std::pair<Rect, Rect>> positions_;
221+
std::unordered_map<SubpixelGlyph,
222+
std::pair<Rect, Rect>,
223+
SubpixelGlyph::Hash,
224+
SubpixelGlyph::Equal>
225+
positions_;
218226

219227
FontGlyphAtlas(const FontGlyphAtlas&) = delete;
220228

impeller/typographer/text_frame.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ void TextFrame::CollectUniqueFontGlyphPairs(
8989
Scalar scale,
9090
Point offset,
9191
const GlyphProperties& properties) const {
92+
std::optional<GlyphProperties> lookup =
93+
(properties.stroke || HasColor())
94+
? std::optional<GlyphProperties>(properties)
95+
: std::nullopt;
9296
for (const TextRun& run : GetRuns()) {
9397
const Font& font = run.GetFont();
9498
auto rounded_scale =
@@ -98,7 +102,7 @@ void TextFrame::CollectUniqueFontGlyphPairs(
98102
run.GetGlyphPositions()) {
99103
Point subpixel = ComputeSubpixelPosition(
100104
glyph_position, font.GetAxisAlignment(), offset, scale);
101-
set.emplace(glyph_position.glyph, subpixel, properties);
105+
set.emplace(glyph_position.glyph, subpixel, lookup);
102106
}
103107
}
104108
}

impeller/typographer/text_run.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
#include <vector>
99

10-
#include "impeller/geometry/matrix.h"
10+
#include "impeller/geometry/point.h"
1111
#include "impeller/typographer/font.h"
1212
#include "impeller/typographer/glyph.h"
1313

0 commit comments

Comments
 (0)