mirror of
https://github.com/godotengine/godot.git
synced 2024-11-11 06:33:10 +00:00
Use custom key structs, instead of raw hashes for the Label3D and TextMesh, to avoid potential hash collisions.
This commit is contained in:
parent
5b3b06187b
commit
329923c6ac
@ -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:
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user