Thread and Recursion Safety
Hosts are generally multi-threaded, those with a GUI will most likely have an interactive thread and a rendering thread, while any host running on a multi-CPU machine may have a render thread per CPU. Host may batch effects off to a render farm, where the same effect has separate frames rendered on completely different machines. OFX needs to address all these situations.
Threads in the host application can be broken into two categories…
main theaads , where any action may be called
render threads where only a subset of actions may be called.
For a given effect instance, there can be only one main thread and zero
or more render threads. An instance must be able to handle simultaneous
actions called on the main and render threads. A plugin can control the
number of simultaneous render threads via the
kOfxImageEffectPluginRenderThreadSafety
effect descriptor property.
The only actions that can be called on a render thread are…
If a plugin cannot support this multi-threading behaviour, it will need to perform explicit locking itself, using the locking mechanisms in the suites defined in ofxMultiThread.h.
This will also mean that the host may need to perform locking on the various function calls over the API. For example, a main and render thread may both simultaneously attempt to access a parameter from a single effect instance. The locking should…
block write/read access
not block on read/read access
be fine grained at the level of individual function calls,
be transparent to the plugin, so it will block until the call succeeds.
For example, a render thread will only cause a parameter to lock out writes only for the duration of the call that reads the parameter, not for the duration of the whole render action. This will allow a main thread to continue writing to the parameter during a render. This is especially important if you have a custom interactive GUI that you want to keep working during a render call.
Note that a main thread should generally issue an abort to any linked render thread when a parameter or other value affecting the effect (eg: time) has been changed by the user. A re-render should then be issued so that a correct frame is created.
How an effect handles simulanteous calls to render is dealt with in the multi-thread rendering section.
Many hosts get around the problem of sharing a single instance in a UI thread and a render thread by having two instances, one for the user to interact with and a render only one that shadows the UI instance.
Recursive Actions
When running on a main thread, some actions may end up being called recursively. A plug-in must be able to deal with this. For example consider the following sequence of events in a plugin…
user sets parameter A in a GUI
host issues
kOfxActionInstanceChanged
actionplugin traps that and sets parameter B
host issues a new
kOfxActionInstanceChanged
action for parameter Bplugin traps that and changes some internal private state and requests the overlay redraw itself
kOfxInteractActionDraw
issued to the effect’s overlayplugin draws overlay
kOfxInteractActionDraw
returns
kOfxActionInstanceChanged
action for parameter B returns
kOfxActionInstanceChanged
action returns
The image effect actions which may trigger a recursive action call on a single instance are…
The interact actions which may trigger a recursive action to be called on the associated plugin instance are…
The image effect actions which may be called recursively are…
kOfxImageEffectActionGetRegionOfDefinition
(as a result of callingOfxImageEffectSuiteV1::clipGetImage()
fromkOfxActionInstanceChanged
)kOfxImageEffectActionGetRegionsOfInterest
(as a result of callingOfxImageEffectSuiteV1::clipGetImage()
fromkOfxActionInstanceChanged
)
The interact actions which may be called recursively are…