Use custom key structs, instead of raw hashes for the Label3D and TextMesh, to avoid potential hash collisions.

This commit is contained in:
bruvzg 2022-06-18 16:14:08 +03:00
parent 5b3b06187b
commit 329923c6ac
No known key found for this signature in database
GPG Key ID: 7960FCF39844EC38
5 changed files with 65 additions and 31 deletions

View File

@ -35,7 +35,7 @@
#include "hash_map.h"
#include "list.h"
template <class TKey, class TData>
template <class TKey, class TData, class Hasher = HashMapHasherDefault, class Comparator = HashMapComparatorDefault<TKey>>
class LRUCache {
private:
struct Pair {
@ -52,7 +52,7 @@ private:
typedef typename List<Pair>::Element *Element;
List<Pair> _list;
HashMap<TKey, Element> _map;
HashMap<TKey, Element, Hasher, Comparator> _map;
size_t capacity;
public:

View File

@ -370,15 +370,8 @@ void Label3D::_generate_glyph_surfaces(const Glyph &p_glyph, Vector2 &r_offset,
bool msdf = TS->font_is_multichannel_signed_distance_field(p_glyph.font_rid);
uint64_t mat_hash;
if (tex != RID()) {
mat_hash = hash_one_uint64(tex.get_id());
} else {
mat_hash = hash_one_uint64(0);
}
mat_hash = hash_fmix32(hash_murmur3_one_64(p_priority | (p_outline_size << 31), mat_hash));
if (!surfaces.has(mat_hash)) {
SurfaceKey key = SurfaceKey(tex.get_id(), p_priority, p_outline_size);
if (!surfaces.has(key)) {
SurfaceData surf;
surf.material = RenderingServer::get_singleton()->material_create();
// Set defaults for material, names need to match up those in StandardMaterial3D
@ -407,9 +400,9 @@ void Label3D::_generate_glyph_surfaces(const Glyph &p_glyph, Vector2 &r_offset,
surf.z_shift = p_priority * pixel_size;
}
surfaces[mat_hash] = surf;
surfaces[key] = surf;
}
SurfaceData &s = surfaces[mat_hash];
SurfaceData &s = surfaces[key];
s.mesh_vertices.resize((s.offset + 1) * 4);
s.mesh_normals.resize((s.offset + 1) * 4);
@ -464,7 +457,7 @@ void Label3D::_shape() {
aabb = AABB();
// Clear materials.
for (const KeyValue<uint64_t, SurfaceData> &E : surfaces) {
for (const KeyValue<SurfaceKey, SurfaceData> &E : surfaces) {
RenderingServer::get_singleton()->free(E.value.material);
}
surfaces.clear();
@ -594,7 +587,7 @@ void Label3D::_shape() {
offset.y -= (TS->shaped_text_get_descent(lines_rid[i]) + line_spacing + font->get_spacing(TextServer::SPACING_BOTTOM)) * pixel_size;
}
for (const KeyValue<uint64_t, SurfaceData> &E : surfaces) {
for (const KeyValue<SurfaceKey, SurfaceData> &E : surfaces) {
Array mesh_array;
mesh_array.resize(RS::ARRAY_MAX);
mesh_array[RS::ARRAY_VERTEX] = E.value.mesh_vertices;
@ -1018,7 +1011,7 @@ Label3D::~Label3D() {
TS->free_rid(text_rid);
RenderingServer::get_singleton()->free(mesh);
for (KeyValue<uint64_t, SurfaceData> E : surfaces) {
for (KeyValue<SurfaceKey, SurfaceData> E : surfaces) {
RenderingServer::get_singleton()->free(E.value.material);
}
surfaces.clear();

View File

@ -76,7 +76,29 @@ private:
RID material;
};
HashMap<uint64_t, SurfaceData> surfaces;
struct SurfaceKey {
uint64_t texture_id;
int32_t priority;
int32_t outline_size;
bool operator==(const SurfaceKey &p_b) const {
return (texture_id == p_b.texture_id) && (priority == p_b.priority) && (outline_size == p_b.outline_size);
}
SurfaceKey(uint64_t p_texture_id, int p_priority, int p_outline_size) {
texture_id = p_texture_id;
priority = p_priority;
outline_size = p_outline_size;
}
};
struct SurfaceKeyHasher {
_FORCE_INLINE_ static uint32_t hash(const SurfaceKey &p_a) {
return hash_murmur3_buffer(&p_a, sizeof(SurfaceKey));
}
};
HashMap<SurfaceKey, SurfaceData, SurfaceKeyHasher> surfaces;
HorizontalAlignment horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER;
VerticalAlignment vertical_alignment = VERTICAL_ALIGNMENT_CENTER;

View File

@ -2190,12 +2190,12 @@ RibbonTrailMesh::RibbonTrailMesh() {
/* TextMesh */
/*************************************************************************/
void TextMesh::_generate_glyph_mesh_data(uint32_t p_hash, const Glyph &p_gl) const {
if (cache.has(p_hash)) {
void TextMesh::_generate_glyph_mesh_data(const GlyphMeshKey &p_key, const Glyph &p_gl) const {
if (cache.has(p_key)) {
return;
}
GlyphMeshData &gl_data = cache[p_hash];
GlyphMeshData &gl_data = cache[p_key];
Dictionary d = TS->font_get_glyph_contours(p_gl.font_rid, p_gl.font_size, p_gl.index);
Vector2 origin = Vector2(p_gl.x_off, p_gl.y_off) * pixel_size;
@ -2437,11 +2437,9 @@ void TextMesh::_create_mesh_array(Array &p_arr) const {
continue;
}
if (glyphs[i].font_rid != RID()) {
uint32_t hash = hash_one_uint64(glyphs[i].font_rid.get_id());
hash = hash_murmur3_one_32(glyphs[i].index, hash);
_generate_glyph_mesh_data(hash, glyphs[i]);
GlyphMeshData &gl_data = cache[hash];
GlyphMeshKey key = GlyphMeshKey(glyphs[i].font_rid.get_id(), glyphs[i].index);
_generate_glyph_mesh_data(key, glyphs[i]);
GlyphMeshData &gl_data = cache[key];
p_size += glyphs[i].repeat * gl_data.triangles.size() * ((has_depth) ? 2 : 1);
i_size += glyphs[i].repeat * gl_data.triangles.size() * ((has_depth) ? 2 : 1);
@ -2496,10 +2494,9 @@ void TextMesh::_create_mesh_array(Array &p_arr) const {
continue;
}
if (glyphs[i].font_rid != RID()) {
uint32_t hash = hash_one_uint64(glyphs[i].font_rid.get_id());
hash = hash_murmur3_one_32(glyphs[i].index, hash);
const GlyphMeshData &gl_data = cache[hash];
GlyphMeshKey key = GlyphMeshKey(glyphs[i].font_rid.get_id(), glyphs[i].index);
_generate_glyph_mesh_data(key, glyphs[i]);
const GlyphMeshData &gl_data = cache[key];
int64_t ts = gl_data.triangles.size();
const Vector2 *ts_ptr = gl_data.triangles.ptr();

View File

@ -475,6 +475,7 @@ private:
sharp = p_sharp;
};
};
struct ContourInfo {
real_t length = 0.0;
bool ccw = true;
@ -484,6 +485,27 @@ private:
ccw = p_ccw;
}
};
struct GlyphMeshKey {
uint64_t font_id;
uint32_t gl_id;
bool operator==(const GlyphMeshKey &p_b) const {
return (font_id == p_b.font_id) && (gl_id == p_b.gl_id);
}
GlyphMeshKey(uint64_t p_font_id, uint32_t p_gl_id) {
font_id = p_font_id;
gl_id = p_gl_id;
}
};
struct GlyphMeshKeyHasher {
_FORCE_INLINE_ static uint32_t hash(const GlyphMeshKey &p_a) {
return hash_murmur3_buffer(&p_a, sizeof(GlyphMeshKey));
}
};
struct GlyphMeshData {
Vector<Vector2> triangles;
Vector<Vector<ContourPoint>> contours;
@ -491,7 +513,7 @@ private:
Vector2 min_p = Vector2(INFINITY, INFINITY);
Vector2 max_p = Vector2(-INFINITY, -INFINITY);
};
mutable HashMap<uint32_t, GlyphMeshData> cache;
mutable HashMap<GlyphMeshKey, GlyphMeshData, GlyphMeshKeyHasher> cache;
RID text_rid;
String text;
@ -517,7 +539,7 @@ private:
mutable bool dirty_font = true;
mutable bool dirty_cache = true;
void _generate_glyph_mesh_data(uint32_t p_hash, const Glyph &p_glyph) const;
void _generate_glyph_mesh_data(const GlyphMeshKey &p_key, const Glyph &p_glyph) const;
void _font_changed();
protected: