Softimage SDK Programmer's Guide > Customizing with the SDK > Custom Fx Operators >

# Rendering

Render User Functions

You can render in one of three ways: by rectangle, line, or pixel. The rectangle method (probably the most natural to most graphics programmers) uses the ufoProcessRenderRectangle user function which contains code to render a rectangular region of an output raster buffer. However, by default the Softimage Compositor parallelizes your code for a multi-processor machine when the ufoProcessRenderLine or ufoProcessRenderPixel user function is defined. The simplest way of ensuring the performance increases (near) linearly with the number of processors available on a multi-processor machine is to supply one of the latter two functions.

Multi-threading

It is recommended that if you supply a ufoProcessRenderLine or ufoProcessRenderPixel function then you ensure that the function is either multi-process safe (MP Safe), or that you turn the automatic multi-threading off. Automatic multi-threading may be turned off completely by calling ufoSetMPSafe once only in the UFO definition function, or on a render pass basis by calling ufoSetMPSafe around the MP unsafe passes.

If you want to handle your own multi-threading, then it is recommended that use the application's multi-threading libraries and the set of utility functions for multi-threading. ufoMPFork creates extra threads that execute the supplied function argument in parallel with the calling thread. ufoMPForkMyId returns an integer within the range 0..n-1 when n is the number of threads running in parallel. The thread with ID 0 is always be the original parent thread. ufoMPForkGetNumProcs returns the number of threads that are running in parallel.

Finally, ufoMPPotentialNumProcs may be used to query the maximum number of potential threads that are created by a call to ufoMPFork. This may be restricted by the number of processors on the host machine, multi-processing licensing and application command line arguments that restrict the number of threads to use.

Multiple Passes

As some rendering methods require multiple scans of the inputs and outputs, rendering can be split into multiple passes. The number of passes required can be set within ufoProcessDefine or any user function before the start of the first pass of a render at a particular frame using ufoProcessSetNumberRenderPasses. Within the render user functions the current render pass can be inquired with ufoProcessGetRenderPass.

Line rendering can also work vertically to allow for multiple pass methods which require vertical scanning of particular passes using ufoProcessSetRenderPassMode.

Render Slicing and Checking for Abort

If rendering is slow, output regions are sliced or tiled into smaller regions by the application, so that it can check for a user interrupt (for example, pressing the Stop button). The region size is chosen, so that rendering is performed in bursts of around 2 seconds in between which it can be halted. If this does not suit the rendering algorithm used, then it can be prevented by calling ufoProcessSetTilingAllow.

If you want to take complete control of rectangle rendering and do not want the application to automatically slice your render, but you do want to check for the user interrupting the current render, then the function ufoProcessCheckAbort can be called intermittently within the rendering code. If it returns a value of 1 then the render should terminate as soon as possible. For display purposes the function also takes a percentage_done argument. If you are performing multi-threading then this should be called with the original thread that the render function was called with.

Unchanged Inputs

Often during editing, subsequent renders at the same frame may have input rasters which have not changed since the previous render. Many rendering techniques may be able to take advantage of this, probably in conjunction with certain parameters being the same, by caching some intermediary result. ufoProcessIsInputDirty in conjunction with ufoProcessResetRasterInDirty can be called for each input to determine this.

Render Mode and Limits

ufoProcessGetRenderMode returns whether the render is a single frame or sequence and whether it is part of an interactive edit or preview sequence or a fully rendered sequence. This is useful for ignoring parameters in a full render which control accelerated methods used in editing or previewing.

The functions ufoProcessGetMinEffectLimit and ufoProcessGetMaxEffectLimit can be used to return current render effect start and end frame limits.

Background Rendering

The function ufoCheckInBackground checks if the main application is running in foreground mode (with interactive user interface) or in background mode (with no user interface). This may be useful for licensing purposes.

Pre- and Post-Render

There are three pairs of user functions which, if supplied, are called before and after rendering a sequence of frames, a frame and a pass, respectively. These can be used to set up commonly used data, allocate, and free temporary rasters and memory buffers and so on. ufoProcessPreSequenceRender and ufoProcessPostSequenceRender are called at either end of a sequence of renders. ufoProcessPreRender and ufoProcessPostRender are called before and after rendering at a frame. ufoProcessPreRenderPass and ufoProcessPostRenderPass are called before and after each pass of rendering at a frame.

In addition, you can supply the user function ufoProcessCanAvoidRendering. This can be used to determine whether processing of the UFO can be avoided because the current parameter setup has no effect. In this event, one of the UFO's inputs can be used in place of its output. Therefore, if processing can be avoided, then the function takes a parameter to be set to the input index that the UFO has no effect on. This replaces a previously unused UFO function ufoProcessHasNoEffect.

Parameter Access

Within the render, user functions and certain pre- and post-render user function parameters may be accessed for their values. ufoProcessGetParamValue/s can be called to get the current value(s) of a parameter, ufoProcessGetParamValueAtTime/s can be called to get the value(s) of a parameter at a specific time (ufoProcessGetTime can be used to get the current frame time of rendering.) These functions return double-precision floating-point values, so conversion to integer is required for parameters of type ufoBooleanParam, ufoEnumParam, and ufoIntegerParam.

You can determine if a parameter has been edited (through some user interface event) by calling ufoProcessIsParamSet.

The ufoProcessParamsEdited function is called whenever any parameters are edited by the user. It supplies the list of parameter indices for the parameters that have been changed. The user can then react to the edit by changing additional parameter values. This function is useful, for example, for controlling presets through a ufoEnumParam parameter, which set a number of other parameters, or for example, if you have a set of parameters which are alternative representations of a single value.

Raster Access

Within the render user functions, editor user functions, and certain pre- and post-render user functions, you can access rasters for reading or writing.

ufoProcessGetRasterIn returns a handle to an input raster and ufoProcessGetRasterOut returns a handle to an output raster. ufoEditorGetRasterViewed returns a handle to the viewed raster during editing.

Given a raster handle, there are a suite of UFO library functions for interacting with the raster (see ufoRaster.h). All returned raster handles should be tested against null as, under certain circumstances, such as prior to processing or getting from unconnected UFO process inputs, the raster may not be available.

All the currently supported raster types are rectangular arrays of pixels, with pixel components (RGB, Alpha, RGB-Alpha) packed together. The raster interface takes account of an arbitrary base offset, width and height associated with the raster's pixel array.

ufoRasterGetLimits, ufoRasterGetWidth, and ufoRasterGetHeight return information on a raster's rectangular geometry.

ufoRasterGetPixelType, ufoRasterGetPixelSize, and ufoRasterComponentSize return information on the pixel type.

ufoRasterGetPixelAddress(x,y) returns the pointer to the pixel at (X,Y). ufoGetBufferAddress returns the base address of the raster's buffer (not necessarily at (0,0)). ufoRasterGetBufferSize returns the full size of the raster's buffer (in bytes).

ufoRasterGetPixelCol, ufoRasterGetPixelColAlpha, and ufoRasterGetPixelAlpha return normalized (0.0..1.0) component values at a pixel. ufoRasterSetPixelCol, ufoRasterSetPixelColAlpha, and ufoRasterSetPixelAlpha set normalized component values at a pixel. These functions work on all types of rasters regardless of their actual type, performing sensible conversions as necessary (detailed in ufoRaster.h and the appendices). These functions do not perform checks for the pixel coordinates that are outside the raster, so when writing UFO effects which override automatic clamping on certain inputs (see ufoProcessSetRasterInEdgeMode) or any effect which reads input pixels at coordinates which are offset from a pixel being rendered to output, you should perform bounds checks.

ufoRasterCopy and ufoRasterCopyPart copy whole and parts of rasters from one to another, handling pixel conversions as necessary. ufoRasterAlloc allocates a temporary raster of a specified pixel type. ufoRasterAllocCopy and ufoRasterAllocCopyPart allocate a copy of whole or part of an existing raster and optionally copy the pixel data from the original to the new. ufoRasterFree frees any raster previously allocated through the UFO interface library. You should use these functions for raster allocation and freeing, as they make use of the Softimage Compositor's memory manager.

Temporal Frame Raster Access

Some types of effects are classified as inter frame, such that for each output at a current frame they need to read a frame or frames from an input which are not at the current frame. For instance, a retiming effect or motion blur effect.

