vt fontcvt: Use a hash to speed up glyph deduplication
Walking a linked list of all glyphs to look for a duplicate is very slow for large fonts (e.g., for CJK character sets). In my test the runtime for a sample 40000 character font went from just over 80 seconds on average to just over 2 seconds. Sponsored by: The FreeBSD Foundation
This commit is contained in:
parent
fe0a62f58d
commit
1b92a37c1c
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=267035
@ -30,6 +30,8 @@
|
|||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__FBSDID("$FreeBSD$");
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/fnv_hash.h>
|
||||||
#include <sys/endian.h>
|
#include <sys/endian.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
@ -49,11 +51,14 @@ static unsigned int width = 8, wbytes, height = 16;
|
|||||||
|
|
||||||
struct glyph {
|
struct glyph {
|
||||||
TAILQ_ENTRY(glyph) g_list;
|
TAILQ_ENTRY(glyph) g_list;
|
||||||
|
SLIST_ENTRY(glyph) g_hash;
|
||||||
uint8_t *g_data;
|
uint8_t *g_data;
|
||||||
unsigned int g_index;
|
unsigned int g_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define FONTCVT_NHASH 4096
|
||||||
TAILQ_HEAD(glyph_list, glyph);
|
TAILQ_HEAD(glyph_list, glyph);
|
||||||
|
static SLIST_HEAD(, glyph) glyph_hash[FONTCVT_NHASH];
|
||||||
static struct glyph_list glyphs[VFNT_MAPS] = {
|
static struct glyph_list glyphs[VFNT_MAPS] = {
|
||||||
TAILQ_HEAD_INITIALIZER(glyphs[0]),
|
TAILQ_HEAD_INITIALIZER(glyphs[0]),
|
||||||
TAILQ_HEAD_INITIALIZER(glyphs[1]),
|
TAILQ_HEAD_INITIALIZER(glyphs[1]),
|
||||||
@ -147,19 +152,18 @@ static struct glyph *
|
|||||||
add_glyph(const uint8_t *bytes, unsigned int map_idx, int fallback)
|
add_glyph(const uint8_t *bytes, unsigned int map_idx, int fallback)
|
||||||
{
|
{
|
||||||
struct glyph *gl;
|
struct glyph *gl;
|
||||||
unsigned int i;
|
int hash;
|
||||||
|
|
||||||
glyph_total++;
|
glyph_total++;
|
||||||
glyph_count[map_idx]++;
|
glyph_count[map_idx]++;
|
||||||
|
|
||||||
for (i = 0; i < VFNT_MAPS; i++) {
|
hash = fnv_32_buf(bytes, wbytes * height, FNV1_32_INIT) % FONTCVT_NHASH;
|
||||||
TAILQ_FOREACH(gl, &glyphs[i], g_list) {
|
SLIST_FOREACH(gl, &glyph_hash[hash], g_hash) {
|
||||||
if (memcmp(gl->g_data, bytes, wbytes * height) == 0) {
|
if (memcmp(gl->g_data, bytes, wbytes * height) == 0) {
|
||||||
glyph_dupe++;
|
glyph_dupe++;
|
||||||
return (gl);
|
return (gl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
gl = malloc(sizeof *gl);
|
gl = malloc(sizeof *gl);
|
||||||
gl->g_data = malloc(wbytes * height);
|
gl->g_data = malloc(wbytes * height);
|
||||||
@ -168,6 +172,7 @@ add_glyph(const uint8_t *bytes, unsigned int map_idx, int fallback)
|
|||||||
TAILQ_INSERT_HEAD(&glyphs[map_idx], gl, g_list);
|
TAILQ_INSERT_HEAD(&glyphs[map_idx], gl, g_list);
|
||||||
else
|
else
|
||||||
TAILQ_INSERT_TAIL(&glyphs[map_idx], gl, g_list);
|
TAILQ_INSERT_TAIL(&glyphs[map_idx], gl, g_list);
|
||||||
|
SLIST_INSERT_HEAD(&glyph_hash[hash], gl, g_hash);
|
||||||
|
|
||||||
glyph_unique++;
|
glyph_unique++;
|
||||||
return (gl);
|
return (gl);
|
||||||
|
Loading…
Reference in New Issue
Block a user