Transitioning from RPR 1.X to 2.0

(Moving from Tahoe DLL to Northstar DLL)

Introduction and General Concepts

RPR 2.0 is a complete rewrite of the RPR rendering backend, but not the overall API. As such, it needs several new concepts to be covered. The general goals of RPR 2.0 are to:

  • Handle larger scenes better with out-of-core geometry and textures;

  • More efficiently scale across multiple devices and with CPU + GPU rendering;

  • Add the required flexibility to describing geometry, lights and materials, particularly in:

    • More light types and physical area lights;

    • Flexible and cross-app material sharing with MaterialX materials;

    • Unlimited possibilities for AOVs with Light Path Expressions;

  • Give better convergence while rendering, usually resulting in less noise for equivalent sample counts.

Along with all this, we also tried to keep RPR 2.0 ‘backwards compatible’ wherever possible. That is, using the same RPR SDK and simply switching the rendering backend from Tahoe (RRP 1.X) to Northstar (RPR 2.0) will work and give a similar result in most cases.

Loading RPR 2.0

Radeon ProRender uses a plugin system for loading the rendering backend. To use RPR 2.0, simply create a render context and load ‘Northstar64.dll’ instead of ‘Tahoe64.dll’ following this tutorial.

rpr_int rpr_2_PluginID = rprRegisterPlugin("Northstar64.dll");
assert(rpr_2_PluginID != -1);
rpr_int plugins[] = { rpr_2_PluginID };
size_t pluginCount = sizeof(plugins) / sizeof(plugins[0]);

// Create context using a single GPU.
// Note that multiple GPUs can be enabled for example with RPR_CREATION_FLAGS_ENABLE_GPU0 | RPR_CREATION_FLAGS_ENABLE_GPU1.
CHECK( rprCreateContext(RPR_API_VERSION, plugins, pluginCount, RPR_CREATION_FLAGS_ENABLE_GPU0, NULL, NULL, &context) );

// Set active plugin.
CHECK( rprContextSetActivePlugin(context, plugins[0]) );

Removed API Features

Compositing and Post Effects

The compositing and post effects functionality in the RPR SDK have been removed, and instead users should use the Radeon Image Filter library. It provides many image filtering, compositing, post effects, and denoising functions and is a more logical place for this range of functionality.

New API Features

New and Changed Light Types

Point Light

Point lights are not possible in physics, due to their infinitesimally small size. However, RPR 2.0, being a physically based renderer, creates a very small sphere light with its center at the point light location. Many applications add a ‘softness’ parameter to their point lights. In cases where softness is desired for point lights, use a sphere light.

Sphere Light

Sphere lights are useful for making point type lights with softness. Increase the radius of a sphere light to make it softer: RadeonProRender.h.

For example, this scene is lit by a sphere light with the following multiple sizes:

Radius: 0.01

Radius: 0.1

Radius: 1

Spot Light

Similarly to point lights, infinitely small spot lights do not exist in nature. However, we are keeping support and the API call for spot lights by using a small disk light. If soft edge falloff to the spot light is desired, use a disk light with a larger radius.

Disk Light

We recommend using a disk light instead of a spot light where increased physical accuracy is desired. The value of the disk light’s radius will adjust the softness: RadeonProRender.h

IES Light

Internally the IES light also uses a disk light: RadeonProRender.h

MaterialX Nodegraphs Loading

RPR 2.0 adds the capability to specify materials using the open standard MaterialX system. Rather than creating nodes of materials, simply pass in a MaterialX file using this API call which will parse the MaterialX file and create appropriate nodes.

Node support in MaterialX is ongoing, and so far includes most of the standard library nodes as well as Standard Surface in the PBR library of MaterialX.

LPE AOVs

Light Path Expressions (LPEs) are an expressive way to use AOVs. Rather than a fixed set of AOVs, the desired outputs can be constructed based on an expression which describes the number of bounces of light the user requires. For more info see OSL Light Path Expressions.

Supported Expressions:

C, R, T, D, G, L and <>, (), [|], *, +.

Expressions not yet Supported:

{}, ?, ^ and lpe group (<L.’group’>)

Examples:

Final Color: ‘C.*’

Transmission: ‘CT.*’

Diffuse Direct: ‘C<RD>L’

Direct Reflection: ‘C<RG>L’

Indirect Diffuse: ‘C<RD>[RT].*’

Shadow Catcher and Reflection Catcher

Shadow Catcher objects and reflection catchers are composed into the Color AOV. However, custom compositing of shadow catchers can be done with the Shadow Catcher AOV while using RIF for compositing.

Getting the Best Performance out of RPR 2.0

