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

TSL: SubgroupFunctionNode #30022

Draft
wants to merge 4 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 3 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
25 changes: 25 additions & 0 deletions src/Three.TSL.js
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,10 @@ export const rotateUV = TSL.rotateUV;
export const roughness = TSL.roughness;
export const round = TSL.round;
export const rtt = TSL.rtt;
export const quadBroadcast = TSL.quadBroadcast;
export const quadSwapDiagonal = TSL.quadSwapDiagonal;
export const quadSwapX = TSL.quadSwapX;
export const quadSwapY = TSL.quadSwapY;
export const sRGBTransferEOTF = TSL.sRGBTransferEOTF;
export const sRGBTransferOETF = TSL.sRGBTransferOETF;
export const sampler = TSL.sampler;
Expand Down Expand Up @@ -434,8 +438,29 @@ export const storageObject = TSL.storageObject;
export const storageTexture = TSL.storageTexture;
export const string = TSL.string;
export const sub = TSL.sub;
export const subgroupAdd = TSL.subgroupAdd;
export const subgroupAll = TSL.subgroupAll;
export const subgroupAnd = TSL.subgroupAnd;
export const subgroupAny = TSL.subgroupAny;
export const subgroupBallot = TSL.subgroupBallot;
export const subgroupBroadcast = TSL.subgroupBroadcast;
export const subgroupBroadcastFirst = TSL.subgroupBroadcastFirst;
export const subgroupElect = TSL.subgroupElect;
export const subgroupExclusiveAdd = TSL.subgroupExclusiveAdd;
export const subgroupExclusiveMul = TSL.subgroupExclusiveMul;
export const subgroupInclusiveAdd = TSL.subgroupInclusiveAdd;
export const subgroupInclusiveMul = TSL.subgroupInclusiveMul;
export const subgroupIndex = TSL.subgroupIndex;
export const subgroupMax = TSL.subgroupMax;
export const subgroupMin = TSL.subgroupMin;
export const subgroupMul = TSL.subgroupMul;
export const subgroupOr = TSL.subgroupOr;
export const subgroupShuffle = TSL.subgroupShuffle;
export const subgroupShuffleDown = TSL.subgroupShuffleDown;
export const subgroupShuffleUp = TSL.subgroupShuffleUp;
export const subgroupShuffleXor = TSL.subgroupShuffleXor;
export const subgroupSize = TSL.subgroupSize;
export const subgroupXor = TSL.subgroupXor;
export const tan = TSL.tan;
export const tangentGeometry = TSL.tangentGeometry;
export const tangentLocal = TSL.tangentLocal;
Expand Down
1 change: 1 addition & 0 deletions src/nodes/TSL.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ export * from './gpgpu/ComputeBuiltinNode.js';
export * from './gpgpu/BarrierNode.js';
export * from './gpgpu/WorkgroupInfoNode.js';
export * from './gpgpu/AtomicFunctionNode.js';
export * from './gpgpu/SubgroupFunctionNode.js';

// lighting
export * from './accessors/Lights.js';
Expand Down
191 changes: 191 additions & 0 deletions src/nodes/gpgpu/SubgroupFunctionNode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
import TempNode from '../core/TempNode.js';
import { addMethodChaining, nodeProxy } from '../tsl/TSLCore.js';

