From 56a4357b20861eb376a41cad721ad419a0806f90 Mon Sep 17 00:00:00 2001 From: Alessandro Mauri Date: Sun, 5 Mar 2023 10:41:40 +0100 Subject: [PATCH] made cache a generic structure --- text_rendering/Makefile | 10 +-- text_rendering/cache.c | 117 --------------------------------- text_rendering/cache.h | 13 ---- text_rendering/font.c | 26 ++++---- text_rendering/generic_cache.h | 100 ++++++++++++++++++++++++++++ text_rendering/stack.h | 6 +- 6 files changed, 120 insertions(+), 152 deletions(-) delete mode 100644 text_rendering/cache.c delete mode 100644 text_rendering/cache.h create mode 100644 text_rendering/generic_cache.h diff --git a/text_rendering/Makefile b/text_rendering/Makefile index 2fdd6ae..6838d1a 100644 --- a/text_rendering/Makefile +++ b/text_rendering/Makefile @@ -5,13 +5,13 @@ CFLAGS = -g -Wall -Wextra -pedantic .PHONY: clean all all: test -cache.o: cache.c cache.h hash.h font.h util.h -font.o: font.c font.h stb_truetype.h stb_image_write.h util.h cache.h +font.o: font.c font.h stb_truetype.h stb_image_write.h util.h \ + generic_cache.h hash.h hash.o: hash.c hash.h util.h main.o: main.c ren.h util.h ren.o: ren.c util.h font.h ren.h stack.h util.o: util.c util.h -test: cache.o font.o hash.o main.o ren.o util.o - ${CC} ${LDFLAGS} -o test cache.o font.o hash.o main.o ren.o util.o +test: font.o hash.o main.o ren.o util.o + ${CC} ${LDFLAGS} -o test font.o hash.o main.o ren.o util.o clean: - rm -f test cache.o font.o hash.o main.o ren.o util.o + rm -f test font.o hash.o main.o ren.o util.o diff --git a/text_rendering/cache.c b/text_rendering/cache.c deleted file mode 100644 index b5489b6..0000000 --- a/text_rendering/cache.c +++ /dev/null @@ -1,117 +0,0 @@ -#define _POSIX_C_SOURCE 200809l -#define _GNU_SOURCE - -#include -#include -#include -#include - -#include "cache.h" -#include "hash.h" -#include "font.h" -#include "util.h" - - -static struct hm_ref *hash_table; -static struct font_glyph cache_array[CACHE_SIZE] = {0}; - -// bitmap size is aligned to word -// 2^6 == 64 bits, number of bits in a uint64_t -#define _BSIZE (((CACHE_SIZE+0x3f)&(~0x3f))>>6) -static uint64_t bitmap[_BSIZE] = {0}; - -// bitmap operations -#define B_RESET() for (int i = 0; i < _BSIZE; bitmap[i++] = 0); -#define B_SET(x) bitmap[(x)>>6] |= (uint64_t)1<<((x)%64) -#define B_TEST(x) (bitmap[(x)>>6]&((uint64_t)1<<((x)%64))) - -// reset the bitmap every n cycles -#define NCYCLES (CACHE_SIZE/2) -static int cycles = 0; - - -static inline void set_bit(unsigned int x) -{ -// printf("cycles: %d, set: %d\n", cycles, x); - cycles = (cycles+1)%NCYCLES; - if (!cycles) B_RESET(); - B_SET(x); -} - - -void cache_init(void) -{ - hash_table = hm_create(CACHE_SIZE); -} - - -void cache_destroy(void) -{ - hm_destroy(hash_table); -} - - -const struct font_glyph * cache_search(unsigned int code) -{ - struct hm_entry *r = hm_search(hash_table, code); - - // miss - if (!r) - return NULL; - - // hit - set_bit((struct font_glyph *)(r->data)-cache_array); - return (struct font_glyph *)(r->data); -} - - -// return the first free spot into the cache -unsigned int cache_get(void) -{ - uint32_t x = 0; - // find an open spot in the cache - for (int b = 0; b < _BSIZE; b++) { - if (bitmap[b] == 0) x = 64; - else x = __builtin_clzll(bitmap[b]); - x = 64-x; - if (!B_TEST(x+64*b)) - return x+64*b; - } - return 0; -} - - -// inserts the font glyph into the cache -const struct font_glyph * cache_insert(const struct font_glyph *g, unsigned int x) -{ - struct font_glyph *spot = NULL; - - // allocation in cache failed - if (B_TEST(x)) - return NULL; - - set_bit(x); - spot = &cache_array[x]; - *spot = *g; - -/* - for (int i = 0; i < _BSIZE; i++) { - //print_byte(bitmap[i]); - //print_byte(bitmap[i]>>8); - //print_byte(bitmap[i]>>16); - //print_byte(bitmap[i]>>24); - //print_byte(bitmap[i]>>32); - //print_byte(bitmap[i]>>40); - //print_byte(bitmap[i]>>48); - //print_byte(bitmap[i]>>56); - printf("%lx", bitmap[i]); - } - printf("\n"); -*/ - - struct hm_entry e = { .code = g->codepoint, .data = spot}; - if (!hm_insert(hash_table, &e)) - return NULL; - - return spot; -} diff --git a/text_rendering/cache.h b/text_rendering/cache.h deleted file mode 100644 index 2ec630a..0000000 --- a/text_rendering/cache.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _CACHE_H -#define _CACHE_H - -#define CACHE_SIZE 512 - -void cache_init(void); -void cache_destroy(void); -const struct font_glyph * cache_search(unsigned int code); -unsigned int cache_get(void); -const struct font_glyph * cache_insert(const struct font_glyph *g, unsigned int idx); - - -#endif diff --git a/text_rendering/font.c b/text_rendering/font.c index e1e2a01..a3c4175 100644 --- a/text_rendering/font.c +++ b/text_rendering/font.c @@ -10,7 +10,10 @@ #include "stb_truetype.h" #include "stb_image_write.h" #include "util.h" -#include "cache.h" + +// generic cache type +#include "generic_cache.h" +CACHE_DECL(cache, struct font_glyph) #define UTF8(c) (c&0x80) @@ -18,7 +21,7 @@ #define BORDER 4 // FIXME: as of now only monospaced fonts work correctly since no kerning information -// is stored +// is stored struct priv { @@ -26,21 +29,18 @@ struct priv { float scale; int baseline; unsigned char *bitmap; + struct cache c; }; #define PRIV(x) ((struct priv *)x->priv) -// only useful for msdf_c -static inline void * _emalloc(size_t x, void *_) { (void)_; return emalloc(x); } -static inline void _efree(void *x, void *_) { (void)_; efree(x); } - - struct font_atlas * font_init(void) { struct font_atlas *p = emalloc(sizeof(struct font_atlas)); memset(p, 0, sizeof(struct font_atlas)); p->priv = emalloc(sizeof(struct priv)); memset(p->priv, 0, sizeof(struct priv)); + PRIV(p)->c = cache_init(); return p; } @@ -96,9 +96,9 @@ int font_free(struct font_atlas *atlas) efree(atlas->atlas); efree(atlas->file); efree(PRIV(atlas)->bitmap); + cache_free(&PRIV(atlas)->c); efree(atlas->priv); efree(atlas); - cache_destroy(); return 0; } @@ -111,7 +111,7 @@ const struct font_glyph * font_get_glyph_texture(struct font_atlas *atlas, unsig if (!updated) updated = &u; const struct font_glyph *r; - if ((r = cache_search(code)) != NULL) { + if ((r = cache_search(&PRIV(atlas)->c, code)) != NULL) { *updated = 0; return r; } @@ -143,12 +143,12 @@ const struct font_glyph * font_get_glyph_texture(struct font_atlas *atlas, unsig atlas->glyph_max_w, PRIV(atlas)->scale, PRIV(atlas)->scale, - 0, 0, + 0, 0, idx); // TODO: bounds check usign atlas height // TODO: clear spot area in the atlas before writing on it - unsigned int spot = cache_get(); + unsigned int spot = cache_get(&PRIV(atlas)->c); unsigned int oy = ((atlas->glyph_max_w * spot) / atlas->width) * atlas->glyph_max_h; unsigned int ox = (atlas->glyph_max_w * spot) % atlas->width; unsigned int w = atlas->width; @@ -177,9 +177,7 @@ const struct font_glyph * font_get_glyph_texture(struct font_atlas *atlas, unsig .y = off_y, .a = adv, }; - const struct font_glyph *ret = cache_insert(&g, spot); - - return ret; + return cache_insert(&PRIV(atlas)->c, &g, g.codepoint, spot); } diff --git a/text_rendering/generic_cache.h b/text_rendering/generic_cache.h new file mode 100644 index 0000000..1285ca5 --- /dev/null +++ b/text_rendering/generic_cache.h @@ -0,0 +1,100 @@ +#ifndef CACHE_GENERIC_H +#define CACHE_GENERIC_H + + +#include "hash.h" + +#define CACHE_SIZE 512 +#define CACHE_NCYCLES (CACHE_SIZE/2) +#define CACHE_BSIZE (((CACHE_SIZE+0x3f)&(~0x3f))>>6) +#define CACHE_BRESET(b) for (int i = 0; i < CACHE_BSIZE; b[i++] = 0); +#define CACHE_BSET(b, x) b[(x)>>6] |= (uint64_t)1<<((x)%64) +#define CACHE_BTEST(b, x) (b[(x)>>6]&((uint64_t)1<<((x)%64))) + +#define CACHE_SET(c, x) \ +{ \ + c->cycles = (c->cycles+1)%CACHE_NCYCLES; \ + if (!c->cycles) CACHE_BRESET(c->bitmap); \ + CACHE_BSET(c->bitmap, x); \ +} + + +#define CACHE_DECL(cachename, type) \ +struct cachename { \ + struct hm_ref *table; \ + type *array; \ + uint64_t *bitmap; \ + int cycles; \ +}; \ +\ +\ +struct cachename cachename##_init(void) \ +{ \ + struct hm_ref *t = hm_create(CACHE_SIZE); \ + type *a = malloc(sizeof(type)*CACHE_SIZE); \ + uint64_t *b = malloc(sizeof(uint64_t)*CACHE_BSIZE); \ + CACHE_BRESET(b); \ + return (struct cachename){ .table = t, .array = a, .bitmap = b, 0}; \ +} \ +\ +\ +void cachename##_free(struct cachename *cache) \ +{ \ + if (cache) { \ + hm_destroy(cache->table); \ + free(cache->array); \ + free(cache->bitmap); \ + } \ +} \ +\ +\ +const type * cachename##_search(struct cachename *cache, unsigned int code) \ +{ \ + if (!cache) \ + return NULL; \ + struct hm_entry *r = hm_search(cache->table, code); \ + /* MISS */ \ + if (!r) \ + return NULL; \ + /* HIT */ \ + CACHE_SET(cache, (type *)(r->data)-cache->array); \ + return (const type *)(r->data); \ +} \ +\ +\ +int cachename##_get(struct cachename *cache) \ +{ \ + if (!cache) \ + return -1; \ + int x = 0; \ + for (int b = 0; b < CACHE_BSIZE; b++) { \ + if (cache->bitmap[b] == 0) x = 64; \ + else x = __builtin_clzll(cache->bitmap[b]); \ + x = 64-x; \ + if (!CACHE_BTEST(cache->bitmap, x+64*b)) \ + return x+64*b; \ + } \ + return 0; \ +} \ +\ +\ +const type * cachename##_insert(struct cachename *cache, const type *g, unsigned int code, int x) \ +{ \ + if (!cache) \ + return NULL; \ + type *spot = NULL; \ + /* x is the index to the cache array, it has to come from the user */ \ + /* check if the spot is free */ \ + if (x < 0 || CACHE_BTEST(cache->bitmap, x)) \ + return NULL; \ + CACHE_SET(cache, x) \ + spot = &(cache->array[x]); \ + *spot = *g; \ + struct hm_entry e = { .code = code, .data = spot}; \ + if (!hm_insert(cache->table, &e)) \ + return NULL; \ + return spot; \ +} \ + + +#endif diff --git a/text_rendering/stack.h b/text_rendering/stack.h index 816565c..85d0216 100644 --- a/text_rendering/stack.h +++ b/text_rendering/stack.h @@ -8,7 +8,7 @@ // FIXME: find a way to not re-hash the whole stack when removing one item // incremental hash for every grow -#define HASH(p, s, h) \ +#define STACK_HASH(p, s, h) \ { \ unsigned char *v = (unsigned char *)(p); \ for (int x = (s); x; x--) { \ @@ -58,7 +58,7 @@ int stackname##_push(struct stackname *stack, type *e) \ if (stackname##_grow(stack, STACK_STEP)) \ return -1; \ stack->items[stack->idx++] = *e; \ - HASH(e, sizeof(type), stack->hash); \ + STACK_HASH(e, sizeof(type), stack->hash); \ return 0; \ } \ \ @@ -68,7 +68,7 @@ type stackname##_pop(struct stackname *stack) \ if (!stack || stack->idx == 0 || stack->size == 0) \ return (type){0}; \ stack->hash = STACK_SALT; \ - HASH(stack->items, sizeof(type)*(stack->idx-1), stack->hash); \ + STACK_HASH(stack->items, sizeof(type)*(stack->idx-1), stack->hash); \ return stack->items[stack->idx--]; \ } \ \