Setting the Iterations Parameter

The RPR_CONTEXT_ITERATIONS parameter is very important for RPR 2.0 as we have completely changed the way the engine works while rendering to get the best performance out of the hardware.

  • If it is set to 1, the render is very slow but still gives you faster feedback as rprContextRender() returns a result quickly. However, the throughput of overall render samples is lower. The value may be lowered in the first few iterations in the IPR for fast feedback.

  • If it is set higher, the optimization we have done kicks in. Thus, it is recommended to set it to a higher value. 32 will be sufficient in most cases.

  • You may see more of a performance boost if you set it higher, and your GPU has more VRAM (16GB+).

  • Of course, you may want to obtain the completed framebuffer for display, but rprContextRender() may not have returned its output if set to a higher value. Here is an example of how to obtain the completed framebuffer correctly.

void renderJob( NextDemo* demo )
{
        Node* accumFB = demo->getFrameBuffer();
        demo->m_napi->render(0, demo->m_res.x, 0, demo->m_res.y, accumFB);//rprContextRender()
        s_done = true;
}
void NextDemo::render()
{
        ApiDemoBase::updateCamera();
        if (m_n == 0 || (getFlag(FLAG_RENDERBUFFER_ACCUM) == 0))
        {
                clearFrameBuffers();
                m_totalTime = 0.f;
        }
        s_done = false;
        std::thread t( &renderJob, this );
        int n = 0;
        while(!s_done)
        {
                Stopwatch sw;sw.start();
                n++;
                std::string cmt = std::to_string( n );
                setComment( cmt.c_str() );
                Node* toneMapFB = m_toneMapBufferProcess();//resolve & read back framebuffer
                draw( toneMapFB, false );
                glfwSwapBuffers( MiRender::s_window );
#if defined(WIN32)
                Sleep(10);
#endif
                sw.stop();
                m_totalTime += sw.getMs();
        }
        t.join();
}

However, for the best efficiently, use the following example to get framebuffers asynchronously.

Obtaining Framebuffers Asynchronously

Internally, RPR 2.0 is tiling renders into an adaptive size optimized for performance. When each batch of tiles is completed, the callback which is set for updating the viewport will be called. This can be used for obtaining the framebuffer asynchronously.

struct ANY_CUSTOM_STRUCT
{
        int i0;
        int i1;
        //  .... any parameters the user wants ...
};
void UpdateCallback( float progress, void* userData )
{
        ANY_CUSTOM_STRUCT* userDataIn = (ANY_CUSTOM_STRUCT*)userData;
        return;
}
void InitRpr()
{
   rpr_int status = RPR_SUCCESS;
        ANY_CUSTOM_STRUCT dataCallback;
        status =  rprContextSetParameterByKeyPtr(context_, RPR_CONTEXT_RENDER_UPDATE_CALLBACK_FUNC, (void*)UpdateCallback); CHECK;
        status =  rprContextSetParameterByKeyPtr(context_, RPR_CONTEXT_RENDER_UPDATE_CALLBACK_DATA, &dataCallback); CHECK;

GPU Memory Usage

  • RPR 2.0 reserves GPU memory in advance for the texture cache. The size of memory reserved is dependent on the VRAM of the GPU. Therefore you may experience higher memory usage than in RPR 1.X, although the memory size excluding the cache is smaller than in RPR 1.X.

  • We have reduced the memory footprint for geometry, so RPR 2.0 can render larger scenes, with more triangles, with the same VRAM size. There is also an out-of-core geometry feature which allows for the possibility of rendering more geometry than would otherwise fit into the VRAM.

  • RPR 2.0 should be able to render higher resolution images with the same VRAM. This is because we have stopped using VRAM for frame buffers, which are now allocated in the system memory.

  • RPR 2.0 controls the VRAM usage for the scene. During rendering, if there is still some VRAM left, it dynamically optimizes to use as much needed for faster rendering. If you don’t want RPR to use more memory for this optimization, set RPR_CONTEXT_ITERATIONS to 1, but this will mean sacrificing some of the rendering speed.

Other Transition Notes

  • Transparent and reflection roughness in RPR 2.0 is the square root of that in RPR 1.X. This means the transmission roughness in RPR 1.X should be the square of the RPR 2.0 value to obtain a similar result. For example: an RPR 2.0 refraction roughness value of 0.1 is equivalent to an RPR 1.X value of 0.01; 0.5 is equivalent to 0.25, etc.

Some Known Issues

  • Rotational motion blur is not correct.

  • The Metal context option does not currently work. On macOS, OpenCL is used even if the Metal context flag is set.