class SubgroupFunctionNode extends TempNode {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mind adding JSDoc for SubgroupFunctionNode?

For new modules, we should add documentation right from the beginning. Use FunctionNode as an orientation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the class, how about this:

This class represents a set of built in WGSL shader functions that synchronously execute an operation across a subgroup, or 'wave', of compute or fragment shader invocations within a workgroup. Typically, these functions will synchronously execute an operation using data from all active invocations within the subgroup, then broadcast that result to all active invocations. In other graphics APIs, subgroup functions are also referred to as wave intrinsics (DirectX/HLSL) or warp intrinsics (CUDA).


static get type() {

return 'SubgroupFunctionNode';

}

constructor( method, aNode = null, bNode = null ) {

super();

this.method = method;

this.aNode = aNode;
this.bNode = bNode;

}

getInputType( builder ) {

const aType = this.aNode ? this.aNode.getNodeType( builder ) : null;
const bType = this.bNode ? this.bNode.getNodeType( builder ) : null;

const aLen = builder.isMatrix( aType ) ? 0 : builder.getTypeLength( aType );
const bLen = builder.isMatrix( bType ) ? 0 : builder.getTypeLength( bType );

if ( aLen > bLen ) {

return aType;

} else {

return bType;

}

}

getNodeType( builder ) {

const method = this.method;

if ( method === SubgroupFunctionNode.SUBGROUP_ELECT ) {

return 'bool';

} else if ( method === SubgroupFunctionNode.SUBGROUP_BALLOT ) {

return 'uvec4';

} else {

return this.getInputType( builder );

}

}

generate( builder, output ) {

const method = this.method;

const type = this.getNodeType( builder );
const inputType = this.getInputType( builder );

const a = this.aNode;
const b = this.bNode;

const params = [];

if (
method === SubgroupFunctionNode.SUBGROUP_BROADCAST ||
method === SubgroupFunctionNode.SUBGROUP_SHUFFLE ||
method === SubgroupFunctionNode.QUAD_BROADCAST
) {

const bType = b.getNodeType( builder );

params.push(
a.build( builder, type ),
b.build( builder, bType === 'float' ? 'int' : type )
);

} else if (
method === SubgroupFunctionNode.SUBGROUP_SHUFFLE_XOR ||
method === SubgroupFunctionNode.SUBGROUP_SHUFFLE_DOWN ||
method === SubgroupFunctionNode.SUBGROUP_SHUFFLE_UP
) {

params.push(
a.build( builder, type ),
b.build( builder, 'uint' )
);

} else {

if ( a !== null ) params.push( a.build( builder, inputType ) );
if ( b !== null ) params.push( b.build( builder, inputType ) );

}

const paramsString = params.length === 0 ? '()' : `( ${params.join( ', ' )} )`;

return builder.format( `${ builder.getMethod( method, type ) }${paramsString}`, type, output );



}

serialize( data ) {

super.serialize( data );

data.method = this.method;

}

deserialize( data ) {

super.deserialize( data );

this.method = data.method;

}

}

// 0 inputs
SubgroupFunctionNode.SUBGROUP_ELECT = 'subgroupElect';

// 1 input
SubgroupFunctionNode.SUBGROUP_BALLOT = 'subgroupBallot';
SubgroupFunctionNode.SUBGROUP_ADD = 'subgroupAdd';
SubgroupFunctionNode.SUBGROUP_INCLUSIVE_ADD = 'subgroupInclusiveAdd';
SubgroupFunctionNode.SUBGROUP_EXCLUSIVE_AND = 'subgroupExclusiveAdd';
SubgroupFunctionNode.SUBGROUP_MUL = 'subgroupMul';
SubgroupFunctionNode.SUBGROUP_INCLUSIVE_MUL = 'subgroupInclusiveMul';
SubgroupFunctionNode.SUBGROUP_EXCLUSIVE_MUL = 'subgroupExclusiveMul';
SubgroupFunctionNode.SUBGROUP_AND = 'subgroupAnd';
SubgroupFunctionNode.SUBGROUP_OR = 'subgroupOr';
SubgroupFunctionNode.SUBGROUP_XOR = 'subgroupXor';
SubgroupFunctionNode.SUBGROUP_MIN = 'subgroupMin';
SubgroupFunctionNode.SUBGROUP_MAX = 'subgroupMax';
SubgroupFunctionNode.SUBGROUP_ALL = 'subgroupAll';
SubgroupFunctionNode.SUBGROUP_ANY = 'subgroupAny';
SubgroupFunctionNode.SUBGROUP_BROADCAST_FIRST = 'subgroupBroadcastFirst';
SubgroupFunctionNode.QUAD_SWAP_X = 'quadSwapX';
SubgroupFunctionNode.QUAD_SWAP_Y = 'quadSwapY';
SubgroupFunctionNode.QUAD_SWAP_DIAGONAL = 'quadSwapDiagonal';

