User Tools

Site Tools

Keeping Memory Usage Low

There are numerous techniques to reduce memory usage in the SDK and the SpeedTree Modeler and Compiler applications. To monitor how much heap space and vertex/index buffer memory the SDK is using, please refer to this section. To reduce areas of possible excess memory use, follow these guidelines.

Geometry and the Core Library

Loading SRT files can consume a fair amount of memory (specifically, the size of the SRT file). Here are a few tips for reducing memory usage after load:

  1. After querying the tree's geometry to build your application's vertex and index buffers, call CCore::DeleteGeometry() on the loaded object to delete the internal copies of the vertices and indices, which represent the bulk of the memory allocated by the load function. Care should be taken about buffer ownership on SRT loads which relates to DeleteGeometry().

  2. In addition to keeping art assets of reasonable size, using the smallest number of unique SRT files in a forest is also recommended (note that this does not restrict the number of trees in a scene, only the number of unique trees). Not only will it reduce the amount of memory used, but it will increase the speed of the forests renders through a reduction in state changes. A few unique SRT files in a given forest can go along way if varied rotations, scales, and hue variation are used.

  3. If you're done using SpeedTree SDK at any point in the application, be sure to call CCore::ShutDown(). It's a static function that will clear up the last remaining memory used by the SDK.

Geometry and the Modeler

There are a number of steps that artists can take to lower memory usage when creating assets in the SpeedTree Modeler.

  • Most importantly, keep in mind that each LOD level uses memory. Specifically, each LOD level uses independent vertex and index tables, so using using fewer LOD levels will save overall memory. Ultimately, after calling CCore::DeleteGeometry(), this memory will reside on the GPU, not in system RAM.
  • Take care not to overbuild geometry. How much of the branches and fronds are still visible when the leaves are on? If they can't be eliminated, can their resolution be reduced? Refer to the Modeler documentation for polygon-reducing techniques to employ.
  • Take advantage of the excellent LOD system and drop out detail as rapidly as possible. Look at trees in the model library for good example LOD implementations.
  • Try to keep the total # of vertices for all LODs for each geometry type below 65,535. Once this threshold is crossed, the SDK index buffer will double in size (switched from 16-bit to 32-bit indices). It takes a whopper of a tree model for one of the geometry types to exceed 65k vertices.
  • Some of the rendering effects require extra texture map space. For example, if normal mapping is not needed or used, be sure not to generate a normal texture atlas (the SDK will default to using flat maps). However, if even one tree model in an atlased forest uses normal mapping, then the Compiler will generate a normal map atlas to match the diffuse atlas and in this case, no memory will be saved by the other trees not using normal maps

Vertex Buffers

The vertex buffers are serialized straight out of the SRT file. The vertex declarations can vary per-model and per-material. The more effects that are enabled through the Compiler's Effect LOD dialog, the larger the vertex declarations will be, increasing the vertex buffer size. 16-bit float and single-byte values are the basic types used. Minimum-effects vertex declarations can be as small as 16 bytes, where high-effect declarations may get as large as 48, 52, or more bytes.

Note that the SDK will use 16-bit indices whenever possible but will shift into 32-bit mode on an as-needed basis. For one tree model (i.e. one SRT file), the SDK will look at all of the branch geometry LODs collectively. If the number of vertices exceeds 65,535, it will use 32-bit indices only for that one tree model's branch geometry. The SDK will then look at fronds and then finally leaf meshes, using the appropriate index size each time.

Textures and the Compiler

The bulk of the memory used by the SDK comes from the texture maps it loads. We encourage programmers to familiarize themselves with the SpeedTree Compiler application, which generates and manages all of the textures used by individual trees and whole forests.

  1. Manage atlas generation carefully. Note where the bulk of the texture is consumed. Can some of the sub-textures be reduced? How much of the atlas is being wasted? Is the map close to the next power-of-2 size down?

  2. The SpeedTree model library ships with very high resolution textures, largely because it's always easier to scale down than to scale up resolution. Can your application get away with smaller versions? If not, then only smaller in some areas?

  3. The Compiler will generate Normal and Specular map atlases by default. Does your application need both? The SDK will default to appropriate placeholder textures on load if none are generated by the Compiler. Note that from a memory usage perspective, if one tree in an atlas uses normal maps, then they may as well all use them since they're included in an atlas that matches the diffuse map in size.

Forest Library

Outside of the Core library, where per-tree memory costs are paramount, the Forest library's memory consumption is directly related to the number of visible tree/grass instances.

Draw Distance

A common mistake is employing too large a draw distance. Long draw distances impact both memory and performance in the following ways:

  • More memory consumed by the CVisibleInstances class to represent the visible 3D trees, their LOD values, and all of the visible billboards.
  • The culling procedures will take longer to execute due to the increased cell count (although 3D tree processing will remain largely unaffected).
  • Longer draw distances will consume considerably more billboard instance vertex buffer space.

Heap Reserves

Use the heap reserve system in the SDK to set limits for various quantities, receiving warnings in most cases when the limits are exceeded.