Преглед изворни кода

TSL: Fix `.toVarying()` analyze for optimization (#31090)

* fix cache of varying inside a conditional of fragment stage

* add `isAssignNode`

* improve optimization system for varyings

* cleanup

* second approach

* Update StackNode.js
sunag пре 10 месеци
родитељ
комит
c35b17794d

+ 9 - 0
src/nodes/core/AssignNode.js

@@ -40,6 +40,15 @@ class AssignNode extends TempNode {
 		 */
 		 */
 		this.sourceNode = sourceNode;
 		this.sourceNode = sourceNode;
 
 
+		/**
+		 * This flag can be used for type testing.
+		 *
+		 * @type {boolean}
+		 * @readonly
+		 * @default true
+		 */
+		this.isAssignNode = true;
+
 	}
 	}
 
 
 	/**
 	/**

+ 14 - 4
src/nodes/core/Node.js

@@ -506,11 +506,21 @@ class Node extends EventDispatcher {
 	 * This stage analyzes the node hierarchy and ensures descendent nodes are built.
 	 * This stage analyzes the node hierarchy and ensures descendent nodes are built.
 	 *
 	 *
 	 * @param {NodeBuilder} builder - The current node builder.
 	 * @param {NodeBuilder} builder - The current node builder.
+	 * @param {?Node} output - The target output node.
 	 */
 	 */
