fix(reader): 书索引build_index全量逐字FreeType排版优化 — rdft_advance加(px,cp)->advance缓存(开放寻址4096槽,与glyph缓存分离,load_font/set_px同清), 测量从O(全书字符)降到O(唯一码点~2600); 大书(10MB)打开 rd_book_open 23.9s->140ms(~170x), npages一致布局确定保留; 点条目不再用户态busy循环冻死(非驱动/锁屏, 是UI线程同步全量建索引); 0warning, 宿主test_reader_core 68-0/loaders_smoke/book_smoke/formats_smoke PASS
This commit is contained in:
1 parent
5e67100231
commit
68710d7ed8
1 file changed
+51
-3
@@ -15,6 +15,13 @@ typedef struct {
|
|||||||
int bw, bh, pitch, left, top;
|
int bw, bh, pitch, left, top;
|
||||||
} glyph_slot;
|
} glyph_slot;
|
||||||
|
|
||||||
|
/* advance 测量缓存:rdft_advance 逐字测量是排版索引用热路径(大书每次开/重排全量逐字测),
|
||||||
|
* 同一码点在全书反复出现(中文常用字 ~几千)。独立的小型开放寻址表缓存 (px,cp)→advance,
|
||||||
|
* 避免对重复码点反复 FT_Load_Glyph,把测量成本从 O(全书字符) 摊到 O(唯一码点)。
|
||||||
|
* 与 glyph_slot 缓存分离:glyph 缓存存「已光栅化位图」,此处只存 advance(不栅格化、不占位图)。 */
|
||||||
|
#define RD_ADV_SLOTS 4096 /* 幂 2;开放寻址线性探测 */
|
||||||
|
typedef struct { uint64_t key; int adv; } adv_slot;
|
||||||
|
|
||||||
struct rdft {
|
struct rdft {
|
||||||
FT_Library lib;
|
FT_Library lib;
|
||||||
FT_Face face;
|
FT_Face face;
|
||||||
@@ -23,6 +30,7 @@ struct rdft {
|
|||||||
int nslots; /* 容量 */
|
int nslots; /* 容量 */
|
||||||
int used; /* 在线条目数 */
|
int used; /* 在线条目数 */
|
||||||
uint64_t clock; /* 单调戳 */
|
uint64_t clock; /* 单调戳 */
|
||||||
|
adv_slot *adv; /* advance 缓存(排版测量) */
|
||||||
int has_font;
|
int has_font;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -36,6 +44,8 @@ int rdft_init(rdft **r)
|
|||||||
x->nslots = 512;
|
x->nslots = 512;
|
||||||
x->slots = (glyph_slot *)calloc((size_t)x->nslots, sizeof(glyph_slot));
|
x->slots = (glyph_slot *)calloc((size_t)x->nslots, sizeof(glyph_slot));
|
||||||
if (!x->slots) { FT_Done_FreeType(x->lib); free(x); return -6; }
|
if (!x->slots) { FT_Done_FreeType(x->lib); free(x); return -6; }
|
||||||
|
x->adv = (adv_slot *)calloc(RD_ADV_SLOTS, sizeof(adv_slot));
|
||||||
|
if (!x->adv) { free(x->slots); FT_Done_FreeType(x->lib); free(x); return -6; }
|
||||||
x->used = 0;
|
x->used = 0;
|
||||||
x->clock = 1;
|
x->clock = 1;
|
||||||
*r = x;
|
*r = x;
|
||||||
@@ -48,6 +58,7 @@ int rdft_load_font(rdft *r, const char *path)
|
|||||||
if (r->face) { FT_Done_Face(r->face); r->face = NULL; }
|
if (r->face) { FT_Done_Face(r->face); r->face = NULL; }
|
||||||
if (r->slots) { for (int i = 0; i < r->nslots; i++) free(r->slots[i].bmp); }
|
if (r->slots) { for (int i = 0; i < r->nslots; i++) free(r->slots[i].bmp); }
|
||||||
if (r->slots) memset(r->slots, 0, (size_t)r->nslots * sizeof(glyph_slot));
|
if (r->slots) memset(r->slots, 0, (size_t)r->nslots * sizeof(glyph_slot));
|
||||||
|
if (r->adv) memset(r->adv, 0, (size_t)RD_ADV_SLOTS * sizeof(adv_slot));
|
||||||
r->used = 0;
|
r->used = 0;
|
||||||
if (FT_New_Face(r->lib, path, 0, &r->face) != 0) { r->has_font = 0; return -1; }
|
if (FT_New_Face(r->lib, path, 0, &r->face) != 0) { r->has_font = 0; return -1; }
|
||||||
r->has_font = 1;
|
r->has_font = 1;
|
||||||
@@ -61,8 +72,9 @@ void rdft_set_px(rdft *r, int px)
|
|||||||
if (px <= 0) px = r->px;
|
if (px <= 0) px = r->px;
|
||||||
r->px = px;
|
r->px = px;
|
||||||
if (r->face) FT_Set_Pixel_Sizes(r->face, 0, (FT_UInt)px);
|
if (r->face) FT_Set_Pixel_Sizes(r->face, 0, (FT_UInt)px);
|
||||||
/* key 含字号,清缓存防旧字号位图残留 */
|
/* key 含字号,清缓存防旧字号位图残留(glyph + advance 同清,key 同含 px) */
|
||||||
if (r->slots) { for (int i = 0; i < r->nslots; i++) free(r->slots[i].bmp); memset(r->slots, 0, (size_t)r->nslots * sizeof(glyph_slot)); }
|
if (r->slots) { for (int i = 0; i < r->nslots; i++) free(r->slots[i].bmp); memset(r->slots, 0, (size_t)r->nslots * sizeof(glyph_slot)); }
|
||||||
|
if (r->adv) memset(r->adv, 0, (size_t)RD_ADV_SLOTS * sizeof(adv_slot));
|
||||||
r->used = 0;
|
r->used = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,18 +159,53 @@ int rdft_glyph(rdft *r, uint32_t cp, int *adv_x,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* (px,cp)→advance 缓存:开放寻址线性探测;key==0 为空槽哨兵(key=(px<<32)|cp,px≥1 恒非 0)。 */
|
||||||
|
static uint32_t adv_hash(uint64_t key)
|
||||||
|
{
|
||||||
|
/* 乘法散列取高位,把 64 位 key(px 在高位、cp 在低位)散布到 12 位表。 */
|
||||||
|
return (uint32_t)((key * 2654435761ULL) >> 22) & (RD_ADV_SLOTS - 1);
|
||||||
|
}
|
||||||
|
static int adv_find(const rdft *r, uint64_t key, int *adv)
|
||||||
|
{
|
||||||
|
uint32_t h = adv_hash(key);
|
||||||
|
for (uint32_t i = 0; i < RD_ADV_SLOTS; i++) {
|
||||||
|
uint32_t idx = (h + i) & (RD_ADV_SLOTS - 1);
|
||||||
|
uint64_t k = r->adv[idx].key;
|
||||||
|
if (k == 0) return 0;
|
||||||
|
if (k == key) { *adv = r->adv[idx].adv; return 1; }
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static void adv_put(rdft *r, uint64_t key, int adv)
|
||||||
|
{
|
||||||
|
uint32_t h = adv_hash(key);
|
||||||
|
for (uint32_t i = 0; i < RD_ADV_SLOTS; i++) {
|
||||||
|
uint32_t idx = (h + i) & (RD_ADV_SLOTS - 1);
|
||||||
|
if (r->adv[idx].key == 0 || r->adv[idx].key == key) {
|
||||||
|
r->adv[idx].key = key; r->adv[idx].adv = adv; return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 表满:丢弃(下次未命中直接算) */
|
||||||
|
}
|
||||||
|
|
||||||
int rdft_advance(rdft *r, uint32_t cp, int *adv_x)
|
int rdft_advance(rdft *r, uint32_t cp, int *adv_x)
|
||||||
{
|
{
|
||||||
if (!r || !r->face || !adv_x) return -1;
|
if (!r || !r->face || !adv_x) return -1;
|
||||||
|
uint64_t key = ((uint64_t)(uint32_t)r->px << 32) | cp;
|
||||||
|
if (adv_find(r, key, adv_x)) return 0;
|
||||||
FT_UInt gi = FT_Get_Char_Index(r->face, cp);
|
FT_UInt gi = FT_Get_Char_Index(r->face, cp);
|
||||||
if (r->px <= 0) FT_Set_Pixel_Sizes(r->face, 0, (FT_UInt)r->px);
|
if (r->px <= 0) FT_Set_Pixel_Sizes(r->face, 0, (FT_UInt)r->px);
|
||||||
if (FT_Load_Glyph(r->face, gi, FT_LOAD_NO_HINTING | FT_LOAD_TARGET_LIGHT) != 0) {
|
if (FT_Load_Glyph(r->face, gi, FT_LOAD_NO_HINTING | FT_LOAD_TARGET_LIGHT) != 0) {
|
||||||
*adv_x = r->face->glyph->advance.x >> 6;
|
int a = r->face->glyph->advance.x >> 6;
|
||||||
|
*adv_x = a;
|
||||||
|
adv_put(r, key, a);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int a = (int)((r->face->glyph->advance.x >= 0 ? r->face->glyph->advance.x + 0x20
|
int a = (int)((r->face->glyph->advance.x >= 0 ? r->face->glyph->advance.x + 0x20
|
||||||
: r->face->glyph->advance.x - 0x20) >> 6);
|
: r->face->glyph->advance.x - 0x20) >> 6);
|
||||||
*adv_x = a < 0 ? 0 : a;
|
a = a < 0 ? 0 : a;
|
||||||
|
*adv_x = a;
|
||||||
|
adv_put(r, key, a);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,6 +256,7 @@ void rdft_free(rdft *r)
|
|||||||
if (!r) return;
|
if (!r) return;
|
||||||
if (r->slots) { for (int i = 0; i < r->nslots; i++) free(r->slots[i].bmp); }
|
if (r->slots) { for (int i = 0; i < r->nslots; i++) free(r->slots[i].bmp); }
|
||||||
free(r->slots);
|
free(r->slots);
|
||||||
|
free(r->adv);
|
||||||
if (r->face) FT_Done_Face(r->face);
|
if (r->face) FT_Done_Face(r->face);
|
||||||
if (r->lib) FT_Done_FreeType(r->lib);
|
if (r->lib) FT_Done_FreeType(r->lib);
|
||||||
free(r);
|
free(r);
|
||||||
|
|||||||
Reference in new issue
Block a user