From 3d9a1198db571973e2760d6f27c771cbe31c844b Mon Sep 17 00:00:00 2001 From: Richard Wilson Date: Wed, 22 Feb 2006 01:58:19 +0000 Subject: [project @ 2006-02-22 01:58:19 by rjw] Reduce constant bitmap overhead per reference by moving to a flag word. Allow bitmaps to be reduced back to their raw data to free extra memory in a highly efficient manner. svn path=/import/netsurf/; revision=2089 --- riscos/bitmap.c | 124 ++++++++++++++++++++++++++++++++--------------------- riscos/bitmap.h | 9 ++-- riscos/history.c | 4 +- riscos/plotters.c | 4 +- riscos/save.c | 9 +--- riscos/thumbnail.c | 2 - 6 files changed, 86 insertions(+), 66 deletions(-) (limited to 'riscos') diff --git a/riscos/bitmap.c b/riscos/bitmap.c index 505b27ee5..f9c66bb34 100644 --- a/riscos/bitmap.c +++ b/riscos/bitmap.c @@ -13,8 +13,6 @@ * sprites. */ -#define NDEBUG - #include #include #include @@ -61,6 +59,14 @@ unsigned int bitmap_compressed_size; */ unsigned int bitmap_compressed_used = 0; +/** Total number of suspendable bitmaps +*/ +unsigned int bitmap_suspendable = 0; + +/** Total number of suspended bitmaps +*/ +unsigned int bitmap_suspended = 0; + /** Compressed data header */ struct bitmap_compressed_header { @@ -145,7 +151,8 @@ void bitmap_quit(void) struct bitmap *bitmap; for (bitmap = bitmap_head; bitmap; bitmap = bitmap->next) - if ((bitmap->persistent) && ((bitmap->modified) || + if ((bitmap->state & BITMAP_PERSISTENT) && + ((bitmap->state & BITMAP_MODIFIED) || (bitmap->filename[0] == '\0'))) bitmap_save_file(bitmap); } @@ -160,7 +167,7 @@ void bitmap_quit(void) * \return an opaque struct bitmap, or NULL on memory exhaustion */ -struct bitmap *bitmap_create(int width, int height, bitmap_state state) +struct bitmap *bitmap_create(int width, int height, unsigned int state) { struct bitmap *bitmap; @@ -172,17 +179,7 @@ struct bitmap *bitmap_create(int width, int height, bitmap_state state) return NULL; bitmap->width = width; bitmap->height = height; - bitmap->opaque = false; - switch (state) { - case BITMAP_CLEAR_MEMORY: - case BITMAP_ALLOCATE_MEMORY: - bitmap->state = state; - break; - default: - LOG(("Invalid bitmap state")); - assert(false); - return false; - } + bitmap->state = state; /* link into our list of bitmaps at the head */ if (bitmap_head) { @@ -212,9 +209,7 @@ struct bitmap *bitmap_create_file(char *file) bitmap = calloc(1, sizeof(struct bitmap)); if (!bitmap) return NULL; - bitmap->opaque = true; - bitmap->persistent = true; - bitmap->state = BITMAP_READY; + bitmap->state = BITMAP_OPAQUE | BITMAP_PERSISTENT | BITMAP_READY; strcpy(bitmap->filename, file); /* link in at the head */ @@ -243,21 +238,14 @@ bool bitmap_initialise(struct bitmap *bitmap) assert(!bitmap->sprite_area); area_size = 16 + 44 + bitmap->width * bitmap->height * 4; - switch (bitmap->state) { - case BITMAP_CLEAR_MEMORY: - bitmap->sprite_area = calloc(1, area_size); - break; - case BITMAP_ALLOCATE_MEMORY: - bitmap->sprite_area = malloc(area_size); - break; - default: - LOG(("Invalid bitmap state")); - assert(false); - return false; - } + if (bitmap->state & BITMAP_CLEAR_MEMORY) + bitmap->sprite_area = calloc(1, area_size); + else + bitmap->sprite_area = malloc(area_size); + if (!bitmap->sprite_area) return false; - bitmap->state = BITMAP_READY; + bitmap->state |= BITMAP_READY; bitmap_direct_used += area_size; /* area control block */ @@ -295,7 +283,11 @@ bool bitmap_initialise(struct bitmap *bitmap) void bitmap_set_opaque(struct bitmap *bitmap, bool opaque) { assert(bitmap); - bitmap->opaque = opaque; + + if (opaque) + bitmap->state |= BITMAP_OPAQUE; + else + bitmap->state &= ~BITMAP_OPAQUE; } @@ -345,7 +337,7 @@ bool bitmap_test_opaque(struct bitmap *bitmap) bool bitmap_get_opaque(struct bitmap *bitmap) { assert(bitmap); - return (bitmap->opaque); + return (bitmap->state & BITMAP_OPAQUE); } @@ -374,18 +366,17 @@ char *bitmap_get_buffer(struct bitmap *bitmap) bitmap->previous = NULL; bitmap_head = bitmap; } - + /* dynamically create the buffer */ - switch (bitmap->state) { - case BITMAP_ALLOCATE_MEMORY: - case BITMAP_CLEAR_MEMORY: - if (!bitmap_initialise(bitmap)) - return NULL; - break; - default: - break; + if (!(bitmap->state & BITMAP_READY)) { + if (!bitmap_initialise(bitmap)) + return NULL; } + /* reset our suspended flag */ + if (bitmap->state & BITMAP_SUSPENDED) + bitmap->state &= ~BITMAP_SUSPENDED; + /* image is already decompressed, no change to image states */ if (bitmap->sprite_area) return ((char *) (bitmap->sprite_area)) + 16 + 44; @@ -493,10 +484,25 @@ bool bitmap_save(struct bitmap *bitmap, const char *path) * \param bitmap a bitmap, as returned by bitmap_create() */ void bitmap_modified(struct bitmap *bitmap) { - bitmap->modified = true; + bitmap->state |= BITMAP_MODIFIED; } +/** + * The bitmap image can be suspended. + * + * \param bitmap a bitmap, as returned by bitmap_create() + * \param private_word a private word to be returned later + * \param invalidate the function to be called upon suspension + */ +void bitmap_set_suspendable(struct bitmap *bitmap, void *private_word, + void (*invalidate)(struct bitmap *bitmap, void *private_word)) { + bitmap->private_word = private_word; + bitmap->invalidate = invalidate; + bitmap_suspendable++; +} + + /** * Performs routine maintenance. */ @@ -504,6 +510,7 @@ void bitmap_maintain(void) { unsigned int memory = 0; unsigned int compressed_memory = 0; + unsigned int suspended = 0; struct bitmap *bitmap = bitmap_head; struct bitmap_compressed_header *header; unsigned int maintain_direct_size; @@ -535,7 +542,8 @@ void bitmap_maintain(void) bitmap->compressed; compressed_memory += header->input_size + sizeof(struct bitmap_compressed_header); - } + } else if (bitmap->state & BITMAP_SUSPENDED) + suspended++; } if (!bitmap) { @@ -543,6 +551,25 @@ void bitmap_maintain(void) bitmap_maintenance_priority = false; return; } + + /* the fastest and easiest way to release memory is by suspending + * images. as such, we try to do this first for as many images as + * possible, potentially freeing up large amounts of memory */ + if (suspended <= (bitmap_suspendable - bitmap_suspended)) { + for (; bitmap; bitmap = bitmap->next) { + if (bitmap->invalidate) { + bitmap->invalidate(bitmap, bitmap->private_word); + free(bitmap->sprite_area); + bitmap->sprite_area = NULL; + bitmap->state |= BITMAP_SUSPENDED; + bitmap->state &= ~BITMAP_READY; + bitmap_direct_used -= 16 + 44 + + bitmap->width * bitmap->height * 4; + bitmap_suspended++; + } + } + return; + } /* under heavy loads, we ignore compression */ if (!bitmap_maintenance_priority) { @@ -608,7 +635,6 @@ void bitmap_decompress(struct bitmap *bitmap) } /* create the image memory/header to decompress to */ - bitmap->state = BITMAP_ALLOCATE_MEMORY; if (!bitmap_initialise(bitmap)) return; @@ -654,7 +680,7 @@ void bitmap_compress(struct bitmap *bitmap) return; /* compress the data */ - if (bitmap->opaque) + if (bitmap->state & BITMAP_OPAQUE) flags |= tinct_OPAQUE_IMAGE; error = _swix(Tinct_Compress, _IN(0) | _IN(2) | _IN(7) | _OUT(0), (char *)(bitmap->sprite_area + 1), @@ -754,7 +780,7 @@ void bitmap_load_file(struct bitmap *bitmap) bitmap->compressed = NULL; return; } - if (bitmap->modified) + if (bitmap->state & BITMAP_MODIFIED) bitmap_delete_file(bitmap); } @@ -769,7 +795,7 @@ void bitmap_save_file(struct bitmap *bitmap) assert(bitmap->compressed || bitmap->sprite_area); /* unmodified bitmaps will still have their file available */ - if (!bitmap->modified && bitmap->filename[0]) { + if ((!(bitmap->state & BITMAP_MODIFIED)) && bitmap->filename[0]) { if (bitmap->sprite_area) free(bitmap->sprite_area); bitmap->sprite_area = NULL; @@ -814,7 +840,7 @@ void bitmap_save_file(struct bitmap *bitmap) free(bitmap->compressed); } bitmap->compressed = NULL; - bitmap->modified = false; + bitmap->state &= ~BITMAP_MODIFIED; LOG(("Saved file to disk")); } } diff --git a/riscos/bitmap.h b/riscos/bitmap.h index 910c201bb..a113d9b1b 100644 --- a/riscos/bitmap.h +++ b/riscos/bitmap.h @@ -16,10 +16,11 @@ struct osspriteop_area; struct bitmap { int width; int height; - bool opaque; - bool modified; - bool persistent; - bitmap_state state; + + unsigned int state; + + void *private_word; + void (*invalidate)(struct bitmap *bitmap, void *private_word); osspriteop_area *sprite_area; /** Uncompressed data, or NULL */ char *compressed; /** Compressed data, or NULL */ diff --git a/riscos/history.c b/riscos/history.c index 46ef458bf..8b9beaa12 100644 --- a/riscos/history.c +++ b/riscos/history.c @@ -179,12 +179,12 @@ void history_add(struct history *history, struct content *content, char *frag_id bitmap = url_store_get_thumbnail(url); if (!bitmap) { bitmap = bitmap_create(WIDTH / 2, HEIGHT / 2, - BITMAP_ALLOCATE_MEMORY); + BITMAP_NEW | BITMAP_CLEAR_MEMORY | + BITMAP_OPAQUE | BITMAP_PERSISTENT); if (!bitmap) { LOG(("Thumbnail initialisation failed.")); return; } - bitmap_set_opaque(bitmap, true); thumbnail_create(content, bitmap, url); } entry->bitmap = bitmap; diff --git a/riscos/plotters.c b/riscos/plotters.c index d59883075..dcce28c38 100644 --- a/riscos/plotters.c +++ b/riscos/plotters.c @@ -326,7 +326,7 @@ bool ro_plot_bitmap(int x, int y, int width, int height, bitmap->height, bg, false, false, false, - bitmap->opaque ? IMAGE_PLOT_TINCT_OPAQUE : + bitmap_get_opaque(bitmap) ? IMAGE_PLOT_TINCT_OPAQUE : IMAGE_PLOT_TINCT_ALPHA); } @@ -344,7 +344,7 @@ bool ro_plot_bitmap_tile(int x, int y, int width, int height, bitmap->height, bg, repeat_x, repeat_y, true, - bitmap->opaque ? IMAGE_PLOT_TINCT_OPAQUE : + bitmap_get_opaque(bitmap) ? IMAGE_PLOT_TINCT_OPAQUE : IMAGE_PLOT_TINCT_ALPHA); } diff --git a/riscos/save.c b/riscos/save.c index 7792e6ccc..e288150a6 100644 --- a/riscos/save.c +++ b/riscos/save.c @@ -801,12 +801,8 @@ void ro_gui_save_object_native(struct content *c, char *path) bitmap_save(c->bitmap, path); break; #endif -#ifdef WITH_PNG - case CONTENT_PNG: -/* error = xosspriteop_save_sprite_file(osspriteop_USER_AREA, c->data.png.sprite_area, path); - break;*/ -#endif #ifdef WITH_MNG + case CONTENT_PNG: case CONTENT_JNG: case CONTENT_MNG: bitmap_save(c->bitmap, path); @@ -1007,12 +1003,11 @@ bool ro_gui_save_create_thumbnail(struct content *c, const char *name) struct bitmap *bitmap; osspriteop_area *area; - bitmap = bitmap_create(34, 34, BITMAP_CLEAR_MEMORY); + bitmap = bitmap_create(34, 34, BITMAP_NEW | BITMAP_OPAQUE | BITMAP_CLEAR_MEMORY); if (!bitmap) { LOG(("Thumbnail initialisation failed.")); return false; } - bitmap_set_opaque(bitmap, true); thumbnail_create(c, bitmap, NULL); area = thumbnail_convert_8bpp(bitmap); bitmap_destroy(bitmap); diff --git a/riscos/thumbnail.c b/riscos/thumbnail.c index e1231cd2d..8c5351cac 100644 --- a/riscos/thumbnail.c +++ b/riscos/thumbnail.c @@ -139,9 +139,7 @@ bool thumbnail_create(struct content *content, struct bitmap *bitmap, /* register the thumbnail with the URL */ if (url) url_store_add_thumbnail(url, bitmap); - bitmap_modified(bitmap); - bitmap->persistent = true; return true; } -- cgit v1.2.3