SDL_Surface refcount: destination surface keep track of surfaces that are mapped to it and automatically invalidate them when it is freed - refcount is kept so that an external application can still create a reference to SDL_Surface. - lock_data was un-used and is now renamed and used as a list keep track of the blitmap
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
diff --git a/include/SDL_surface.h b/include/SDL_surface.h
index 0f11d17..2bffb81 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 77de36c..84b6932 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 8f511c0..9ff590e 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 3ec9093..5539465 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;
}