BatchMicroNode is the base class for custom micro nodes which shall receive a batch of input values in their Process method and compute the corresponding output values. You should prefer this over a BasicMicroNode when the Process method consists of just a few simple operations: Then the calling overhead of nodes is significant, and it can be reduced when a single call to Process handles a whole batch of values. Of course this only holds when there is a proper batch of values, for example in the context of shading there's usually just one set of values.
To implement a BatchMicroNode, you have to derive a new class from BatchMicroNode and add a function template
{Result<void> Process(Batch<...>&)} (no const in front of Batch) to that class with a list of those ports between the angular brackets which shall be accessed by the node. Within the Process method you have to write a for loop over the batch as in the example shown below. The ports have to be defined by MAXON_PORT macros in a micro node group class. Usually the BatchMicroNode class is a member of that micro node group class:
// This class defines a micro node group which adds batches of two Int values by a BatchMicroNode.
class MyBatchAddNode
{
public:
// Declaration of the input and output ports of the micro node group.
MAXON_PORT_INPUT(Int, in1);
MAXON_PORT_INPUT(Int, in2);
MAXON_PORT_OUTPUT(Int, out);
// Implementation of the single custom micro node.
class Impl : public BatchMicroNode
{
public:
// The Process method needs to specify which ports of the group the micro node accesses, in this case all ports.
// If the group contains more than one micro node, each micro node usually needs only a subset of the ports.
//
// The PORTMODE template parameter allows to instantiate the Process method with different port modes, see PortMode.
//
// Note that there's no const in front of Batch!
Result<void> Process(Batch<in1, in2, out>& batch) const
{
// Iterate over the batch. Again there's no const in front of auto.
for (auto& ports : batch)
{
// Do the computation for a single set of values.
ports.out.Update(ports.in1() + ports.in2());
}
return OK;
}
};
// The Init function will be called to set up the micro node group
// when you call CreateNode<MyBatchAddNode>() or as part of the MAXON_CORENODE_REGISTER macro.
static Result<void> Init(const MicroNodeGroupRef& group)
{
iferr_scope;
group.AddChild<Impl>() iferr_return;
return OK;
}
};
There is the helper class OperatorNode to simplify the implementation of a core node class consisting of a single BatchMicroNode. If you want to implement a core node class consisting of a single BatchMicroNode which just invokes an existing C++ function or operator (as in the example with the + operator) you can also use one of the macros MAXON_CORENODE_FUNCTION, MAXON_CORENODE_OPERATOR_UNARY and MAXON_CORENODE_OPERATOR_BINARY.
|
using | MicroNodeClass = BatchMicroNode |
|
template<typename... PORTS> |
using | Batch = PortsAccess< PORTSACCESS_FLAGS::BATCH, PORTS... > |
|
using | ProcessFn = Result< void >(*)(const MicroNode *, const void *,) |
|
enum class | TYPE {
INVALID
,
BASIC
,
BATCH
,
SPLIT_MERGE
,
ITERATION
,
SEQUENCING
,
RECURSION_STEP
,
CURRENT_ITERATION_VALUE
,
CURRENT_ITERATION_VALUE_WITH_INIT
,
COPY
,
SET_TRUE
,
NOP
,
SUBTRACTIVE_DOMAIN
,
JOIN
,
CONTROL_TRANSFER
,
MAX_WITHOUT_FLAG
,
VARIABLE_MASK
,
MIN_FLAG
,
VALUE_PORT_MASK
,
INPUT_PORT_MASK
,
EXPORTED_PORT
,
VIRTUAL_INPUT_PORT
,
OUTPUT_PORT_MASK
,
VARIABLE
,
PORT_MASK
,
FACTOR_MASK
,
ROOT
,
WHILE_CONDITION
,
INDEFINITE_LOOP
,
BLOCK
,
TOP_LEVEL_FACTOR_MASK
,
FRAME_MASK
,
TOP_LEVEL_FRAME
,
FRAME
,
EVENT_MASK
,
EVENT
,
FACTOR_HEAD_MASK
,
BLOCK_HEAD
,
CONDITIONAL_HEAD
,
RECURSION_HEAD
,
DEFINITE_FACTOR_HEAD_MASK
,
CONTAINER_LOOP_HEAD_MASK
,
CONTAINER_OUTPUT_HEAD_MASK
,
DEFINITE_FACTOR_MASK
,
CONTAINER_OUTPUT_ELEMENT_MASK
,
INDEXABLE_FACTOR_MASK
,
DIMENSIONAL_FACTOR_TEST
,
CONTAINER_LOOP_MASK
,
DEFINITE_LOOP_HEAD
,
CONTAINER_LOOP_HEAD
,
ARRAY_LOOP_HEAD
,
CONTAINER_LOOP
,
ARRAY_LOOP
,
CONTAINER_OUTPUT_HEAD
,
CONTAINER_OUTPUT_ELEMENT
,
ARRAY_OUTPUT_ELEMENT
,
DEFINITE_LOOP
,
GENERIC_DEFINITE_LOOP
,
RECURSION
,
INPUT_ELEMENT_MASK
,
ARRAY_INPUT_ELEMENT
,
CONTAINER_INPUT_ELEMENT
,
INPUT_MASK
,
OUTPUT_MASK
,
CONDITIONAL_MASK
,
IF
,
CONTAINER_MASK
,
CONTAINER
,
ARRAY_CONTAINER
,
ARRAY
,
CONTAINER_OUTPUT_MASK
,
CONTAINER_OUTPUT
,
CONTAINER_INPUT_GROUP_MASK
,
CONTAINER_INPUT_GROUP
,
FACTOR_WITH_FACTOR_VARIABLE
,
ALL
} |
|
enum class | FLAGS : Int64 {
NONE
,
STATE
,
STATE_MODIFIER
,
LOCAL
,
PERMANENT
,
CACHED
,
CURRENT_ITV
,
NEXT_ITV
,
CONTAINER_MEMBER
,
COMMUTATIVE
,
STATE_MAPPER
,
PARAMETER
,
INPUT_WITHOUT_VALUE
,
OUTER_DOMAIN
,
SUSPEND
,
INDEPENDENT
,
INCLUDE_IN_PREDECESSORS
,
FACTOR_REFERENCE
,
OPTIONAL_INPUT
,
CURRENT_ITV_GROUP
,
NEXT_ITV_GROUP
,
NEW_UNIQUE_NAME
,
TIME_LOOP
,
UNDERSCORE_NUMBER_PREFIX
,
WRAPPER_DONT_WRAP
,
WRAPPER_HIDDEN
,
WRAPPER_KEEP_LETTER_CASE
,
WRAPPER_LAMBDA
,
WRAPPER_USE_ATTRIBUTE_RESOURCES
,
WRAPPER_FIXED_VARIADIC
,
WRAPPER_COPIED_VARIADIC
,
WRAPPER_INNER_DOMAIN
,
WRAPPER_OUTER_DOMAIN
,
WRAPPER_ENCLOSING_DOMAIN
,
WRAPPER_STREAM
,
WRAPPER_CONTEXT
,
NO_LIFETIME_PORT
,
NO_FACTOR_NODES
,
WRAPPER_FLAGS
,
ITV_MASK
,
ITV_GROUP_MASK
,
PORT_MODIFIERS
,
MODIFIERS
,
PORTINFO_FLAGS
,
ALL
} |
|
enum class | PORTSACCESS_FLAGS {
NONE
,
ITERATION
,
CONTAINER_MASK
,
CONST_MASK
,
BATCH
,
BATCH_ACCESS
,
CONTAINER
,
CONST_CONTAINER
,
DIRECT_ACCESS_TEST
} |
|
template<typename PORT > |
using | Input = typename PORT::PrivateInput |
|
template<typename... PORTS> |
using | Ports = typename PortsAccess< PORTSACCESS_FLAGS::NONE, PORTS... >::Members |
|