Skip to content

Commit 9fb80cf

Browse files
aardgooseaardgoose
andauthored
WebGPURenderer: partial compute() shader support for WebGL backend (#27367)
* compute support * code bot fixes * add StorageBufferAttribute * adapt to storagetBufferAttribute * dynamically realign the size of storage buffer based on backend * compute examples takes too much time to init for puppeteer * Add StorageBufferAttribute.create() --------- Co-authored-by: aardgoose <angus.sawyer@email.com>
1 parent 2e5df1c commit 9fb80cf

23 files changed

+562
-123
lines changed

examples/jsm/nodes/accessors/BufferAttributeNode.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,14 @@ class BufferAttributeNode extends InputNode {
6767

6868
const nodeType = this.getNodeType( builder );
6969

70-
const nodeUniform = builder.getBufferAttributeFromNode( this, nodeType );
71-
const propertyName = builder.getPropertyName( nodeUniform );
70+
const nodeAttribute = builder.getBufferAttributeFromNode( this, nodeType );
71+
const propertyName = builder.getPropertyName( nodeAttribute );
7272

7373
let output = null;
7474

75-
if ( builder.shaderStage === 'vertex' ) {
75+
if ( builder.shaderStage === 'vertex' || builder.shaderStage === 'compute' ) {
76+
77+
this.name = propertyName;
7678

7779
output = propertyName;
7880

examples/jsm/nodes/accessors/StorageBufferNode.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import BufferNode from './BufferNode.js';
2+
import { bufferAttribute } from './BufferAttributeNode.js';
23
import { addNodeClass } from '../core/Node.js';
34
import { nodeObject } from '../shadernode/ShaderNode.js';
5+
import { varying } from '../core/VaryingNode.js';
46

57
class StorageBufferNode extends BufferNode {
68

@@ -10,6 +12,9 @@ class StorageBufferNode extends BufferNode {
1012

1113
this.isStorageBufferNode = true;
1214

15+
this._attribute = null;
16+
this._varying = null;
17+
1318
}
1419

1520
getInputType( /*builder*/ ) {
@@ -18,6 +23,28 @@ class StorageBufferNode extends BufferNode {
1823

1924
}
2025

26+
generate( builder ) {
27+
28+
if ( builder.isAvailable( 'storageBuffer' ) ) return super.generate( builder );
29+
30+
const nodeType = this.getNodeType( builder );
31+
32+
if ( this._attribute === null ) {
33+
34+
this._attribute = bufferAttribute( this.value );
35+
this._varying = varying( this._attribute );
36+
37+
}
38+
39+
40+
const output = this._varying.build( builder, nodeType );
41+
42+
builder.registerTransform( output, this._attribute );
43+
44+
return output;
45+
46+
}
47+
2148
}
2249

2350
export default StorageBufferNode;

examples/jsm/nodes/utils/ArrayElementNode.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ class ArrayElementNode extends Node { // @TODO: If extending from TempNode it br
2424
const nodeSnippet = this.node.build( builder );
2525
const indexSnippet = this.indexNode.build( builder, 'uint' );
2626

27+
if ( this.node.isStorageBufferNode && ! builder.isAvailable( 'storageBuffer' ) ) {
28+
29+
return nodeSnippet;
30+
31+
}
32+
2733
return `${nodeSnippet}[ ${indexSnippet} ]`;
2834

2935
}

examples/jsm/renderers/common/Backend.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,12 @@ class Backend {
174174

175175
}
176176

177+
has( object ) {
178+
179+
return this.data.has( object );
180+
181+
}
182+
177183
delete( object ) {
178184

179185
this.data.delete( object );

examples/jsm/renderers/common/Bindings.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class Bindings extends DataMap {
4848

4949
const nodeBuilderState = this.nodes.getForCompute( computeNode );
5050

51-
const bindings = nodeBuilderState.bindings.compute;
51+
const bindings = nodeBuilderState.bindings;
5252

5353
data.bindings = bindings;
5454

examples/jsm/renderers/common/Pipelines.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,18 +42,18 @@ class Pipelines extends DataMap {
4242

4343
// get shader
4444

45-
const nodeBuilder = this.nodes.getForCompute( computeNode );
45+
const nodeBuilderState = this.nodes.getForCompute( computeNode );
4646

4747
// programmable stage
4848

49-
let stageCompute = this.programs.compute.get( nodeBuilder.computeShader );
49+
let stageCompute = this.programs.compute.get( nodeBuilderState.computeShader );
5050

5151
if ( stageCompute === undefined ) {
5252

5353
if ( previousPipeline && previousPipeline.computeProgram.usedTimes === 0 ) this._releaseProgram( previousPipeline.computeProgram );
5454

55-
stageCompute = new ProgrammableStage( nodeBuilder.computeShader, 'compute' );
56-
this.programs.compute.set( nodeBuilder.computeShader, stageCompute );
55+
stageCompute = new ProgrammableStage( nodeBuilderState.computeShader, 'compute', nodeBuilderState.transforms, nodeBuilderState.nodeAttributes );
56+
this.programs.compute.set( nodeBuilderState.computeShader, stageCompute );
5757

5858
backend.createProgram( stageCompute );
5959

examples/jsm/renderers/common/ProgrammableStage.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ let _id = 0;
22

33
class ProgrammableStage {
44

5-
constructor( code, type ) {
5+
constructor( code, type, transforms = null, attributes = null ) {
66

77
this.id = _id ++;
88

99
this.code = code;
1010
this.stage = type;
11+
this.transforms = transforms;
12+
this.attributes = attributes;
1113

1214
this.usedTimes = 0;
1315

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { InstancedBufferAttribute } from 'three';
2+
3+
class StorageBufferAttribute extends InstancedBufferAttribute {
4+
5+
constructor( array, itemSize ) {
6+
7+
super( array, itemSize );
8+
9+
this.isStorageBufferAttribute = true;
10+
11+
}
12+
13+
static create( count, itemSize, typeClass = Float32Array ) {
14+
15+
return new StorageBufferAttribute( new typeClass( count * itemSize ), itemSize );
16+
17+
}
18+
19+
}
20+
21+
export default StorageBufferAttribute;

examples/jsm/renderers/common/nodes/NodeBuilderState.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
class NodeBuilderState {
22

3-
constructor( vertexShader, fragmentShader, computeShader, nodeAttributes, bindings, updateNodes, updateBeforeNodes ) {
3+
constructor( vertexShader, fragmentShader, computeShader, nodeAttributes, bindings, updateNodes, updateBeforeNodes, transforms = [] ) {
44

55
this.vertexShader = vertexShader;
66
this.fragmentShader = fragmentShader;
77
this.computeShader = computeShader;
8+
this.transforms = transforms;
89

910
this.nodeAttributes = nodeAttributes;
1011
this.bindings = bindings;

examples/jsm/renderers/common/nodes/Nodes.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ class Nodes extends DataMap {
164164

165165
nodeBuilderState = this._createNodeBuilderState( nodeBuilder );
166166

167-
computeData.nodeBuilderState = nodeBuilder;
167+
computeData.nodeBuilderState = nodeBuilderState;
168168

169169
}
170170

@@ -181,7 +181,8 @@ class Nodes extends DataMap {
181181
nodeBuilder.getAttributesArray(),
182182
nodeBuilder.getBindings(),
183183
nodeBuilder.updateNodes,
184-
nodeBuilder.updateBeforeNodes
184+
nodeBuilder.updateBeforeNodes,
185+
nodeBuilder.transforms
185186
);
186187

187188
}

0 commit comments

Comments
 (0)