User Tools

Site Tools


Using the Reserves System

The SpeedTree SDK has a series of “reserve” values that allow the developer some measure of control over when and how many heap allocations are made. These reserves mostly affect streaming and culling operations in the Forest library.

For console developers especially, keeping heap fragmentation under control is a key concern. The term “reserve” in this context is similar to std::vector<>'s reserve() function (don't worry, we don't use STL in the SpeedTree SDK). Without a reserve call, std::vector<> will double its capacity as it grows, fragmenting the heap unnecessarily, especially when we may already know its final size before populating it. By providing the SpeedTree SDK a few hint reserve values, it's possible to reduce the number of heap allocations it needs to make as well as to prevent any allocations from being made in the render loop.

Note that if the SDK exceeds these values, it should not result in an error. The worst case may be that the SDK makes a heap allocation during the render loop, but the SDK can be put in a mode to issue warnings when this happens.


Using the System

The heap reserve system is centered around the SHeapReserves structure defined in Forest.h:

struct SHeapReserves
{
    // the max number base trees expected to be used in a given forest (not many 
    // more than 20-30 is recommended)
    st_int32  m_nMaxBaseTrees;                      
 
    // the max number of tree cells visible at any one time in the camera frustum
    st_int32  m_nMaxVisibleTreeCells;
    // the max number of grass cells visible at any one time in the camera frustum
    st_int32  m_nMaxVisibleGrassCells;
    // the max number of terrain cells visible at any one time in the camera frustum
    st_int32  m_nMaxVisibleTerrainCells;
 
    // across all base trees, the max number of instances in any tree cell
    st_int32  m_nMaxTreeInstancesInAnyCell;
    // for any single base grass, the max number of instances in any grass cell
    st_int32  m_nMaxPerBaseGrassInstancesInAnyCell; 
 
    // # of expected shadow maps; isn't dynamic and should never exceed 4
    st_int32  m_nNumShadowMaps;
};

For an example usage, look at the CMyApplication::SetHeapReserves() function in MyApplication.cpp in the reference application. It uses a SHeapReserves object to set up reserves for the tree stream/cull system, the grass stream/cull systems, and the shadow system. It also uses another example function, CMyInstancesContainer::ComputeHeapReserveGuess(), which takes parameters about the current parameters and makes pretty solid guesses at reasonable max values for each of the member variables in SHeapReserves. Several are based on the shape of the frustum on the cell sizes used in each.

Note: Outside of the terrain system and a few other example data structures in the reference application, only the CVisibleInstances class uses the SHeapReserves structure. Be sure to address each instance where this class is instantiated and used: main tree view, each grass layer, light views, alternate views (e.g. window-in-window), etc.

Ideally, users will know enough about the limits of their own forests to be able to set-up exact values per level or world that are not safe guesses. Reserves can be set again, but new objects will need to be used (that is, once an object has its reserves set, they can't be changed with ease, especially if lower values are used).

Note that the terrain system also accepts reserve values, but our terrain system is merely an example to round-out our reference application. While users are welcome to use parts or all of it, we assume each user has their own terrain system.


Warning System

If the reserves have been set properly, no heap allocation should need to be made after the various system have been initialized. If an allocation is made, it's possible to have the SDK issue a warning through the Core library's error system.

In Core.h, uncomment “#define ST_RUNTIME_HEAP_CHECK” and recompile the Core and Forest libraries. This enables a utility macro called ST_HEAP_ALLOC_CHECK which monitors changing capacities at key locations within the SDK (mostly the Forest library). The warning will provide source file and line number as well as which reserve hint should be changed to prevent the allocation in the future.