377 lines
7.6 KiB
C
377 lines
7.6 KiB
C
|
#include "evas_common.h"
|
||
|
|
||
|
static Evas_Hash * images = NULL;
|
||
|
static Evas_Object_List * cache = NULL;
|
||
|
static int cache_size = 0;
|
||
|
static int cache_usage = 0;
|
||
|
|
||
|
#if 0
|
||
|
int
|
||
|
image_debug_hash_cb(Evas_Hash *hash, const char *key, void *data, void *fdata)
|
||
|
{
|
||
|
RGBA_Image *im;
|
||
|
|
||
|
im = data;
|
||
|
printf(" [%i] %3ix%3i %6i %6i [%2x %2x] %i %s\n",
|
||
|
im->references,
|
||
|
im->image->w, im->image->h,
|
||
|
im->image->w * im->image->h * 4,
|
||
|
image_ram_usage(im),
|
||
|
im->flags & RGBA_IMAGE_IS_DIRTY,
|
||
|
im->flags & RGBA_IMAGE_INDEXED,
|
||
|
im->info.format,
|
||
|
im->info.file);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
image_debug(void)
|
||
|
{
|
||
|
Evas_Object_List *l;
|
||
|
|
||
|
printf("active images:\n");
|
||
|
evas_hash_foreach(images, image_debug_hash_cb, NULL);
|
||
|
printf("cache size: %i\n", cache_size);
|
||
|
printf("cache usage: %i\n", cache_usage);
|
||
|
printf("cached images:\n");
|
||
|
for (l = cache; l; l = l->next)
|
||
|
{
|
||
|
RGBA_Image *im;
|
||
|
|
||
|
im = l;
|
||
|
printf(" [%i] %3ix%3i %6i %6i [%2x %2x] %i %s\n",
|
||
|
im->references,
|
||
|
im->image->w, im->image->h,
|
||
|
im->image->w * im->image->h * 4,
|
||
|
image_ram_usage(im),
|
||
|
im->flags & RGBA_IMAGE_IS_DIRTY,
|
||
|
im->flags & RGBA_IMAGE_INDEXED,
|
||
|
im->info.format,
|
||
|
im->info.file);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
void
|
||
|
image_init(void)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
RGBA_Surface *
|
||
|
image_surface_new(void)
|
||
|
{
|
||
|
RGBA_Surface *is;
|
||
|
|
||
|
is = calloc(1, sizeof(RGBA_Surface));
|
||
|
return is;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
image_surface_free(RGBA_Surface *is)
|
||
|
{
|
||
|
image_surface_dealloc(is);
|
||
|
free(is);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
image_surface_alloc(RGBA_Surface *is)
|
||
|
{
|
||
|
is->data = malloc(is->w * is->h * sizeof(DATA32));
|
||
|
}
|
||
|
|
||
|
void
|
||
|
image_surface_dealloc(RGBA_Surface *is)
|
||
|
{
|
||
|
if ((is->data) && (!is->no_free))
|
||
|
{
|
||
|
free(is->data);
|
||
|
is->data = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
RGBA_Image *
|
||
|
image_create(int w, int h)
|
||
|
{
|
||
|
RGBA_Image *im;
|
||
|
|
||
|
im = image_new();
|
||
|
if (!im) return NULL;
|
||
|
im->image = image_surface_new();
|
||
|
if (!im->image)
|
||
|
{
|
||
|
image_free(im);
|
||
|
return NULL;
|
||
|
}
|
||
|
im->image->w = w;
|
||
|
im->image->h = h;
|
||
|
image_surface_alloc(im->image);
|
||
|
if (!im->image->data)
|
||
|
{
|
||
|
image_free(im);
|
||
|
return NULL;
|
||
|
}
|
||
|
im->flags = RGBA_IMAGE_IS_DIRTY;
|
||
|
im->references = 1;
|
||
|
return im;
|
||
|
}
|
||
|
|
||
|
RGBA_Image *
|
||
|
image_new(void)
|
||
|
{
|
||
|
RGBA_Image *im;
|
||
|
|
||
|
im = calloc(1, sizeof(RGBA_Image));
|
||
|
if (!im) return NULL;
|
||
|
im->flags = RGBA_IMAGE_NOTHING;
|
||
|
return im;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
image_free(RGBA_Image *im)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
if (im->image) image_surface_free(im->image);
|
||
|
for (i = 0; i < im->mipmaps.num; i++)
|
||
|
{
|
||
|
if (im->mipmaps.levels[i])
|
||
|
image_surface_free(im->mipmaps.levels[i]);
|
||
|
}
|
||
|
if (im->mipmaps.levels) free(im->mipmaps.levels);
|
||
|
if (im->info.file) free(im->info.file);
|
||
|
if (im->info.key) free(im->info.key);
|
||
|
if (im->info.comment) free(im->info.comment);
|
||
|
free(im);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
image_ref(RGBA_Image *im)
|
||
|
{
|
||
|
im->references++;
|
||
|
if (im->references == 1) /* we were in cache - take us out */
|
||
|
{
|
||
|
image_uncache(im);
|
||
|
image_store(im);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
image_unref(RGBA_Image *im)
|
||
|
{
|
||
|
im->references--;
|
||
|
if (im->references <= 0) /* we were are now in cache - put us in */
|
||
|
{
|
||
|
image_unstore(im);
|
||
|
if ((cache_size > 0) &&
|
||
|
(!(im->flags & RGBA_IMAGE_IS_DIRTY)))
|
||
|
{
|
||
|
image_cache(im);
|
||
|
image_flush_cache();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
image_free(im);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
image_cache(RGBA_Image *im)
|
||
|
{
|
||
|
int ram;
|
||
|
|
||
|
if (im->flags & RGBA_IMAGE_INDEXED) return;
|
||
|
im->flags |= RGBA_IMAGE_INDEXED;
|
||
|
cache = evas_object_list_prepend(cache, im);
|
||
|
ram = image_ram_usage(im);
|
||
|
cache_usage += ram;
|
||
|
image_flush_cache();
|
||
|
}
|
||
|
|
||
|
void
|
||
|
image_uncache(RGBA_Image *im)
|
||
|
{
|
||
|
int ram;
|
||
|
|
||
|
if (!(im->flags & RGBA_IMAGE_INDEXED)) return;
|
||
|
im->flags &= ~RGBA_IMAGE_INDEXED;
|
||
|
cache = evas_object_list_remove(cache, im);
|
||
|
ram = image_ram_usage(im);
|
||
|
cache_usage -= ram;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
image_flush_cache(void)
|
||
|
{
|
||
|
Evas_Object_List *l, *l_next;
|
||
|
|
||
|
if (!cache) return;
|
||
|
if (cache_usage < cache_size) return;
|
||
|
|
||
|
for (l = cache->last; l;)
|
||
|
{
|
||
|
RGBA_Image *im;
|
||
|
|
||
|
l_next = l->prev;
|
||
|
im = (RGBA_Image *)l;
|
||
|
image_uncache(im);
|
||
|
image_free(im);
|
||
|
if (cache_usage <= cache_size) return;
|
||
|
l = l_next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
image_set_cache(int size)
|
||
|
{
|
||
|
cache_size = size;
|
||
|
image_flush_cache();
|
||
|
}
|
||
|
|
||
|
int
|
||
|
image_get_cache(void)
|
||
|
{
|
||
|
return cache_size;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
image_store(RGBA_Image *im)
|
||
|
{
|
||
|
char *key;
|
||
|
int l1, l2, l3;
|
||
|
char buf[256];
|
||
|
|
||
|
if (im->flags & RGBA_IMAGE_IS_DIRTY) return;
|
||
|
if (im->flags & RGBA_IMAGE_INDEXED) return;
|
||
|
if ((!im->info.file) && (!im->info.key)) return;
|
||
|
l1 = 0;
|
||
|
if (im->info.file) l1 = strlen(im->info.file);
|
||
|
l2 = 0;
|
||
|
if (im->info.key) l2 = strlen(im->info.key);
|
||
|
snprintf(buf, sizeof(buf), "%llx", im->timestamp);
|
||
|
l3 = strlen(buf);
|
||
|
key = malloc(l1 + 3 + l2 + 3 + l3 +1);
|
||
|
if (!key) return;
|
||
|
key[0] = 0;
|
||
|
if (im->info.file) strcpy(key, im->info.file);
|
||
|
strcat(key, "/:/");
|
||
|
if (im->info.key) strcat(key, im->info.key);
|
||
|
strcat(key, "/:/");
|
||
|
strcat(key, buf);
|
||
|
images = evas_hash_add(images, key, im);
|
||
|
free(key);
|
||
|
im->flags |= RGBA_IMAGE_INDEXED;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
image_unstore(RGBA_Image *im)
|
||
|
{
|
||
|
char *key;
|
||
|
int l1, l2, l3;
|
||
|
char buf[256];
|
||
|
|
||
|
if (!(im->flags & RGBA_IMAGE_INDEXED)) return;
|
||
|
if ((!im->info.file) && (!im->info.key)) return;
|
||
|
l1 = 0;
|
||
|
if (im->info.file) l1 = strlen(im->info.file);
|
||
|
l2 = 0;
|
||
|
if (im->info.key) l2 = strlen(im->info.key);
|
||
|
snprintf(buf, sizeof(buf), "%llx", im->timestamp);
|
||
|
l3 = strlen(buf);
|
||
|
key = malloc(l1 + 3 + l2 + 3 + l3 +1);
|
||
|
if (!key) return;
|
||
|
key[0] = 0;
|
||
|
if (im->info.file) strcpy(key, im->info.file);
|
||
|
strcat(key, "/:/");
|
||
|
if (im->info.key) strcat(key, im->info.key);
|
||
|
strcat(key, "/:/");
|
||
|
strcat(key, buf);
|
||
|
images = evas_hash_del(images, key, im);
|
||
|
free(key);
|
||
|
im->flags &= ~RGBA_IMAGE_INDEXED;
|
||
|
}
|
||
|
|
||
|
|
||
|
RGBA_Image *
|
||
|
image_find(const char *filename, const char *key, DATA64 timestamp)
|
||
|
{
|
||
|
Evas_Object_List *l;
|
||
|
RGBA_Image *im;
|
||
|
char *str;
|
||
|
int l1, l2, l3;
|
||
|
char buf[256];
|
||
|
|
||
|
if ((!filename) && (!key)) return NULL;
|
||
|
l1 = 0;
|
||
|
if (filename) l1 = strlen(filename);
|
||
|
l2 = 0;
|
||
|
if (key) l2 = strlen(key);
|
||
|
sprintf(buf, "%llx", timestamp);
|
||
|
l3 = strlen(buf);
|
||
|
str = malloc(l1 + 3 + l2 + 3 + l3 +1);
|
||
|
if (!str) return NULL;
|
||
|
str[0] = 0;
|
||
|
if (filename) strcpy(str, filename);
|
||
|
strcat(str, "/:/");
|
||
|
if (key) strcat(str, key);
|
||
|
strcat(str, "/:/");
|
||
|
strcat(str, buf);
|
||
|
im = evas_hash_find(images, str);
|
||
|
free(str);
|
||
|
if (im) return im;
|
||
|
|
||
|
for (l = cache; l; l = l->next)
|
||
|
{
|
||
|
int ok;
|
||
|
|
||
|
im = (RGBA_Image *)l;
|
||
|
ok = 0;
|
||
|
if ((filename) && (im->info.file) &&
|
||
|
(!strcmp(filename, im->info.file)))
|
||
|
ok++;
|
||
|
if ((!filename) && (!im->info.file))
|
||
|
ok++;
|
||
|
if ((key) && (im->info.key) &&
|
||
|
(!strcmp(key, im->info.key)))
|
||
|
ok++;
|
||
|
if ((!key) && (!im->info.key))
|
||
|
ok++;
|
||
|
if (im->timestamp == timestamp)
|
||
|
ok++;
|
||
|
if (ok >= 3) return im;
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
image_ram_usage(RGBA_Image *im)
|
||
|
{
|
||
|
int ram = 0;
|
||
|
int i;
|
||
|
|
||
|
ram += sizeof(struct _RGBA_Image);
|
||
|
if (im->info.file) ram += strlen(im->info.file);
|
||
|
if (im->info.key) ram += strlen(im->info.key);
|
||
|
if (im->info.comment) ram += strlen(im->info.comment);
|
||
|
if ((im->image) && (im->image->data) && (!im->image->no_free))
|
||
|
ram += im->image->w * im->image->h * sizeof(DATA32);
|
||
|
ram += im->mipmaps.num * sizeof(RGBA_Surface);
|
||
|
for (i = 0; i < im->mipmaps.num; i++)
|
||
|
{
|
||
|
if ((im->mipmaps.levels[i]) && (im->mipmaps.levels[i]->data) && (!im->mipmaps.levels[i]->no_free))
|
||
|
ram += im->mipmaps.levels[i]->w * im->mipmaps.levels[i]->h * sizeof(DATA32);
|
||
|
}
|
||
|
return ram;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
image_dirty(RGBA_Image *im)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
image_unstore(im);
|
||
|
im->flags |= RGBA_IMAGE_IS_DIRTY;
|
||
|
for (i = 0; i < im->mipmaps.num; i++)
|
||
|
image_surface_dealloc(im->mipmaps.levels[i]);
|
||
|
}
|
||
|
|