copyToWithAlpha and createImageFromData memory management

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

copyToWithAlpha and createImageFromData memory management

Post by LunaRebirth »

Hi,

I'm trying to allow creating a new texture, which is taking one texture and copying another texture on top of it.
Then, I want to either save that texture in case I use it again, or drop it and remove it entirely from memory (when the object using it is destroyed, ofc).
However, I'm having troubles managing the memory for this.

Code: Select all

 
int texId = 0;
void copyTo(string fromImg, string toImg)
{
    // Grab the texture to place over the other texture
    ITexture* thisTex = driver->getTexture(fromImg.c_str());
    if (!thisTex)
        return;
    // Grab the texture to place over
    ITexture* sourceTex = driver->getTexture(toImg.c_str());
    if (!sourceTex)
        return;
    // Create a new image from the base texture
    IImage* sourceImg = driver->createImageFromData (
        sourceTex->getColorFormat(),
        sourceTex->getSize(),
        sourceTex->lock(ETLM_READ_ONLY),
        true
    );
    sourceTex->unlock();
 
    // Create a new image from the texture we're going to place over the previous texture
    IImage* newImg = driver->createImageFromData (
        thisTex->getColorFormat(),
        dimension2d<u32>(100, 100),
        thisTex->lock(ETLM_READ_ONLY),
        false // CRASH in COpenGLCoreTexture if this is set to true
    );
    thisTex->unlock();
 
    // Copy on top of other texture
    sourceImg->copyToWithAlpha(newImg, vector2d<int>(0,0), rect<s32>(0,0,100,100), SColor(255,255,255,255));
    sourceImg->drop();
 
    // Store the texture as, e.g. "MyTexture_2" so later I can getTexture "MyTexture_2" with the new image copied over it
    ITexture* newTex = driver->addTexture((fromImg + "_" + to_string(texId++)).c_str(), newImg);
    newImg->drop();
}
 
With this current code, my memory usage goes up about 15MB, then when I destroy the object referencing this new image (newTex, in this case), goes down about 8MB totaling a 7MB leak somewhere.
CuteAlien
Admin
Posts: 9646
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: copyToWithAlpha and createImageFromData memory managemen

Post by CuteAlien »

Without testing only suspicious thing I see on first look is the createImageFromData which tries to own memory from a texture lock(). You mentioned crash in other... this one should also crash unless you are a bit lucky (crashes can be a bit random). Don't try to take over memory from a texture lock() as the texture itself still owns it. So you try to release it twice. Thought doesn't sound like a leak.

If you use trunk or ogl-es branch there is btw. a trick now to find Irrlicht reference counted objects which never got drop'ed or deleted. But needs to recompile Irrlicht and should only be used in debug (as it will slown down things a bit). You can compile Irrlicht with _IRR_COMPILE_WITH_LEAK_HUNTER_ in IrrCompileConfig.h. Then before quitting your application (and after closing devices) you can call irr::LeakHunter::getReferenceCountedObjects() which will return an array with all objects which never got released. Thought doesn't work for stuff like internal memory.

If that doesn't help - I'll try to take another look under the week.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Re: copyToWithAlpha and createImageFromData memory managemen

Post by LunaRebirth »

Ohh I will try with the __IRR_COMPILE_WITH_LEAK_HUNTER_. I didn't realize that was an option.

What should I be doing instead of lock()'ing?
I thought that was how you access the pixel data of the texture, unless I'm mistaken?
CuteAlien
Admin
Posts: 9646
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: copyToWithAlpha and createImageFromData memory managemen

Post by CuteAlien »

The lock() is fine. I meant the true parameter in your first call to createImageFromData. In second call you use false and mention a crash - same crash can/will/should happen on first one. Also has to be false.

Also minor note: Second createImageFromData with fixed size of 100x100 will look pretty strange if thisTex isn't having a width of 100 originally.

Not seeing any other error, memory handling seems to be fine. How do you check for memory usage?
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Re: copyToWithAlpha and createImageFromData memory managemen

Post by LunaRebirth »

Gotcha.

Yes the images are all the same size (100x100).

Here's what I'm doing to test my reference counters, after setting that flag to false:

Code: Select all

 
void test()
{
    std::map<IReferenceCounted*, bool> beginObjs;
    auto arr = irr::LeakHunter::getReferenceCountedObjects();
    for (u32 i = 0; i < arr.size(); i++)
    {
        IReferenceCounted* obj = (IReferenceCounted*)arr[i];
 
        beginObjs[obj] = true;
    }
 
    std::string copy1 = "copy1.png";
    std::string copy2 = "copy2.png";
 
    copyTo(copy1, copy2); // Creates new texture "copy3.png"
        driver->getTexture("copy3.png")->drop();
 
    std::map<IReferenceCounted*, bool> endObjs;
    arr = irr::LeakHunter::getReferenceCountedObjects();
    for (u32 i = 0; i < arr.size(); i++)
    {
        IReferenceCounted* obj = (IReferenceCounted*)arr[i];
 
        endObjs[obj] = true;
    }
 
    std::map<IReferenceCounted*, bool>::iterator it;
    for (it = beginObjs.begin(); it != beginObjs.end(); it++)
    {
        endObjs.erase(it->first);
    }
    // endObjs should now have everything new
}
 
Theoretically when debugging, endObjs should only contain anything that wasn't deallocated since calling my copyTo() function.

I expected to see no IReferenceCounted objects, as I drop the newly created image directly after creating it, but actually there are 2 objects left in endObjs, both of which have a DebugName of 0x0 (NULL) and a ReferenceCounter of 1.

I was trying to figure out what these 2 references are being left from, and found that adding this to my copyTo function removed both references:
sourceTex->drop()

However, dropping this causes my client to crash the next time I try to use copyTo() again.
Crashes at sourceTex->lock(ETLM_READ_ONLY).


I'm watching Task Manager to monitor memory usage, and for every copyTo() call with a different texture, I can see there's a memory leak somewhere. I tried using Visual Studio's memory analyzer but unfortunately it hasn't been super helpful, only referring me to a call to COpenGLCoreTexture but not much else.
CuteAlien
Admin
Posts: 9646
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: copyToWithAlpha and createImageFromData memory managemen

Post by CuteAlien »

Never call drop() unless you did call grab(), created the objects with new() or after calling an Irrlicht method which starts with 'create'.

All textures you load with getTexture end up in the Irrlicht texture cache. To remove a texture from cache call driver->removeTexture. But note that if you do that it will actually re-load the texture in the next getTexture call (that's basically the point of the texture cache, you load identical textures only once instead of getting a new one every time you call getTexture).

If Irrlicht texture cache is something you'd like to avoid you can also take over memory management yourself. grab() textures after driver->getTexture and then call driver->removeTexture() immediately on them. Then you took over their memory handling and are responsible yourself for it.

And totally unrelated hint - check out std::set if you need a container which just keeps each object once. It's doing that (works like std::map with just keys and no need for a value).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Post Reply