Page tree

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Note

In order to facilitate the reuse of the same parameter enumeration for pattern output computation, it is highly recommended that all outputs be placed at the beginning of the parameter table.

Initialization and Synchronization

Anchor

...

dynamicparameters

...

dynamicparameters

...

Dynamic Parameters

A plugin can create its parameter table dynamically based on the parameters provided to each instance of the plugin. This dynamically created table is created using the CreateInstanceData() method, and should be saved in the paramtable member of the InstanceData. If the associated memory need to be freed, if should be taken care of in the freefunc() routine. Generally, static interfaces should be preferred over dynamic interfaces due to their extra memory expense. If the paramtable member remains null, all instances will share the parameter table returned by GetParamTable(). In order to prevent the renderer from filtering out dynamic parameters as bad inputs, a plugin that is using a dynamically created table should have a k_RixSCAnyType entry in its plugin parameter table.

Initialization and Synchronization

Anchor
initialization
initialization
Plugin initialization

In order to initialize the plugin, the renderer will call Init() once. Even if the plugin is evoked multiple times during the render with different arguments, Init() will still be called only once during the lifetime of the render. The RixContext parameter can be used by the plugin to request any RixInterfaces services provided by the renderer. Any expensive memory allocations or operations that can be reused during the lifetime of the plugin can be performed in this routine. Upon successful initialization, this routine should return a zero status.

Finalize() is the companion to Init(), called at the end of rendering with the expectation that any data allocated within the Init() implementation will be released.

Plugin instance initialization

Depending on the paradigm used by the plugin type, CreateInstanceData() or CreateXXX() will be called once per plugin instance:

  • CreateInstanceData() allows the plugin instance to create private data (stored in InstanceData::data), that will then be provided back to the various plugin methods the renderer will call during rendering.
  • CreateXXX() returns a C++ object that should store its own representation of the plugin instance. The renderer will call methods on this object during rendering (instead of calling plugin methods).

The renderer provides the unique evocation parameters that triggered the creation of the plugin instance through the the RixParameterList class.

RixParameterList allows for the evaluation of the plugin instance parameters via the EvalParam() method. To aid in this, it allows for the querying via RixParameterList::GetParamInfo() of whether the parameters have been unset (and are therefore at their default value), set as a uniform value, or are part of a network  connection, i.e. the parameter is computed by an upstream node in the shading graph. A network connection is understood to be a varying quantity, and its value cannot be evaluated at the time that CreateInstanceData is evoked; this is why EvalParam() will return k_RixSCInvalidDetail if the parameter is a network connection. Otherwise, EvalParam() can be used to get an understanding of the uniform, non-varying parameters that are passed to the shading instance, and these can be used to perform any precomputations as needed.

Anchor
synchronization
synchronization
Plugin Synchronization

The Synchronize() routine allows the plugin to respond to synchronization signals delivered by the renderer. This call may happen multiple times during a render session and/or during a given render.

The renderer may provide additional information to the plugin via the input parameter RixParameterList. These signals include:

  • k_RixSCRenderBegin: The renderer is being initialized.
  • k_RixSCRenderEnd: The renderer is about to end.
  • k_RixSCInstanceEdit: Currently unused.
  • k_RixSCCancel: Currently unused.
  • k_RixSCCheckpointRecover: A signal that the renderer is about to restart rendering from a checkpoint. The

In order to initialize the plugin, the renderer will call Init() once. Even if the plugin is evoked multiple times during the render with different arguments, Init() will still be called only once during the lifetime of the render. The RixContext parameter can be used by the plugin to request any RixInterfaces services provided by the renderer. Any expensive memory allocations or operations that can be reused during the lifetime of the plugin can be performed in this routine. Upon successful initialization, this routine should return a zero status.

Finalize() is the companion to Init(), called at the end of rendering with the expectation that any data allocated within the Init() implementation will be released.

Plugin instance initialization

