Add software_16 cache.

SVN revision: 32169
This commit is contained in:
Gustavo Sverzut Barbieri 2007-10-26 18:53:39 +00:00
parent 5482c36015
commit 55f6c5f046
5 changed files with 352 additions and 57 deletions

View File

@ -14,6 +14,7 @@ evas_engine.c \
evas_soft16.h \
evas_soft16_dither_mask.c \
evas_soft16_main.c \
evas_soft16_image_cache.c \
evas_soft16_image_unscaled.c \
evas_soft16_image_scaled_sampled.c \
evas_soft16_font.c \
@ -32,6 +33,7 @@ evas_engine.c \
evas_soft16.h \
evas_soft16_dither_mask.c \
evas_soft16_main.c \
evas_soft16_image_cache.c \
evas_soft16_image_unscaled.c \
evas_soft16_image_scaled_sampled.c \
evas_soft16_font.c \

View File

@ -491,16 +491,23 @@ eng_image_data_get(void *data, void *image, int to_write, DATA32 **image_data)
{
Soft16_Image *im_new;
im_new = soft16_image_new(im->w, im->h, im->stride, im->have_alpha, im->pixels, 1);
if (!im_new) return im;
im_new = soft16_image_new(im->w, im->h, im->stride, im->have_alpha,
im->pixels, 1);
if (!im_new)
{
if (image_data) *image_data = NULL;
return im;
}
soft16_image_free(im);
im = im_new;
}
if (im->cache_key)
soft16_image_cache_del(im);
}
if (image_data) *image_data = (DATA32 *) im->pixels;
return image;
return im;
}
static void *
@ -532,23 +539,19 @@ eng_image_draw(void *data, void *context, void *surface, void *image, int src_x,
static void
eng_image_cache_flush(void *data)
{
int tmp_size;
tmp_size = evas_common_image_get_cache();
evas_common_image_set_cache(0);
evas_common_image_set_cache(tmp_size);
soft16_image_cache_flush();
}
static void
eng_image_cache_set(void *data, int bytes)
{
evas_common_image_set_cache(bytes);
soft16_image_cache_size_set(bytes);
}
static int
eng_image_cache_get(void *data)
{
return evas_common_image_get_cache();
return soft16_image_cache_size_get();
}
static void *

View File

@ -58,6 +58,9 @@
#define pld(addr, off)
#endif /* __ARMEL__ */
#define IMG_BYTE_SIZE(stride, height, has_alpha) \
((stride) * (height) * (!(has_alpha) ? 2 : 3))
typedef struct _Soft16_Image Soft16_Image;
struct _Soft16_Image
@ -75,9 +78,10 @@ struct _Soft16_Image
Evas_Image_Load_Opts lo; // load options
const char *cache_key;
unsigned char have_alpha : 1; // 1 if we have halpha
unsigned char free_pixels : 1; // 1 if pixels should be freed
unsigned char free_alpha : 1; // 1 if alpha mask should be freed
};
/**
@ -85,6 +89,7 @@ struct _Soft16_Image
*/
Soft16_Image *soft16_image_new(int w, int h, int stride, int have_alpha, DATA16 *pixels, int copy);
void soft16_image_free(Soft16_Image *im);
void soft16_image_destroy(Soft16_Image *im);
Soft16_Image *soft16_image_load(const char *file, const char *key, int *error, Evas_Image_Load_Opts *lo);
void soft16_image_load_data(Soft16_Image *im);
void soft16_image_draw(Soft16_Image *src, Soft16_Image *dst, RGBA_Draw_Context *dc, int src_region_x, int src_region_y, int src_region_w, int src_region_h, int dst_region_x, int dst_region_y, int dst_region_w, int dst_region_h, int smooth);
@ -99,6 +104,17 @@ void soft16_image_draw_scaled_sampled(Soft16_Image *src, Soft16_Image *dst, RGBA
void soft16_image_convert_from_rgb(Soft16_Image *im, const DATA32 *src);
void soft16_image_convert_from_rgba(Soft16_Image *im, const DATA32 *src);
/**
* Image cache (evas_soft16_image_cache.c)
*/
void soft16_image_cache_flush(void);
int soft16_image_cache_size_get(void);
void soft16_image_cache_size_set(int limit);
Soft16_Image *soft16_image_cache_get(const char *cache_key);
void soft16_image_cache_put(Soft16_Image *im);
void soft16_image_cache_add(Soft16_Image *im, const char *cache_key);
void soft16_image_cache_del(Soft16_Image *im);
/**
* Rectangle (evas_soft16_rectangle.c)

View File

@ -0,0 +1,294 @@
/**
* Software 16 image cache system.
*
* Images backed by files are registered in a hash table (_soft16_cache.hash)
* for fast lookup of existing, thus avoiding duplication of data.
*
* Images considered live, or in use, are those with im->references >
* 0, these are NOT accounted in the cache limits, but they're still
* available in the hash table for lookup.
*
* As soon as some image is not in use anymore (im->references == 0),
* it's put into cache and appended to a linked list
* (_soft16_cache.lru) if it fit into limits, if required, older
* elements will be removed to make room.
*
* Images that are tainted (pixels were modified), are removed from
* cache.
*
* Just payload size (pixels, with alpha) are accounted in
* calculation, shallow images (without real data), are accounted as
* regular images.
*/
#include "evas_soft16.h"
#include <assert.h>
#ifndef DEBUG_CACHE
//#define DEBUG_CACHE
#endif
#ifndef DEBUG_COLOR
#define DEBUG_COLOR
#endif
#ifdef DEBUG_COLOR
#define COLOR_CLEAR "\033[0m"
#define COLOR_RED "\033[31m"
#define COLOR_GREEN "\033[32m"
#define COLOR_YELLOW "\033[33m"
#define COLOR_BLUE "\033[34m"
#define COLOR_MAGENTA "\033[35m"
#define COLOR_CYAN "\033[36m"
#else
#define COLOR_CLEAR ""
#define COLOR_RED ""
#define COLOR_GREEN ""
#define COLOR_YELLOW ""
#define COLOR_BLUE ""
#define COLOR_MAGENTA ""
#define COLOR_CYAN ""
#endif
#ifdef DEBUG_CACHE
static inline void
_dbg(const char *file, int line, const char *func, const char *color, const char *fmt, ...)
{
char msg[4096];
va_list args;
va_start(args, fmt);
vsnprintf(msg, sizeof(msg), fmt, args);
va_end(args);
fprintf(stderr, "DBG: %s%s:%d:%s"COLOR_CLEAR" %s\n", color, file, line, func, msg);
}
#define dbg(fmt, ...) \
_dbg(__FILE__, __LINE__, __FUNCTION__, COLOR_CLEAR, fmt, ##__VA_ARGS__)
#define dbg_color(col, fmt, ...) \
_dbg(__FILE__, __LINE__, __FUNCTION__, col, fmt, ##__VA_ARGS__)
#else
#define dbg(fmt, ...) do {} while (0)
#define dbg_color(col, fmt, ...) do {} while (0)
#endif
typedef struct _Soft16_Cache Soft16_Cache;
struct _Soft16_Cache {
Evas_Hash *hash; /**< every known image */
Evas_List *lru; /**< unused images, from older to newer */
int limit; /**< maximum size in bytes to keep with unused images */
int used; /**< current amount in bytes used by unused images */
};
static Soft16_Cache _soft16_cache = {NULL, NULL, 0, 0};
static inline void
soft16_image_cache_destroy_image(Soft16_Image *im)
{
_soft16_cache.hash = evas_hash_del(_soft16_cache.hash, im->cache_key, im);
evas_stringshare_del(im->cache_key);
soft16_image_destroy(im);
}
void
soft16_image_cache_flush(void)
{
Evas_List *n;
dbg_color(COLOR_RED, "cache flush");
for (n = _soft16_cache.lru; n != NULL; n = n->next)
soft16_image_cache_destroy_image(n->data);
_soft16_cache.lru = evas_list_free(_soft16_cache.lru);
_soft16_cache.used = 0;
}
static int
soft16_image_cache_image_size_get(Soft16_Image *im)
{
return IMG_BYTE_SIZE(im->stride, im->h, im->have_alpha);
}
static void
soft16_image_cache_free(int bytes)
{
Evas_List *n;
dbg_color(COLOR_RED, "BEG cache free %d bytes, used %d of %d...",
bytes, _soft16_cache.used, _soft16_cache.limit);
if (bytes >= _soft16_cache.used)
{
soft16_image_cache_flush();
return;
}
n = _soft16_cache.lru;
while (bytes > 0 && n != NULL)
{
Soft16_Image *im;
int size;
im = n->data;
size = soft16_image_cache_image_size_get(im);
bytes -= size;
_soft16_cache.used -= size;
soft16_image_cache_destroy_image(im);
n = _soft16_cache.lru = evas_list_remove_list(_soft16_cache.lru, n);
}
assert(_soft16_cache.used >= 0);
dbg_color(COLOR_RED, "END cache is now %d of %d",
_soft16_cache.used, _soft16_cache.limit);
}
int
soft16_image_cache_size_get(void)
{
return _soft16_cache.limit;
}
void
soft16_image_cache_size_set(int limit)
{
dbg("old: %d, new: %d, used: %d",
_soft16_cache.limit, limit, _soft16_cache.used);
if (limit < _soft16_cache.used && limit >= 0)
soft16_image_cache_free(_soft16_cache.used - limit);
_soft16_cache.limit = limit;
}
static void
soft16_image_cache_lru_del(Soft16_Image *im)
{
Evas_List *n;
dbg_color(COLOR_YELLOW, "im=%p\n", im);
for (n = _soft16_cache.lru; n != NULL; n = n->next)
if (n->data == im)
break;
if (!n)
return;
_soft16_cache.lru = evas_list_remove_list(_soft16_cache.lru, n);
_soft16_cache.used -= soft16_image_cache_image_size_get(im);
dbg_color(COLOR_YELLOW, " found, remove from cache, stats %d of %d",
_soft16_cache.used, _soft16_cache.limit);
}
static void
soft16_image_cache_lru_add(Soft16_Image *im)
{
_soft16_cache.lru = evas_list_append(_soft16_cache.lru, im);
_soft16_cache.used += soft16_image_cache_image_size_get(im);
dbg_color(COLOR_YELLOW, " add to cache, stats %d of %d",
_soft16_cache.used, _soft16_cache.limit);
}
#define STAT_GAP 2
Soft16_Image *
soft16_image_cache_get(const char *cache_key)
{
Soft16_Image *im;
dbg_color(COLOR_GREEN, "cache_key=[%s]", cache_key);
im = evas_hash_find(_soft16_cache.hash, cache_key);
if (im)
{
time_t t;
t = time(NULL);
if ((t - im->laststat) > STAT_GAP)
{
struct stat st;
if (stat(im->file, &st) < 0) return NULL;
if (st.st_mtime != im->timestamp) return NULL;
im->laststat = t;
}
dbg_color(COLOR_GREEN, " found %p, [%s][%s] %dx%d, refernces=%d",
im, im->file, im->key, im->w, im->h, im->references);
if (im->references == 0)
soft16_image_cache_lru_del(im);
im->references++;
}
else
dbg_color(COLOR_GREEN, "not found!");
return im;
}
void
soft16_image_cache_put(Soft16_Image *im)
{
int size;
assert(im);
assert(im->cache_key);
assert(im->references == 0);
dbg_color(COLOR_CYAN, "BEG im=%p, cache_key=%s", im, im->cache_key);
size = soft16_image_cache_image_size_get(im);
dbg(" sizes: im=%d, used=%d, limit=%d", size,
_soft16_cache.used, _soft16_cache.limit);
if (size + _soft16_cache.used > _soft16_cache.limit)
{
if (size > _soft16_cache.limit)
{
dbg_color(COLOR_CYAN, " image doesn't fit in cache, destroy");
soft16_image_cache_del(im);
soft16_image_destroy(im);
return;
}
soft16_image_cache_free(_soft16_cache.used - size);
dbg(" freed cache space, now %d available",
_soft16_cache.limit - _soft16_cache.used);
}
soft16_image_cache_lru_add(im);
dbg_color(COLOR_CYAN, "END cache stats: used=%d, limit=%d",
_soft16_cache.used, _soft16_cache.limit);
}
void
soft16_image_cache_add(Soft16_Image *im, const char *cache_key)
{
assert(im);
assert(cache_key);
assert(im->cache_key == NULL);
dbg_color(COLOR_MAGENTA, "im=%p, cache_key=%s", im, cache_key);
im->cache_key = evas_stringshare_add(cache_key);
_soft16_cache.hash = evas_hash_add(_soft16_cache.hash, im->cache_key, im);
}
void
soft16_image_cache_del(Soft16_Image *im)
{
assert(im);
assert(im->cache_key != NULL);
dbg_color(COLOR_MAGENTA, "im=%p, cache_key=%s", im, im->cache_key);
_soft16_cache.hash = evas_hash_del(_soft16_cache.hash, im->cache_key, im);
soft16_image_cache_lru_del(im);
evas_stringshare_del(im->cache_key);
im->cache_key = NULL;
}

View File

@ -1,10 +1,5 @@
#include "evas_soft16.h"
#define IMG_BYTE_SIZE(stride, height, has_alpha) \
((stride) * (height) * (!(has_alpha) ? 2 : 3))
static Evas_Hash *_soft16_image_cache_hash = NULL;
static inline int
_calc_stride(int w)
{
@ -109,50 +104,28 @@ soft16_image_cache_key_from_img(const Soft16_Image *im, char *buf,
void
soft16_image_free(Soft16_Image *im)
{
if (!im) return;
if (!im)
return;
im->references--;
if (im->references > 0) return;
if (im->file)
{
char buf[4096 + 1024];
soft16_image_cache_key_from_img(im, buf, sizeof(buf));
_soft16_image_cache_hash = evas_hash_del(_soft16_image_cache_hash,
buf, im);
}
if (im->references > 0)
return;
if (im->cache_key)
soft16_image_cache_put(im);
else
soft16_image_destroy(im);
}
void
soft16_image_destroy(Soft16_Image *im)
{
if (im->file) evas_stringshare_del(im->file);
if (im->key) evas_stringshare_del(im->key);
if (im->free_pixels) free(im->pixels);
free(im);
}
#define STAT_GAP 2
static Soft16_Image *
soft16_image_cache_get(const char *cache_key)
{
Soft16_Image *im;
im = evas_hash_find(_soft16_image_cache_hash, cache_key);
if (im)
{
time_t t;
t = time(NULL);
if ((t - im->laststat) > STAT_GAP)
{
struct stat st;
if (stat(im->file, &st) < 0) return NULL;
if (st.st_mtime != im->timestamp) return NULL;
im->laststat = t;
}
im->references++;
}
return im;
}
static Soft16_Image *
soft16_image_load_new(const char *file, const char *key,
Evas_Image_Load_Opts *lo)
@ -192,13 +165,17 @@ soft16_image_load(const char *file, const char *key, int *error,
char buf[4096 + 1024];
*error = 0;
if (!file) return NULL;
if (!file)
return NULL;
soft16_image_cache_key(lo, key, file, buf, sizeof(buf));
im = soft16_image_cache_get(buf);
if (im) return im;
if (im)
return im;
im = soft16_image_load_new(file, key, lo);
if (im) _soft16_image_cache_hash = evas_hash_add(_soft16_image_cache_hash, buf, im);
if (im)
soft16_image_cache_add(im, buf);
return im;
}
@ -453,7 +430,7 @@ soft16_image_alpha_set(Soft16_Image *im, int have_alpha)
if (im->have_alpha == have_alpha) return im;
im->have_alpha = have_alpha;
if ((im->pixels) && (im->free_pixels))
if ((im->pixels) && (im->free_pixels) && (im->references == 1))
{
int size;
@ -469,6 +446,9 @@ soft16_image_alpha_set(Soft16_Image *im, int have_alpha)
im->alpha = (DATA8*)(im->pixels + size);
memset(im->alpha, 0x1f, size);
}
if (im->cache_key)
soft16_image_cache_remove(im);
return im;
}
else