-
Notifications
You must be signed in to change notification settings - Fork 57
Launch Parameters
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.
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 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.
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.
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.
-
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 eachOWLParams
object is associated with a CUDA stream, and there is a very big difference between async launches that use the sameOWLParams
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 timeowlLaunch2D()
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.