-	analyze( builder ) {
+	analyze( builder, output = null ) {
 
 
 		const usageCount = builder.increaseUsage( this );
 		const usageCount = builder.increaseUsage( this );
 
 
+		if ( this.parents === true ) {
+
+			const nodeData = builder.getDataFromNode( this, 'any' );
+			nodeData.stages = nodeData.stages || {};
+			nodeData.stages[ builder.shaderStage ] = nodeData.stages[ builder.shaderStage ] || [];
+			nodeData.stages[ builder.shaderStage ].push( output );
+
+		}
+
 		if ( usageCount === 1 ) {
 		if ( usageCount === 1 ) {
 
 
 			// node flow children
 			// node flow children
@@ -521,7 +531,7 @@ class Node extends EventDispatcher {
 
 
 				if ( childNode && childNode.isNode === true ) {
 				if ( childNode && childNode.isNode === true ) {
 
 
-					childNode.build( builder );
+					childNode.build( builder, this );
 
 
 				}
 				}
 
 
@@ -600,7 +610,7 @@ class Node extends EventDispatcher {
 	 * - **generate**: Generates the shader code for the node. Returns the generated shader string.
 	 * - **generate**: Generates the shader code for the node. Returns the generated shader string.
 	 *
 	 *
 	 * @param {NodeBuilder} builder - The current node builder.
 	 * @param {NodeBuilder} builder - The current node builder.
-	 * @param {?string} [output=null] - Can be used to define the output type.
+	 * @param {string|Node|null} [output=null] - Can be used to define the output type.
 	 * @return {Node|string|null} The result of the build process, depending on the build stage.
 	 * @return {Node|string|null} The result of the build process, depending on the build stage.
 	 */
 	 */
 	build( builder, output = null ) {
 	build( builder, output = null ) {
@@ -669,7 +679,7 @@ class Node extends EventDispatcher {
 
 
 		} else if ( buildStage === 'analyze' ) {
 		} else if ( buildStage === 'analyze' ) {
 
 
-			this.analyze( builder );
+			this.analyze( builder, output );
 
 
 		} else if ( buildStage === 'generate' ) {
 		} else if ( buildStage === 'generate' ) {
 
 

+ 33 - 7
src/nodes/core/NodeBuilder.js

@@ -2285,27 +2285,53 @@ class NodeBuilder {
 	 * @param {Node} node - The node to execute.
 	 * @param {Node} node - The node to execute.
 	 * @param {?string} output - Expected output type. For example 'vec3'.
 	 * @param {?string} output - Expected output type. For example 'vec3'.
 	 * @param {?string} propertyName - The property name to assign the result.
 	 * @param {?string} propertyName - The property name to assign the result.
-	 * @return {Object}
+	 * @return {Object|Node|null} The code flow or node.build() result.
 	 */
 	 */
 	flowNodeFromShaderStage( shaderStage, node, output = null, propertyName = null ) {
 	flowNodeFromShaderStage( shaderStage, node, output = null, propertyName = null ) {
 
 
+		const previousTab = this.tab;
+		const previousCache = this.cache;
 		const previousShaderStage = this.shaderStage;
 		const previousShaderStage = this.shaderStage;
+		const previousContext = this.context;
 
 
 		this.setShaderStage( shaderStage );
 		this.setShaderStage( shaderStage );
 
 
-		const flowData = this.flowChildNode( node, output );
+		const context = { ...this.context };
+		delete context.nodeBlock;
 
 
-		if ( propertyName !== null ) {
+		this.cache = this.globalCache;
+		this.tab = '\t';
+		this.context = context;
 
 
-			flowData.code += `${ this.tab + propertyName } = ${ flowData.result };\n`;
+		let result = null;
 
 
-		}
+		if ( this.buildStage === 'generate' ) {
+
+			const flowData = this.flowChildNode( node, output );
+
+			if ( propertyName !== null ) {
 
 
-		this.flowCode[ shaderStage ] = this.flowCode[ shaderStage ] + flowData.code;
+				flowData.code += `${ this.tab + propertyName } = ${ flowData.result };\n`;
+
+			}
+
+			this.flowCode[ shaderStage ] = this.flowCode[ shaderStage ] + flowData.code;
+
+			result = flowData;
+
+		} else {
+
+			result = node.build( this );
+
+		}
 
 
 		this.setShaderStage( previousShaderStage );
 		this.setShaderStage( previousShaderStage );
 
 
-		return flowData;
+		this.cache = previousCache;
+		this.tab = previousTab;
+		this.context = previousContext;
+
+		return result;
 
 
 	}
 	}
 
 

+ 24 - 1
src/nodes/core/StackNode.js

@@ -251,9 +251,32 @@ class StackNode extends Node {
 
 
 		setCurrentStack( this );
 		setCurrentStack( this );
 
 
+		const buildStage = builder.buildStage;
+
 		for ( const node of this.nodes ) {
 		for ( const node of this.nodes ) {
 
 
-			node.build( builder, 'void' );
+			if ( buildStage === 'setup' ) {
+
+				node.build( builder );
+
+			} else if ( buildStage === 'analyze' ) {
+
+				node.build( builder, this );
+
+			} else if ( buildStage === 'generate' ) {
+
+				const stages = builder.getDataFromNode( node, 'any' ).stages;
+				const parents = stages && stages[ builder.shaderStage ];
+
+				if ( node.isVarNode && parents && parents.length === 1 && parents[ 0 ] && parents[ 0 ].isStackNode ) {
+
+					continue; // skip var nodes that are only used in .toVarying()
+
+				}
+
+				node.build( builder, 'void' );
+
+			}
 
 
 		}
 		}
 
 

+ 9 - 0
src/nodes/core/VarNode.js

@@ -72,6 +72,15 @@ class VarNode extends Node {
 		 */
 		 */
 		this.readOnly = readOnly;
 		this.readOnly = readOnly;
 
 
+		/**
+		 *
+		 * Add this flag to the node system to indicate that this node require parents.
+		 *
+		 * @type {boolean}
+		 * @default true
+		 */
+		this.parents = true;
+
 	}
 	}
 
 
 	getMemberType( builder, name ) {
 	getMemberType( builder, name ) {

+ 4 - 1
src/nodes/core/VaryingNode.js

@@ -97,6 +97,7 @@ class VaryingNode extends Node {
 
 
 		this.interpolationType = type;
 		this.interpolationType = type;
 		this.interpolationSampling = sampling;
 		this.interpolationSampling = sampling;
+
 		return this;
 		return this;
 
 
 	}
 	}
@@ -150,13 +151,15 @@ class VaryingNode extends Node {
 
 
 		this.setupVarying( builder );
 		this.setupVarying( builder );
 
 
+		builder.flowNodeFromShaderStage( NodeShaderStage.VERTEX, this.node );
+
 	}
 	}
 
 
 	analyze( builder ) {
 	analyze( builder ) {
 
 
 		this.setupVarying( builder );
 		this.setupVarying( builder );
 
 
-		return this.node.analyze( builder );
+		builder.flowNodeFromShaderStage( NodeShaderStage.VERTEX, this.node );
 
 
 	}
 	}
 
 

粤ICP备19079148号