diff --git a/text_rendering/Makefile b/text_rendering/Makefile index 8ecf368..873f226 100644 --- a/text_rendering/Makefile +++ b/text_rendering/Makefile @@ -1,6 +1,6 @@ CC = gcc LDFLAGS = -lm -lgrapheme -lSDL2 -lGLEW -lGL -CFLAGS = -ggdb3 -Wall -Wextra -pedantic -fno-omit-frame-pointer +CFLAGS = -ggdb3 -Wall -Wextra -pedantic -std=c11 -Wno-unused-function -fno-omit-frame-pointer .PHONY: clean all all: test @@ -12,5 +12,5 @@ ren.o: ren.c util.h font.h ren.h generic_stack.h util.o: util.c util.h test: font.o main.o ren.o util.o ${CC} ${LDFLAGS} -o test font.o main.o ren.o util.o -clean: +clean: rm -f test font.o main.o ren.o util.o diff --git a/text_rendering/font.c b/text_rendering/font.c index a9b5611..400817e 100644 --- a/text_rendering/font.c +++ b/text_rendering/font.c @@ -62,7 +62,7 @@ int font_load(struct font_atlas *atlas, const char *path, int size) dump_file(path, &(atlas->file), &(atlas->file_size)); err = stbtt_InitFont(&(PRIV(atlas)->stb), (unsigned char *)atlas->file, 0); - ERROR(err == 0, -1); + if (err == 0) return -1; int ascent, descent, linegap, baseline; int x0,y0,x1,y1; diff --git a/text_rendering/generic_cache.h b/text_rendering/generic_cache.h index 908d32f..3d0c067 100644 --- a/text_rendering/generic_cache.h +++ b/text_rendering/generic_cache.h @@ -5,26 +5,26 @@ #include "generic_hash.h" #define CACHE_SIZE 512 -#define CACHE_NCYCLES (CACHE_SIZE/2) +#define CACHE_NCYCLES (CACHE_SIZE*2/3) #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_BSET(b, x) b[(x)>>6] |= (uint64_t)1<<((x)&63) +#define CACHE_BTEST(b, x) (b[(x)>>6]&((uint64_t)1<<((x)&63))) // FIXME: this cache implementation is not really generic since it expects an unsigned // as the code and not a generic type -// FIXME: when resetting the bitmap all references to overwritten elements are -// invalidated, this really means that -// 1) we get data mismatches -// 2) this is not a good LRU cache -#define CACHE_SET(c, x) \ +#define CACHE_USED(c, x) \ { \ if (++(c->cycles) > CACHE_NCYCLES) { \ - CACHE_BRESET(c->bitmap); \ - c->cycles=0;} \ - CACHE_BSET(c->bitmap, x); \ + for (int i = 0; i < CACHE_BSIZE; i++) { \ + c->present[i] &= c->used[i]; \ + c->used[i] = 0; \ + } \ + c->cycles = 0; \ + } \ + CACHE_BSET(c->used, x); \ } @@ -33,18 +33,21 @@ HASH_DECL(name##table, uint32_t, uint32_t, hashfn, cmpfn) \ struct name { \ struct name##table_ref *table; \ type *array; \ - uint64_t *bitmap; \ + uint64_t *present, *used; \ int cycles; \ }; \ \ \ +/* FIXME: check for allocation errors */ \ struct name name##_init(void) \ { \ struct name##table_ref *t = name##table_create(CACHE_SIZE); \ type *a = malloc(sizeof(type)*CACHE_SIZE); \ - uint64_t *b = malloc(sizeof(uint64_t)*CACHE_BSIZE); \ - CACHE_BRESET(b); \ - return (struct name){ .table = t, .array = a, .bitmap = b, 0}; \ + uint64_t *p = malloc(sizeof(uint64_t)*CACHE_BSIZE); \ + uint64_t *u = malloc(sizeof(uint64_t)*CACHE_BSIZE); \ + CACHE_BRESET(p); \ + CACHE_BRESET(u); \ + return (struct name){.table=t, .array=a, .present=p, .used=u, 0}; \ } \ \ \ @@ -53,7 +56,8 @@ void name##_free(struct name *cache) \ if (cache) { \ name##table_destroy(cache->table); \ free(cache->array); \ - free(cache->bitmap); \ + free(cache->present); \ + free(cache->used); \ } \ } \ \ @@ -66,21 +70,25 @@ const type * name##_search(struct name *cache, uint32_t code) \ /* MISS */ \ if (!r || !cmpfn(code, r->code)) \ return NULL; \ + /* MISS, the data is not valid (not present) */ \ + if (!CACHE_BTEST(cache->present, r->data)) \ + return NULL; \ /* HIT, set as recently used */ \ - CACHE_SET(cache, r->data); \ + CACHE_USED(cache, r->data); \ return (&cache->array[r->data]); \ } \ \ \ +/* Look for a free spot in the present bitmap and return its index */ \ int name##_get(struct name *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]); \ + if (cache->present[b] == 0) x = 64; \ + else x = __builtin_clzll(cache->present[b]); \ x = 64-x; \ - if (!CACHE_BTEST(cache->bitmap, x+64*b)) \ + if (!CACHE_BTEST(cache->present, x+64*b)) \ return x+64*b; \ } \ return 0; \ @@ -93,9 +101,12 @@ const type * name##_insert(struct name *cache, const type *g, uint32_t code, int 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)) \ + if (x < 0 || CACHE_BTEST(cache->present, x)) \ return NULL; \ - CACHE_SET(cache, x) \ + /* Set used and present */ \ + CACHE_USED(cache, x) \ + CACHE_BSET(cache->present, x); \ + CACHE_BSET(cache->used, x); \ spot = &(cache->array[x]); \ *spot = *g; \ struct name##table_entry e = { .code = code, .data = x}; \ diff --git a/text_rendering/genmake.sh b/text_rendering/genmake.sh index 3bcf991..3bb1ce3 100755 --- a/text_rendering/genmake.sh +++ b/text_rendering/genmake.sh @@ -16,7 +16,8 @@ rm -f objlist cat > Makefile << EOF CC = gcc LDFLAGS = -lm -lgrapheme -lSDL2 -lGLEW -lGL -CFLAGS = -ggdb3 -Wall -Wextra -pedantic -fno-omit-frame-pointer +CFLAGS = -ggdb3 -Wall -Wextra -pedantic -std=c11 \ +-Wno-unused-function -fno-omit-frame-pointer .PHONY: clean all all: test @@ -30,7 +31,7 @@ done mainrule='test: ' linkcmd=' ${CC} ${LDFLAGS} -o test ' -cleanrule='clean: +cleanrule='clean: rm -f test ' while IFS="" read -r line; do mainrule="$mainrule $line" diff --git a/text_rendering/util.h b/text_rendering/util.h index fcfdbaa..6712805 100644 --- a/text_rendering/util.h +++ b/text_rendering/util.h @@ -1,8 +1,7 @@ #ifndef _UTIL_H #define _UTIL_H - -#define ERROR(expr, ret, ...) if (expr) { __VA_ARGS__; return ret; } +#include void * emalloc(unsigned long int size); @@ -18,4 +17,18 @@ void print_byte(unsigned char byte); void stopwatch_start(void); double stopwatch_get(void); +#define TIME_SEC(f) \ +{ \ + stopwatch_start(); \ + f; \ + printf("\"%s\" took %f seconds", #f, stopwatch_get()); \ +} + +#define TIME_MS(f) \ +{ \ + stopwatch_start(); \ + f; \ + printf("\"%s\" took %f ms", #f, stopwatch_get()*1000.0f); \ +} + #endif