summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/SDL_surface.h4
-rw-r--r--src/video/SDL_pixels.c72
-rw-r--r--src/video/SDL_pixels_c.h2
-rw-r--r--src/video/SDL_surface.c2
4 files changed, 67 insertions, 13 deletions
diff --git a/include/SDL_surface.h b/include/SDL_surface.h
index 0f11d178e..2bffb8115 100644
--- a/include/SDL_surface.h
+++ b/include/SDL_surface.h
@@ -80,7 +80,9 @@ typedef struct SDL_Surface
/** information needed for surfaces requiring locks */
int locked; /**< Read-only */
- void *lock_data; /**< Read-only */
+
+ /** list of BlitMap that hold a reference to this surface */
+ void *list_blitmap; /**< Private */
/** clipping information */
SDL_Rect clip_rect; /**< Read-only */
diff --git a/src/video/SDL_pixels.c b/src/video/SDL_pixels.c
index 77de36c51..84b693217 100644
--- a/src/video/SDL_pixels.c
+++ b/src/video/SDL_pixels.c
@@ -1023,6 +1023,62 @@ SDL_AllocBlitMap(void)
return (map);
}
+
+typedef struct SDL_ListNode
+{
+ void *entry;
+ struct SDL_ListNode *next;
+} SDL_ListNode;
+
+void
+SDL_InvalidateAllBlitMap(SDL_Surface *surface)
+{
+ SDL_ListNode *l = surface->list_blitmap;
+
+ surface->list_blitmap = NULL;
+
+ while (l) {
+ SDL_ListNode *tmp = l;
+ SDL_InvalidateMap((SDL_BlitMap *)l->entry);
+ l = l->next;
+ SDL_free(tmp);
+ }
+}
+
+static void SDL_ListAdd(SDL_ListNode **head, void *ent);
+static void SDL_ListRemove(SDL_ListNode **head, void *ent);
+
+void
+SDL_ListAdd(SDL_ListNode **head, void *ent)
+{
+ SDL_ListNode *node = SDL_malloc(sizeof (*node));
+
+ if (node == NULL) {
+ SDL_OutOfMemory();
+ return;
+ }
+
+ node->entry = ent;
+ node->next = *head;
+ *head = node;
+}
+
+void
+SDL_ListRemove(SDL_ListNode **head, void *ent)
+{
+ SDL_ListNode **ptr = head;
+
+ while (*ptr) {
+ if ((*ptr)->entry == ent) {
+ SDL_ListNode *tmp = *ptr;
+ *ptr = (*ptr)->next;
+ SDL_free(tmp);
+ return;
+ }
+ ptr = &(*ptr)->next;
+ }
+}
+
void
SDL_InvalidateMap(SDL_BlitMap * map)
{
@@ -1030,10 +1086,8 @@ SDL_InvalidateMap(SDL_BlitMap * map)
return;
}
if (map->dst) {
- /* Release our reference to the surface - see the note below */
- if (--map->dst->refcount <= 0) {
- SDL_FreeSurface(map->dst);
- }
+ /* Un-register from the destination surface */
+ SDL_ListRemove((SDL_ListNode **)&(map->dst->list_blitmap), map);
}
map->dst = NULL;
map->src_palette_version = 0;
@@ -1104,14 +1158,8 @@ SDL_MapSurface(SDL_Surface * src, SDL_Surface * dst)
map->dst = dst;
if (map->dst) {
- /* Keep a reference to this surface so it doesn't get deleted
- while we're still pointing at it.
-
- A better method would be for the destination surface to keep
- track of surfaces that are mapped to it and automatically
- invalidate them when it is freed, but this will do for now.
- */
- ++map->dst->refcount;
+ /* Register BlitMap to the destination surface, to be invalidated when needed */
+ SDL_ListAdd((SDL_ListNode **)&(map->dst->list_blitmap), map);
}
if (dstfmt->palette) {
diff --git a/src/video/SDL_pixels_c.h b/src/video/SDL_pixels_c.h
index 8f511c0d2..9ff590e0c 100644
--- a/src/video/SDL_pixels_c.h
+++ b/src/video/SDL_pixels_c.h
@@ -37,6 +37,8 @@ extern void SDL_InvalidateMap(SDL_BlitMap * map);
extern int SDL_MapSurface(SDL_Surface * src, SDL_Surface * dst);
extern void SDL_FreeBlitMap(SDL_BlitMap * map);
+extern void SDL_InvalidateAllBlitMap(SDL_Surface *surface);
+
/* Miscellaneous functions */
extern void SDL_DitherColors(SDL_Color * colors, int bpp);
extern Uint8 SDL_FindColor(SDL_Palette * pal, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
diff --git a/src/video/SDL_surface.c b/src/video/SDL_surface.c
index 3ec9093cf..553946516 100644
--- a/src/video/SDL_surface.c
+++ b/src/video/SDL_surface.c
@@ -1328,6 +1328,8 @@ SDL_FreeSurface(SDL_Surface * surface)
}
SDL_InvalidateMap(surface->map);
+ SDL_InvalidateAllBlitMap(surface);
+
if (--surface->refcount > 0) {
return;
}