1
0
Fork 0
mirror of https://github.com/TerryCavanagh/VVVVVV.git synced 2024-12-22 17:49:43 +01:00

Fix memory leak with ApplyFilter

The intention of the recent refactor was to make it so that the
temporary surfaces would be allocated only once, when the mode is
enabled, and be freed upon exit.

To do this, Graphics.cpp owns the pointers, and passes them to
ApplyFilter to modify. Except ApplyFilter doesn't actually modify the
pointers, because it's only a single pointer, not a pointer-to-pointer.
So every frame of rendering it would actually be creating a new surface
and leaking memory.

To fix this, they need to be pointer-to-pointer variables that get
modified.

I also added error logs in case the surface creation failed.
This commit is contained in:
Misa 2023-10-27 10:21:18 -07:00
parent 791310fa5d
commit ea1a014145
3 changed files with 27 additions and 20 deletions

View file

@ -3244,7 +3244,7 @@ void Graphics::screenshake(void)
{
if (gameScreen.badSignalEffect)
{
ApplyFilter(tempFilterSrc, tempFilterDest);
ApplyFilter(&tempFilterSrc, &tempFilterDest);
}
set_render_target(tempShakeTexture);
@ -3282,7 +3282,7 @@ void Graphics::render(void)
{
if (gameScreen.badSignalEffect)
{
ApplyFilter(tempFilterSrc, tempFilterDest);
ApplyFilter(&tempFilterSrc, &tempFilterDest);
}
set_render_target(NULL);

View file

@ -144,43 +144,50 @@ void UpdateFilter(void)
}
}
void ApplyFilter(SDL_Surface* src, SDL_Surface* dest)
void ApplyFilter(SDL_Surface** src, SDL_Surface** dest)
{
if (src == NULL)
{
src = SDL_CreateRGBSurface(0, SCREEN_WIDTH_PIXELS, SCREEN_HEIGHT_PIXELS, 32, 0, 0, 0, 0);
}
if (dest == NULL)
{
dest = SDL_CreateRGBSurface(0, SCREEN_WIDTH_PIXELS, SCREEN_HEIGHT_PIXELS, 32, 0, 0, 0, 0);
}
if (src == NULL || dest == NULL)
{
SDL_assert(0 && "NULL src or dest!");
return;
}
const int result = SDL_RenderReadPixels(gameScreen.m_renderer, NULL, 0, src->pixels, src->pitch);
if (*src == NULL)
{
*src = SDL_CreateRGBSurface(0, SCREEN_WIDTH_PIXELS, SCREEN_HEIGHT_PIXELS, 32, 0, 0, 0, 0);
}
if (*dest == NULL)
{
*dest = SDL_CreateRGBSurface(0, SCREEN_WIDTH_PIXELS, SCREEN_HEIGHT_PIXELS, 32, 0, 0, 0, 0);
}
if (*src == NULL || *dest == NULL)
{
WHINE_ONCE_ARGS(("Could not create temporary surfaces: %s", SDL_GetError()));
return;
}
const int result = SDL_RenderReadPixels(gameScreen.m_renderer, NULL, 0, (*src)->pixels, (*src)->pitch);
if (result != 0)
{
SDL_FreeSurface(src);
SDL_FreeSurface(*src);
WHINE_ONCE_ARGS(("Could not read pixels from renderer: %s", SDL_GetError()));
return;
}
const int red_offset = rand() % 4;
for (int x = 0; x < src->w; x++)
for (int x = 0; x < (*src)->w; x++)
{
for (int y = 0; y < src->h; y++)
for (int y = 0; y < (*src)->h; y++)
{
const int sampley = (y + (int) graphics.lerp(oldscrollamount, scrollamount)) % 240;
const SDL_Color pixel = ReadPixel(src, x, sampley);
const SDL_Color pixel = ReadPixel(*src, x, sampley);
Uint8 green = pixel.g;
Uint8 blue = pixel.b;
const SDL_Color pixel_offset = ReadPixel(src, SDL_min(x + red_offset, 319), sampley);
const SDL_Color pixel_offset = ReadPixel(*src, SDL_min(x + red_offset, 319), sampley);
Uint8 red = pixel_offset.r;
double mult;
@ -216,9 +223,9 @@ void ApplyFilter(SDL_Surface* src, SDL_Surface* dest)
blue = SDL_max(blue - (distX + distY), 0);
const SDL_Color color = {red, green, blue, pixel.a};
DrawPixel(dest, x, y, color);
DrawPixel(*dest, x, y, color);
}
}
SDL_UpdateTexture(graphics.gameTexture, NULL, dest->pixels, dest->pitch);
SDL_UpdateTexture(graphics.gameTexture, NULL, (*dest)->pixels, (*dest)->pitch);
}

View file

@ -12,6 +12,6 @@ void DrawPixel(SDL_Surface* surface, int x, int y, SDL_Color color);
SDL_Color ReadPixel(const SDL_Surface* surface, int x, int y);
void UpdateFilter(void);
void ApplyFilter(SDL_Surface* src, SDL_Surface* dest);
void ApplyFilter(SDL_Surface** src, SDL_Surface** dest);
#endif /* GRAPHICSUTIL_H */