Skip to content

Commit

Permalink
SDL_Surface refcount: destination surface keep track of surfaces
Browse files Browse the repository at this point in the history
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
  • Loading branch information
1bsyl committed Sep 7, 2020
1 parent cce6c60 commit ebc12a2
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 13 deletions.
4 changes: 3 additions & 1 deletion include/SDL_surface.h
Expand Up @@ -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 */
Expand Down
72 changes: 60 additions & 12 deletions src/video/SDL_pixels.c
Expand Up @@ -1023,17 +1023,71 @@ 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)
{
if (!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;
Expand Down Expand Up @@ -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) {
Expand Down
2 changes: 2 additions & 0 deletions src/video/SDL_pixels_c.h
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions src/video/SDL_surface.c
Expand Up @@ -1328,6 +1328,8 @@ SDL_FreeSurface(SDL_Surface * surface)
}
SDL_InvalidateMap(surface->map);

SDL_InvalidateAllBlitMap(surface);

if (--surface->refcount > 0) {
return;
}
Expand Down

0 comments on commit ebc12a2

Please sign in to comment.