[SDL] Out of memory

Started by
5 comments, last by Mybowlcut 13 years, 9 months ago
I seem to be getting an out of memory error after this experimental function is called:
SDL_Surface* draw_line_to(const PointI& source, const PointI& target, const SDL_Color& colour){    using namespace Surface_Tools;    SDL_Surface* surface = NULL;    PointI p1, p2;    if(source.x < target.x)    {        p1.x = source.x;        p2.x = target.x;    }    else    {        p1.x = target.x;        p2.x = source.x;    }    if(source.y < target.y)    {        p1.y = source.y;        p2.y = target.y;    }    else    {        p1.y = target.y;        p2.y = source.y;    }        surface = create_blank_surface(p2 - p1);    bool steep = abs(p2.y - p1.y) > abs(p2.x - p1.x);    if(steep)    {        std::swap(p1.x, p1.y);        std::swap(p2.x, p2.y);    }    if(p1.x > p2.x)    {        std::swap(p1.x, p2.x);        std::swap(p1.y, p2.y);    }    int delta_x = p2.x - p1.x;    int delta_y = abs(p2.y - p1.y);    int error = delta_x / 2;    int y_step = 0;    int y = p1.y;    y_step = p1.y < p2.y ? 1 : -1;    for(int x = p1.x; x < p2.x; ++x)    {        if(steep)        {            set_pixel(surface, y, x, colour);        }        else        {            set_pixel(surface, x, y, colour);        }        error = error - delta_y;        if(error < 0)        {            y += y_step;            error += delta_x;        }    }    return surface;}

