[Impeller] hash less text stuff per frame for text rendering. (flutter/engine#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
This commit is contained in:
parent
dd277de7d9
commit
a2faed00c7
@ -222,8 +222,11 @@ bool TextContents::Render(const ContentContext& renderer,
|
|||||||
Point subpixel = TextFrame::ComputeSubpixelPosition(
|
Point subpixel = TextFrame::ComputeSubpixelPosition(
|
||||||
glyph_position, font.GetAxisAlignment(), offset_, scale_);
|
glyph_position, font.GetAxisAlignment(), offset_, scale_);
|
||||||
std::optional<std::pair<Rect, Rect>> maybe_atlas_glyph_bounds =
|
std::optional<std::pair<Rect, Rect>> maybe_atlas_glyph_bounds =
|
||||||
font_atlas->FindGlyphBounds(
|
font_atlas->FindGlyphBounds(SubpixelGlyph{
|
||||||
SubpixelGlyph{glyph_position.glyph, subpixel, properties_});
|
glyph_position.glyph, subpixel,
|
||||||
|
(properties_.stroke || frame_->HasColor())
|
||||||
|
? std::optional<GlyphProperties>(properties_)
|
||||||
|
: std::nullopt});
|
||||||
if (!maybe_atlas_glyph_bounds.has_value()) {
|
if (!maybe_atlas_glyph_bounds.has_value()) {
|
||||||
VALIDATION_LOG << "Could not find glyph position in the atlas.";
|
VALIDATION_LOG << "Could not find glyph position in the atlas.";
|
||||||
continue;
|
continue;
|
||||||
|
@ -208,7 +208,7 @@ static void DrawGlyph(SkCanvas* canvas,
|
|||||||
const ScaledFont& scaled_font,
|
const ScaledFont& scaled_font,
|
||||||
const SubpixelGlyph& glyph,
|
const SubpixelGlyph& glyph,
|
||||||
const Rect& scaled_bounds,
|
const Rect& scaled_bounds,
|
||||||
const GlyphProperties& prop,
|
const std::optional<GlyphProperties>& prop,
|
||||||
bool has_color) {
|
bool has_color) {
|
||||||
const auto& metrics = scaled_font.font.GetMetrics();
|
const auto& metrics = scaled_font.font.GetMetrics();
|
||||||
SkGlyphID glyph_id = glyph.glyph.index;
|
SkGlyphID glyph_id = glyph.glyph.index;
|
||||||
@ -222,18 +222,17 @@ static void DrawGlyph(SkCanvas* canvas,
|
|||||||
sk_font.setSubpixel(true);
|
sk_font.setSubpixel(true);
|
||||||
sk_font.setSize(sk_font.getSize() * scaled_font.scale);
|
sk_font.setSize(sk_font.getSize() * scaled_font.scale);
|
||||||
|
|
||||||
auto glyph_color =
|
auto glyph_color = prop.has_value() ? prop->color.ToARGB() : SK_ColorBLACK;
|
||||||
has_color ? glyph.properties.color.ToARGB() : SK_ColorBLACK;
|
|
||||||
|
|
||||||
SkPaint glyph_paint;
|
SkPaint glyph_paint;
|
||||||
glyph_paint.setColor(glyph_color);
|
glyph_paint.setColor(glyph_color);
|
||||||
glyph_paint.setBlendMode(SkBlendMode::kSrc);
|
glyph_paint.setBlendMode(SkBlendMode::kSrc);
|
||||||
if (prop.stroke) {
|
if (prop.has_value() && prop->stroke) {
|
||||||
glyph_paint.setStroke(true);
|
glyph_paint.setStroke(true);
|
||||||
glyph_paint.setStrokeWidth(prop.stroke_width * scaled_font.scale);
|
glyph_paint.setStrokeWidth(prop->stroke_width * scaled_font.scale);
|
||||||
glyph_paint.setStrokeCap(ToSkiaCap(glyph.properties.stroke_cap));
|
glyph_paint.setStrokeCap(ToSkiaCap(prop->stroke_cap));
|
||||||
glyph_paint.setStrokeJoin(ToSkiaJoin(glyph.properties.stroke_join));
|
glyph_paint.setStrokeJoin(ToSkiaJoin(prop->stroke_join));
|
||||||
glyph_paint.setStrokeMiter(prop.stroke_miter * scaled_font.scale);
|
glyph_paint.setStrokeMiter(prop->stroke_miter * scaled_font.scale);
|
||||||
}
|
}
|
||||||
canvas->save();
|
canvas->save();
|
||||||
canvas->translate(glyph.subpixel_offset.x, glyph.subpixel_offset.y);
|
canvas->translate(glyph.subpixel_offset.x, glyph.subpixel_offset.y);
|
||||||
@ -384,12 +383,12 @@ static Rect ComputeGlyphSize(const SkFont& font,
|
|||||||
Scalar scale) {
|
Scalar scale) {
|
||||||
SkRect scaled_bounds;
|
SkRect scaled_bounds;
|
||||||
SkPaint glyph_paint;
|
SkPaint glyph_paint;
|
||||||
if (glyph.properties.stroke) {
|
if (glyph.properties.has_value() && glyph.properties->stroke) {
|
||||||
glyph_paint.setStroke(true);
|
glyph_paint.setStroke(true);
|
||||||
glyph_paint.setStrokeWidth(glyph.properties.stroke_width * scale);
|
glyph_paint.setStrokeWidth(glyph.properties->stroke_width * scale);
|
||||||
glyph_paint.setStrokeCap(ToSkiaCap(glyph.properties.stroke_cap));
|
glyph_paint.setStrokeCap(ToSkiaCap(glyph.properties->stroke_cap));
|
||||||
glyph_paint.setStrokeJoin(ToSkiaJoin(glyph.properties.stroke_join));
|
glyph_paint.setStrokeJoin(ToSkiaJoin(glyph.properties->stroke_join));
|
||||||
glyph_paint.setStrokeMiter(glyph.properties.stroke_miter * scale);
|
glyph_paint.setStrokeMiter(glyph.properties->stroke_miter * scale);
|
||||||
}
|
}
|
||||||
font.getBounds(&glyph.glyph.index, 1, &scaled_bounds, &glyph_paint);
|
font.getBounds(&glyph.glyph.index, 1, &scaled_bounds, &glyph_paint);
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
|
#include "fml/hash_combine.h"
|
||||||
#include "impeller/geometry/color.h"
|
#include "impeller/geometry/color.h"
|
||||||
#include "impeller/geometry/path.h"
|
#include "impeller/geometry/path.h"
|
||||||
#include "impeller/geometry/point.h"
|
#include "impeller/geometry/point.h"
|
||||||
@ -32,6 +33,19 @@ struct GlyphProperties {
|
|||||||
struct ScaledFont {
|
struct ScaledFont {
|
||||||
Font font;
|
Font font;
|
||||||
Scalar scale;
|
Scalar scale;
|
||||||
|
|
||||||
|
struct Hash {
|
||||||
|
constexpr std::size_t operator()(const impeller::ScaledFont& sf) const {
|
||||||
|
return fml::HashCombine(sf.font.GetHash(), sf.scale);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Equal {
|
||||||
|
constexpr bool operator()(const impeller::ScaledFont& lhs,
|
||||||
|
const impeller::ScaledFont& rhs) const {
|
||||||
|
return lhs.font.IsEqual(rhs.font) && lhs.scale == rhs.scale;
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@ -40,18 +54,58 @@ struct ScaledFont {
|
|||||||
struct SubpixelGlyph {
|
struct SubpixelGlyph {
|
||||||
Glyph glyph;
|
Glyph glyph;
|
||||||
Point subpixel_offset;
|
Point subpixel_offset;
|
||||||
GlyphProperties properties;
|
std::optional<GlyphProperties> properties;
|
||||||
|
|
||||||
SubpixelGlyph(Glyph p_glyph,
|
SubpixelGlyph(Glyph p_glyph,
|
||||||
Point p_subpixel_offset,
|
Point p_subpixel_offset,
|
||||||
GlyphProperties p_properties)
|
std::optional<GlyphProperties> p_properties)
|
||||||
: glyph(p_glyph),
|
: glyph(p_glyph),
|
||||||
subpixel_offset(p_subpixel_offset),
|
subpixel_offset(p_subpixel_offset),
|
||||||
properties(p_properties) {}
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Equal {
|
||||||
|
constexpr bool operator()(const impeller::SubpixelGlyph& lhs,
|
||||||
|
const impeller::SubpixelGlyph& rhs) const {
|
||||||
|
if (!lhs.properties.has_value() && !rhs.properties.has_value()) {
|
||||||
|
return lhs.glyph.index == rhs.glyph.index &&
|
||||||
|
lhs.glyph.type == rhs.glyph.type &&
|
||||||
|
lhs.subpixel_offset == rhs.subpixel_offset;
|
||||||
|
}
|
||||||
|
return lhs.glyph.index == rhs.glyph.index &&
|
||||||
|
lhs.glyph.type == rhs.glyph.type &&
|
||||||
|
lhs.subpixel_offset == rhs.subpixel_offset &&
|
||||||
|
lhs.properties.has_value() && rhs.properties.has_value() &&
|
||||||
|
lhs.properties->color.ToARGB() == rhs.properties->color.ToARGB() &&
|
||||||
|
lhs.properties->stroke == rhs.properties->stroke &&
|
||||||
|
lhs.properties->stroke_cap == rhs.properties->stroke_cap &&
|
||||||
|
lhs.properties->stroke_join == rhs.properties->stroke_join &&
|
||||||
|
lhs.properties->stroke_miter == rhs.properties->stroke_miter &&
|
||||||
|
lhs.properties->stroke_width == rhs.properties->stroke_width;
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
using FontGlyphMap =
|
using FontGlyphMap =
|
||||||
std::unordered_map<ScaledFont, std::unordered_set<SubpixelGlyph>>;
|
std::unordered_map<ScaledFont,
|
||||||
|
std::unordered_set<SubpixelGlyph,
|
||||||
|
SubpixelGlyph::Hash,
|
||||||
|
SubpixelGlyph::Equal>,
|
||||||
|
ScaledFont::Hash,
|
||||||
|
ScaledFont::Equal>;
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
/// @brief A font along with a glyph in that font rendered at a particular
|
/// @brief A font along with a glyph in that font rendered at a particular
|
||||||
@ -66,46 +120,4 @@ struct FontGlyphPair {
|
|||||||
|
|
||||||
} // namespace impeller
|
} // namespace impeller
|
||||||
|
|
||||||
template <>
|
|
||||||
struct std::hash<impeller::ScaledFont> {
|
|
||||||
constexpr std::size_t operator()(const impeller::ScaledFont& sf) const {
|
|
||||||
return fml::HashCombine(sf.font.GetHash(), sf.scale);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct std::equal_to<impeller::ScaledFont> {
|
|
||||||
constexpr bool operator()(const impeller::ScaledFont& lhs,
|
|
||||||
const impeller::ScaledFont& rhs) const {
|
|
||||||
return lhs.font.IsEqual(rhs.font) && lhs.scale == rhs.scale;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct std::hash<impeller::SubpixelGlyph> {
|
|
||||||
constexpr std::size_t operator()(const impeller::SubpixelGlyph& sg) const {
|
|
||||||
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 <>
|
|
||||||
struct std::equal_to<impeller::SubpixelGlyph> {
|
|
||||||
constexpr bool operator()(const impeller::SubpixelGlyph& lhs,
|
|
||||||
const impeller::SubpixelGlyph& rhs) const {
|
|
||||||
return lhs.glyph.index == rhs.glyph.index &&
|
|
||||||
lhs.glyph.type == rhs.glyph.type &&
|
|
||||||
lhs.subpixel_offset == rhs.subpixel_offset &&
|
|
||||||
lhs.properties.color.ToARGB() == rhs.properties.color.ToARGB() &&
|
|
||||||
lhs.properties.stroke == rhs.properties.stroke &&
|
|
||||||
lhs.properties.stroke_cap == rhs.properties.stroke_cap &&
|
|
||||||
lhs.properties.stroke_join == rhs.properties.stroke_join &&
|
|
||||||
lhs.properties.stroke_miter == rhs.properties.stroke_miter &&
|
|
||||||
lhs.properties.stroke_width == rhs.properties.stroke_width;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // FLUTTER_IMPELLER_TYPOGRAPHER_FONT_GLYPH_PAIR_H_
|
#endif // FLUTTER_IMPELLER_TYPOGRAPHER_FONT_GLYPH_PAIR_H_
|
||||||
|
@ -136,7 +136,11 @@ class GlyphAtlas {
|
|||||||
const Type type_;
|
const Type type_;
|
||||||
std::shared_ptr<Texture> texture_;
|
std::shared_ptr<Texture> texture_;
|
||||||
|
|
||||||
std::unordered_map<ScaledFont, FontGlyphAtlas> font_atlas_map_;
|
std::unordered_map<ScaledFont,
|
||||||
|
FontGlyphAtlas,
|
||||||
|
ScaledFont::Hash,
|
||||||
|
ScaledFont::Equal>
|
||||||
|
font_atlas_map_;
|
||||||
|
|
||||||
GlyphAtlas(const GlyphAtlas&) = delete;
|
GlyphAtlas(const GlyphAtlas&) = delete;
|
||||||
|
|
||||||
@ -214,7 +218,11 @@ class FontGlyphAtlas {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
friend class GlyphAtlas;
|
friend class GlyphAtlas;
|
||||||
std::unordered_map<SubpixelGlyph, std::pair<Rect, Rect>> positions_;
|
std::unordered_map<SubpixelGlyph,
|
||||||
|
std::pair<Rect, Rect>,
|
||||||
|
SubpixelGlyph::Hash,
|
||||||
|
SubpixelGlyph::Equal>
|
||||||
|
positions_;
|
||||||
|
|
||||||
FontGlyphAtlas(const FontGlyphAtlas&) = delete;
|
FontGlyphAtlas(const FontGlyphAtlas&) = delete;
|
||||||
|
|
||||||
|
@ -89,6 +89,10 @@ void TextFrame::CollectUniqueFontGlyphPairs(
|
|||||||
Scalar scale,
|
Scalar scale,
|
||||||
Point offset,
|
Point offset,
|
||||||
const GlyphProperties& properties) const {
|
const GlyphProperties& properties) const {
|
||||||
|
std::optional<GlyphProperties> lookup =
|
||||||
|
(properties.stroke || HasColor())
|
||||||
|
? std::optional<GlyphProperties>(properties)
|
||||||
|
: std::nullopt;
|
||||||
for (const TextRun& run : GetRuns()) {
|
for (const TextRun& run : GetRuns()) {
|
||||||
const Font& font = run.GetFont();
|
const Font& font = run.GetFont();
|
||||||
auto rounded_scale =
|
auto rounded_scale =
|
||||||
@ -98,7 +102,7 @@ void TextFrame::CollectUniqueFontGlyphPairs(
|
|||||||
run.GetGlyphPositions()) {
|
run.GetGlyphPositions()) {
|
||||||
Point subpixel = ComputeSubpixelPosition(
|
Point subpixel = ComputeSubpixelPosition(
|
||||||
glyph_position, font.GetAxisAlignment(), offset, scale);
|
glyph_position, font.GetAxisAlignment(), offset, scale);
|
||||||
set.emplace(glyph_position.glyph, subpixel, properties);
|
set.emplace(glyph_position.glyph, subpixel, lookup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "impeller/geometry/matrix.h"
|
#include "impeller/geometry/point.h"
|
||||||
#include "impeller/typographer/font.h"
|
#include "impeller/typographer/font.h"
|
||||||
#include "impeller/typographer/glyph.h"
|
#include "impeller/typographer/glyph.h"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user