|On this page|
In geometry networks, you can put a part of the network inside a compiled block (if all the nodes inside are "compilable"). In a way, this makes the block act as if they were one node.
This imposes a number of restrictions on how the network can work, but can potentially deliver big benefits in the right circumstances.
The main benefit is multithreaded for-each loops where the network runs the same block of nodes over a large number of separate pieces. Compiled blocks let Houdini spread those iterations across multiple cores.
Another benefit is more efficient use of OpenCL. Normally, even if a node processes geometry on the graphics card, the geometry must be copied back into main memory after each node, because any other node could potentially try to access it. In a compiled block, however, multiple OpenCL-based nodes can keep data on the graphics card as they process it without copying it back, increasing speed.
In a normal network, each node theoretically makes a copy of the geometry it’s working on. There are lots of optimizations to make this efficient in practice, but it still has a cost. In a compiled block the nodes can work in-place on the same geometry because external references are not allowed. This can give compiled blocks additional speedups.
Unfortunately, to get these benefits, we had to limit some of the flexibility that makes working in Houdini dynamic and fluid.
Only "compile-able" nodes
You can only used nodes that have been modified to allow compiling inside compiled blocks. You can enable a badge in the network editor to see which nodes can’t be used in a compiled block.
We are continuing to convert nodes based on perceived need. We will probably never get to all the hundreds of existing SOPs. If there’s a node you want to use inside a compiled block that isn’t converted yet, let us know.
The stamp expression function is the ultimate spooky action at a distance. It relies on any node being able to force another node anywhere else in the network to cook. This complete freedom is not possible with compiled blocks.
No local variables, no per-component expressions
When a node is part of a compiled block, its algorithm is compiled into the block’s operation, and its parameters are left behind. Expressions are not evaluated over each component in the geometry. Only expressions that work statically "ahead of time" on the entire geometry will work (for example, reading from a numbered input).
If you need to do something per-component (for example, move points based on the value of a point attribute), you must use a VEX-based node, such as Attribute Wrangle.
stamp(), this restriction might be lifted someday, depending on how necessary it proves.)
No internal geometry references by name
Normally, if you need information about another node, you can evaluate an expression and refer to that node by its path. For example,
npoints("/obj/sphere1") to get the number of points in a node’s geometry. This isn’t very efficient, but it works. In a compiled block, you can’t refer to the geometry in a node using the node path. To accomplish the same thing in a compiled block, you need to replace internal named references with references to spare inputs.
You can reference channel values on nodes inside the block by path (for example,
ch("../sphere1/tx")). You just can’t read geometry, as in a
You can reference geometry outside the compiled block, however all access to the exterior node will be serialized by a lock, so it will probably hurt performance in a threaded loop. In this case you would use a spare input instead.
Nodes outside the block can reference geometry on nodes inside the block, but doing so cook the interior node (and any dependencies) normally, without any of the benefits of compilation.
Nodes can’t read from their direct inputs
Expressions can’t read data from/about the node’s direct inputs (for example,
point(0, …) or
npoints(0)). You have to use a spare input to reference the input node.
This is another restriction that may be partially lifted in a future version of Houdini, at least for input 0.
Disabled/hidden parameters are not evaluated
This is true for all compile-able SOPs, even outside a compiled block. Previously, each SOP would determine which parameters to evaluate in its own cooking code. Now, the cook logic is divorced from parameter evaluation. This means that parameters need to be pre-evaluated. To avoid creating fake time dependency on disabled parameters (or making potentially expensive evaluations), the pre-evaluation skips disabled and hidden parameters.
Stop Condition not supported
The Stop Condition on For Each nodes isn’t supported inside a compiled block.
At this point in their development, in a production environment, you should probably resist the urge to try to add compiled blocks everywhere trying to gain maximum efficiency. The drawbacks mean the reward is often not worth the effort.
Target use of compiled blocks where they will give the most benefit: in iterations over large numbers of pieces.
You might want to get your network working and "finalized", and then based on profiling, try converting any "slow" parts into compiled blocks.
Create a compiled block
Put loops inside the compiled block, rather than a compiled block inside a loop.
On the For-Each Block End node of the top-level loop, turn on Multithread when compiled.
Turning on this checkbox tells Houdini to distribute the different iterations of this loop to different cores. You probably only want to do it on the outer loop to avoid an explosion of the number of distributed tasks.
When using compiled blocks and loops, you must be careful to properly encapsulate and nest each block with Begin/End nodes at the "borders" of each block. Visually, in the network, wires crossing into a block should only be connected to block begin nodes.
In this network, the wire to
merge3 crosses a block boundary. This would be valid in a normal cook, where Houdini would just re-cook that path each iteration. The loops in a compiled block are compiled as a separate unit, however, so they have to stand on their own.
The fix is to insert a Block Begin node before the merge, to properly nest the compiled and looping blocks. Set the Method parameter on this Begin node to "Fetch input".
As noted in the restrictions section, geometry expressions can’t reference the node’s direct inputs, or in named nodes.
The rule is there can’t be any "surprises" (dynamic expressions) about what to cook. Any SOPs that need data from another SOP in the compiled block have to make this clear "statically" before they cook, not during the cook.
(The case of VEX-based nodes such as Attribute Wrangle and Attribute Expression is a bit different. In a VEX node,
point(0, …) will work in VEX because the VEX SOPs have always evaluated all their inputs as it is very inefficient to try and evaluate them on demand.)
The workaround for this is to add a spare input to the node, and point that input to the node you want to reference. Then you can use the spare input’s number where you would otherwise use a node path. Spare inputs are pre-cooked before the compiled block runs. This allows multiple threads can refer to the pre-cooked geometry without having to worry about locking.
For expression functions that take a node path string as an argument (for example,
npoints("/obj/sphere1")), you can substitute an integer instead to refer to an input (for example,
Use a spare input to reference another node
Tips and notes
Spare inputs are also useful to refer to extra geometry inputs in a Wrangle node (beyond the four direct inputs Wrangle nodes come with).
If you put the display flag on a node inside a compiled block, the network will cook normally (uncompiled) to that point. The display flag must be on or after the block end node for the block to compile.
You can turn on a badge to see which nodes you cannot use inside a compiled block.
In the network editor, choose View ▸ Display Options or press D. The set the pop-up menu for Compilable SOP badge to "normal" or "large". Nodes that you cannot use in a compiled block will be marked with the badge.
No support for compiling this node type
Many SOP node types have not yet been converted to work in compiled blocks. See the tips above for how to turn on a badge in the network editor showing which nodes are not compilable.
If there’s a node you need to use inside a compiled block that isn’t supported yet, let us know. It will help us decide which nodes to focus on converting.
Attempt to internally reference a compiled node
You cannot reference nodes inside a compiled block by name. Use a spare input and refer to the node using the spare input number instead. See spare inputs.
Violation of strict nesting of blocks. Incompatible For Block Begin encountered while processing Block End. A Block Begin in Fetch Input mode may be needed
See nesting blocks. Look at the nodes mentioned in the error message and see if they have wires crossing into a block that are connected to something other than a block/loop begin node.
To fix this problem, add a loop/compiled block begin node to the incoming wire. For loop begin nodes, if you just want to use the input, set the Method to "Fetch input".