Use RAII_SDL_Surface to track SDL-only main canvas surface

The Rebirth main screen grd_curscreen borrows the memory allocated by
SDL_CreateRGBSurface to store its data.  Store the pointer to that
surface inside grd_curscreen and make grd_curscreen responsible for
freeing the surface.
This commit is contained in:
Kp 2022-11-06 18:18:57 +00:00
parent ae46a5b3b0
commit 7effca68f0
3 changed files with 48 additions and 29 deletions

View File

@ -35,6 +35,11 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
#include "pack.h"
#include <array>
#if DXX_USE_SDLIMAGE || !DXX_USE_OGL
#include <memory>
#include <SDL_video.h>
#endif
namespace dcx {
enum class gr_fade_level : uint8_t
@ -232,13 +237,55 @@ struct grs_main_canvas : grs_canvas, prohibit_void_ptr<grs_main_canvas>
~grs_main_canvas();
};
// Creates a canvas that is part of another canvas. This can be used to make
// a window on the screen. The address of the raw pixel data is inherited from
// the parent canvas.
struct grs_subcanvas : grs_canvas, prohibit_void_ptr<grs_subcanvas>
{
using prohibit_void_ptr<grs_subcanvas>::operator &;
};
#if DXX_USE_SDLIMAGE || !DXX_USE_OGL
struct RAII_SDL_Surface
{
struct deleter
{
void operator()(SDL_Surface *s) const
{
SDL_FreeSurface(s);
}
};
std::unique_ptr<SDL_Surface, deleter> surface;
constexpr RAII_SDL_Surface() = default;
RAII_SDL_Surface(RAII_SDL_Surface &&) = default;
RAII_SDL_Surface &operator=(RAII_SDL_Surface &&) = default;
explicit RAII_SDL_Surface(SDL_Surface *const s) :
surface(s)
{
}
};
#endif
class grs_screen : prohibit_void_ptr<grs_screen>
{ // This is a video screen
screen_mode sc_mode;
public:
grs_screen &operator=(grs_screen &) = delete;
grs_screen &operator=(grs_screen &&) = default;
#if DXX_USE_OGL
/* OpenGL builds allocate the backing data for the canvas, so use
* grs_main_canvas to ensure it is freed when appropriate.
*/
grs_main_canvas sc_canvas; // Represents the entire screen
#else
/* SDL builds borrow the backing data from the SDL_Surface, so use
* grs_subcanvas for the canvas because the memory is owned by SDL and will
* be freed by SDL_FreeSurface. Store the associated SDL_Surface alongside
* the canvas, so that it is freed at the same time.
*/
RAII_SDL_Surface sdl_surface;
grs_subcanvas sc_canvas;
#endif
fix sc_aspect; //aspect ratio (w/h) for this screen
uint16_t get_screen_width() const
{
@ -262,15 +309,6 @@ public:
//=========================================================================
// Canvas functions:
// Creates a canvas that is part of another canvas. this can be used to make
// a window on the screen. the canvas structure is malloc'd; the address of
// the raw pixel data is inherited from the parent canvas.
struct grs_subcanvas : grs_canvas, prohibit_void_ptr<grs_subcanvas>
{
using prohibit_void_ptr<grs_subcanvas>::operator &;
};
// Free the bitmap, but not the pixel data buffer
class grs_subbitmap : public grs_bitmap
{

View File

@ -50,24 +50,6 @@ namespace dcx {
namespace {
#if DXX_USE_SDLIMAGE
struct RAII_SDL_Surface
{
struct deleter
{
void operator()(SDL_Surface *s) const
{
SDL_FreeSurface(s);
}
};
std::unique_ptr<SDL_Surface, deleter> surface;
explicit RAII_SDL_Surface(SDL_Surface *const s) :
surface(s)
{
}
};
#endif
#if !DXX_USE_OGL && DXX_USE_SCREENSHOT_FORMAT_LEGACY
[[nodiscard]]
static int pcx_encode_byte(ubyte byt, ubyte cnt, PHYSFS_File *fid);

View File

@ -123,6 +123,7 @@ int gr_set_mode(screen_mode mode)
}
*grd_curscreen = {};
grd_curscreen->sdl_surface = RAII_SDL_Surface(canvas);
grd_curscreen->set_screen_width_height(w, h);
grd_curscreen->sc_aspect = fixdiv(grd_curscreen->get_screen_width() * GameCfg.AspectX, grd_curscreen->get_screen_height() * GameCfg.AspectY);
gr_init_canvas(grd_curscreen->sc_canvas, reinterpret_cast<unsigned char *>(canvas->pixels), bm_mode::linear, w, h);
@ -171,7 +172,6 @@ int gr_init()
}
grd_curscreen = std::make_unique<grs_screen>();
*grd_curscreen = {};
if (!CGameCfg.WindowMode && !CGameArg.SysWindow)
sdl_video_flags|=SDL_FULLSCREEN;
@ -204,7 +204,6 @@ void gr_close()
gr_installed = 0;
grd_curscreen.reset();
SDL_ShowCursor(1);
SDL_FreeSurface(canvas);
}
}