Explorar o código

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

bruvzg %!s(int64=3) %!d(string=hai) anos
pai
achega
329923c6ac

+ 2 - 2
core/templates/lru.h

@@ -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:

+ 7 - 14
scene/3d/label_3d.cpp

@@ -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();

+ 23 - 1
scene/3d/label_3d.h

@@ -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;

+ 9 - 12
scene/resources/primitive_meshes.cpp

@@ -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();

+ 24 - 2
scene/resources/primitive_meshes.h

@@ -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: