summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--debug/debug_bitmap.c16
-rw-r--r--gtk/gtk_bitmap.c17
-rw-r--r--image/bitmap.h16
-rw-r--r--image/gif.c8
-rw-r--r--image/gifread.c4
-rw-r--r--image/jpeg.c3
-rw-r--r--image/mng.c2
-rw-r--r--riscos/bitmap.c124
-rw-r--r--riscos/bitmap.h9
-rw-r--r--riscos/history.c4
-rw-r--r--riscos/plotters.c4
-rw-r--r--riscos/save.c9
-rw-r--r--riscos/thumbnail.c2
13 files changed, 138 insertions, 80 deletions
diff --git a/debug/debug_bitmap.c b/debug/debug_bitmap.c
index 6d7cd3f44..9c8942f7d 100644
--- a/debug/debug_bitmap.c
+++ b/debug/debug_bitmap.c
@@ -29,10 +29,11 @@ struct bitmap {
*
* \param width width of image in pixels
* \param height width of image in pixels
+ * \param state a flag word indicating the initial state
* \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;
bitmap = calloc(sizeof *bitmap + width * height * 4, 1);
@@ -120,3 +121,16 @@ bool bitmap_save(struct bitmap *bitmap, const char *path)
*/
void bitmap_modified(struct bitmap *bitmap) {
}
+
+
+/**
+ * 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 suspend the function to be called upon suspension
+ * \param resume the function to be called when resuming
+ */
+void bitmap_set_suspendable(struct bitmap *bitmap, void *private_word,
+ void (*invalidate)(struct bitmap *bitmap, void *private_word)) {
+}
diff --git a/gtk/gtk_bitmap.c b/gtk/gtk_bitmap.c
index 26b6b5a37..58fff8280 100644
--- a/gtk/gtk_bitmap.c
+++ b/gtk/gtk_bitmap.c
@@ -29,11 +29,11 @@ struct bitmap;
*
* \param width width of image in pixels
* \param height width of image in pixels
- * \param clear whether to clear the image ready for use
+ * \param state a flag word indicating the initial state
* \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)
{
GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8,
width, height);
@@ -146,3 +146,16 @@ bool bitmap_save(struct bitmap *bitmap, const char *path)
*/
void bitmap_modified(struct bitmap *bitmap) {
}
+
+
+/**
+ * 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 suspend the function to be called upon suspension
+ * \param resume the function to be called when resuming
+ */
+void bitmap_set_suspendable(struct bitmap *bitmap, void *private_word,
+ void (*invalidate)(struct bitmap *bitmap, void *private_word)) {
+}
diff --git a/image/bitmap.h b/image/bitmap.h
index c187b3ecb..bae1e1a15 100644
--- a/image/bitmap.h
+++ b/image/bitmap.h
@@ -20,18 +20,20 @@
#include <stdbool.h>
#include <stdlib.h>
-typedef enum {
- BITMAP_READY, /** Bitmap buffer is ready */
- BITMAP_ALLOCATE_MEMORY, /** Allocate memory */
- BITMAP_CLEAR_MEMORY, /** Clear the memory */
-} bitmap_state;
+#define BITMAP_NEW 0
+#define BITMAP_OPAQUE (1 << 0) /** image is opaque */
+#define BITMAP_MODIFIED (1 << 1) /** buffer has been modified */
+#define BITMAP_PERSISTENT (1 << 2) /** retain between sessions */
+#define BITMAP_CLEAR_MEMORY (1 << 3) /** memory should be wiped */
+#define BITMAP_SUSPENDED (1 << 4) /** currently suspended */
+#define BITMAP_READY (1 << 5) /** fully initialised */
struct content;
/** An opaque image. */
struct bitmap;
-struct bitmap *bitmap_create(int width, int height, bitmap_state state);
+struct bitmap *bitmap_create(int width, int height, unsigned int state);
void bitmap_set_opaque(struct bitmap *bitmap, bool opaque);
bool bitmap_test_opaque(struct bitmap *bitmap);
bool bitmap_get_opaque(struct bitmap *bitmap);
@@ -40,5 +42,7 @@ size_t bitmap_get_rowstride(struct bitmap *bitmap);
void bitmap_destroy(struct bitmap *bitmap);
bool bitmap_save(struct bitmap *bitmap, const char *path);
void bitmap_modified(struct bitmap *bitmap);
+void bitmap_set_suspendable(struct bitmap *bitmap, void *private_word,
+ void (*invalidate)(struct bitmap *bitmap, void *private_word));
#endif
diff --git a/image/gif.c b/image/gif.c
index 312139173..5bd2c25aa 100644
--- a/image/gif.c
+++ b/image/gif.c
@@ -35,6 +35,7 @@
#ifdef WITH_GIF
+static void nsgif_invalidate(struct bitmap *bitmap, void *private_word);
static void nsgif_animate(void *p);
static void nsgif_get_frame(struct content *c);
@@ -105,6 +106,8 @@ bool nsgif_convert(struct content *c, int iwidth, int iheight) {
c->data.gif.current_frame = 0;
if (gif->frame_count_partial > 1)
schedule(gif->frames[0].frame_delay, nsgif_animate, c);
+ else
+ bitmap_set_suspendable(gif->frame_image, gif, nsgif_invalidate);
/* Exit as a success
*/
@@ -113,6 +116,11 @@ bool nsgif_convert(struct content *c, int iwidth, int iheight) {
return true;
}
+void nsgif_invalidate(struct bitmap *bitmap, void *private_word) {
+ struct gif_animation *gif = (struct gif_animation *)private_word;
+
+ gif->decoded_frame = -1;
+}
bool nsgif_redraw(struct content *c, int x, int y,
int width, int height,
diff --git a/image/gifread.c b/image/gifread.c
index ba26452d8..9d81bb6a7 100644
--- a/image/gifread.c
+++ b/image/gifread.c
@@ -204,7 +204,7 @@ int gif_initialise(struct gif_animation *gif) {
/* Initialise the sprite header
*/
- if ((gif->frame_image = bitmap_create(gif->width, gif->height, BITMAP_ALLOCATE_MEMORY)) == NULL) {
+ if ((gif->frame_image = bitmap_create(gif->width, gif->height, BITMAP_NEW)) == NULL) {
gif_finalise(gif);
return GIF_INSUFFICIENT_MEMORY;
}
@@ -283,7 +283,7 @@ static int gif_initialise_sprite(struct gif_animation *gif, unsigned int width,
/* Allocate some more memory
*/
- if ((buffer = bitmap_create(max_width, max_height, BITMAP_ALLOCATE_MEMORY)) == NULL)
+ if ((buffer = bitmap_create(max_width, max_height, BITMAP_NEW)) == NULL)
return GIF_INSUFFICIENT_MEMORY;
bitmap_destroy(gif->frame_image);
gif->frame_image = buffer;
diff --git a/image/jpeg.c b/image/jpeg.c
index 3efe698df..197a977b4 100644
--- a/image/jpeg.c
+++ b/image/jpeg.c
@@ -94,7 +94,7 @@ bool nsjpeg_convert(struct content *c, int w, int h)
width = cinfo.output_width;
height = cinfo.output_height;
- bitmap = bitmap_create(width, height, BITMAP_ALLOCATE_MEMORY);
+ bitmap = bitmap_create(width, height, BITMAP_NEW | BITMAP_OPAQUE);
if (bitmap)
pixels = bitmap_get_buffer(bitmap);
if ((!bitmap) || (!pixels)) {
@@ -107,7 +107,6 @@ bool nsjpeg_convert(struct content *c, int w, int h)
warn_user("NoMemory", 0);
return false;
}
- bitmap_set_opaque(bitmap, true);
rowstride = bitmap_get_rowstride(bitmap);
do {
diff --git a/image/mng.c b/image/mng.c
index 838595960..cb4a7eef4 100644
--- a/image/mng.c
+++ b/image/mng.c
@@ -190,7 +190,7 @@ mng_bool nsmng_processheader(mng_handle mng, mng_uint32 width, mng_uint32 height
LOG(("processing header (%p) %d, %d", c, width, height));
- c->bitmap = bitmap_create(width, height, BITMAP_ALLOCATE_MEMORY);
+ c->bitmap = bitmap_create(width, height, BITMAP_NEW);
if (!c->bitmap) {
msg_data.error = messages_get("NoMemory");
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
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 <assert.h>
#include <stdbool.h>
#include <string.h>
@@ -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,17 +484,33 @@ 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.
*/
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;
}