From 29ad172896b7da1dadb60299fc973fc1cfb10db2 Mon Sep 17 00:00:00 2001 From: "p.kosyh" Date: Wed, 6 Oct 2010 12:41:56 +0000 Subject: [PATCH] dangerous but cool commit. Normal word cache. --- src/sdl-instead/cache.c | 112 ++++++++++++++++++++++++++++----- src/sdl-instead/cache.h | 2 +- src/sdl-instead/graphics.c | 124 +++++++++++++++++++++++++++++-------- src/sdl-instead/graphics.h | 5 +- 4 files changed, 199 insertions(+), 44 deletions(-) diff --git a/src/sdl-instead/cache.c b/src/sdl-instead/cache.c index 82d4ae7..5f8b0c6 100644 --- a/src/sdl-instead/cache.c +++ b/src/sdl-instead/cache.c @@ -3,22 +3,52 @@ #include "list.h" #include "cache.h" +#define HASH_SIZE 1023 + typedef struct { struct list_head list; int size; int max_size; cache_free_fn free_fn; + struct list_head hash[HASH_SIZE]; + struct list_head vhash[HASH_SIZE]; } __cache_t; typedef struct { struct list_head list; + struct list_head *hash; + struct list_head *vhash; char *name; void *data; - int free_it; + int used; } __cache_e_t; +typedef struct { + struct list_head list; + struct list_head *data; +} __hash_item_t; + +/* #define GOLDEN_RATIO_PRIME_32 0x9e370001UL */ +#include +static unsigned long hash_addr(void *p) +{ + return (long)p; +} +static u_int32_t hash_string(const char *str) +{ + u_int32_t hash = 0; + int i; + int len = strlen(str); + for (i = 0; i < len; i++) { + hash ^= str[i]; /* GOLDEN_RATIO_PRIME_32; */ + hash = (hash << 11) | (hash >> 21); + } + return hash; +} + cache_t cache_init(int size, cache_free_fn free_fn) { + int i = 0; __cache_t *c = malloc(sizeof(__cache_t)); if (!c) return NULL; @@ -26,6 +56,10 @@ cache_t cache_init(int size, cache_free_fn free_fn) c->size = 0; c->max_size = size; c->free_fn = free_fn; + for (i = 0; i < HASH_SIZE; i++) { + INIT_LIST_HEAD(&c->hash[i]); + INIT_LIST_HEAD(&c->vhash[i]); + } return (cache_t)c; } @@ -35,8 +69,12 @@ static void cache_e_free(cache_t cache, __cache_e_t *cc) if (!c) return; free(cc->name); - if (c->free_fn && cc->free_it) + if (c->free_fn && !cc->used) c->free_fn(cc->data); + list_del(cc->hash); + free(cc->hash); + list_del(cc->vhash); + free(cc->vhash); list_del((struct list_head*)cc); free(cc); } @@ -62,12 +100,14 @@ void cache_free(cache_t cache) static __cache_e_t *cache_lookup(cache_t cache, const char *name) { struct list_head *pos; + struct list_head *list; __cache_t *c = cache; __cache_e_t *cc; if (!c || !name) - return NULL; - list_for_each(pos, &c->list) { - cc = (__cache_e_t*) pos; + return NULL; + list = &c->hash[hash_string(name) % HASH_SIZE]; + list_for_each(pos, list) { + cc = (__cache_e_t*)((__hash_item_t*)pos)->data; if (!strcmp(cc->name, name)) return cc; } @@ -77,23 +117,29 @@ static __cache_e_t *cache_lookup(cache_t cache, const char *name) static __cache_e_t *cache_data(cache_t cache, void *p) { struct list_head *pos; + struct list_head *list; + __cache_t *c = cache; __cache_e_t *cc; if (!c || !p) return NULL; - list_for_each(pos, &c->list) { - cc = (__cache_e_t*) pos; + list = &c->vhash[hash_addr(p) % HASH_SIZE]; + list_for_each(pos, list) { + cc = (__cache_e_t*)((__hash_item_t*)pos)->data; if (p == cc->data) return cc; } return NULL; } -void cache_forget(cache_t cache, void *p) +int cache_forget(cache_t cache, void *p) { __cache_e_t *cc = cache_data(cache, p); - if (cc) - cc->free_it = 1; + if (cc && cc->used) { + cc->used --; + return 0; + } + return -1; } void *cache_get(cache_t cache, const char *name) @@ -105,7 +151,7 @@ void *cache_get(cache_t cache, const char *name) cc = cache_lookup(cache, name); if (!cc) return NULL; - cc->free_it = 0; /* need again! */ + cc->used ++; /* need again! */ list_move((struct list_head*)cc, &c->list); /* first place */ // printf("%p\n", cc->data); return cc->data; @@ -126,7 +172,10 @@ int cache_have(cache_t cache, void *p) int cache_add(cache_t cache, const char *name, void *p) { __cache_e_t *cc; + __hash_item_t *hh; + __hash_item_t *vh; __cache_t *c = cache; + struct list_head *list; if (!c || !name) return -1; cc = cache_lookup(cache, name); @@ -135,20 +184,51 @@ int cache_add(cache_t cache, const char *name, void *p) cc = malloc(sizeof(__cache_e_t)); if (!cc) return -1; + hh = malloc(sizeof(__hash_item_t)); + if (!hh) { + free(cc); + return -1; + } + + vh = malloc(sizeof(__hash_item_t)); + if (!vh) { + free(hh); + free(cc); + return -1; + } + cc->name = strdup(name); if (!cc->name) { + free(vh); + free(hh); free(cc); return -1; } cc->data = p; - cc->free_it = 0; + cc->used = 1; + cc->hash = (struct list_head*) hh; + cc->vhash = (struct list_head*) vh; + list_add((struct list_head*)cc, &c->list); + list = &c->hash[hash_string(name) % HASH_SIZE]; + hh->data = (struct list_head*)cc; + list_add((struct list_head*)hh, list); + + list = &c->vhash[hash_addr(p) % HASH_SIZE]; + vh->data = (struct list_head*)cc; + list_add((struct list_head*)vh, list); + c->size ++; // printf("size: %d:%s\n", c->size, name); - if (c->size > c->max_size) { - c->size --; - cache_e_free(cache, (__cache_e_t *)c->list.prev); + + while (c->size > c->max_size) { + __cache_e_t *cc; + cc = (__cache_e_t *)c->list.prev; + if (!cc->used) { + c->size --; + cache_e_free(cache, (__cache_e_t *)c->list.prev); + } else + break; } return 0; } - diff --git a/src/sdl-instead/cache.h b/src/sdl-instead/cache.h index 679c24b..5615b88 100644 --- a/src/sdl-instead/cache.h +++ b/src/sdl-instead/cache.h @@ -6,7 +6,7 @@ typedef void (*cache_free_fn)(void *p); extern cache_t cache_init(int size, cache_free_fn); extern void cache_free(cache_t cache); -extern void cache_forget(cache_t cache, void *p); +extern int cache_forget(cache_t cache, void *p); extern void cache_zap(cache_t cache); extern void *cache_get(cache_t cache, const char *name); extern int cache_add(cache_t cache, const char *name, void *p); diff --git a/src/sdl-instead/graphics.c b/src/sdl-instead/graphics.c index 0511e6c..eb58fc3 100644 --- a/src/sdl-instead/graphics.c +++ b/src/sdl-instead/graphics.c @@ -162,6 +162,7 @@ static struct { {"yellowgreen", 0x9acd32}, {NULL, 0x0}, }; + int gfx_parse_color ( const char *spec, color_t *def) @@ -1236,22 +1237,6 @@ struct word *word_new(const char *str) return w; } -void word_free(struct word *word) -{ - if (!word) - return; -// if (word->img) -// gfx_free_image(word->img); - if (word->word) - free(word->word); - if (word->prerend) - SDL_FreeSurface(word->prerend); - if (word->hlprerend) - SDL_FreeSurface(word->hlprerend); - word->hlprerend = word->prerend = NULL; - free(word); -} - struct line { int y; int h; @@ -1265,6 +1250,7 @@ struct line { struct layout *layout; }; + int word_geom(word_t v, int *x, int *y, int *w, int *h) { int xx, yy, ww, hh; @@ -1389,6 +1375,8 @@ void line_align(struct line *line, int width, int style, int nl) return line_right(line, width); } +void word_free(struct word *word); + void line_free(struct line *line) { struct word *w; @@ -1474,6 +1462,8 @@ struct layout { int scnt[4]; int lstyle; cache_t img_cache; + cache_t prerend_cache; + cache_t hlprerend_cache; }; struct word_list { @@ -1498,6 +1488,28 @@ struct textbox { int h; }; +void word_free(struct word *word) +{ + if (!word) + return; +// if (word->img) +// gfx_free_image(word->img); + if (word->word) + free(word->word); + + if (word->prerend) { + cache_forget(word->line->layout->prerend_cache, word->prerend); +// SDL_FreeSurface(word->prerend); + } + + if (word->hlprerend) { + cache_forget(word->line->layout->hlprerend_cache, word->hlprerend); +// SDL_FreeSurface(word->hlprerend); + } + word->hlprerend = word->prerend = NULL; + free(word); +} + struct xref *xref_new(char *link) { struct xref *p; @@ -1613,6 +1625,11 @@ void layout_add_xref(struct layout *layout, struct xref *xref) return; } +void sdl_surface_free(void *p) +{ + SDL_FreeSurface(p); +} + struct layout *layout_new(fnt_t fn, int w, int h) { struct layout *l; @@ -1634,6 +1651,8 @@ struct layout *layout_new(fnt_t fn, int w, int h) l->acol = gfx_col(255, 0, 0); l->box = NULL; l->img_cache = cache_init(GFX_CACHE_SIZE, gfx_free_image); + l->prerend_cache = cache_init(WORD_CACHE_SIZE, sdl_surface_free); + l->hlprerend_cache = cache_init(LINK_CACHE_SIZE, sdl_surface_free); memset(l->scnt, 0, sizeof(l->scnt)); memset(l->saved_align, 0, sizeof(l->saved_align)); memset(l->saved_valign, 0, sizeof(l->saved_valign)); @@ -1731,7 +1750,11 @@ void txt_layout_free(layout_t lay) _txt_layout_free(lay); if (lay) { cache_free(layout->img_cache); + cache_free(layout->prerend_cache); + cache_free(layout->hlprerend_cache); layout->img_cache = NULL; + layout->prerend_cache = NULL; + layout->hlprerend_cache = NULL; free(lay); } } @@ -2068,37 +2091,86 @@ void txt_layout_link_style(layout_t lay, int style) layout->lstyle = style; } +static char *word_cache_string(struct word *w, u_int32_t style) +{ + char *p; + int len = 0; + len = (w->word)?strlen(w->word):0; + len += 16; + p = malloc(len); + if (!p) + return NULL; + sprintf(p, "%s-%08x", (w->word)?w->word:"", style); + return p; +} + static void word_render(struct layout *layout, struct word *word, int x, int y) { + char *wc = NULL; SDL_Surface *s; + SDL_Surface *prerend = NULL; + SDL_Surface *hlprerend = NULL; SDL_Color fgcol = { .r = layout->col.r, .g = layout->col.g, .b = layout->col.b }; SDL_Color lcol = { .r = layout->lcol.r, .g = layout->lcol.g, .b = layout->lcol.b }; SDL_Color acol = { .r = layout->acol.r, .g = layout->acol.g, .b = layout->acol.b }; + u_int32_t style; - if (word->xref && !word->style) + if (!word->xref) { + style = (fgcol.r << 24) + (fgcol.g << 16) + (fgcol.b << 8); + } else if (word->xref->active) { + style = (acol.r << 24) + (acol.g << 16) + (acol.b << 8); + } else { + style = (lcol.r << 24) + (lcol.g << 16) + (lcol.b << 8); + } + + if (word->xref && !word->style) { TTF_SetFontStyle((TTF_Font *)(layout->fn), layout->lstyle); - else + wc = word_cache_string(word, layout->lstyle | style); + } else { TTF_SetFontStyle((TTF_Font *)(layout->fn), word->style); - + wc = word_cache_string(word, word->style | style); + } + if (!wc) + return; + if (!word->xref) { if (!word->prerend) { - word->prerend = TTF_RenderUTF8_Blended((TTF_Font *)(layout->fn), word->word, fgcol); - word->prerend = gfx_display_alpha(word->prerend); + prerend = cache_get(layout->prerend_cache, wc); + if (!prerend) { + word->prerend = TTF_RenderUTF8_Blended((TTF_Font *)(layout->fn), word->word, fgcol); + word->prerend = gfx_display_alpha(word->prerend); + cache_add(layout->prerend_cache, wc, word->prerend); + } else { + word->prerend = prerend; + } } s = word->prerend; } else if (word->xref->active) { if (!word->hlprerend) { - word->hlprerend = TTF_RenderUTF8_Blended((TTF_Font *)(layout->fn), word->word, acol); - word->hlprerend = gfx_display_alpha(word->hlprerend); + hlprerend = cache_get(layout->hlprerend_cache, wc); + if (!hlprerend) { + word->hlprerend = TTF_RenderUTF8_Blended((TTF_Font *)(layout->fn), word->word, acol); + word->hlprerend = gfx_display_alpha(word->hlprerend); + cache_add(layout->hlprerend_cache, wc, word->hlprerend); + } else { + word->hlprerend = hlprerend; + } } s = word->hlprerend; } else { if (!word->prerend) { - word->prerend = TTF_RenderUTF8_Blended((TTF_Font *)(layout->fn), word->word, lcol); - word->prerend = gfx_display_alpha(word->prerend); + prerend = cache_get(layout->prerend_cache, wc); + if (!prerend) { + word->prerend = TTF_RenderUTF8_Blended((TTF_Font *)(layout->fn), word->word, lcol); + word->prerend = gfx_display_alpha(word->prerend); + cache_add(layout->prerend_cache, wc, word->prerend); + } else { + word->prerend = prerend; + } } s = word->prerend; } + free(wc); if (!s) return; gfx_draw(s, x, y); @@ -3195,7 +3267,7 @@ int gfx_init(void) if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) { fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError()); return -1; - } + } return 0; } diff --git a/src/sdl-instead/graphics.h b/src/sdl-instead/graphics.h index c1f0f33..21b5f77 100644 --- a/src/sdl-instead/graphics.h +++ b/src/sdl-instead/graphics.h @@ -1,10 +1,13 @@ #ifndef __GRAPHICS_H__ #define __GRAPHICS_H__ -#define GFX_CACHE_SIZE 32 +#define GFX_CACHE_SIZE 64 #define GFX_MAX_CACHED_W 256 #define GFX_MAX_CACHED_H 256 +#define WORD_CACHE_SIZE 1024 +#define LINK_CACHE_SIZE 64 + typedef void* gtimer_t; typedef void* img_t; typedef void* fnt_t;