This is the documentation for Enlighten.

Allocating working memory


Overview

This example demonstrates how to solve for the input lighting and output irradiance. Four additional temporary working memory buffers are required for the per-frame update loop:

  • One for the input lighting
  • One for the irradiance
  • One to receive the final output (persistent if using temporal solves)
  • One to receive the intermediate bounce output (persistent if using temporal solves)

The intermediate bounce output is generated as a secondary output of the irradiance solver, and is used as the input to the EndInputLighting pass.

When using temporal solves, the bounce output also accumulates lighting difference values; therefore it is necessary to use a unique persistent buffer for each system. The same applies to the final output textures since the temporal solver may only update this partially (or not at all) depending on the lighting changes.

Setting up a memory allocator

You must set a memory allocator before you can create or use any Enlighten object, including the IPrecompute object.
This is a change from the behaviour of previous Enlighten releases.

The file GeoBase/GeoMemory.h contains a virtual class MemoryAllocator and the associated function SetMemoryAllocator().

Enlighten ships with a default memory allocator, GeoMemoryDefault, which is implemented using the standard C library memory functions. You can either use this allocator, or instead implement a custom allocator to tie into your own memory management or to track memory usage.

Example using Enlighten's default memory allocator

Use this code in your main function, to ensure that the memory allocator exists for the full duration of your program:

Geo::GeoMemoryDefault alloc;
Geo::SetMemoryAllocator(&alloc);
Using a different memory allocator

To use a different allocator, derive from the MemoryAllocator class and call SetMemoryAllocator() as above.

The Enlighten runtime does not use the realloc function, so you can provide a dummy implementation for runtime use. However, if you are using the low-level precompute API then a proper implementation of realloc is required.

Ensure correct alignment if you change the actual allocation/de-allocation; otherwise errors may occur.

Working buffer for the input lighting

The input lighting task requires a small amount of scratchspace working memory. It depends on the list of lights passed to the task to work out the size of the required buffer:

// reserve workspace memory
Geo::u32 workspaceSizeRequired = Enlighten::CalcRequiredScratchSpaceMemory(lights, numLights);
void *   scratchMemory         = GEO_ALIGNED_MALLOC(workspaceSizeRequired, 16);

When solving input lighting for many systems, simply allocate a single buffer large enough for the largest task and then reuse it.

Working buffer for the solver

The solve functions also require some scratchspace working memory. The size depends on a given system's budget and the number of dependencies. Use the RadSystemCore structure to query Enlighten and thus get a working buffer of exactly the right size:

// reserve workspace memory
Geo::u32 irradianceMemoryRequired = Enlighten::CalcRequiredIrradianceTaskWorkspaceMemory(&myRadSystemCore);
void*    irradianceWorkspace      = GEO_ALIGNED_MALLOC(irradianceMemoryRequired, 128);

Output texture buffers

Allocate a buffer to receive the radiosity output:

// Create radiosity output texture.
Geo::s32 outputTextureSize       = radCore->m_MetaData.m_OutputWidth * radCore->m_MetaData.m_OutputHeight;
Geo::s32 outputTextureMemorySize = outputTextureSize * 8; // fp16 output = 8 bytes per pixel

void*    irradianceOutput        = GEO_ALIGNED_MALLOC(outputTextureMemorySize, 16);

Optionally allocate buffer(s) for directional irradiance output:

// Create directional output texture(s).
Geo::s32 outputTextureSize       = radCore->m_MetaData.m_OutputWidth * radCore->m_MetaData.m_OutputHeight;
Geo::s32 outputTextureMemorySize = outputTextureSize * 4; // 8 bit per channel output = 4 bytes per pixel

// A single output texture for luminance-based directional irradiance
void*    directionalOutput       = GEO_ALIGNED_MALLOC(outputTextureMemorySize, 16);

// or alternatively, three output textures for colour-separated directional irradiance
void*    directionalOutputR      = GEO_ALIGNED_MALLOC(outputTextureMemorySize, 16);
void*    directionalOutputG      = GEO_ALIGNED_MALLOC(outputTextureMemorySize, 16);
void*    directionalOutputB      = GEO_ALIGNED_MALLOC(outputTextureMemorySize, 16);

The code sample above is simplified to assume a linear buffer with no extra padding per row (that is, the stride is set to the width). In practice, although the output texture has a width which is a multiple of 4, its data stride may be different to the actual width, depending on the graphics driver. In this case, it is more convenient to allocate the output buffer to be the same data size of the texture, and pass the appropriate stride to the Enlighten solver.

Persistent data buffer

Use the RadSystemCore to ask for the persistent data requirements:

Geo::s32 bounceOutputSize = Enlighten::CalcRequiredPersistentDataSize(&myRadSystemCore);
void*    bounceOutput     = GEO_ALIGNED_MALLOC(bounceOutputSize, 16);