Depending on the paradigm used by the plugin type, CreateInstanceData() or CreateXXX() will be called once per plugin instance:

  • CreateInstanceData() allows the plugin instance to create private data (stored in InstanceData::data), that will then be provided back to the various plugin methods the renderer will call during rendering.
  • CreateXXX() returns a C++ object that should store its own representation of the plugin instance. The renderer will call methods on this object during rendering (instead of calling plugin methods).

The renderer provides the unique evocation parameters that triggered the creation of the plugin instance through the the RixParameterList class.

RixParameterList allows for the evaluation of the plugin instance parameters via the EvalParam() method. To aid in this, it allows for the querying via RixParameterList::GetParamInfo() of whether the parameters have been unset (and are therefore at their default value), set as a uniform value, or are part of a network  connection, i.e. the parameter is computed by an upstream node in the shading graph. A network connection is understood to be a varying quantity, and its value cannot be evaluated at the time that CreateInstanceData is evoked; this is why EvalParam() will return k_RixSCInvalidDetail if the parameter is a network connection. Otherwise, EvalParam() can be used to get an understanding of the uniform, non-varying parameters that are passed to the shading instance, and these can be used to perform any precomputations as needed.

...

The Synchronize() routine allows the plugin to respond to synchronization signals delivered by the renderer. This call may happen multiple times during a render session and/or during a given render.

The renderer may provide additional information to the plugin via the input parameter RixParameterList. These signals include:

  • k_RixSCRenderBegin: The renderer is being initialized.
  • k_RixSCRenderEnd: The renderer is about to end.
  • k_RixSCInstanceEdit: Currently unused.
  • k_RixSCCancel: Currently unused.
  • k_RixSCCheckpointRecover: A signal that the renderer is about to restart rendering from a checkpoint. The parameter list will contain a single constant integer "increment" which contains the increment value from which the renderer will restart.
  • k_RixSCCheckpointWrite: A signal that the renderer is about to write a checkpoint. The parameter list will contain two values: a constant integer "increment" indicating the increment value the renderer will write, and a constant string "reason" which contains one of three values: "checkpoint", "exiting", or "finished", indicating why the renderer is writing the checkpoint.
  • k_RixSCIncrementBarrier: A signal that the rendering of an new increment is about to begin. This signal will only be received if the integrator has set wantsIncrementBarrier to true in the RixIntegratorEnvironment. The parameter list will contain a single constant integer "increment" which contains the increment value from which the renderer will restart.
  • k_RixSCCheckpointWrite: A signal that the renderer is about to render.

Plugin instance synchronization

Similarly to Synchronize(), the SynchronizeInstanceData() method allows the plugin instance to update its state when a render starts.

There are some subtle differences with Synchronize() though:

  • there is no synchronization message, it is always assumed to be k_RixSCRenderBegin
  • the plugin instance must subscribe to this mechanism, by appropriately setting InstanceData::synchronizeHints duringCreateInstanceData()

If the plugin type doesn't use CreateInstanceData() but CreateXXX(), the created objects will sometimes expose an Edit() or Synchronize() method.

Closures synchronization

Closures are transient objects with a very short lifetime, and are re-created with such a frequency that there is no need for synchronization mechanism.

Interactive rendering sessions

Because Init() and CreateInstanceData() are only called once during a rendering session, they are unable to capture edits that may have happened after the previous render.

  • write a checkpoint. The parameter list will contain two values: a constant integer "increment" indicating the increment value the renderer will write, and a constant string "reason" which contains one of three values: "checkpoint", "exiting", or "finished", indicating why the renderer is writing the checkpoint.
  • k_RixSCIncrementBarrier: A signal that the rendering of an new increment is about to begin. This signal will only be received if the integrator has set wantsIncrementBarrier to true in the RixIntegratorEnvironment. The parameter list will contain a single constant integer "increment" which contains the increment value the renderer is about to render.

Plugin instance synchronization

Similarly to Synchronize(), the SynchronizeInstanceData() method allows the plugin instance to update its state when a render starts.

