Browse Source

add: freetypefont增加码点快速检索机制

zengeshuai 4 months ago
parent
commit
36890b828b
1 changed files with 101 additions and 13 deletions
  1. 101 13
      components/freetypefont/src/luat_freetypefont.c

+ 101 - 13
components/freetypefont/src/luat_freetypefont.c

@@ -18,7 +18,9 @@
 #define FREETYPE_ASCENT_RATIO    0.80f
 
 // 位图缓存容量
-#define FREETYPE_CACHE_CAPACITY 100
+#define FREETYPE_CACHE_CAPACITY 128
+// 码点 -> glyph index 缓存槽位(需为 2 的幂以便快速哈希)
+#define FREETYPE_CODEPOINT_CACHE_SIZE 256
 
 typedef struct {
     luat_freetypefont_state_t state;
@@ -70,6 +72,15 @@ typedef struct {
 static freetype_cache_entry_t g_ft_cache[FREETYPE_CACHE_CAPACITY];
 static uint32_t g_ft_cache_stamp = 0;
 
+typedef struct {
+    uint32_t codepoint;
+    uint16_t glyph_index;
+    uint8_t in_use;
+    uint32_t last_used;
+} freetype_cp_cache_entry_t;
+
+static freetype_cp_cache_entry_t g_ft_cp_cache[FREETYPE_CODEPOINT_CACHE_SIZE];
+
 extern luat_lcd_conf_t *lcd_dft_conf;
 extern luat_color_t BACK_COLOR;
 
@@ -132,6 +143,18 @@ static uint32_t freetype_clamp_u32(uint64_t value) {
     return value > UINT32_MAX ? UINT32_MAX : (uint32_t)value;
 }
 
+static uint32_t freetype_next_stamp(void) {
+    g_ft_cache_stamp++;
+    if (g_ft_cache_stamp == 0) {
+        g_ft_cache_stamp = 1;
+    }
+    return g_ft_cache_stamp;
+}
+
+static void freetype_cp_cache_clear(void) {
+    memset(g_ft_cp_cache, 0, sizeof(g_ft_cp_cache));
+}
+
 static void freetype_cache_clear(void) {
     for (size_t i = 0; i < FREETYPE_CACHE_CAPACITY; ++i) {
         freetype_cache_entry_t *entry = &g_ft_cache[i];
@@ -142,6 +165,7 @@ static void freetype_cache_clear(void) {
             memset(entry, 0, sizeof(*entry));
         }
     }
+    freetype_cp_cache_clear();
     g_ft_cache_stamp = 0;
 }
 
@@ -149,10 +173,7 @@ static void freetype_cache_touch(freetype_cache_entry_t *entry) {
     if (!entry) {
         return;
     }
-    entry->last_used = ++g_ft_cache_stamp;
-    if (g_ft_cache_stamp == 0) {
-        g_ft_cache_stamp = 1;
-    }
+    entry->last_used = freetype_next_stamp();
 }
 
 static freetype_cache_entry_t *freetype_cache_find(uint16_t glyph_index, uint8_t font_size, uint8_t supersample) {
@@ -221,6 +242,62 @@ static freetype_cache_entry_t *freetype_cache_insert(uint16_t glyph_index, uint8
     return entry;
 }
 
+static freetype_cp_cache_entry_t *freetype_cp_cache_lookup(uint32_t codepoint) {
+    if (FREETYPE_CODEPOINT_CACHE_SIZE == 0) {
+        return NULL;
+    }
+    uint32_t mask = FREETYPE_CODEPOINT_CACHE_SIZE - 1u;
+    uint32_t start = (uint32_t)((codepoint * 2654435761u) & mask);
+    for (uint32_t probe = 0; probe < FREETYPE_CODEPOINT_CACHE_SIZE; ++probe) {
+        freetype_cp_cache_entry_t *entry = &g_ft_cp_cache[(start + probe) & mask];
+        if (!entry->in_use) {
+            return NULL;
+        }
+        if (entry->codepoint == codepoint) {
+            entry->last_used = freetype_next_stamp();
+            return entry;
+        }
+    }
+    return NULL;
+}
+
+static void freetype_cp_cache_insert(uint32_t codepoint, uint16_t glyph_index) {
+    if (FREETYPE_CODEPOINT_CACHE_SIZE == 0) {
+        return;
+    }
+    uint32_t mask = FREETYPE_CODEPOINT_CACHE_SIZE - 1u;
+    uint32_t start = (uint32_t)((codepoint * 2654435761u) & mask);
+    freetype_cp_cache_entry_t *empty_slot = NULL;
+    for (uint32_t probe = 0; probe < FREETYPE_CODEPOINT_CACHE_SIZE; ++probe) {
+        freetype_cp_cache_entry_t *entry = &g_ft_cp_cache[(start + probe) & mask];
+        if (!entry->in_use) {
+            empty_slot = entry;
+            break;
+        }
+        if (entry->codepoint == codepoint) {
+            entry->glyph_index = glyph_index;
+            entry->last_used = freetype_next_stamp();
+            return;
+        }
+    }
+    freetype_cp_cache_entry_t *target = empty_slot;
+    if (!target) {
+        uint32_t oldest = UINT32_MAX;
+        size_t oldest_idx = 0;
+        for (size_t i = 0; i < FREETYPE_CODEPOINT_CACHE_SIZE; ++i) {
+            if (g_ft_cp_cache[i].last_used < oldest) {
+                oldest = g_ft_cp_cache[i].last_used;
+                oldest_idx = i;
+            }
+        }
+        target = &g_ft_cp_cache[oldest_idx];
+    }
+    target->codepoint = codepoint;
+    target->glyph_index = glyph_index;
+    target->in_use = 1;
+    target->last_used = freetype_next_stamp();
+}
+
 static uint32_t freetype_calc_fallback_advance(unsigned char font_size) {
     float adv = (float)font_size * FREETYPE_ADVANCE_RATIO;
     if (adv < 1.0f) {
@@ -547,14 +624,25 @@ int luat_freetypefont_draw_utf8(int x, int y, const char *utf8, unsigned char fo
         uint64_t glyph_stamp = timing_enabled ? freetype_now_us() : 0;
 
         uint16_t glyph_index = 0;
-        int rc = ttf_lookup_glyph_index(&g_ft_ctx.font, cp, &glyph_index);
-        if (timing_enabled) {
-            slot->time_lookup_us = glyph_stamp ? freetype_elapsed_step(&glyph_stamp) : 0;
-            sum_lookup_us += slot->time_lookup_us;
-        }
-        if (rc != TTF_OK) {
-            glyph_count++;
-            continue;
+        int rc = TTF_OK;
+        freetype_cp_cache_entry_t *cp_entry = freetype_cp_cache_lookup(cp);
+        if (cp_entry) {
+            glyph_index = cp_entry->glyph_index;
+            if (timing_enabled) {
+                slot->time_lookup_us = glyph_stamp ? freetype_elapsed_step(&glyph_stamp) : 0;
+                sum_lookup_us += slot->time_lookup_us;
+            }
+        } else {
+            rc = ttf_lookup_glyph_index(&g_ft_ctx.font, cp, &glyph_index);
+            if (timing_enabled) {
+                slot->time_lookup_us = glyph_stamp ? freetype_elapsed_step(&glyph_stamp) : 0;
+                sum_lookup_us += slot->time_lookup_us;
+            }
+            if (rc != TTF_OK) {
+                glyph_count++;
+                continue;
+            }
+            freetype_cp_cache_insert(cp, glyph_index);
         }
 
         slot->glyph_index = glyph_index;