[2.1] How to properly unload meshes

Discussion area about developing with Ogre2 branches (2.1, 2.2 and beyond)
Post Reply
chchwy
Gnoblar
Posts: 23
Joined: Fri Feb 10, 2017 1:40 am
x 8

[2.1] How to properly unload meshes

Post by chchwy » Mon May 06, 2019 5:38 am

Hey guys,

Just wondering the correct way to unload a scene for freeing up memory.

Currently I am using the following function to destroy things, I passed a scene node to it and destroy everything under the node.
But it doesn't work as I expected, the meshes did disappear and got removed from the scene tree but the memory usage didn't go down.

Code: Select all

void DestroyItemRecursively(Ogre::SceneNode* node, Ogre::SceneManager* sceneManager)
{
    auto count = node->numAttachedObjects();

    std::vector<Ogre::MovableObject*> attachObjects;
    attachObjects.reserve(count);
    for (auto i = 0; i < count; ++i)
    {
        Ogre::MovableObject* movable = node->getAttachedObject(i);
        attachObjects.push_back(movable);
    }
    node->detachAllObjects();

    for (Ogre::MovableObject* movable : attachObjects)
    {
        sceneManager->destroyMovableObject(movable);
    }

    for (int i = 0; i < node->numChildren(); ++i)
    {
        Ogre::SceneNode* child = static_cast<Ogre::SceneNode*>(node->getChild(i));
        DestroyItemRecursively(child, sceneManager);
    }
    node->removeAndDestroyAllChildren();
}
What's the correct way to completely unload 3d models and get the memory back?
Do I have to remove Hlms materials and textures from the resource managers by their name manually?
Is there any way I can remove the unused materials and textures automatically?

Thanks.
Last edited by chchwy on Fri May 10, 2019 1:52 am, edited 1 time in total.
0 x

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4044
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 216
Contact:

Re: [2.1] How to properly unload meshes

Post by dark_sylinc » Thu May 09, 2019 8:01 pm

Your code appears correct.

But there's more to it:
  • Meshes don't get unloaded from GPU memory (aka VRAM). You need to call mesh->unload() for that. If you call MeshManager::getSingleton().remove( mesh ) then the mesh gets permanently removed and can't be used again (unless it's manually registered again)
  • The VaoManager has memory pools of VRAM. When a Mesh gets unloaded, the memory gets back into the pool. But the pool will still consume memory as per the OS's concerns. VaoManager::cleanupEmptyPools will restore that memory. Note that VaoManagers have an internal memory budget (i.e. minimum pool size) and thus will only release excess of pool memory.
  • Ogre internally has CPU pools for efficiently parsing Entity, Item and Nodes. These pools may have gotten too big, and won't go down even if you've destroyed the entities/items/nodes. You can reclaim that memory by calling SceneManager::shrinkToFitMemoryPools
  • Textures managed by HlmsTextureManager need to be released manually via HlmsTextureManager::destroyTexture, and they should not be in use by an HlmsDatablock when that happens (Texture memory management is one of the main reasons 2.2 branch was created!)
See the sample at Samples/2.0/Tests/MemoryCleanup/MemoryCleanupGameState.cpp (OGRE_BUILD_TESTS in CMake must be set). I can't remember if that sample got added in 2.2 or 2.1 though.

Note that these tips apply if you're very tight on memory (e.g. cellphone apps). If you're not having memory problems, Ogre assumes you will likely soon be using that memory again (e.g. an Item using that Mesh again gets creates, you reach a similar same number of items that you used to).

If you shrink excessively, you will only hurt performance as the price you paid at initialization time will now be paid periodically. Think of it like calling std::vector::shrink_to_fit() too often.
On shutdown Ogre will free this memory.
1 x

chchwy
Gnoblar
Posts: 23
Joined: Fri Feb 10, 2017 1:40 am
x 8

Re: [2.1] How to properly unload meshes

Post by chchwy » Fri May 10, 2019 2:45 am

Thank you for the detailed and informative explanation!

We are working on an iPad app so that's why we put a lot of attention on memory. Definitely we will try those tips.

I have a few more questions about the textures.

Since we are using the Ogre glTF plugin and it creates textures via Ogre::TextureManager rather than HlmsTextureManager, is there any difference between these 2 managers while unloading textures?

And as you said, I have to destroy the HlmsDatablock before unloading textures from HlmsTextureManager. So the right order to unload things is:
  1. Iterate through the scene tree and get all datablocks from Ogre::Item
  2. delete nodes & items
  3. get all texture pointers from the datablocks in step 1
  4. destroy datablocks
  5. destroy textures in HlmsTextureManager
Is it correct?
Last edited by chchwy on Fri May 10, 2019 3:42 am, edited 2 times in total.
0 x

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4044
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 216
Contact:

Re: [2.1] How to properly unload meshes

Post by dark_sylinc » Fri May 10, 2019 2:52 am

chchwy wrote:
Fri May 10, 2019 2:45 am
Since we are using the Ogre glTF plugin and it creates textures via Ogre::TextureManager rather than HlmsTextureManager, is there any difference between these 2 managers while unloading textures?
HlmsTextureManager is actually more like a "helper" system that internally uses TextureManager. Its main job is to put multiple textures into one giant array texture so draw call commands can be batched together, and its secondary job is to ensure correct loading of certain textures (e.g. ensure normal maps are loaded as RG8_SNORM).
Strictly speaking, the HlmsTextureManager is not necessary.

If you use TextureManager directly, then you don't need the HlmsTextureManager to intervene at all. Removal of textures created via TextureManager then is the same as with meshes (tex->unload() to free memory, TextureManager::getSingleton().remove to delete all memory pointers and make the texture completely unavailable)
chchwy wrote:
Fri May 10, 2019 2:45 am
  1. Iterate through the scene tree and get all datablocks from Ogre::Item
  2. delete nodes & items
  3. get all texture pointers from the datablocks in step 1
  4. destroy datablocks
  5. destroy textures from HlmsTextureManager
Is it correct?
Yes (but in your case it would be TextureManager)
0 x

Post Reply