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;