Skip to content

Commit 73eddcb

Browse files
WebGPURenderer: Introduced .toConst(), Const(), Var() (#30251)
* WebGPURenderer: Introduced variable.toLet() * change API to toConst() * const/let both backends? * const/let handle both backends * cleanup code * more cleanup * cleanup * add NodeBuilder.isDeterministic() and updates * readonly suffix * improve naming * added `Const`, `Var` --------- Co-authored-by: sunag <[email protected]>
1 parent ac467cf commit 73eddcb

File tree

9 files changed

+169
-18
lines changed

9 files changed

+169
-18
lines changed

src/Three.TSL.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ export const colorSpaceToWorking = TSL.colorSpaceToWorking;
114114
export const colorToDirection = TSL.colorToDirection;
115115
export const compute = TSL.compute;
116116
export const cond = TSL.cond;
117+
export const Const = TSL.Const;
117118
export const context = TSL.context;
118119
export const convert = TSL.convert;
119120
export const convertColorSpace = TSL.convertColorSpace;
@@ -219,6 +220,7 @@ export const lights = TSL.lights;
219220
export const linearDepth = TSL.linearDepth;
220221
export const linearToneMapping = TSL.linearToneMapping;
221222
export const localId = TSL.localId;
223+
export const globalId = TSL.globalId;
222224
export const log = TSL.log;
223225
export const log2 = TSL.log2;
224226
export const logarithmicDepthToViewZ = TSL.logarithmicDepthToViewZ;
@@ -496,6 +498,7 @@ export const uv = TSL.uv;
496498
export const uvec2 = TSL.uvec2;
497499
export const uvec3 = TSL.uvec3;
498500
export const uvec4 = TSL.uvec4;
501+
export const Var = TSL.Var;
499502
export const varying = TSL.varying;
500503
export const varyingProperty = TSL.varyingProperty;
501504
export const vec2 = TSL.vec2;

src/nodes/core/NodeBuilder.js

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1604,23 +1604,38 @@ class NodeBuilder {
16041604
* @param {String?} name - The variable's name.
16051605
* @param {String} [type=node.getNodeType( this )] - The variable's type.
16061606
* @param {('vertex'|'fragment'|'compute'|'any')} [shaderStage=this.shaderStage] - The shader stage.
1607+
* @param {Boolean} [readOnly=false] - Whether the variable is read-only or not.
1608+
*
16071609
* @return {NodeVar} The node variable.
16081610
*/
1609-
getVarFromNode( node, name = null, type = node.getNodeType( this ), shaderStage = this.shaderStage ) {
1611+
getVarFromNode( node, name = null, type = node.getNodeType( this ), shaderStage = this.shaderStage, readOnly = false ) {
16101612

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

16131615
let nodeVar = nodeData.variable;
16141616

16151617
if ( nodeVar === undefined ) {
16161618

1619+
const idNS = readOnly ? '_const' : '_var';
1620+
16171621
const vars = this.vars[ shaderStage ] || ( this.vars[ shaderStage ] = [] );
1622+
const id = this.vars[ idNS ] || ( this.vars[ idNS ] = 0 );
1623+
1624+
if ( name === null ) {
1625+
1626+
name = ( readOnly ? 'nodeConst' : 'nodeVar' ) + id;
1627+
1628+
this.vars[ idNS ] ++;
1629+
1630+
}
16181631

1619-
if ( name === null ) name = 'nodeVar' + vars.length;
1632+
nodeVar = new NodeVar( name, type, readOnly );
16201633

1621-
nodeVar = new NodeVar( name, type );
1634+
if ( ! readOnly ) {
16221635

1623-
vars.push( nodeVar );
1636+
vars.push( nodeVar );
1637+
1638+
}
16241639

16251640
nodeData.variable = nodeVar;
16261641

@@ -1630,6 +1645,35 @@ class NodeBuilder {
16301645

16311646
}
16321647

1648+
/**
1649+
* Returns whether a Node or its flow is deterministic, useful for use in `const`.
1650+
*
1651+
* @param {Node} node - The varying node.
1652+
* @return {Boolean} Returns true if deterministic.
1653+
*/
1654+
isDeterministic( node ) {
1655+
1656+
if ( node.isMathNode ) {
1657+
1658+
return this.isDeterministic( node.aNode ) &&
1659+
( node.bNode ? this.isDeterministic( node.bNode ) : true ) &&
1660+
( node.cNode ? this.isDeterministic( node.cNode ) : true );
1661+
1662+
} else if ( node.isOperatorNode ) {
1663+
1664+
return this.isDeterministic( node.aNode ) &&
1665+
( node.bNode ? this.isDeterministic( node.bNode ) : true );
1666+
1667+
} else if ( node.isConstNode ) {
1668+
1669+
return true;
1670+
1671+
}
1672+
1673+
return false;
1674+
1675+
}
1676+
16331677
/**
16341678
* Returns an instance of {@link NodeVarying} for the given varying node.
16351679
*

src/nodes/core/NodeVar.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ class NodeVar {
1111
*
1212
* @param {String} name - The name of the variable.
1313
* @param {String} type - The type of the variable.
14+
* @param {Boolean} [readOnly=false] - The read-only flag.
1415
*/
15-
constructor( name, type ) {
16+
constructor( name, type, readOnly = false ) {
1617

1718
/**
1819
* This flag can be used for type testing.
@@ -37,6 +38,13 @@ class NodeVar {
3738
*/
3839
this.type = type;
3940

41+
/**
42+
* The read-only flag.
43+
*
44+
* @type {boolean}
45+
*/
46+
this.readOnly = readOnly;
47+
4048
}
4149

4250
}

src/nodes/core/VarNode.js

Lines changed: 75 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ class VarNode extends Node {
2626
*
2727
* @param {Node} node - The node for which a variable should be created.
2828
* @param {String?} name - The name of the variable in the shader.
29+
* @param {Boolean?} readOnly - The read-only flag.
2930
*/
30-
constructor( node, name = null ) {
31+
constructor( node, name = null, readOnly = false ) {
3132

3233
super();
3334

@@ -64,6 +65,15 @@ class VarNode extends Node {
6465
*/
6566
this.isVarNode = true;
6667

68+
/**
69+
*
70+
* The read-only flag.
71+
*
72+
* @type {Boolean}
73+
* @default false
74+
*/
75+
this.readOnly = readOnly;
76+
6777
}
6878

6979
getHash( builder ) {
@@ -80,15 +90,50 @@ class VarNode extends Node {
8090

8191
generate( builder ) {
8292

83-
const { node, name } = this;
93+
const { node, name, readOnly } = this;
94+
const { renderer } = builder;
95+
96+
const isWebGPUBackend = renderer.backend.isWebGPUBackend === true;
97+
98+
let isDeterministic = false;
99+
let shouldTreatAsReadOnly = false;
100+
101+
if ( readOnly ) {
102+
103+
isDeterministic = builder.isDeterministic( node );
84104

85-
const nodeVar = builder.getVarFromNode( this, name, builder.getVectorType( this.getNodeType( builder ) ) );
105+
shouldTreatAsReadOnly = isWebGPUBackend ? readOnly : isDeterministic;
106+
107+
}
108+
109+
const vectorType = builder.getVectorType( this.getNodeType( builder ) );
110+
const snippet = node.build( builder, vectorType );
111+
112+
const nodeVar = builder.getVarFromNode( this, name, vectorType, undefined, shouldTreatAsReadOnly );
86113

87114
const propertyName = builder.getPropertyName( nodeVar );
88115

89-
const snippet = node.build( builder, nodeVar.type );
116+
let declarationPrefix = propertyName;
117+
118+
if ( shouldTreatAsReadOnly ) {
119+
120+
const type = builder.getType( nodeVar.type );
121+
122+
if ( isWebGPUBackend ) {
123+
124+
declarationPrefix = isDeterministic
125+
? `const ${ propertyName }`
126+
: `let ${ propertyName }`;
127+
128+
} else {
129+
130+
declarationPrefix = `const ${ type } ${ propertyName }`;
90131

91-
builder.addLineFlowCode( `${propertyName} = ${snippet}`, this );
132+
}
133+
134+
}
135+
136+
builder.addLineFlowCode( `${ declarationPrefix } = ${ snippet }`, this );
92137

93138
return propertyName;
94139

@@ -108,13 +153,36 @@ export default VarNode;
108153
*/
109154
const createVar = /*@__PURE__*/ nodeProxy( VarNode );
110155

111-
addMethodChaining( 'toVar', ( ...params ) => createVar( ...params ).append() );
156+
/**
157+
* TSL function for creating a var node.
158+
*
159+
* @function
160+
* @param {Node} node - The node for which a variable should be created.
161+
* @param {String?} name - The name of the variable in the shader.
162+
* @returns {VarNode}
163+
*/
164+
export const Var = ( node, name = null ) => createVar( node, name ).append();
165+
166+
/**
167+
* TSL function for creating a const node.
168+
*
169+
* @function
170+
* @param {Node} node - The node for which a constant should be created.
171+
* @param {String?} name - The name of the constant in the shader.
172+
* @returns {VarNode}
173+
*/
174+
export const Const = ( node, name = null ) => createVar( node, name, true ).append();
175+
176+
// Method chaining
177+
178+
addMethodChaining( 'toVar', Var );
179+
addMethodChaining( 'toConst', Const );
112180

113181
// Deprecated
114182

115183
export const temp = ( node ) => { // @deprecated, r170
116184

117-
console.warn( 'TSL: "temp" is deprecated. Use ".toVar()" instead.' );
185+
console.warn( 'TSL: "temp( node )" is deprecated. Use "Var( node )" or "node.toVar()" instead.' );
118186

119187
return createVar( node );
120188

src/nodes/gpgpu/ComputeBuiltinNode.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,14 @@ export const numWorkgroups = /*@__PURE__*/ computeBuiltin( 'numWorkgroups', 'uve
204204
*/
205205
export const workgroupId = /*@__PURE__*/ computeBuiltin( 'workgroupId', 'uvec3' );
206206

207+
/**
208+
* TSL function for creating a `globalId` builtin node. A non-linearized 3-dimensional
209+
* representation of the current invocation's position within a 3D global grid.
210+
*
211+
* @function
212+
* @returns {ComputeBuiltinNode<uvec3>}
213+
*/
214+
export const globalId = /*@__PURE__*/ computeBuiltin( 'globalId', 'uvec3' );
207215
/**
208216
* TSL function for creating a `localId` builtin node. A non-linearized 3-dimensional
209217
* representation of the current invocation's position within a 3D workgroup grid.

src/nodes/math/MathNode.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,15 @@ class MathNode extends TempNode {
6565
*/
6666
this.cNode = cNode;
6767

68+
/**
69+
* This flag can be used for type testing.
70+
*
71+
* @type {Boolean}
72+
* @readonly
73+
* @default true
74+
*/
75+
this.isMathNode = true;
76+
6877
}
6978

7079
/**

src/nodes/math/OperatorNode.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,15 @@ class OperatorNode extends TempNode {
6565
*/
6666
this.bNode = bNode;
6767

68+
/**
69+
* This flag can be used for type testing.
70+
*
71+
* @type {Boolean}
72+
* @readonly
73+
* @default true
74+
*/
75+
this.isOperatorNode = true;
76+
6877
}
6978

7079
/**

src/renderers/webgpu/WebGPUBackend.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -948,7 +948,7 @@ class WebGPUBackend extends Backend {
948948

949949
//
950950

951-
const encoder = device.createCommandEncoder( {} );
951+
const encoder = device.createCommandEncoder( { label: 'clear' } );
952952
const currentPass = encoder.beginRenderPass( {
953953
colorAttachments,
954954
depthStencilAttachment
@@ -973,11 +973,13 @@ class WebGPUBackend extends Backend {
973973
const groupGPU = this.get( computeGroup );
974974

975975

976-
const descriptor = {};
976+
const descriptor = {
977+
label: 'computeGroup_' + computeGroup.id
978+
};
977979

978980
this.initTimestampQuery( computeGroup, descriptor );
979981

980-
groupGPU.cmdEncoderGPU = this.device.createCommandEncoder();
982+
groupGPU.cmdEncoderGPU = this.device.createCommandEncoder( { label: 'computeGroup_' + computeGroup.id } );
981983

982984
groupGPU.passEncoderGPU = groupGPU.cmdEncoderGPU.beginComputePass( descriptor );
983985

src/renderers/webgpu/nodes/WGSLNodeBuilder.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,7 +1364,7 @@ ${ flowData.code }
13641364

13651365
if ( shaderStage === 'compute' ) {
13661366

1367-
this.getBuiltin( 'global_invocation_id', 'id', 'vec3<u32>', 'attribute' );
1367+
this.getBuiltin( 'global_invocation_id', 'globalId', 'vec3<u32>', 'attribute' );
13681368
this.getBuiltin( 'workgroup_id', 'workgroupId', 'vec3<u32>', 'attribute' );
13691369
this.getBuiltin( 'local_invocation_id', 'localId', 'vec3<u32>', 'attribute' );
13701370
this.getBuiltin( 'num_workgroups', 'numWorkgroups', 'vec3<u32>', 'attribute' );
@@ -1729,7 +1729,7 @@ ${ flowData.code }
17291729

17301730
if ( flow.length > 0 ) flow += '\n';
17311731

1732-
flow += `\t// flow -> ${ slotName }\n\t`;
1732+
flow += `\t// flow -> ${ slotName }\n`;
17331733

17341734
}
17351735

@@ -2007,7 +2007,7 @@ ${shaderData.codes}
20072007
fn main( ${shaderData.attributes} ) {
20082008
20092009
// system
2010-
instanceIndex = id.x + id.y * numWorkgroups.x * u32(${workgroupSize}) + id.z * numWorkgroups.x * numWorkgroups.y * u32(${workgroupSize});
2010+
instanceIndex = globalId.x + globalId.y * numWorkgroups.x * u32(${workgroupSize}) + globalId.z * numWorkgroups.x * numWorkgroups.y * u32(${workgroupSize});
20112011
20122012
// vars
20132013
${shaderData.vars}

0 commit comments

Comments
 (0)