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);