Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: SFML2.0 - excessive memory usage when loading images  (Read 1910 times)

0 Members and 1 Guest are viewing this topic.

starkhorn

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • Email
SFML2.0 - excessive memory usage when loading images
« on: November 23, 2014, 04:22:42 am »
Hi Folks,

I'm still new to programming and sfml (using sfml2.0). I've noticed that the memory usage goes way up very quickly in my system task manager (5-6GB within 10-15min of play for example).

I'm trying to do a simple RISK type war strategy game where I have a map of the world divided up into specific regions, i.e. Spain, France etc.
So I've got a Region class which will have a jpg image filename that I want to load into the program and display the region. The region color changes depending on which nation controls that particular region.
So nothing too fancy at all. I've essentially followed the tutorial http://sfml-dev.org/tutorials/2.0/graphics-sprite.php in order to determine how to load in images via SFML.

So I've created a region class, which has a texture, sprite, filename and a position. See below.

class Region
{
public:
        Region();
       
        struct Position
        {
                int xPos;
                int yPos;
        };

        string getRegionImageFileName();
        Position getImagePosition();
        sf::Texture getRegionImageTexture();
        sf::Sprite getRegionImageFileSprite();


private:
       
        string regionImageFileName;
        Position imagePosition;
        sf::Texture  regionImageFileTexture;
        sf::Sprite regionImageFileSprite;
};
 

So in the main game loop create a vector of this Region class which defines all of these parameters. (I actually read it in from a text file but that is really relevant for my question). I also have a drawEngine class which has pointer to the Region vector that contains all of the regions. It also has a Sprite, sprite pointer and texture pointer defined as well as the renderwindow.

class drawEngine
{
public:
        drawEngine();

        int drawAllRegions(); //this draws out the list of regions to the screen.
        void drawRegion(Region passed_Region);
        sf::RenderWindow gameWindow;

private:
        vector<Region> *regionListPtr;
       
        void initSpriteTextureData(Region passed_Region);
        sf::Sprite * spritePtr;
        sf::Sprite sprite;
        sf::Texture * texture;
};
 

So during each turn, I need to go through this vector and display each region's image file at the correct position.I have a function drawAllRegions() that goes through the vector and calls the drawRegion function.

int drawEngine::drawAllRegions()
{
        gameWindow.clear(sf::Color::Black);

        for (int i = 0; i < regionListPtr->size(); i++)
        {
                drawRegion(regionListPtr->at(i));
        }
       
        mapBorder.setFillColor(sf::Color::Transparent);
        return 0;
}
 

The drawRegion function inturn calls the initSpriteTextureData function to define the drawEngine's sprite. Once defined, this function draws the sprite.

void drawEngine::drawRegion(Region passed_Region)
{
        initSpriteTextureData(passed_Region);
        gameWindow.draw(sprite);
}
 

As you can see the initSpriteTextureData function, gets the data defined in the Region class and then defines the drawEngine's sprite.

void drawEngine::initSpriteTextureData(Region passed_Region)
{
        spritePtr = &passed_Region.getRegionImageFileSprite();
        texture = &passed_Region.getRegionImageTexture();
        texture->loadFromFile(passed_Region.getRegionImageFileName());
        spritePtr->setTexture(*texture);
        spritePtr->setPosition(passed_Region.getImagePosition().xPos,passed_Region.getImagePosition().yPos);
       
        //  Add set color according to nation color
        Nation::nationRGB tempNatColour = passed_Region.RegionNationOwnerPtr->getNationColour();
        spritePtr->setColor(sf::Color(tempNatColour.red,tempNatColour.green,tempNatColour.blue));
       
        sprite=*spritePtr;
}
 

Now I've confirmed that this is the part of the code that is eating up all of the memory as I commented out the line below and the game went through fine without using up hardly any memory at all.

texture->loadFromFile(passed_Region.getRegionImageFileName());
 

Clearly the way I am doing it is not the most efficient way, i.e. I am loading from file each time initSpriteTextureData is called. This load image file can get called a few hundred of times in a single iteration of the game loop. Obviously I'm being dumb here as I literally just followed how to load an image from the tutorial and didn't concern myself with memory issues. :)

My question, is there a most efficient memory-usage wise way to load in the images once from file into memory and then use the memory copy instead? Please bear in mind that I am still trying to learn SFML so appreciate this might be a silly question.

I've read the below "http://sfml-dev.org/documentation/2.0/classsf_1_1Texture.php", and I've seen the loadfromMemory function. The name of the function suggests it but, does this allow me to re-use a image file that has already been loaded from a file? I assume that this should stop the memory usage increasing?

I am very confused by the parameters below:-

data   Pointer to the file data in memory
size   Size of the data to load, in bytes

How can I keep track of where the image file data is stored in memory? Also is the size parameter the file-size or is that defined somewhere else?

Many thanks in advance.

Hapax

  • Hero Member
  • *****
  • Posts: 3364
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: SFML2.0 - excessive memory usage when loading images
« Reply #1 on: November 23, 2014, 04:44:57 am »
You should only be loading a texure (especially from a file) at (or near) the beginning of a program (or when changing texture sets, or need to dynamically switch on the graphic card etc.). You then can assign these textures to sprites as needed.

That said, I'm unaware if there were any bugs related to this in v2.0. You should seriously consider upgrading to v2.1 and if you're feeling and extraordinary need for less bugs etc., you could consider building SFML from the latest source (or download a pre-built version from Nightly Builds)
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

starkhorn

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • Email
Re: SFML2.0 - excessive memory usage when loading images
« Reply #2 on: November 23, 2014, 08:27:48 am »
Ahh ok, makes perfect sense. So I've changed it around to load from file only during the initial phase and then set the texture on a sprite during the draw region function. No excessive memory usage and it goes super fast now! Many many thanks for pointing me in the correct direction.

No bug, just bad programming! :) however I will upgrade to 2.1 to be safe.
« Last Edit: November 24, 2014, 03:28:18 am by starkhorn »

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re: SFML2.0 - excessive memory usage when loading images
« Reply #3 on: November 24, 2014, 02:21:54 pm »
however I will upgrade to 2.1 to be safe.
I would recommend to upgrade to the latest SFML revision on GitHub, a lot of things have improved since 2.1. If you don't want to build SFML yourself, eXpl0it3r's Nightly Builds are always an option.

About your code, there are a few things. First, I would not omit the std:: prefix... It helps you see directly that things are from the standard library and potentially avoids naming conflicts. Especially in headers, using namespace is an absolute no-go. Furthermore, vector<Region> *regionListPtr; as a member is a bit questionable, why the pointer?

And instead of iterating like
for (int i = 0; i < regionListPtr->size(); i++)
{
    drawRegion(regionListPtr->at(i));
}
you could use the correct types, the (for iterators) more efficient pre-increment, and the faster operator[] which has no useless bound check.
for (std::size_t i = 0; i < regionListPtr->size(); ++i)
   drawRegion((*regionListPtr)[i]);

In general, for iteration you should prefer iterators over indices, since not every container provides the latter. This is also equally or more efficient.
for (auto itr = regionListPtr->begin(); itr != regionListPtr->end(); ++itr)
   drawRegion(*itr);

If you simply iterate over all elements, the range-based for loop is also a possibility, making your code much more readable:
for (const Region& r : *regionListPtr)
   drawRegion(r);
« Last Edit: November 24, 2014, 02:28:47 pm by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development: