made cache a generic structure
This commit is contained in:
parent
93f93a594e
commit
56a4357b20
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
100
text_rendering/generic_cache.h
Normal file
100
text_rendering/generic_cache.h
Normal file
@ -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…
Reference in New Issue
Block a user