-
-
Notifications
You must be signed in to change notification settings - Fork 36k
Description
Description
Related: #30759
A computed node created outside the loop and used multiple times within it is not stored in a temporary variable. In other cases, such nodes are stored in a temporary variable if they are used multiple times.
With #31459, we don't have to explicitly call toVar()
before assigning to a variable, and the number of uses is automatically tracked by TSL so we usually don't have to use toVar()
to create a mutable node, or look for multiple uses and add caching statements by calling toVar()
or toConst()
. But with the behavior above, and in a fairly complex node graph, it's very hard to track which nodes rely on a node created outside of the loop, so I'm inclined to add toVar()
or toConst()
for a safety reason when I cannot afford to debug the transpiled code. But doing this obscures the intent of the code and take less advantage of the automatic optimization.
Example
// Some expensive function:
const g = Fn(() => {
const sum = vec3(0)
Loop({ start: 0, end: 10_000, condition: '<' }, () => {
sum.addAssign(0.0001)
})
return sum
})
// A loop relies on the result of the above function.
const f = Fn(() => {
const t = g()
const sum = vec3(0)
Loop({ start: 0, end: 10, condition: '<' }, () => {
sum.addAssign(t)
})
return sum
})
outoutNode = f()
The above outoutNode
is transpiled as:
// vars
var nodeVar0 : vec3<f32>;
var nodeVar1 : vec3<f32>;
// flow
// code
nodeVar0 = vec3<f32>( 0.0, 0.0, 0.0 );
for ( var i : i32 = 0; i < 10; i ++ ) {
nodeVar1 = vec3<f32>( 0.0, 0.0, 0.0 );
for ( var i : i32 = 0; i < 10000; i ++ ) {
nodeVar1 = ( nodeVar1 + vec3<f32>( 0.0001 ) );
}
nodeVar0 = ( nodeVar0 + nodeVar1 );
}
// result
output.color = vec4<f32>( nodeVar0, 1.0 );
Calling toVar()
or toConst()
on t
creates a temporary variable outside of the loop, as stated before.
If we have another loop, the latter loop uses the result in the previous loop, which is also a weird behavior:
const f = Fn(() => {
const t = g()
const sum = vec3(0)
Loop({ start: 0, end: 10, condition: '<' }, () => {
sum.addAssign(t)
})
Loop({ start: 0, end: 10, condition: '<' }, () => {
sum.addAssign(t)
})
return sum
})
This is transpiled as:
var nodeVar0 : vec3<f32>;
var nodeVar1 : vec3<f32>;
// flow
// code
nodeVar0 = vec3<f32>( 0.0, 0.0, 0.0 );
for ( var i : i32 = 0; i < 10; i ++ ) {
nodeVar1 = vec3<f32>( 0.0, 0.0, 0.0 );
for ( var i : i32 = 0; i < 10000; i ++ ) {
nodeVar1 = ( nodeVar1 + vec3<f32>( 0.0001 ) );
}
nodeVar0 = ( nodeVar0 + nodeVar1 );
}
for ( var i : i32 = 0; i < 10; i ++ ) {
nodeVar0 = ( nodeVar0 + nodeVar1 );
}
// result
output.color = vec4<f32>( nodeVar0, 1.0 );
Solution
If a node used in a loop satisfies the following conditions, for example:
- It is not a variable or constant node.
- It has no dependencies on the nodes in the loop stack.
then assume it may be used multiple times, and store it in a temporary variable outside of the loop stack.
Alternatives
Add documentation on the limitation about the automatic optimization.
Additional context
No response