OGRE-Next  2.3
Object-Oriented Graphics Rendering Engine
Tunning memory consumption and resources

Ogre has the following samples to show how to cleanup memory:

  1. Samples/2.0/Tutorials/Tutorial_Memory
  2. Samples/2.0/Tests/MemoryCleanup
  3. Samples/2.0/Tests/TextureResidency

Memory is not released immediately. Of special relevance functions for cleanup are:

  1. SceneManager::shrinkToFitMemoryPools
  2. VaoManager::cleanupEmptyPools

Notice that these can take a large time as they defragment memory thus they should not be called aggressively

For tracking resource consumption there is:

  1. VaoManager::getMemoryStats (see Samples/2.0/Tutorials/Tutorial_Memory)
  2. TextureGpuManager::dumpStats
  3. TextureGpuManager::dumpMemoryUsage

Grouping textures by type

You can iterate through all textures (TextureGpuManager::getEntries) and call:

  1. TextureGpu::getSettingsDesc to get a string describing the texture
  2. TextureGpu::getSizeBytes
  3. TextureGpu::getSourceType to understand where it comes from (regular textures vs compositor vs shadow mapping, etc)

Dynamic vs Default buffers

BT_DEFAULT_DYNAMIC is optimized for data that is modified every frame from scratch. It's rare to have to have a lot of this type of data except for particle FXs.

By default we triple the buffer size because Ogre manually synchronizes data to prevent arbitrary stalls. Ogre 1.x let the driver handle synchronization.

If your code was structured to map the buffer, even though you should be using BT_DEFAULT then we recommend you simply use a malloc'ed memory ptr:

// Old code
void *data = buffer->map( ... );
// write to data
buffer->unmap();
// New code
// write to data
buffer->upload( data, 0, numElements );
OGRE_FREE_SIMD( data, MEMCATEGORY_GEOMETRY ); // Or leave the pointer around for reuse later
#define OGRE_FREE_SIMD(ptr, category)
Free the memory allocated with either OGRE_MALLOC_SIMD or OGRE_ALLOC_T_SIMD. Category is required to ...
Definition: OgreMemoryAllocatorConfig.h:478
#define OGRE_MALLOC_SIMD(bytes, category)
Allocate a block of raw memory aligned to SIMD boundaries, and indicate the category of usage.
Definition: OgreMemoryAllocatorConfig.h:470
@ MEMCATEGORY_GEOMETRY
Geometry held in main memory.
Definition: OgreMemoryAllocatorConfig.h:164

Tweaking default memory consumption by VaoManager

When initializing Ogre through the first Root::createRenderWindow, you can provide settings via NameValuePairList params.

It accepts the following

// Use double buffer instead of triple buffer to decrease latency,
// lowers BT_DEFAULT_DYNAMIC consumption
params.insert( std::make_pair( "VaoManager::mDynamicBufferMultiplier", "2" ) );
// Used by GL3+ & Metal
params["VaoManager::CPU_INACCESSIBLE"] = Ogre::StringConverter::toString( 8u * 1024u * 1024u );
params["VaoManager::CPU_ACCESSIBLE_DEFAULT"] = Ogre::StringConverter::toString( 4u * 1024u * 1024u );
params["VaoManager::CPU_ACCESSIBLE_PERSISTENT"] = Ogre::StringConverter::toString( 8u * 1024u * 1024u ;
params["VaoManager::CPU_ACCESSIBLE_PERSISTENT_COHERENT"] = Ogre::StringConverter::toString( 4u * 1024u * 1024u );
// Used by Vulkan
params["VaoManager::CPU_INACCESSIBLE"] = Ogre::StringConverter::toString( 64u * 1024u * 1024u );
params["VaoManager::CPU_WRITE_PERSISTENT"] = Ogre::StringConverter::toString( 16u * 1024u * 1024u );
params["VaoManager::CPU_WRITE_PERSISTENT_COHERENT"] = Ogre::StringConverter::toString( 16u * 1024u * 1024u ;
params["VaoManager::CPU_READ_WRITE"] = Ogre::StringConverter::toString( 4u * 1024u * 1024u );
params["VaoManager::TEXTURES_OPTIMAL"] = Ogre::StringConverter::toString( 64u * 1024u * 1024u );
// Used by D3D11
params["VaoManager::VERTEX_IMMUTABLE"] = Ogre::StringConverter::toString( 4u * 1024u * 1024u );
params["VaoManager::VERTEX_DEFAULT"] = Ogre::StringConverter::toString( 8u * 1024u * 1024u );
params["VaoManager::VERTEX_DYNAMIC"] = Ogre::StringConverter::toString( 4u * 1024u * 1024u );
params["VaoManager::INDEX_IMMUTABLE"] = Ogre::StringConverter::toString( 4u * 1024u * 1024u );
params["VaoManager::INDEX_DEFAULT"] = Ogre::StringConverter::toString( 4u * 1024u * 1024u );
params["VaoManager::INDEX_DYNAMIC"] = Ogre::StringConverter::toString( 4u * 1024u * 1024u );
params["VaoManager::SHADER_IMMUTABLE"] = Ogre::StringConverter::toString( 4u * 1024u * 1024u );
params["VaoManager::SHADER_DEFAULT"] = Ogre::StringConverter::toString( 4u * 1024u * 1024u );
params["VaoManager::SHADER_DYNAMIC"] = Ogre::StringConverter::toString( 4u * 1024u * 1024u );
static String toString(float val, unsigned short precision=0, unsigned short width=0, char fill=' ', std::ios::fmtflags flags=std::ios::fmtflags(0))
Converts a float to a String.

Note the default settings are different for Mobile (Android + iOS) builds

Vulkan and <tt>TEXTURES_OPTIMAL</tt>

The pool VaoManager::TEXTURES_OPTIMAL is used on many GPUs but not all of them.

As it depends on VkPhysicalDeviceLimits::bufferImageGranularity property. When this value is 1, then VaoManager::TEXTURES_OPTIMAL pool is not used because all texture memory will go to the VaoManager::CPU_INACCESSIBLE pool. Mostly AMD, and some Intel and Qualcomm GPUs are able to use this.

When the property is not 1, then all textures are placed into VaoManager::TEXTURES_OPTIMAL while buffers go into VaoManager::CPU_INACCESSIBLE.