[Font] Use key structure instead of raw hash for LRU cache to avoid collisions.
This commit is contained in:
parent
f7cf9fb148
commit
9b53bd90bb
|
@ -270,24 +270,18 @@ void Font::set_cache_capacity(int p_single_line, int p_multi_line) {
|
|||
}
|
||||
|
||||
Size2 Font::get_string_size(const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
|
||||
uint64_t hash = p_text.hash64();
|
||||
hash = hash_djb2_one_64(p_font_size, hash);
|
||||
if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
|
||||
hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash);
|
||||
hash = hash_djb2_one_64(p_jst_flags.operator int64_t(), hash);
|
||||
}
|
||||
hash = hash_djb2_one_64(p_direction, hash);
|
||||
hash = hash_djb2_one_64(p_orientation, hash);
|
||||
bool fill = (p_alignment == HORIZONTAL_ALIGNMENT_FILL);
|
||||
ShapedTextKey key = ShapedTextKey(p_text, p_font_size, fill ? p_width : 0.0, fill ? p_jst_flags : TextServer::JUSTIFICATION_NONE, TextServer::BREAK_NONE, p_direction, p_orientation);
|
||||
|
||||
Ref<TextLine> buffer;
|
||||
if (cache.has(hash)) {
|
||||
buffer = cache.get(hash);
|
||||
if (cache.has(key)) {
|
||||
buffer = cache.get(key);
|
||||
} else {
|
||||
buffer.instantiate();
|
||||
buffer->set_direction(p_direction);
|
||||
buffer->set_orientation(p_orientation);
|
||||
buffer->add_string(p_text, Ref<Font>(this), p_font_size);
|
||||
cache.insert(hash, buffer);
|
||||
cache.insert(key, buffer);
|
||||
}
|
||||
|
||||
buffer->set_width(p_width);
|
||||
|
@ -300,17 +294,11 @@ Size2 Font::get_string_size(const String &p_text, HorizontalAlignment p_alignmen
|
|||
}
|
||||
|
||||
Size2 Font::get_multiline_string_size(const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
|
||||
uint64_t hash = p_text.hash64();
|
||||
hash = hash_djb2_one_64(p_font_size, hash);
|
||||
hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash);
|
||||
hash = hash_djb2_one_64(p_brk_flags.operator int64_t(), hash);
|
||||
hash = hash_djb2_one_64(p_jst_flags.operator int64_t(), hash);
|
||||
hash = hash_djb2_one_64(p_direction, hash);
|
||||
hash = hash_djb2_one_64(p_orientation, hash);
|
||||
ShapedTextKey key = ShapedTextKey(p_text, p_font_size, p_width, p_jst_flags, p_brk_flags, p_direction, p_orientation);
|
||||
|
||||
Ref<TextParagraph> lines_buffer;
|
||||
if (cache_wrap.has(hash)) {
|
||||
lines_buffer = cache_wrap.get(hash);
|
||||
if (cache_wrap.has(key)) {
|
||||
lines_buffer = cache_wrap.get(key);
|
||||
} else {
|
||||
lines_buffer.instantiate();
|
||||
lines_buffer->set_direction(p_direction);
|
||||
|
@ -319,7 +307,7 @@ Size2 Font::get_multiline_string_size(const String &p_text, HorizontalAlignment
|
|||
lines_buffer->set_width(p_width);
|
||||
lines_buffer->set_break_flags(p_brk_flags);
|
||||
lines_buffer->set_justification_flags(p_jst_flags);
|
||||
cache_wrap.insert(hash, lines_buffer);
|
||||
cache_wrap.insert(key, lines_buffer);
|
||||
}
|
||||
|
||||
lines_buffer->set_alignment(p_alignment);
|
||||
|
@ -329,24 +317,18 @@ Size2 Font::get_multiline_string_size(const String &p_text, HorizontalAlignment
|
|||
}
|
||||
|
||||
void Font::draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, const Color &p_modulate, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
|
||||
uint64_t hash = p_text.hash64();
|
||||
hash = hash_djb2_one_64(p_font_size, hash);
|
||||
if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
|
||||
hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash);
|
||||
hash = hash_djb2_one_64(p_jst_flags.operator int64_t(), hash);
|
||||
}
|
||||
hash = hash_djb2_one_64(p_direction, hash);
|
||||
hash = hash_djb2_one_64(p_orientation, hash);
|
||||
bool fill = (p_alignment == HORIZONTAL_ALIGNMENT_FILL);
|
||||
ShapedTextKey key = ShapedTextKey(p_text, p_font_size, fill ? p_width : 0.0, fill ? p_jst_flags : TextServer::JUSTIFICATION_NONE, TextServer::BREAK_NONE, p_direction, p_orientation);
|
||||
|
||||
Ref<TextLine> buffer;
|
||||
if (cache.has(hash)) {
|
||||
buffer = cache.get(hash);
|
||||
if (cache.has(key)) {
|
||||
buffer = cache.get(key);
|
||||
} else {
|
||||
buffer.instantiate();
|
||||
buffer->set_direction(p_direction);
|
||||
buffer->set_orientation(p_orientation);
|
||||
buffer->add_string(p_text, Ref<Font>(this), p_font_size);
|
||||
cache.insert(hash, buffer);
|
||||
cache.insert(key, buffer);
|
||||
}
|
||||
|
||||
Vector2 ofs = p_pos;
|
||||
|
@ -366,17 +348,11 @@ void Font::draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_t
|
|||
}
|
||||
|
||||
void Font::draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, const Color &p_modulate, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
|
||||
uint64_t hash = p_text.hash64();
|
||||
hash = hash_djb2_one_64(p_font_size, hash);
|
||||
hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash);
|
||||
hash = hash_djb2_one_64(p_brk_flags.operator int64_t(), hash);
|
||||
hash = hash_djb2_one_64(p_jst_flags.operator int64_t(), hash);
|
||||
hash = hash_djb2_one_64(p_direction, hash);
|
||||
hash = hash_djb2_one_64(p_orientation, hash);
|
||||
ShapedTextKey key = ShapedTextKey(p_text, p_font_size, p_width, p_jst_flags, p_brk_flags, p_direction, p_orientation);
|
||||
|
||||
Ref<TextParagraph> lines_buffer;
|
||||
if (cache_wrap.has(hash)) {
|
||||
lines_buffer = cache_wrap.get(hash);
|
||||
if (cache_wrap.has(key)) {
|
||||
lines_buffer = cache_wrap.get(key);
|
||||
} else {
|
||||
lines_buffer.instantiate();
|
||||
lines_buffer->set_direction(p_direction);
|
||||
|
@ -385,7 +361,7 @@ void Font::draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const S
|
|||
lines_buffer->set_width(p_width);
|
||||
lines_buffer->set_break_flags(p_brk_flags);
|
||||
lines_buffer->set_justification_flags(p_jst_flags);
|
||||
cache_wrap.insert(hash, lines_buffer);
|
||||
cache_wrap.insert(key, lines_buffer);
|
||||
}
|
||||
|
||||
Vector2 ofs = p_pos;
|
||||
|
@ -402,24 +378,18 @@ void Font::draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const S
|
|||
}
|
||||
|
||||
void Font::draw_string_outline(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_size, const Color &p_modulate, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
|
||||
uint64_t hash = p_text.hash64();
|
||||
hash = hash_djb2_one_64(p_font_size, hash);
|
||||
if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
|
||||
hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash);
|
||||
hash = hash_djb2_one_64(p_jst_flags.operator int64_t(), hash);
|
||||
}
|
||||
hash = hash_djb2_one_64(p_direction, hash);
|
||||
hash = hash_djb2_one_64(p_orientation, hash);
|
||||
bool fill = (p_alignment == HORIZONTAL_ALIGNMENT_FILL);
|
||||
ShapedTextKey key = ShapedTextKey(p_text, p_font_size, fill ? p_width : 0.0, fill ? p_jst_flags : TextServer::JUSTIFICATION_NONE, TextServer::BREAK_NONE, p_direction, p_orientation);
|
||||
|
||||
Ref<TextLine> buffer;
|
||||
if (cache.has(hash)) {
|
||||
buffer = cache.get(hash);
|
||||
if (cache.has(key)) {
|
||||
buffer = cache.get(key);
|
||||
} else {
|
||||
buffer.instantiate();
|
||||
buffer->set_direction(p_direction);
|
||||
buffer->set_orientation(p_orientation);
|
||||
buffer->add_string(p_text, Ref<Font>(this), p_font_size);
|
||||
cache.insert(hash, buffer);
|
||||
cache.insert(key, buffer);
|
||||
}
|
||||
|
||||
Vector2 ofs = p_pos;
|
||||
|
@ -439,17 +409,11 @@ void Font::draw_string_outline(RID p_canvas_item, const Point2 &p_pos, const Str
|
|||
}
|
||||
|
||||
void Font::draw_multiline_string_outline(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, int p_size, const Color &p_modulate, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
|
||||
uint64_t hash = p_text.hash64();
|
||||
hash = hash_djb2_one_64(p_font_size, hash);
|
||||
hash = hash_djb2_one_64(hash_murmur3_one_float(p_width), hash);
|
||||
hash = hash_djb2_one_64(p_brk_flags.operator int64_t(), hash);
|
||||
hash = hash_djb2_one_64(p_jst_flags.operator int64_t(), hash);
|
||||
hash = hash_djb2_one_64(p_direction, hash);
|
||||
hash = hash_djb2_one_64(p_orientation, hash);
|
||||
ShapedTextKey key = ShapedTextKey(p_text, p_font_size, p_width, p_jst_flags, p_brk_flags, p_direction, p_orientation);
|
||||
|
||||
Ref<TextParagraph> lines_buffer;
|
||||
if (cache_wrap.has(hash)) {
|
||||
lines_buffer = cache_wrap.get(hash);
|
||||
if (cache_wrap.has(key)) {
|
||||
lines_buffer = cache_wrap.get(key);
|
||||
} else {
|
||||
lines_buffer.instantiate();
|
||||
lines_buffer->set_direction(p_direction);
|
||||
|
@ -458,7 +422,7 @@ void Font::draw_multiline_string_outline(RID p_canvas_item, const Point2 &p_pos,
|
|||
lines_buffer->set_width(p_width);
|
||||
lines_buffer->set_break_flags(p_brk_flags);
|
||||
lines_buffer->set_justification_flags(p_jst_flags);
|
||||
cache_wrap.insert(hash, lines_buffer);
|
||||
cache_wrap.insert(key, lines_buffer);
|
||||
}
|
||||
|
||||
Vector2 ofs = p_pos;
|
||||
|
|
|
@ -47,9 +47,44 @@ class TextParagraph;
|
|||
class Font : public Resource {
|
||||
GDCLASS(Font, Resource);
|
||||
|
||||
struct ShapedTextKey {
|
||||
String text;
|
||||
int font_size = 14;
|
||||
float width = 0.f;
|
||||
BitField<TextServer::JustificationFlag> jst_flags = TextServer::JUSTIFICATION_NONE;
|
||||
BitField<TextServer::LineBreakFlag> brk_flags = TextServer::BREAK_MANDATORY;
|
||||
TextServer::Direction direction = TextServer::DIRECTION_AUTO;
|
||||
TextServer::Orientation orientation = TextServer::ORIENTATION_HORIZONTAL;
|
||||
|
||||
bool operator==(const ShapedTextKey &p_b) const {
|
||||
return (font_size == p_b.font_size) && (width == p_b.width) && (jst_flags == p_b.jst_flags) && (brk_flags == p_b.brk_flags) && (direction == p_b.direction) && (orientation == p_b.orientation) && (text == p_b.text);
|
||||
}
|
||||
|
||||
ShapedTextKey() {}
|
||||
ShapedTextKey(const String &p_text, int p_font_size, float p_width, BitField<TextServer::JustificationFlag> p_jst_flags, BitField<TextServer::LineBreakFlag> p_brk_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
|
||||
text = p_text;
|
||||
font_size = p_font_size;
|
||||
width = p_width;
|
||||
jst_flags = p_jst_flags;
|
||||
brk_flags = p_brk_flags;
|
||||
direction = p_direction;
|
||||
orientation = p_orientation;
|
||||
}
|
||||
};
|
||||
|
||||
struct ShapedTextKeyHasher {
|
||||
_FORCE_INLINE_ static uint32_t hash(const ShapedTextKey &p_a) {
|
||||
uint32_t hash = p_a.text.hash();
|
||||
hash = hash_murmur3_one_32(p_a.font_size, hash);
|
||||
hash = hash_murmur3_one_float(p_a.width, hash);
|
||||
hash = hash_murmur3_one_32(p_a.brk_flags | (p_a.jst_flags << 6) | (p_a.direction << 12) | (p_a.orientation << 15), hash);
|
||||
return hash_fmix32(hash);
|
||||
}
|
||||
};
|
||||
|
||||
// Shaped string cache.
|
||||
mutable LRUCache<uint64_t, Ref<TextLine>> cache;
|
||||
mutable LRUCache<uint64_t, Ref<TextParagraph>> cache_wrap;
|
||||
mutable LRUCache<ShapedTextKey, Ref<TextLine>, ShapedTextKeyHasher> cache;
|
||||
mutable LRUCache<ShapedTextKey, Ref<TextParagraph>, ShapedTextKeyHasher> cache_wrap;
|
||||
|
||||
protected:
|
||||
// Output.
|
||||
|
|
Loading…
Reference in New Issue