int main(int argc, char* argv[]){    Logger::Initialise("log.txt");    SDL_Systems::Initialise_SDL();    SDL_Systems::Initialise_Mixer(44100, MIX_DEFAULT_FORMAT, 2, 4096);    Surface_Cache::Initialise(SDL_Tools::Colours::WHITE);    SDL_Renderer renderer(640, 480, 24, "Test", SDL_Tools::Colours::BLACK);    SDL_Surface* x = draw_line_to(        to_point_type<float, int>(PointF(10.0f, 10.0f)),        to_point_type<float, int>(PointF(30.0f, 20.0f)),        SDL_Tools::colour(255, 0, 0));    Surface missile_sfc("missile.png", false);


After that function is called, any other attempts to load images with SDL fails, yielding "Out of memory" errors when SDL_GetError is called. I suspected it may have been the function below, but I am not sure:
SDL_Surface* Surface_Tools::create_blank_surface(const PointI& size, int depth){    using namespace SDL_Tools;    SDL_Surface* sfc = SDL_CreateRGBSurface(SDL_SWSURFACE, size.x, size.y, depth,        r_mask, g_mask, b_mask, a_mask);    if(!sfc)    {                throw LRE_Exception("SDL_CreateRGBSurface failed in create_blank_surface: " +            std::string(SDL_GetError()));    }    SDL_Surface* ret = SDL_DisplayFormat(sfc);    SDL_FreeSurface(sfc);    if(!ret)    {        throw LRE_Exception("Could not create surface in create_blank_surface: " +            std::string(SDL_GetError()));    }    return ret;}


Is there anything fishy with my SDL code that could cause this problem? I am initialising SDL before doing any work with SDL.

Cheers.

Advertisement
Probably a data problem. I note that you don't check the actual sizes of the points in create_blank_surface. Maybe your PointI subtraction routine is broken? Or perhaps the default parameter to create_blank_surface, which you've not shown us, is something invalid.
Quote:Original post by Kylotan
Probably a data problem. I note that you don't check the actual sizes of the points in create_blank_surface. Maybe your PointI subtraction routine is broken? Or perhaps the default parameter to create_blank_surface, which you've not shown us, is something invalid.

Yeah, I didn't check it as it was a quick and dirty experiment to try out line drawing algorithms. Here is the operator-:
friend const Point operator-(const Point& lhs, const Point& rhs)    {	    return Point(lhs.x - rhs.x, lhs.y - rhs.y);    }

Default parameter:
SDL_Surface* create_blank_surface(const PointI& size, int depth = 32);

I'm truly puzzled by this...

I suggest you add some logging to show exactly what values you are passing in to SDL_CreateRGBSurface. I expect that the problem will become quite obvious when you look at them.

I note that you also say "after this experimental function is called". Do you actually mean "during this function"? Or is it only subsequent calls? The logging should show you exactly where you start to get the memory errors.
Quote:Original post by Kylotan
I suggest you add some logging to show exactly what values you are passing in to SDL_CreateRGBSurface. I expect that the problem will become quite obvious when you look at them.

I note that you also say "after this experimental function is called". Do you actually mean "during this function"? Or is it only subsequent calls? The logging should show you exactly where you start to get the memory errors.


I'm passing in these values to SDL_CreateRGBSurface:
size.x=20 size.y=10 depth=32 r_mask=255 g_mask=65280 b_mask=16711680 a_mask=4278190080

I meant subsequent calls to surface-related SDL functions. The first surface-related SDL function eventually called is this one:
raw_surface_ptr Surface_Cache::Load_Surface(const boost_path& file_name,bool is_colour_key, Opt_SDL_Colour colour_key){    using namespace Surface_Tools;    std::string fn = boost::filesystem::complete(file_name).file_string();	raw_surface_ptr loaded;	raw_surface_ptr optimized;	Uint32 map_colour_key = 0;	loaded = make_raw_surface_ptr(IMG_Load(fn.c_str()));	if(loaded.get() == NULL && !fn.empty())	{		throw LRE_Exception(			"Surface at: " + fn + " failed to load.\nSDL: " + SDL_GetError());	}	optimized = make_raw_surface_ptr(SDL_DisplayFormat(loaded.get()));	if(optimized.get() == NULL)	{		throw LRE_Exception(			"Surface at: " + fn + " failed to optimise.\nSDL: " + SDL_GetError());	}	if(is_colour_key)	{        // Do we want user-specified colour key or default?        const SDL_Colour ckey = colour_key ? *colour_key : def_colour_key;		// Create the colour key.		map_colour_key = SDL_MapRGB(optimized->format, ckey.r, ckey.g, ckey.b);		// Sets the colour key to the Surface.		SDL_SetColorKey(optimized.get(), SDL_RLEACCEL | SDL_SRCCOLORKEY, map_colour_key);	}    fn_sfc_cache.insert(std::make_pair(file_name.file_string(), optimized));	LOG("Surface " + file_name.file_string() + " loaded.");	return optimized;}

The "Out of memory" error occurs on this line:
loaded = make_raw_surface_ptr(IMG_Load(fn.c_str()));


Cheers.

And this works if you take out your call to draw_line_to()?
Quote:Original post by Kylotan
And this works if you take out your call to draw_line_to()?

If I take that out, it crashes on this line in draw_line_to() which is called in my render loop:
set_pixel(surface, x, y, colour);

with x=102 and y=402, which is greater than the surface size because it is w=427 h=127. I'd say this is to do with the if(steep) check and that I'd have to create the surface size as a square based on the largest x/y component... Got it! Thanks for the prompting Kylotan. :D

Another thing I had to change was take p1 from x & y when setting the pixel, because it was in screen coordinates instead of surface coordinates:
SDL_Surface* draw_line_to(const PointI& source, const PointI& target, const SDL_Color& colour){    using namespace Surface_Tools;    SDL_Surface* surface = NULL;    PointI p1, p2;    if(source.x < target.x)    {        p1.x = source.x;        p2.x = target.x;    }    else    {        p1.x = target.x;        p2.x = source.x;    }    if(source.y < target.y)    {        p1.y = source.y;        p2.y = target.y;    }    else    {        p1.y = target.y;        p2.y = source.y;    }    PointI diff(p2 - p1);    int largest_component = std::max<int>(diff.x, diff.y);    PointI sfc_size(largest_component, largest_component);        surface = create_blank_surface(sfc_size);    bool steep = abs(p2.y - p1.y) > abs(p2.x - p1.x);    if(steep)    {        std::swap(p1.x, p1.y);        std::swap(p2.x, p2.y);    }    if(p1.x > p2.x)    {        std::swap(p1.x, p2.x);        std::swap(p1.y, p2.y);    }    int delta_x = p2.x - p1.x;    int delta_y = abs(p2.y - p1.y);    int error = delta_x / 2;    int y_step = 0;    int y = p1.y;    y_step = p1.y < p2.y ? 1 : -1;    for(int x = p1.x; x < p2.x; ++x)    {        if(steep)        {            set_pixel(surface, y - p1.y, x - p1.x, colour);        }        else        {            set_pixel(surface, x - p1.x, y - p1.y, colour);        }        error = error - delta_y;        if(error < 0)        {            y += y_step;            error += delta_x;        }    }    return surface;}

This topic is closed to new replies.

Advertisement