clintbellanger / flare

Free Libre Action Roleplaying Engine
http://clintbellanger.net/rpg/
GNU General Public License v3.0
166 stars 41 forks source link

Thoughts on memory usage. #857

Closed stefanbeller closed 12 years ago

stefanbeller commented 12 years ago

So I measured the memory usage of flare using the tool massif tool in the valgrind framework. I am using the default configuration (Just clicked on "Reset all settings") The hero is just standing near the teleport zone in ydrakka pass. Here is an image of the heap memory being used: https://raw.github.com/stefanbeller/flare/memory_analysis/memory_detailed.png

At the top of the image there is all the heap, which is then split up into multiple locations which are each annotated and if they are large enough these locations are annotated again to find the largest memory usage.

So when you take the heap at the top (having 145MB) and check the children of that tree, you'll notice that about 134 MB are eaten by SDL_CreateRGBSurface. If you follow the the children again, you'll see that the EnemyManager accounts for 71.8 MB (about half the memory being used!).

In the enemies manager all the enemy sprite sheets are loaded and that's the memory we are looking for. So how to optimize those? The images need to be uncompressed in memory to have fast access to them, so there is no real thing we can do in coding.

The one thing we can do is reducing the actual size of the sprite sheets. Have a look at them: https://raw.github.com/stefanbeller/flare/memory_analysis/mods/fantasycore/images/enemies/zombie.png

There is lots of transparent area. It doesn't matter for saving it on disk as there it is compressed. But if such an image is loaded into RAM it gets uncompressed and each transparent unneeded tile accounts its full one pixel memory (well each pixel gets 4 bytes, but the number of all the pixels make it large.)

If I understood @clintbellanger correctly, we want to have as little SDLSurfaces (these sprite sheets) as possible, as there comes other overhead if we chop such a sprite sheet up in dozens of new smaller sheets.

So I propose to reduce the distance between each of two frames individually and put the coordinates of each frame into a config file. This will remove lots of transparent space hence reduce the memory.

I wonder if it would be easy to write a tool for this or if such a tool already exists. That tool would read in a sprite sheet and locate the individual frames. Then the size of all the frames needs to be detected. A new image and a config file could be written containing a compressed version of a sprite sheet. The config file would need to exactly describe where a single frame is to be found.

As of now the animations configs are rather easy to understand (and probably also to write) because of the grid like structure of the spritesheet, see https://github.com/stefanbeller/flare/blob/memory_analysis/mods/fantasycore/animations/zombie.txt

Only once we define the grid at the very beginning and then the different animations are described by giving an index and the number how many following frames are required. This would likely change to a more complex format, but assuming a tool exists to shrink images and writing the new config I think that would be a viable way.

What do you think?

stefanbeller commented 12 years ago

Oh just noticed, this would not only help reducing the enemy managers memory, but also of the PowerManager. The tileset class already follows such an approach to define each tile individually.

clintbellanger commented 12 years ago

This is called sprite sheet "packing".

There would be significant memory savings doing this for the enemy sprite sheets. It'd be a small saving for other images, like powers.

The hero is different; it's hard to predict the total size needed per frame because we're combining several layers. It would be possible to try "packing" the hero images at runtime, but that would make changing equipment terribly slow. I think sacrificing the memory needed to hold unpacked hero images is completely fine.

We'd definitely want to automate this for the enemy sprite sheets. It's possible ImageMagick can do this (with montage perhaps), but we might have to write our own utility if we want to export the x,y,w,h,offx,offy of each frame.

Note 1: We should still accept the current style of sprite sheets. If no per-tile definition is provided, use the single frame size as we currently do. This helps with testing new animations and will help modders who want to use simple sprite sheets.

Note 2: this kind of aggressive optimization should wait until Beta, but it's fine to talk about it now.

stefanbeller commented 12 years ago

So the sprite sheet packing is possible now. Once I'll find some more time I try to come up with a good sprite sheet packing tool which allows to read and write the animation definition files of flare. The current status of that tool should be found on my master branch.

TODO for flare regarding this issue:

clintbellanger commented 12 years ago

Awesome. The gains for entities are the major win here. Most other animations are tiny and can probably do without packing. Example, the powers animations could simply be trimmed by the artist.