made cache a generic structure

master
Alessandro Mauri 1 year ago
parent 93f93a594e
commit 56a4357b20
  1. 10
      text_rendering/Makefile
  2. 117
      text_rendering/cache.c
  3. 13
      text_rendering/cache.h
  4. 26
      text_rendering/font.c
  5. 100
      text_rendering/generic_cache.h
  6. 6
      text_rendering/stack.h

@ -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

@ -1,117 +0,0 @@
#define _POSIX_C_SOURCE 200809l
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#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;
}

@ -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

@ -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);
}

@ -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

@ -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--]; \
} \
\

Loading…
Cancel
Save