Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebGPURenderer: Add Array Type Variable Declaration Support #30376

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions src/nodes/core/NodeBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -1612,10 +1612,11 @@ class NodeBuilder {
* @param {String} [type=node.getNodeType( this )] - The variable's type.
* @param {('vertex'|'fragment'|'compute'|'any')} [shaderStage=this.shaderStage] - The shader stage.
* @param {Boolean} [readOnly=false] - Whether the variable is read-only or not.
* @param {Number} [arrayLength=1] - The variable's length in case of an array type.
*
* @return {NodeVar} The node variable.
*/
getVarFromNode( node, name = null, type = node.getNodeType( this ), shaderStage = this.shaderStage, readOnly = false ) {
getVarFromNode( node, name = null, type = node.getNodeType( this ), shaderStage = this.shaderStage, readOnly = false, arrayLength = 1 ) {

const nodeData = this.getDataFromNode( node, shaderStage );

Expand All @@ -1636,7 +1637,7 @@ class NodeBuilder {

}

nodeVar = new NodeVar( name, type, readOnly );
nodeVar = new NodeVar( name, type, readOnly, arrayLength );

if ( ! readOnly ) {

Expand Down Expand Up @@ -2134,11 +2135,14 @@ class NodeBuilder {
*
* @param {String} type - The variable's type.
* @param {String} name - The variable's name.
* @param {Number} [arrayLength=1] - The variable's length in case of an array type.
* @return {String} The shader string.
*/
getVar( type, name ) {
getVar( type, name, arrayLength ) {

return `${ this.getType( type ) } ${ name }`;
const length = arrayLength > 1 ? `[ ${ arrayLength } ]` : '';

return `${ this.getType( type ) }${ length } ${ name }`;

}

Expand All @@ -2158,7 +2162,7 @@ class NodeBuilder {

for ( const variable of vars ) {

snippet += `${ this.getVar( variable.type, variable.name ) }; `;
snippet += `${ this.getVar( variable.type, variable.name, variable.arrayLength ) }; `;

}

Expand Down
10 changes: 9 additions & 1 deletion src/nodes/core/NodeVar.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ class NodeVar {
* @param {String} name - The name of the variable.
* @param {String} type - The type of the variable.
* @param {Boolean} [readOnly=false] - The read-only flag.
* @param {Number} [arrayLength=1] - The variable's length in case of an array type.
*/
constructor( name, type, readOnly = false ) {
constructor( name, type, readOnly = false, arrayLength = 1 ) {

/**
* This flag can be used for type testing.
Expand Down Expand Up @@ -45,6 +46,13 @@ class NodeVar {
*/
this.readOnly = readOnly;

/**
* The length of the variable in case of an array type.
*
* @type {Number}
*/
this.arrayLength = arrayLength;

}

}
Expand Down
77 changes: 71 additions & 6 deletions src/nodes/core/VarNode.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Node from './Node.js';
import { addMethodChaining, nodeProxy } from '../tsl/TSLCore.js';
import { nodeObject, addMethodChaining, nodeProxy } from '../tsl/TSLCore.js';
import ArrayElementNode from '../utils/ArrayElementNode.js';

/** @module VarNode **/

Expand Down Expand Up @@ -74,6 +75,14 @@ class VarNode extends Node {
*/
this.readOnly = readOnly;

/**
* The length of the variable in case of an array type.
*
* @type {Number}
* @default 1
*/
this.arrayLength = 1;

}

getHash( builder ) {
Expand All @@ -88,6 +97,58 @@ class VarNode extends Node {

}

/**
* Sets the length of the variable in case of an array type.
* This method is chainable.
*
* @param {Number} length - The variable's length.
* @return {VarNode} The current node.
*/
toArray( length ) {

this.arrayLength = length;

return this;

}

/**
* Specific to array element
* Returns an array element node that represents the access to a specific element
*
* @param {IndexNode} indexNode - The index node.
* @return {ArrayElementNode} The array element node.
*/
element( indexNode ) {

return nodeObject( new ArrayElementNode( this, nodeObject( indexNode ) ) );

}

/**
* Specific to array element
* The data type of the array elements.
*
* @param {NodeBuilder} builder - The current node builder.
* @return {String} The element type.
*/

getElementType( builder ) {

const type = this.getNodeType( builder );
const elementType = builder.getElementType( type );

if ( this.arrayLength > 1 ) {

return this.getNodeType( builder );

}

return elementType;

}


generate( builder ) {

const { node, name, readOnly } = this;
Expand All @@ -109,21 +170,21 @@ class VarNode extends Node {
const vectorType = builder.getVectorType( this.getNodeType( builder ) );
const snippet = node.build( builder, vectorType );

const nodeVar = builder.getVarFromNode( this, name, vectorType, undefined, shouldTreatAsReadOnly );
const nodeVar = builder.getVarFromNode( this, name, vectorType, undefined, shouldTreatAsReadOnly, this.arrayLength );

const propertyName = builder.getPropertyName( nodeVar );

let declarationPrefix = propertyName;

if ( shouldTreatAsReadOnly ) {

const type = builder.getType( nodeVar.type );
const type = builder.getType( nodeVar.type, this.arrayLength );

if ( isWebGPUBackend ) {

declarationPrefix = isDeterministic
? `const ${ propertyName }`
: `let ${ propertyName }`;
? `const ${ propertyName }: ${ type }`
: `let ${ propertyName }: ${ type }`;

} else {

Expand All @@ -133,7 +194,11 @@ class VarNode extends Node {

}

builder.addLineFlowCode( `${ declarationPrefix } = ${ snippet }`, this );
if ( this.arrayLength <= 1 ) {

builder.addLineFlowCode( `${ declarationPrefix } = ${ snippet }`, this );

}

return propertyName;

Expand Down
2 changes: 1 addition & 1 deletion src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ ${ flowData.code }

for ( const variable of vars ) {

snippets.push( `${ this.getVar( variable.type, variable.name ) };` );
snippets.push( `${ this.getVar( variable.type, variable.name, variable.arrayLength ) };` );

}

Expand Down
22 changes: 17 additions & 5 deletions src/renderers/webgpu/nodes/WGSLNodeBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -1464,11 +1464,12 @@ ${ flowData.code }
*
* @param {String} type - The variable's type.
* @param {String} name - The variable's name.
* @param {Number} arrayLength - The variable's length.
* @return {String} The WGSL snippet that defines a variable.
*/
getVar( type, name ) {
getVar( type, name, arrayLength ) {

return `var ${ name } : ${ this.getType( type ) }`;
return `var ${ name } : ${ this.getType( type, arrayLength ) }`;

}

Expand All @@ -1487,7 +1488,7 @@ ${ flowData.code }

for ( const variable of vars ) {

snippets.push( `\t${ this.getVar( variable.type, variable.name ) };` );
snippets.push( `\t${ this.getVar( variable.type, variable.name, variable.arrayLength ) };` );

}

Expand Down Expand Up @@ -1822,11 +1823,22 @@ ${ flowData.code }
* Returns the WGSL type of the given node data type.
*
* @param {String} type - The node data type.
* @param {Number} [arrayLength=1] - The length of the type.
* @return {String} The WGSL type.
*/
getType( type ) {
getType( type, arrayLength = 1 ) {

return wgslTypeLib[ type ] || type;
const baseType = wgslTypeLib[ type ] || type;

// Return base type if length is 1 or not provided
if ( ! arrayLength || arrayLength <= 1 ) {

return baseType;

}

// Return array type with specified length for arrays
return `array<${baseType}, ${arrayLength}>`;

}

Expand Down
Loading