Houdini 20.0 Geometry

Compiled blocks

You can mark a chain of compilable SOPs as a compiled block which can execute much faster in parallel.

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 it 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 is working on. There are a lot of optimizations that can 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 use nodes that have been modified to allow compiling inside compiled blocks. You can enable a badge in the network editor to see the nodes that cannot be used in a compiled block.

We are continuing to convert nodes based on perceived need. It is unlikely that we will get to all the existing SOPs (numbered in the hundreds), but if there is a node you would like to use inside a compiled block that has not yet been converted, let us know.

No stamp() expression

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.

(Unlike, stamp(), this restriction may be lifted someday, depending on necessity.)

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 is not very efficient, but it works. In a compiled block, you cannot 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 cannot read geometry, as in a point expression.

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 could use a spare input instead.

Nodes outside the block can reference geometry on nodes inside the block, but doing so would cook the interior node (and any dependencies) normally, without any of the benefits of compilation.

Nodes cannot read from their direct inputs

Expressions cannot 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 the 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 is not supported inside a compiled block.


At this point in the development of compiled blocks, resist the urge to overuse compiled blocks in an attempt to gain maximum efficiency, especially in a production environment. The drawbacks are such that the reward is often not worth the effort.

  • Target the use of compiled blocks where they will give the most benefit - in iterations over large numbers of pieces.

  • You may want to get your network working and finalized, and then based on profiling, try converting any slow parts of the network into compiled blocks.

How to

Houdini will attempt to compile everything between one or more Compile Block Begin nodes and a corresponding Compile Block End node.

To...Do this

Create a compiled block

  1. In the network editor, open the ⇥ Tab menu and choose Compiled Block to create a pair of compiled block nodes.

    Houdini automatically creates a pair of Begin and End nodes wired together.

  2. You can wire the block into your network, and wire the nodes to compile between the Begin and End nodes.

Compiled loops

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 may want to do this only on the outer loop to avoid an explosion of the number of distributed tasks.

Nesting blocks

When using compiled blocks and loops, 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.

Spare inputs

As noted in the restrictions section, geometry expressions in a compiled block cannot reference the node’s direct inputs, and you cannot reference nodes inside a compiled block by name. The rule is there cannot 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 VEX SOPs always evaluate all their inputs, as it is very inefficient to 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 to 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 use an integer instead to refer to an input (for example, npoints(-1)).

To...Do this

Use a spare input to reference another node

  1. Select the compiled node in which you want to reference the geometry of another node.

  2. In the parameter editor, click the Gear menu and choose Add Spare Input.

    Houdini adds a new parameter at the end of the node’s interface to represent the input.

  3. In the Spare Input n field, enter the path of the node you want to reference.

  4. Hover over the Spare Input n label to get a tooltip showing the number to use in geometry expressions to refer to the spare input (for example, npoints(-1)).

    (Spare input references count down, so while the first direct input is 0 and the second direct input is 1, the first spare input is -1, the second is -2, and so on.)

Tips and notes

  • Spare inputs are also useful for referring to extra geometry inputs in a Wrangle node (beyond the four direct inputs that Wrangle nodes come with).

  • If you turn on 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 after the Block End node for the block to compile.

  • You can turn on a badge to see the nodes you cannot use inside a compiled block.

    In the network editor, choose View ▸ Display Options or press D. In the Context Specific Badges tab, set Non-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 yet to be converted to work in compiled blocks. See the tips above for how to turn on a badge in the network editor to show the nodes that are not compilable.

If there is a node you would like to use inside a compiled block that is not yet supported, 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.

See also






  • Destruction

    How to break different types of materials.


Next steps

Guru level