// 2 inputs
SubgroupFunctionNode.SUBGROUP_BROADCAST = 'subgroupBroadcast';
SubgroupFunctionNode.SUBGROUP_SHUFFLE = 'subgroupShuffle';
SubgroupFunctionNode.SUBGROUP_SHUFFLE_XOR = 'subgroupShuffleXor';
SubgroupFunctionNode.SUBGROUP_SHUFFLE_UP = 'subgroupShuffleUp';
SubgroupFunctionNode.SUBGROUP_SHUFFLE_DOWN = 'subgroupShuffleDown';
SubgroupFunctionNode.QUAD_BROADCAST = 'quadBroadcast';

export default SubgroupFunctionNode;

export const subgroupElect = /*@__PURE__*/ nodeProxy( SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_ELECT );
export const subgroupBallot = /*@__PURE__*/ nodeProxy( SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_BALLOT );
export const subgroupAdd = /*@__PURE__*/ nodeProxy( SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_ADD );
export const subgroupInclusiveAdd = /*@__PURE__*/ nodeProxy( SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_INCLUSIVE_ADD );
export const subgroupExclusiveAdd = /*@__PURE__*/ nodeProxy( SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_EXCLUSIVE_AND );
export const subgroupMul = /*@__PURE__*/ nodeProxy( SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_MUL );
export const subgroupInclusiveMul = /*@__PURE__*/ nodeProxy( SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_INCLUSIVE_MUL );
export const subgroupExclusiveMul = /*@__PURE__*/ nodeProxy( SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_EXCLUSIVE_MUL );
export const subgroupAnd = /*@__PURE__*/ nodeProxy( SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_AND );
export const subgroupOr = /*@__PURE__*/ nodeProxy( SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_OR );
export const subgroupXor = /*@__PURE__*/ nodeProxy( SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_XOR );
export const subgroupMin = /*@__PURE__*/ nodeProxy( SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_MIN );
export const subgroupMax = /*@__PURE__*/ nodeProxy( SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_MAX );
export const subgroupAll = /*@__PURE__*/ nodeProxy( SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_ALL );
export const subgroupAny = /*@__PURE__*/ nodeProxy( SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_ANY );
export const subgroupBroadcastFirst = /*@__PURE__*/ nodeProxy( SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_BROADCAST_FIRST );
export const quadSwapX = /*@__PURE__*/ nodeProxy( SubgroupFunctionNode, SubgroupFunctionNode.QUAD_SWAP_X );
export const quadSwapY = /*@__PURE__*/ nodeProxy( SubgroupFunctionNode, SubgroupFunctionNode.QUAD_SWAP_Y );
export const quadSwapDiagonal = /*@__PURE__*/ nodeProxy( SubgroupFunctionNode, SubgroupFunctionNode.QUAD_SWAP_DIAGONAL );
export const subgroupBroadcast = /*@__PURE__*/ nodeProxy( SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_BROADCAST );
export const subgroupShuffle = /*@__PURE__*/ nodeProxy( SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_SHUFFLE );
export const subgroupShuffleXor = /*@__PURE__*/ nodeProxy( SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_SHUFFLE_XOR );
export const subgroupShuffleUp = /*@__PURE__*/ nodeProxy( SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_SHUFFLE_UP );
export const subgroupShuffleDown = /*@__PURE__*/ nodeProxy( SubgroupFunctionNode, SubgroupFunctionNode.SUBGROUP_SHUFFLE_DOWN );
export const quadBroadcast = /*@__PURE__*/ nodeProxy( SubgroupFunctionNode, SubgroupFunctionNode.QUAD_BROADCAST );

addMethodChaining( 'subgroupElect', subgroupElect );
Loading