Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Major Memory Issue in Allegro 5 Project

This thread is locked; no one can reply to it. rss feed Print
Major Memory Issue in Allegro 5 Project
gamepopper
Member #15,975
June 2015
avatar

Hey guys,

I'm working on an Allegro 5 game and have some huge memory problems. The game is a Roguelike Shmup where every visual asset is made from ASCII characters, this means that every visual element has originated from a .ttf font file and a series of chars or strings.

oUifz6h.gif

So from the GIF above, it all looks good. The game also has a level generator and the ability for a player to move around and collide with the walls, and there's even enemies and items to interact with. The problem lies when I saw it running in the Windows Task Manager:

{"name":"CG-p5POXIAAe_Wz.png","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/8\/f\/8f49b86905ebb7e1bd1be336944d60ed.png","w":596,"h":87,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/8\/f\/8f49b86905ebb7e1bd1be336944d60ed"}CG-p5POXIAAe_Wz.png

I decided to let it run through Visual Studio's Memory Usage Profiler to see where this 1.8GB RAM usage is coming from, and this is what I find:

{"name":"CG-xjUiW0AAe1Xa.png","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/4\/8\/48a35912ce2facca0c5ba77e7a151b06.png","w":596,"h":77,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/4\/8\/48a35912ce2facca0c5ba77e7a151b06"}CG-xjUiW0AAe1Xa.png

So it appears a lot of memory is being used in allocating and destroying data within the allegro library.

My best theory so far as to why I've got this huge memory load is because of the way I'm creating the visual assets. In order to make it possible to create more visually interesting assets and reduce the amount of text rendering calls, I instead create and render bitmaps. The string of characters are then drawn onto the bitmaps in a process like this:

#SelectExpand
14ALLEGRO_BITMAP* bitmap = al_create_bitmap(FrameWidth, FrameHeight); 15ALLEGRO_FONT* font = al_load_ttf_font("Assets\\lucon.ttf", 32, 0); 16 17al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); 18 19al_set_target_bitmap(bitmap); 20al_clear_to_color(al_map_rgba(0, 0, 0, 0)); 21al_draw_text(font, al_map_rgb(255, 245, 36), FrameWidth/2.0f, -2, ALLEGRO_ALIGN_CENTRE, "@"); 22al_flip_display(); 23al_set_target_backbuffer(Reg::Display); 24al_destroy_font(font); 25 26al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA);

This way each object, including a Particle System, will use a bitmap each. instead of one to many text draw calls.

So this will probably be obvious, but considering you know the framework more than I do, I was wondering if you have any advice for what could be causing the issue based on the above evidence, and any way I can do it better so it won't require at least 2GB of memory to run.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

It only does what you tell it to. How many objects (and therefore, how many bitmaps) do you have?

You may want to consolidate all your drawing onto a single buffer bitmap, despite having to re-render it perhaps many times. With HW accel, A5 does fairly well at drawing many thousands of objects per frame, and you can usually get away with redrawing on every frame.

More code would probably be helpful too. You may have a memory leak somewhere as well.

Chris Katko
Member #1,881
January 2002
avatar

Do you have a memory leak? Are temporary assets not getting freed?

Are you doing anything sketchy, like storing thousands of individual bitmaps for every variation of your fonts when you could just modify them as you draw? (ala a complete font stored for the color red, instead of the normal white font that gets colored red as it is drawn.)

It's also possible you've got a huge bitmap overhead by storing tons of tiny bitmaps (each with their own header data), when you could be storing them all on a few textures and using sub-bitmaps to draw them. (Someone who knows A5's allocation strategy chime in. It certainly doesn't automatically group small sprites onto single textures, does it?)

Ala this would be a single texture/bitmap in memory:

{"name":"ASCII-vga.gif","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/f\/3\/f37148e48cd3c467e6b72630ecda2e87.gif","w":290,"h":160,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/f\/3\/f37148e48cd3c467e6b72630ecda2e87"}ASCII-vga.gif

And you would only draw the specific coordinates, or use sub-bitmaps to draw it.

-----sig:
“Programs should be written for people to read, and only incidentally for machines to execute.” - Structure and Interpretation of Computer Programs
"Political Correctness is fascism disguised as manners" --George Carlin

gamepopper
Member #15,975
June 2015
avatar

Okay well the example above is what would be called in a game object's initialise function, so it's only called once on the creation of an object.

In the scene above, there are two objects (the tilemap and the purple portal), the tilemap uses one bitmap that when rendered is separated into fixed size tiles for rendering a 2D array, and the portal has two bitmaps, one for the centre and one for the particle system (the particles only store position, rotation and scaling data, each particle renders from one single texture).

There is also one bitmap for the "GEM FINDER" logo and two font variables for the large fonts and the small font.

So that makes four unique bitmaps and two unique fonts being used for rendering.

The entire scene is rendered onto a bitmap to act as a buffer, so it can be scaled and then rendered onto the backbuffer.

#SelectExpand
55float sx = Reg::WindowWidth / (float)Reg::ScreenWidth; 56float sy = Reg::WindowHeight / (float)Reg::ScreenHeight; 57float scale = std::fminf(sx, sy); 58 59float scaleW = Reg::ScreenWidth * scale; 60float scaleH = Reg::ScreenHeight * scale; 61float scaleX = (Reg::WindowWidth - scaleW) / 2; 62float scaleY = (Reg::WindowHeight - scaleH) / 2; 63 64al_set_target_bitmap(Reg::Buffer); 65al_clear_to_color(al_map_rgb(0, 0, 0)); 66 67Render(); 68al_flip_display(); 69 70al_set_target_backbuffer(Reg::Display); 71al_clear_to_color(al_map_rgb(0, 0, 0)); 72al_draw_scaled_bitmap(Reg::Buffer, 0, 0, Reg::ScreenWidth, Reg::ScreenHeight, scaleX, scaleY, scaleW, scaleH, 0); 73al_flip_display();

Also, to make things more accessible, the Allegro_Display, the Allegro_EventQueue and some details about the screensize and frame rate are kept in a static class called Reg.

beoran
Member #12,636
March 2011

Do you clean up your bitmaps after use with al_destroy_bitmap taking care not to leak any?

Also , in Allegro 5 you can get scaling for free using transformations. You don't need a buffer bitmap, just set a scaling transform and then draw to the screen directly.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

That doesn't sound all that memory intensive. Are you copying your objects? That could explain multiple allocations on Init() calls in the constructors. Do you have a destructor that frees the memory used?

Also, TaskManager is not so useful for memory usage statistics. Much of that memory could have been freed by your application, but not have been reclaimed by Windows yet, as there wasn't a need for it.

However the memory profile from VS you showed makes it look like you have a runaway memory leak, so I'm not sure what to think.

Can you try to create a smaller example program that demonstrates this same behaviour?

gamepopper
Member #15,975
June 2015
avatar

Solved the issue, and god this is embarrassing.

Turns out I completely missed the draw function of the TitleState scene, which had this line:

ALLEGRO_BITMAP* UILayer = al_create_bitmap(1280, 720);

It was not being used at all, and was being called around 120 per second. -_-

So now the game runs at a more reasonable 33MB of memory.

{"name":"CHARc4NXIAAKJ06.png","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/1\/4\/14af16b4fa7b33001fde284610b577c0.png","w":572,"h":16,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/1\/4\/14af16b4fa7b33001fde284610b577c0"}CHARc4NXIAAKJ06.png

beoran
Member #12,636
March 2011

As I suspected, but good to hear you found it! :)

Go to: