Date: Fri, 29 Mar 2024 07:53:14 +0000 (UTC) Message-ID: <208810559.465.1711698794925@ip-10-0-0-233.us-west-2.compute.internal> Subject: Exported From Confluence MIME-Version: 1.0 Content-Type: multipart/related; boundary="----=_Part_464_1063724575.1711698794924" ------=_Part_464_1063724575.1711698794924 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Content-Location: file:///C:/exported.html
This documentation is for developers who wish to author custom d=
isplay filter plugins. Note that these are distinct from display (non-filte=
r) plugins. See the RixDisplayFilter.h
header for complete det=
ails.
Display filter plugins interpose between the renderer core=E2=80=99s fra= mebuffer and the display plugins. They may read and write the contents of v= arious AOV channels for the pixels in a region that is on its way to any di= splay plugins for I/O.
Display filters do not apply to deep data!
When the renderer wishes to send a bucket (a.k.a. tile) of 2D pixels to = the display plugins for I/O such as display in an interactive frame buffer = or to commit to an image file, it first makes a copy of the pixels as they = currently appear in its internal framebuffer. This copy includes all of the= AOV channels associated with the current camera. (Multi-camera scenarios s= uch as stereo renders have a separate framebuffer for each camera and send = pixels to their associated display plugins at different times.)
If there is an active display filter plugin for the scene, the renderer = will then invoke that plugin and give it access to the pixels. The filter i= s then free to read from and write to any of the channels for any of the pi= xels within the bucket.
Note that the render only directly invokes a single display filter at a = time. Given multiple display filters defined for a scene, the last one wins= . E.g.:
Display= Filter "PxrCopyAOVDisplayFilter" "move" "string readAov" "sampleCount" "str= ing writeAov" "gradedSampleCount" DisplayFilter "PxrGradeDisplayFilter" "grade" "string aov" "gradedSampleCou= nt" "color whitePoint" [128 128 128] DisplayFilter "PxrDisplayFilterCombiner" "combo" "reference displayfilter[2= ] filter" ["move" "grade"]
As shown here, however, a display filter may be given a reference to ano=
ther that precedes it. The standard PxrDisplayFilterCombiner
, =
for example, simply runs a chain of other display filters in sequence.
Once the display filter invoked by the renderer returns, the AOVs in the= copy of the pixels are demuxed to all of the display plugins that need to = show or write them for that bucket.
It is very important to understand that the changes made by a display fi= lter plugin are never actually commited back to the framebuffer. They apply= only in passing on a copy of pixels on their way to the display plugins. F= or IPR renders and checkpointing, this means that display filters can be ap= plied continuously as the render resolves and do not need to worry about th= eir cumulative effects with each progressive pass or checkpoint.
RixDisplayFilter
InterfaceDisplay filters implement the RixDisplayFilter
interface fo=
und in RixDisplayFilter.h
. A RixDisplayFilter
is =
a subclass of RixShadingP=
lugin
, and therefore shares the same initialization, synchroniza=
tion, and parameter table logic as other shading plugins. Therefore to star=
t developing your own display filter, you can #include "RixDisplayFil=
ter.h"
and make sure that your display filter class implements the r=
equired methods inherited from the RixShadingPlugin interface: Init()=
, Finalize()
, Synchronize()
, GetPara=
mTable()
, and CreateInstanceData()
. You should also use=
the RIX_DISPLAYFILTERCREATE()
and RIX_DISPLAYFILTERDEST=
ROY()
macros to define the CreateRixDisplayFilter()
and=
DestroyRixDisplayFilter()
functions for creating and destroyi=
ng instances of your class.
Often, you will want to have your CreateInstanceData()
map =
AOV names from the parameter list to RixChannelID
values. Thes=
e channel ids can be found by inspecting the RixIntegratorEnvironment=
. E.g.:
RixRende= rState* state =3D reinterpret_cast<RixRenderState*>(ctx.GetRixInterfa= ce(k_RixRenderState)); RixRenderState::FrameInfo frame; state->GetFrameInfo(&frame); RixIntegratorEnvironment const* env =3D reinterpret_cast<RixIntegratorEn= vironment const*>( frame.integratorEnv); std::string name("foo"); std::vector<RixChannelId> ids; for (int index =3D 0; index < env->numDisplays; ++index) if (env->displays[index].channel =3D=3D name) ids.push_back(env->displays[index].id)
Note that there may be more than one match for a given name. This may be=
caused by either the =E2=80=9Cstring source=E2=80=9D
paramete=
r to a display channel or the particular AOV being output multiple times. T=
ypically, a display filter will store the list of matches and apply itself =
to all of them.
Finally, your display filter subclass must implement the main Filt=
er()
method of the RixDisplayFilter interface. This method may be ca=
lled simultaneously from multiple threads for the same plugin and data inst=
ances and so must be thread-safe and re-entrant.
RixDisplayFilter::Filter()
The Filter()
method is where the action takes place:
virtual = void Filter( RixDisplayFilterContext& fCtx, RtPointer instanceData) =3D 0;
Each time the renderer wants to send out a bucket to the display it call=
s the Filter()
method with both a RixDisplayFilterContex=
t
giving access to the bucket data, and with the blind pointer to th=
e instance data that the plugin setup for itself in CreateInstanceDat=
a()
.
Most plugins will immediately cast this later pointer to a pointer or re=
ference to the internal structure that the plugin uses to stash its interna=
l data for this particular plugin instance. Note that at startup, the rende=
rer will typically only create a single instance of the plugin class via a call to the function defined by the RIX_DISPLAYFILTERCREATE(=
)
macro. But it may call CreateInstanceData()
many time=
s, each with a different parameter list from the scene. Class memb=
er data will thus be shared across all invocations while the instance=
Data
pointer passed back to the Filter()
will be unique=
to its invocation for a specific parameter list.
The RixDisplayFilterContext
currently provides four main th=
ings:
xmin
, ymin
, xmax
, and ymax=
fields give the coordinates of the bucket=E2=80=99s rectangle relat=
ive to the image. They are inclusive on the lower bounds and exclusive on t=
he upper bounds. Note that due to filter padding, they may be negative or e=
xtend outside the image proper.
Read()
and Write()
method al=
low the plugin to inspect and change the pixel data. The coordinates must b=
e inside the bucket boundary or else a read will simply store a black resul=
t and a write will be silently ignored. Note that with multi-camera renderi=
ng not all possible channel ids found in the integrator environment may be =
valid during a given call to Filter()
. The read and write func=
tions will return false when called with a channel that is not valid for th=
e current instance data.
ReadRegion()
offers=
the ability to fetch a copy of an arbitrary rectangle of pixels from anywh=
ere in the framebuffer (with zero padding for pixels outside the image). Li=
ke Read()
, it may fail for some channels. Note that due to mul=
ti-threading, successive calls to ReadRegion()
may produce dif=
ferent results (and different results from the equivalent Read()) as other rendering threads may continue to update the framebuffer and t=
his may produce transitory bucket artifacts if a display filter does not ta=
ke care. By contrast, the standard Read()
and Write() calls work on data locked to the current thread and so are stable. See=
the source to the PxrEdgeDetect plugin in the examples bundle for a use of=
this call.
IsEnabled()
call allows a display filter plugin to get a p=
ointer to the instance data for another plugin instance and determine if th=
at instance is currently enabled. This allows one Filter()
inv=
ocation to recursively invoke another filter instance's Filter() function. See the source to the PxrDisplayFilterCombiner in the examples=
bundle for use of this to chain together plugins.