C++ Plugins & Macros¶
This section provides an overview of the “skeleton” of a basic plugin
definition, including an explanation of the roles of the various MI_*
macros. These macros are responsible for importing types, instantiating
variants, and providing run-time type information.
Example code¶
Consider the following hypothetical plugin MyPlugin:
NAMESPACE_BEGIN(mitsuba)
template <typename Float, typename Spectrum>
class MyPlugin : public PluginInterface<Float, Spectrum> {
public:
MI_IMPORT_BASE(PluginInterface, m_some_member, some_method)
MI_IMPORT_TYPES()
MyPlugin();
Spectrum foo(..., Mask active) const override {
MI_MASKED_FUNCTION(ProfilerPhase::MyEval, active)
// ...
}
/// Indicate the name of this class (for logging)
MI_DECLARE_CLASS(MyPlugin)
};
/// Implement RTTI data structures
MI_EXPORT_PLUGIN(MyPlugin)
NAMESPACE_END(mitsuba)
Macros¶
MI_MASK_ARGUMENT(mask)¶
This macro typically occurs at the beginning of a function that takes a mask as an argument.
void my_method(..., Mask active) {
MI_MASK_ARGUMENT(active);
}
Masking is not really needed on scalar variants: if a function is called, we
assume that active=true. Masking can unfortunately decrease performance in
this case due to the generation of extra branches. Here, MI_MASK_ARGUMENT
therefore expands to
if constexpr (is_scalar_v<Float>)
active = true;
which turns the mask argument into a compile-time constant on scalar targets,
allowing the compiler to optimize away the undesired branches.
MI_MASK_ARGUMENT is also part of the next macro.
MI_MASKED_FUNCTION(phase, mask)¶
This macro builds on the MI_MASK_ARGUMENT macro and typically occurs at
the beginning of a function that takes a mask as an argument.
void my_method(..., Mask mask) {
MI_MASKED_FUNCTION(ProfilerPhase::MyMethod, active);
}
Masking is not really needed on scalar variants: if a function is called, we
assume that active=true. Masking can unfortunately decrease performance in
this case due to the generation of extra branches. Here,
MI_MASKED_FUNCTION macro expands to
if constexpr (is_scalar_v<Float>)
active = true;
ScopedPhase _(ProfilerPhase::MyMethod);
which turns the mask argument into a compile-time constant on scalar targets, allowing the compiler to optimize away the undesired branches.
Mitsuba ships with a powerful sampling profiler that facilitates tracking down
hot-spots during rendering. The last line of this macro (ScopedPhase)
informs this profiler that we are currently executing a function that belongs
to the profiler phase phase.
MI_IMPORT_BASE(Name, …)¶
Because most Mitsuba classes are templates, attributes and methods of parent
classes are not visible by default. They can be imported explicitly via using
Base::some_method; statements, but writing many such statements is tiresome.
The variadic macro MI_IMPORT_BASE expands into arbitrarily many such
using statements. For example,
MI_IMPORT_BASE(Name, m_some_member, some_method)
expands to
using Base = Name<Float, Spectrum>;
using Base::m_some_member;
using Base::some_method;
MI_IMPORT_CORE_TYPES()¶
This macro will generate a sequence of using declarations to import the
Mitsuba core types (e.g. Vector{1/2/3}{i/u/f/d}, Point{1/2/3}{i/u/f/d},
…). They are automatically inferred from the definition of Float.
Note
A type named Float must exist preceding evaluation of this macro.
For example,
using Float = float;
MI_IMPORT_CORE_TYPES()
// expands to:
// ...
using Point2f = Point<Float, 2>;
using Point3f = Point<Float, 3>;
// ...
using BoundingBox3f = BoundingBox<Point3f>;
// ...
MI_IMPORT_TYPES(…)¶
This macro invokes MI_IMPORT_CORE_TYPES() and furthermore imports
rendering-related types, such as Ray3f, SurfaceInteraction3f, BSDF,
etc. These templated aliases will depend on the preceding declaration of the
Float and Spectrum.
It is also possible to pass other types as arguments, for which templated aliases will be created:
using Float = float;
using Spectrum = Spectrum<Float, 4>;
MI_IMPORT_TYPES(MyType1, MyType2)
// expands to:
MI_IMPORT_CORE_TYPES()
// ...
using Ray3f = Ray<Point<Float, 3>, Spectrum>;
// ...
using SurfaceInteraction3f = SurfaceInteraction<Float, Spectrum>;
// ...
using MyType1 = MyType1<Float, Spectrum>; // alias for the optional parameters
using MyType2 = MyType2<Float, Spectrum>;
MI_DECLARE_CLASS(Name)¶
This macro should be invoked within the class declaration of the plugin.
The provided Name parameter is picked up by log messages, warnings, or
errors that are triggered by the plugin.
MI_EXPORT_PLUGIN(Name)¶
This macro will explicitly instantiate all enabled variants of a plugin:
MI_EXPORT_PLUGIN(Name)
// expands to:
template class MI_EXPORT Name<float, Color<float, 1>> // scalar_mono
template class MI_EXPORT Name<float, Spectrum<float, 4>> // scalar_spectral
// ...