ufoProcessGetRasterInAtFrame returns the raster for an input at a specified frame. The function includes a field argument which is used when field rendering (see ufoProcessFieldRendering). Each call to ufoProcessGetRasterInAtFrame with a unique frame (and field) will lock a raster in memory by the Softimage Compositor's memory manager until ufoProcessReleaseRasterInAtFrame is subsequently called with that frame. It is very important to use this function to unlock memory from the memory manager and not keep too many frames locked in memory simultaneously. If you don't call ufoProcessReleaseRasterInAtFrame then all accessed frame rasters will remain locked until after the UFO process has finished rendering at that frame. Currently, temporal access only works if the input is connected directly to a clip. ufoProcessIsRasterInTemporal can be used to check this. The function ufoProcessGetRasterInTemporalLimits() returns the frame limits available for temporal access on an input.

Scaled and Cropped Rendering

The Softimage Compositor uses two principal techniques for accelerating the performance of rendering for interactive updating of effects during editing:

- Scaled rendering, where rendering can be performed at an arbitrary reduced resolution. The render method must take into account scaling of any geometric parameters by the render scale factor. The UFO library function ufoProcessGetRenderScale gets the X and Y scale factor. This technique trades variable amounts of precision against speed.

- Cropped rendering, where a rectangular subregion of the whole region to be rendered is selected. Cropping may also occur explicitly as the result of using a Crop process or transformation process, or implicitly through render-economizing techniques employed by the Softimage Compositor's hierarchy traversal method.

To obtain the full render resolution, ufoProcessGetFullRenderRectangle returns the full rectangle resolution of the final target clip in the process hierarchy being rendered, regardless of any render cropping, scaling or use of reduced resolution material. This is useful for any effect which is based on a position or region relative to the full render region, such as a swirl around the centre or an explode from the centre.

Region Calculation

By default, an input has its edge mode set to ufoEdgeClamp such that an output render region will automatically be clamped to the limits of the input. However, UFO effects whose output render region may include pixels outside the input will need to call ufoProcessSetRasterInEdgeMode to set the edge mode to ufoEdgeNoClamp and then perform their own limits checks on the input region when rendering. Effects that would use this include scaling down, and compositing of smaller images onto larger backgrounds.

When you render a hierarchy of processes of arbitrary complexity, the Softimage Compositor uses cropping techniques to minimize the regions required to be rendered. By default, the Softimage Compositor assumes that there is a one-to-one mapping between input pixels and output pixels. Effects, such as composites and colour space manipulations, perform calculations on pixel values at the same position in the inputs as the pixel being rendered in the output.

The defined region of a process' output is the bounding rectangle of the effect it can produce in an output raster given the bounding rectangle regions supplied to its inputs. Effects such as geometric transformations (scales, rotations, perspective, warps, etc.) can define output regions which are larger, smaller, or offset from those defined on its inputs. If a UFO process can do this, then you should supply the ufoProcessCalcDefinedRectangle user function. This is called before a frame is rendered and after all the process parameters have been set with their current values. The function call supplies the defined regions of each input and should return the defined region for all outputs. If this function is not supplied, the output defined region is assumed to be the same as the first input defined region.

The needed region of a process's input is the maximum bounding rectangle it needs to be supplied in an input in order to produce the required effect within the supplied output region. Effects such as convolutions which perform calculations on a number of input pixels in a vicinity around the corresponding output pixel, need input regions which are larger than the supplied needed output region by half the size of the convolution kernel in each direction. Effects, such as geometric transformations, need an input region which is the inverse transformation of the supplied needed output region.

If a UFO process is required to render some arbitrary rectangular region on its outputs, and in turn it pre-requires rectangular regions on its inputs to be rendered which may be greater, smaller and/or offset from that output region, then you should supply the ufoProcessCalcNeedRectangles user function. This is called before a frame is rendered and after all the process parameters have been set with their current values. The function call supplies the needed region of output and should return the needed region for all inputs. If this function is not supplied, the input needed regions are assumed to be the same as the output needed region.

With both region calculation user functions, the supplied rectangle regions do not take into account any render scaling and the returned rectangle regions should not either.

It is important that you understand the requirement of these functions if you want your UFO process to behave properly when there is any cropping (automatically or manually) during rendering.