Skip to content

Launch Parameters

Ingo Wald edited this page Nov 6, 2020 · 2 revisions

Launch parameters are a very powerful tool to efficiently - and with low overhead - specify data that changes from frame to frame. They are entirely optional, but very powerful.

Note this section assumes that the reader is already familiar with the concept of OWL "Variables"; if you are not, you may want to read the Variables page first.

The Concept of Launch Parameters in OptiX

Before going into how launch params works in OWL, it's important to first understand how they work in OptiX.

Launch parameters - in OptiX speak - are a way of specifying GPU "constant memory" data for a launch that is globally visible to all the programs used in the launch. Eg, let's assume you have the following skeleton code in your device code:

struct MyLaunchParams {
   int frameID;
   float4 *frameBuffer;
   OptixTraversableHandle worldIAS;
};
__constant__ MyLaunchParams optixLaunchParams;

OPTIX_RAYGEN_PROGRAM(renderFrame)() { 
   .... optixLaunchParams.frameBuffer[...] = .... ;
}

OPTIX_CLOSEST_HIT_PROGRAM(TriMeshCH)() { ... }

In this example, the optixLaunchParams will be globally visible to any of the programs that may get executed during a launch (i.e., both raygen and CH program will see it).

The value of this optixLaunchParams is constant for the duration of one launch, but can take different values for different launches; in particular, changing the launch params between two launches does not require rebuilding the SBT or recompiling any programs, so is very(!) lightweight way of specifying frequently changing data like camera position, frame buffer pointers, random number seeds, etc.

In fact, launch params can even contain different values for different launches that are running asynchronously, and/or in parallel ... they're awesome.

Launch Params in OWL

Launch params are often overlooked, maybe because they're optional (you don't have to use any at all if you do not want to!), and/or because it may seem more natural to pass parameters to a raygen program in the same way one would pass them to closest-hit or any-hit programs (ie, through the SBT). They do, however, have a lot of very useful properties: e.g., they can be changed without rebuilding the SBT, they can have different values during async launches, they live in constant memory (instead of global memory for SBT data), they are globally visible in all programs (without wasting registers for passing pointers to shared data), etc.

Due to that usefulness, OWL treats launch params as "prime citizens"; in fact, making launch params as easy to use as possible was one of the key objectives behind OWL, and many of its advanced concepts (asynchronous launches and CUDA interop) work through the OWLParams mechanism.

Assuming you have a few variables you want to be globally accessible to all programs in your pipeline/context, and/or that you want to change frequently per frame. If so, you'd first put those into a struct, and declare a global constant-memory variable named optixLaunchParams, e.g., like that:

struct MyGlobals {
   Camera  camera;
   int     frameID;
   float4 *frameBuffer;
   OptixTraversableHandle world;
};
__constant__ MyGlobals optixLaunchParams;

You can then access this optixLaunchParams in every program.

Important: though you can declare the struct any way you want, the constant-memory variable that holds these launch parameters has to be called optixLaunchParams - you can assign different values for different launches, but the name cannot be changed.

Creating, Setting, and Using Launch Params (LPs) on the Host

Once that struct has been defined, you can declare its variables (see above), and create an object of type OWLParams as follows:

OWLVarDecl myGlobalsVars[] = { .... see page on 'variables'... };
OWLParams  lp = owlParamsCreate(context,sizeof(MyGlobals),myGLobalsVars,-1);

... and can then set its variables like for any other object that can take variables:

owlParamsSet1i(lp,"frameID",frameID++);
owlParamsSet3f(lp,"camera.origin", ....);
....

Once all of the variables required for the next launch have been set, you can then launch a raygen program with the given LPs through owlLaunch2D():

owlLaunch2D(myRayGen, launchSize.x, launchSize.y, lp);

Upon encountering this call, OWL will automatically gather and upload the required variables (including any potential type translations for group, texture, or buffer variables, see above), will copy them into the specified constant-memory variable named optixLaunchParams, and will then execute the given raygen program (with given launch dimensions). By default it will then wait for that launch to complete, but this can be changed, as I'll describe in a second.

LPs can be changed between launches; and you'll obviously have to change only those variables that you do want to change; variables, once set, will retain their values across multiple launches, until they get explicitly assigned a new value.

Advanced Use Cases

The way we just described launch params should be sufficient for most use cases. You can, however, do more with launch params (in particular, they can be used for advanced CUDA interop and asynch launches). For more info on how to use this, please see the page dedicated to advanced launch params usage.

Frequently Asked Questions

  • can I change the name of the "optixLaunchParams" on the device? No, you cannot. The name of this variable gets baked into the OptiX context.

  • Can I change the value of the optixLaunchParams for different launches? Absolutely, that's what they're for. The __ constant __ only means that they live in constant memory for the duration of one launch, but they can absoltely have different values for different launches.

  • Can different launches have different OWLParam objects? Absolutely; you can. Note however that each OWLParams object is associated with a CUDA stream, and there is a very big difference between async launches that use the same OWLParams object (these will be async with respect to the host, but will serialize among themselves), vs asynch launches that each use a different such object (these can also run in parallel to each other). More information on that is on the "OWL for Blackbelts" page.

  • Can I change an OWLParams object while a launch or async launch is running? Absolutely. For regular, synchronous launches the launch is completed by the time owlLaunch2D() returns, anyway; and even for async launches OWL will make sure that a safe "frozen" version of these values gets created for each launch - so changing variables right after a async launch is perfectly safe.

  • What if I have different RayGen Programs that each expect different parameters?. There are multiple ways of doing this; please see the "OWL for Blackbelts" page.