There are some subtle differences with Synchronize() though:

  • there is no synchronization message, it is always assumed to be k_RixSCRenderBegin
  • the plugin instance must subscribe to this mechanism, by appropriately setting InstanceData::synchronizeHints duringCreateInstanceData()

If the plugin type doesn't use CreateInstanceData() but CreateXXX(), the created objects will sometimes expose an Edit() or Synchronize() method.

Closures synchronization

Closures are transient objects with a very short lifetime, and are re-created with such a frequency that there is no need for synchronization mechanism.

Interactive rendering sessions

Because Init() and CreateInstanceData() are only called once during a rendering session, they are unable to capture edits that may have happened after the previous render.

It is therefore strongly recommended for these two methods to only rely on data that was explicitly provided (e.g. the plugin instance parameter list). In particular, special care should be taken not to query options or anything related to the render state (displays, integrator environment, lpe-related quantities, etc...) for the following reasons:

...

  • RixBxdf::GetInstanceHints() is called after CreateInstanceData() but before SynchronizeInstanceData(). As a consequence, if a bxdf instance's hint depends on a global option or on the render state, edits will have no effect. This will lead to counter-intuitive behaviors, and it is strongly recommended for bxdf instance hints to only depend on the shader parameters provided to CreateInstanceData()
  • RixPattern::Bake2dOutput() and RixPattern::Bake3dOutput() are called after CreateInstanceData() but before SynchronizeInstanceData(). The same limitations as the one described in the item above apply.
  • RixLight::Edit() and RixLight::SynchronizeInstanceData() are currently not called.

Misc

...

Overview

The following table summarizes the structure of the various RixShadingPlugin, in relation to initialization and synchronization. All plugins use the RixShadingPlugin::Init() and RixShadingPlugin::Finalize() calls.

Plugin

RixShadingPlugin

subclass

Instance
representation

Generates a closure

(per RixShadingContext)

bxdfRixBxdfFactoryInstanceData::dataYes, RixBxdf
displacementRixDisplacementFactoryInstanceData::dataYes, RixDisplacement
display filterRixDisplayFilterInstanceData::dataNo
integratorRixIntegratorFactoryRixIntegratorNo
lightRixLightFactoryRixLightNo
light filterRixLightFilterInstanceData::dataNo
patternRixPattern

InstanceData::data

No
projectionRixProjectionFactoryRixProjectionNo
sample filterRixSampleFilterInstanceData::dataNo

Examples

PxrDiffuse

First, note that while the bxdf plugin is published and exposed as 'PxrDiffuse', it is comprised of two classes:

...

Code Block
languagecpp
    plist->GetParamInfo(k_presence, &typ, &cnx1);
    if(cnx1 == k_RixSCNetworkValue)
    {
        if (cachePresence == 0)
        {
            req |= k_ComputesPresence;
        }
        else
        {
            req |= k_ComputesPresence | k_PresenceCanBeCached;
        }
    }

PxrDirt

For a more complicated example of instance data usage, consider the PxrDirt pattern. Its instance data routine caches the values of many uniform parameters and reuses them in PxrDirt::ComputeOutputParams(), knowing that its .args file prohibits those parameters from being set to network connections.

Code Block
languagecpp
    Data *data = static_cast<Data*>(instanceData->data);

    data->numSamples = 4;
    data->distribution = k_distributionCosine;
    data->cosineSpread = 1.0f;
    data->falloff = 0.0f;
    data->maxDistance = 0.0f;
    data->direction = k_directionOutside;
    data->raySpread = 1.0f;

    params->EvalParam(k_numSamples, 0, &data->numSamples);
    data->numSamples = RixMax(1, data->numSamples);
    params->EvalParam(k_distribution, 0, &data->distribution);
    params->EvalParam(k_cosineSpread, 0, &data->cosineSpread);
    params->EvalParam(k_falloff, 0, &data->falloff);
    params->EvalParam(k_maxDistance, 0, &data->maxDistance);
    params->EvalParam(k_direction, 0, &data->direction);

...

...


Anchor
installation
installation
Installation

...