Page tree

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 7 Next »

Contents

Introduction

RixShadingPlugin is the base class for RixBxdfFactory, RixDisplacementFactory, RixDisplayFilter, RixIntegrator, RixLightFilter, RixLightFactory, RixPattern, RixProjection, and RixSampleFilter. These are plugins that implement services for the renderer.

Here, it is important to distinguish between two types of plugins: ones that need to create many lightweight instances over the course of a render, and ones that do not. RixBxdf, RixDisplacement, and RixLight represent lightweight instances that may be created many times during the course of a single render, and therefore are not directly subclasses of RixShadingPlugin. Instead, instancees of those classes are returned by the appropriate Factory (e.g. RixBxdfFactory), with the Factory itself being the subclass of RixShadingPlugin.

RixIntegrator, RixDisplayFilter, RixLightFilter, RixPatternRixProjection, and RixSampleFilter do not create many lightweight instances. As such, these classes are directly subclasses of RixShadingPlugin.

All RixShadingPlugins share common methods related to initialization, synchronization with the renderer, and management of lightweight instances.

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.

Parameter Table

All shading plugins are expected to return a description of their input and output parameters via the GetParamTable() method. This returns a pointer to an array of RixSCParamInfo, containing one entry for each input and output parameter, as well as an extra empty entry to mark the end of the table. This parameter table is used by the renderer to ensure proper type checking and validate the connections of upstream and downstream nodes. As such, each entry in the table should set a name, a type (RixSCType enumeration), detail (varying vs uniform, RixSCDetail enumeration), and access (input vs output, RixSCAccess enumeration). These table entries also need to be kept in sync with the associated .args file.

The ordinal position of a parameter in the parameter table is the integer paramId used to evaluate parameter inputs using the RixShadingContext::EvalParam method; see RixShadingContext for more information.

Synchronization

The Synchronize() routine allows the plugin to respond to synchronization signals delivered by the renderer. 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 the renderer is about to render.

Lightweight instancing

For shading plugin types which support the creation of multiple lightweight instance classes not derived from RixShadingPlugin (i.e. RixBxdf, RixDisplacement, and RixLight), the renderer can potentially create many, many instances over the course of the render. Therefore, it is important to keep the cost of instantiation low. In order to reduce the cost of these instantiations, the renderer offers the ability to track custom instance data with every unique evocation of the plugin. By unique evocation, we generally mean the unique set of parameters given to the material definition.

The shading plugin can create instance data using the CreateInstanceData() method. Instance data is usually a function of the instance parameters (supplied to CreateInstanceData via the RixParameterList), and using these parameters plugins may bake a cached understanding of their behavior/requirements into a private representation that the renderer will automatically track with the instance. This allows the plugin to avoid repeated computations with each new instantiation.

If the shading plugin does create instance data, it should be stored in the data field of the InstanceData struct. If the data requires non-trivial deletion, the freefunc field of the InstanceData struct should be set to a function that the renderer will invoke when the plugin instance will no longer be needed. A trivial implementation of CreateInstanceData() produces no instance data and returns a non-zero value.

Any instance data that is created will be automatically returned by the renderer when the lightweight instance is created - for example, when RixBxdfFactory::BeginScatter() is invoked to create a RixBxdf. The implementation of BeginScatter() is now free to use this instance data to reduce the cost of creating the associated RixBxdf.

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, along with a corresponding 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.

CreateInstanceData() may be called in multiple threads, and so its implementation should be re-entrant and thread-safe.