X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/1b66e7e5ab419c5f91fc799c50addc42ef36e23b..c801d85f158c4cba50b588807daabdcbd0ed3853:/src/gdk_imlib/cache.c diff --git a/src/gdk_imlib/cache.c b/src/gdk_imlib/cache.c new file mode 100644 index 0000000000..4e750df20c --- /dev/null +++ b/src/gdk_imlib/cache.c @@ -0,0 +1,496 @@ +#define _GNU_SOURCE +#include "gdk_imlib.h" +#include "gdk_imlib_private.h" + +/* uncomment this to compile imlib's cahce with pixmap accounting output */ +/*#define PIXMAP_ACCOUNTING */ + +void +gdirty_pixmaps(GdkImlibImage * im) +{ + struct pixmap_cache *ptr; + + ptr = id->cache.pixmap; + while (ptr) + { + if ((ptr->im == im) && ((!ptr->file) || (!strcmp(im->filename, ptr->file)))) + ptr->dirty = 1; + ptr = ptr->next; + } +} + +void +gdirty_images(GdkImlibImage * im) +{ + struct image_cache *ptr; + + ptr = id->cache.image; + while (ptr) + { + if ((!strcmp(im->filename, ptr->file)) && (im == ptr->im)) + { + ptr->dirty = 1; + return; + } + ptr = ptr->next; + } +} + +void +gfind_pixmap(GdkImlibImage * im, int width, int height, GdkPixmap ** pmap, GdkBitmap ** mask) +{ + struct pixmap_cache *ptr; + + ptr = id->cache.pixmap; + while (ptr) + { + if ((ptr->im == im) && (ptr->width == width) && (ptr->height == height) && + ((!ptr->file) || (!strcmp(im->filename, ptr->file))) && + (!ptr->dirty)) + { + if (ptr->refnum > 0) + ptr->refnum++; + else + { + ptr->refnum++; + id->cache.num_pixmap++; + if (ptr->pmap) + id->cache.used_pixmap -= width * height * id->x.depth; + if (ptr->shape_mask) + id->cache.used_pixmap -= width * height; + if (id->cache.used_pixmap < 0) + { + id->cache.used_pixmap = 0; + fprintf(stderr, "IMLIB: uhoh.. caching problems.... meep meep\n"); + } + } + if (ptr->prev) + { + ptr->prev->next = ptr->next; + if (ptr->next) + ptr->next->prev = ptr->prev; + ptr->next = id->cache.pixmap; + ptr->next->prev = ptr; + id->cache.pixmap = ptr; + ptr->prev = NULL; + } + *pmap = ptr->pmap; + *mask = ptr->shape_mask; + return; + } + ptr = ptr->next; + } + *pmap = NULL; + *mask = NULL; +} + +GdkImlibImage * +gfind_image(char *file) +{ + struct image_cache *ptr; + + ptr = id->cache.image; + while (ptr) + { + if ((!strcmp(file, ptr->file)) && (!ptr->dirty)) + { + if (ptr->refnum) + ptr->refnum++; + else + { + ptr->refnum++; + id->cache.num_image++; + id->cache.used_image -= ptr->im->rgb_width * ptr->im->rgb_height * 3; + if (id->cache.used_image < 0) + { + id->cache.used_image = 0; + fprintf(stderr, "IMLIB: uhoh.. caching problems.... meep meep\n"); + } + } + if (ptr->prev) + { + ptr->prev->next = ptr->next; + if (ptr->next) + ptr->next->prev = ptr->prev; + ptr->next = id->cache.image; + ptr->next->prev = ptr; + id->cache.image = ptr; + ptr->prev = NULL; + } + return ptr->im; + } + ptr = ptr->next; + } + return NULL; +} + +void +gfree_pixmappmap(GdkPixmap * pmap) +{ + struct pixmap_cache *ptr; + + ptr = id->cache.pixmap; + while (ptr) + { + if ((ptr->pmap == pmap) || (ptr->shape_mask == pmap)) + { + if (ptr->shape_mask == pmap) + return; + if (ptr->refnum > 0) + { + ptr->refnum--; + if (ptr->refnum == 0) + { + id->cache.num_pixmap--; + if (ptr->pmap) + id->cache.used_pixmap += ptr->width * ptr->height * id->x.depth; + if (ptr->shape_mask) + id->cache.used_pixmap += ptr->width * ptr->height; + } + } + return; + } + ptr = ptr->next; + } + gdk_pixmap_unref(pmap); +} + +void +gfree_image(GdkImlibImage * im) +{ + struct image_cache *ptr; + + ptr = id->cache.image; + while (ptr) + { + if (im == ptr->im) + { + if (ptr->refnum) + { + ptr->refnum--; + if (!ptr->refnum) + { + id->cache.num_image--; + id->cache.used_image += ptr->im->rgb_width * ptr->im->rgb_height * 3; + } + } + return; + } + ptr = ptr->next; + } + gnullify_image(im); +} + +void +gflush_image(GdkImlibImage * im) +{ + if (im) + im->cache = 0; +} + +void +gadd_image(GdkImlibImage * im, char *file) +{ + struct image_cache *ptr; + struct image_cache *n; + + if ((!im) || (!file)) + return; + ptr = id->cache.image; + n = malloc(sizeof(struct image_cache)); + + if (!n) + return; + n->prev = NULL; + n->next = ptr; + n->file = malloc(strlen(file) + 1); + if (!n->file) + { + free(n); + return; + } + strcpy(n->file, file); + n->im = im; + n->refnum = 1; + n->dirty = 0; + if (n->next) + n->next->prev = n; + id->cache.image = n; + id->cache.num_image++; +} + +void +gadd_pixmap(GdkImlibImage * im, int width, int height, XImage * xim, XImage * sxim) +{ + struct pixmap_cache *ptr; + struct pixmap_cache *n; + + if (!im) + return; + ptr = id->cache.pixmap; + n = malloc(sizeof(struct pixmap_cache)); + + if (!n) + return; + n->prev = NULL; + n->next = ptr; + n->im = im; + if (im->filename) + { + n->file = malloc(strlen(im->filename) + 1); + if (n->file) + strcpy(n->file, im->filename); + } + else + n->file = NULL; + n->refnum = 1; + n->dirty = 0; + n->width = width; + n->height = height; + n->pmap = im->pixmap; + n->shape_mask = im->shape_mask; + n->xim = xim; + n->sxim = sxim; + if (n->next) + n->next->prev = n; + id->cache.pixmap = n; + id->cache.num_pixmap++; +} + +void +gclean_caches() +{ + { + struct image_cache *ptr = NULL; + struct image_cache *pptr = NULL; + struct image_cache *last = NULL; + int newlast; + + /* find the back of the list */ + ptr = id->cache.image; + while (ptr) + { + last = ptr; + ptr = ptr->next; + } + newlast = 0; + ptr = last; + /* remove all images that are tagged non-cachable, and have 0 */ + /* references , even if the cache has spare room. */ + while (ptr) + { + if (!ptr->refnum) + { + if (!ptr->im->cache) + { + if (ptr == last) + newlast = 1; + id->cache.used_image -= ptr->im->rgb_width * ptr->im->rgb_height * 3; + gnullify_image(ptr->im); + if (pptr) + ptr = pptr->prev; + if (ptr->prev) + ptr->prev->next = ptr->next; + else + id->cache.image = ptr->next; + if (ptr->next) + ptr->next->prev = ptr->prev; + if (ptr->file) + free(ptr->file); + free(ptr); + ptr = NULL; + } + } + if (ptr) + ptr = ptr->prev; + if (newlast) + { + last = NULL; + ptr = id->cache.image; + while (ptr) + { + last = ptr; + ptr = ptr->next; + } + newlast = 0; + ptr = last; + } + } + /* find the back of the list */ + ptr = id->cache.image; + last = NULL; + while (ptr) + { + last = ptr; + ptr = ptr->next; + } + newlast = 0; + ptr = last; + /* while the amount of data in the cache is greater than the set */ + /* amount, delete the last entry (last used) from the unreferenced */ + /* cached 24-bit images */ + while (id->cache.used_image > id->cache.size_image) + { + while (ptr) + { + if (ptr->refnum < 1) + { + if (ptr == last) + newlast = 1; + id->cache.used_image -= ptr->im->rgb_width * ptr->im->rgb_height * 3; + gnullify_image(ptr->im); + if (ptr->prev) + ptr->prev->next = ptr->next; + else + id->cache.image = ptr->next; + if (ptr->next) + ptr->next->prev = ptr->prev; + if (ptr->file) + free(ptr->file); + free(ptr); + ptr = NULL; + break; + } + if (ptr) + ptr = ptr->prev; + } + if (newlast) + { + last = NULL; + ptr = id->cache.image; + while (ptr) + { + last = ptr; + ptr = ptr->next; + } + newlast = 0; + ptr = last; + } + if (!ptr) + break; + } + } + { + struct pixmap_cache *ptr; + struct pixmap_cache *last; + int newlast; + +#ifdef PIXMAP_ACCOUNTING + int total, total2, num, num2; + + printf("--------- Pixmap cashe zise %i / %i with %i pixmaps referenced\n", + id->cache.used_pixmap, id->cache.size_pixmap, + id->cache.num_pixmap); + ptr = id->cache.pixmap; + total = 0; + total2 = 0; + num = 0; + num2 = 0; + while (ptr) + { + printf("Pmap for file %s REFNUM %3i SIZE %4ix%4i PMAP %8x MASK %8x\n", + ptr->file, ptr->refnum, ptr->width, ptr->height, ptr->pmap, + ptr->shape_mask); + if (ptr->refnum > 0) + { + total += (ptr->width * ptr->height * id->x.depth); + if (ptr->shape_mask) + total += (ptr->width * ptr->height); + num++; + } + else + { + total2 += (ptr->width * ptr->height * id->x.depth); + if (ptr->shape_mask) + total2 += (ptr->width * ptr->height); + num2++; + } + ptr = ptr->next; + } + printf("Accounting Data:\n"); + printf("*** total pixmap's in cache %i with %i pixmaps\n", + total, num); + printf("*** total unreffed pixmap's in cache %i with %i pixmaps\n\n", + total2, num2); +#endif + /* find the back of the list */ + ptr = id->cache.pixmap; + last = NULL; + while (ptr) + { + last = ptr; + ptr = ptr->next; + } + newlast = 0; + ptr = last; + /* while the amount of data in the cache is greater than the set */ + /* amount, delete the last entry (last used) from the unreferenced */ + /* cached pixmaps */ + while (id->cache.used_pixmap > id->cache.size_pixmap) + { + while (ptr) + { + if (ptr->refnum < 1) + { + if (ptr == last) + newlast = 1; + if (ptr->pmap) + id->cache.used_pixmap -= ptr->width * ptr->height * id->x.depth; + if (ptr->shape_mask) + id->cache.used_pixmap -= ptr->width * ptr->height; + if (ptr->pmap) + gdk_pixmap_unref(ptr->pmap); + if (ptr->shape_mask) + gdk_pixmap_unref(ptr->shape_mask); + if (ptr->xim) + XDestroyImage(ptr->xim); + if (ptr->sxim) + XDestroyImage(ptr->sxim); + if (ptr->prev) + ptr->prev->next = ptr->next; + else + id->cache.pixmap = ptr->next; + if (ptr->next) + ptr->next->prev = ptr->prev; + if (ptr->file) + free(ptr->file); + free(ptr); + ptr = NULL; + break; + } + if (ptr) + ptr = ptr->prev; + } + if (newlast) + { + last = NULL; + ptr = id->cache.pixmap; + while (ptr) + { + last = ptr; + ptr = ptr->next; + } + newlast = 0; + ptr = last; + } + if (!ptr) + break; + } + } +} + +void +gnullify_image(GdkImlibImage * im) +{ + if (!im) + return; + if (im->rgb_data) + free(im->rgb_data); + if (im->alpha_data) + free(im->alpha_data); + if (im->pixmap) + gfree_pixmappmap(im->pixmap); + if (im->filename) + free(im->filename); + free(im); +}