Use uthash for the sprite position cache
This commit is contained in:
@@ -48,6 +48,7 @@ typedef uint16_t hyperlink_id_type;
|
||||
typedef int key_type;
|
||||
#define HYPERLINK_MAX_NUMBER UINT16_MAX
|
||||
typedef uint16_t combining_type;
|
||||
typedef uint16_t glyph_index;
|
||||
typedef uint32_t pixel;
|
||||
typedef unsigned int index_type;
|
||||
typedef uint16_t sprite_index;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "emoji.h"
|
||||
#include "unicode-data.h"
|
||||
#include "charsets.h"
|
||||
#include "glyph-cache.h"
|
||||
|
||||
#define MISSING_GLYPH 4
|
||||
#define MAX_NUM_EXTRA_GLYPHS 8u
|
||||
@@ -33,16 +34,6 @@ typedef struct {
|
||||
glyph_index data[MAX_NUM_EXTRA_GLYPHS];
|
||||
} ExtraGlyphs;
|
||||
|
||||
typedef struct SpritePosition SpritePosition;
|
||||
struct SpritePosition {
|
||||
SpritePosition *next;
|
||||
bool filled, rendered, colored;
|
||||
sprite_index x, y, z;
|
||||
uint8_t ligature_index;
|
||||
glyph_index glyph;
|
||||
ExtraGlyphs extra_glyphs;
|
||||
};
|
||||
|
||||
#define SPECIAL_FILLED_MASK 1
|
||||
#define SPECIAL_VALUE_MASK 2
|
||||
#define EMPTY_FILLED_MASK 4
|
||||
@@ -81,7 +72,7 @@ typedef enum { SPACER_STARTEGY_UNKNOWN, SPACERS_BEFORE, SPACERS_AFTER } SpacerSt
|
||||
typedef struct {
|
||||
PyObject *face;
|
||||
// Map glyphs to sprite map co-ords
|
||||
SpritePosition sprite_map[1024];
|
||||
SpritePosition *sprite_position_hash_table;
|
||||
hb_feature_t* ffs_hb_features;
|
||||
size_t num_ffs_hb_features;
|
||||
SpecialGlyphCache special_glyph_cache[SPECIAL_GLYPH_CACHE_SIZE];
|
||||
@@ -151,7 +142,8 @@ free_maps(Font *font) {
|
||||
}\
|
||||
memset(font->attr, 0, sizeof(font->attr)); \
|
||||
}
|
||||
free_a_map(SpritePosition, sprite_map);
|
||||
free_sprite_position_hash_table(&font->sprite_position_hash_table);
|
||||
font->sprite_position_hash_table = NULL;
|
||||
free_a_map(SpecialGlyphCache, special_glyph_cache);
|
||||
#undef free_a_map
|
||||
}
|
||||
@@ -258,42 +250,20 @@ do_increment(FontGroup *fg, int *error) {
|
||||
}
|
||||
|
||||
|
||||
static inline bool
|
||||
extra_glyphs_equal(ExtraGlyphs *a, ExtraGlyphs *b) {
|
||||
for (size_t i = 0; i < MAX_NUM_EXTRA_GLYPHS; i++) {
|
||||
if (a->data[i] != b->data[i]) return false;
|
||||
if (a->data[i] == 0) return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static SpritePosition*
|
||||
sprite_position_for(FontGroup *fg, Font *font, glyph_index glyph, ExtraGlyphs *extra_glyphs, uint8_t ligature_index, int *error) {
|
||||
glyph_index idx = glyph & (SPECIAL_GLYPH_CACHE_SIZE - 1);
|
||||
SpritePosition *s = font->sprite_map + idx;
|
||||
// Optimize for the common case of glyph under 1024 already in the cache
|
||||
if (LIKELY(s->glyph == glyph && s->filled && extra_glyphs_equal(&s->extra_glyphs, extra_glyphs) && s->ligature_index == ligature_index)) return s; // Cache hit
|
||||
while(true) {
|
||||
if (s->filled) {
|
||||
if (s->glyph == glyph && extra_glyphs_equal(&s->extra_glyphs, extra_glyphs) && s->ligature_index == ligature_index) return s; // Cache hit
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
if (!s->next) {
|
||||
s->next = calloc(1, sizeof(SpritePosition));
|
||||
if (s->next == NULL) { *error = 1; return NULL; }
|
||||
}
|
||||
s = s->next;
|
||||
static glyph_index glyphs[MAX_NUM_EXTRA_GLYPHS + 4];
|
||||
unsigned glyph_count = 1; glyphs[0] = glyph;
|
||||
glyph_index *eg = extra_glyphs->data;
|
||||
|
||||
while(*eg) { glyphs[glyph_count++] = *eg++; }
|
||||
bool created;
|
||||
SpritePosition *s = find_or_create_sprite_position(&font->sprite_position_hash_table, glyphs, glyph_count, ligature_index, &created);
|
||||
if (!s) { *error = 1; return NULL; }
|
||||
if (created) {
|
||||
s->x = fg->sprite_tracker.x; s->y = fg->sprite_tracker.y; s->z = fg->sprite_tracker.z;
|
||||
do_increment(fg, error);
|
||||
}
|
||||
s->glyph = glyph;
|
||||
memcpy(&s->extra_glyphs, extra_glyphs, sizeof(ExtraGlyphs));
|
||||
s->ligature_index = ligature_index;
|
||||
s->filled = true;
|
||||
s->rendered = false;
|
||||
s->colored = false;
|
||||
s->x = fg->sprite_tracker.x; s->y = fg->sprite_tracker.y; s->z = fg->sprite_tracker.z;
|
||||
do_increment(fg, error);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -388,6 +358,7 @@ free_font_groups(void) {
|
||||
free(font_groups); font_groups = NULL;
|
||||
font_groups_capacity = 0; num_font_groups = 0;
|
||||
}
|
||||
free_glyph_cache_global_resources();
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -19,7 +19,6 @@ typedef struct {
|
||||
} StringCanvas;
|
||||
|
||||
// API that font backends need to implement
|
||||
typedef uint16_t glyph_index;
|
||||
unsigned int glyph_id_for_codepoint(PyObject *, char_type);
|
||||
int get_glyph_width(PyObject *, glyph_index);
|
||||
bool is_glyph_empty(PyObject *, glyph_index);
|
||||
|
||||
67
kitty/glyph-cache.c
Normal file
67
kitty/glyph-cache.c
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* glyph-cache.c
|
||||
* Copyright (C) 2021 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#include "glyph-cache.h"
|
||||
#include "uthash.h"
|
||||
|
||||
|
||||
#undef uthash_fatal
|
||||
#define uthash_fatal(msg) fatal(msg)
|
||||
|
||||
|
||||
typedef struct SpritePosItem {
|
||||
SpritePositionHead
|
||||
UT_hash_handle hh;
|
||||
glyph_index key[];
|
||||
} SpritePosItem;
|
||||
|
||||
static glyph_index *scratch = NULL;
|
||||
static unsigned scratch_sz = 0;
|
||||
|
||||
|
||||
void
|
||||
free_glyph_cache_global_resources(void) {
|
||||
free(scratch);
|
||||
scratch = NULL; scratch_sz = 0;
|
||||
}
|
||||
|
||||
|
||||
static inline unsigned
|
||||
key_size_for_glyph_count(unsigned count) { return count + 2; }
|
||||
|
||||
|
||||
SpritePosition*
|
||||
find_or_create_sprite_position(SpritePosition **head_, glyph_index *glyphs, glyph_index count, glyph_index ligature_index, bool *created) {
|
||||
SpritePosItem **head = (SpritePosItem**)head_, *p;
|
||||
const unsigned key_sz = key_size_for_glyph_count(count);
|
||||
if (key_sz > scratch_sz) {
|
||||
scratch = realloc(scratch, key_sz + 16);
|
||||
if (!scratch) return NULL;
|
||||
scratch_sz = key_sz + 16;
|
||||
}
|
||||
const unsigned key_sz_bytes = key_sz * sizeof(glyph_index);
|
||||
scratch[0] = count; scratch[1] = ligature_index;
|
||||
memcpy(scratch + 2, glyphs, count * sizeof(glyph_index));
|
||||
HASH_FIND(hh, *head, scratch, key_sz_bytes, p);
|
||||
if (p) { *created = false; return (SpritePosition*)p; }
|
||||
|
||||
p = calloc(1, sizeof(SpritePosItem) + key_sz_bytes);
|
||||
if (!p) return NULL;
|
||||
memcpy(p->key, scratch, key_sz_bytes);
|
||||
HASH_ADD(hh, *head, key, key_sz_bytes, p);
|
||||
*created = true;
|
||||
return (SpritePosition*)p;
|
||||
}
|
||||
|
||||
void
|
||||
free_sprite_position_hash_table(SpritePosition **head_) {
|
||||
SpritePosItem **head = (SpritePosItem**)head_, *s, *tmp;
|
||||
HASH_ITER(hh, *head, s, tmp) {
|
||||
HASH_DEL(*head, s);
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
23
kitty/glyph-cache.h
Normal file
23
kitty/glyph-cache.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "data-types.h"
|
||||
|
||||
#define SpritePositionHead \
|
||||
bool rendered, colored; \
|
||||
sprite_index x, y, z; \
|
||||
|
||||
typedef struct SpritePosition {
|
||||
SpritePositionHead
|
||||
} SpritePosition;
|
||||
|
||||
|
||||
void free_glyph_cache_global_resources(void);
|
||||
void free_sprite_position_hash_table(SpritePosition **head);
|
||||
SpritePosition*
|
||||
find_or_create_sprite_position(SpritePosition **head, glyph_index *glyphs, glyph_index count, glyph_index ligature_index, bool *created);
|
||||
@@ -49,6 +49,7 @@ class Rendering(BaseTest):
|
||||
sprite_map_set_limits(10, 2)
|
||||
sprite_map_set_layout(5, 5)
|
||||
self.ae(test_sprite_position_for(0), (0, 0, 0))
|
||||
self.ae(test_sprite_position_for(0), (0, 0, 0))
|
||||
self.ae(test_sprite_position_for(1), (1, 0, 0))
|
||||
self.ae(test_sprite_position_for(2), (0, 1, 0))
|
||||
self.ae(test_sprite_position_for(3), (1, 1, 0))
|
||||
|
||||
Reference in New Issue
Block a user