Skip to content

Commit 1bc9388

Browse files
author
aardgoose
committed
prototye big buffer
refactored and remove global state
1 parent 66aa8ff commit 1bc9388

File tree

7 files changed

+213
-19
lines changed

7 files changed

+213
-19
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
2+
class CommonUniformBuffer {
3+
4+
constructor( bufferSize = 0, alignment = 0 ) {
5+
6+
let buffer = null;
7+
8+
if ( bufferSize > 0 ) {
9+
10+
buffer = new Float32Array( bufferSize );
11+
12+
}
13+
14+
// offset in bytes to first free buffer entry
15+
16+
this.startFree = 0;
17+
this.buffer = buffer;
18+
this.aligment = alignment;
19+
20+
}
21+
22+
allocate( byteLength ) {
23+
24+
if ( this.startFree + length > this.byteLength ) return false;
25+
26+
// uniformGroups within buffer must be aligned correctly per WebGPU spec.
27+
const paddedByteLength = Math.ceil( byteLength / this.aligment ) * this.aligment;
28+
29+
const bpe = this.buffer.BYTES_PER_ELEMENT;
30+
31+
const buffer = this.buffer.subarray( this.startFree / bpe , ( this.startFree + byteLength ) / bpe );
32+
33+
this.startFree += paddedByteLength;
34+
35+
return buffer;
36+
37+
}
38+
39+
get byteLength() {
40+
41+
return this.buffer === null ? 0 : this.buffer.byteLength;
42+
43+
}
44+
45+
get arrayBuffer() {
46+
47+
return this.buffer.buffer;
48+
49+
}
50+
51+
}
52+
53+
export default CommonUniformBuffer;

examples/jsm/renderers/common/Renderer.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ class Renderer {
6060

6161
this.info = new Info();
6262

63+
this.commonBufferSize = 0;
64+
6365
// internals
6466

6567
this._pixelRatio = 1;

examples/jsm/renderers/common/UniformsGroup.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ class UniformsGroup extends UniformBuffer {
1313

1414
this.uniforms = [];
1515

16+
this._buffer = null;
17+
this._byteLength = null;
18+
1619
}
1720

1821
addUniform( uniform ) {
@@ -57,6 +60,8 @@ class UniformsGroup extends UniformBuffer {
5760

5861
get byteLength() {
5962

63+
if ( this._byteLength !== null ) return this._byteLength;
64+
6065
let offset = 0; // global buffer offset in bytes
6166

6267
for ( let i = 0, l = this.uniforms.length; i < l; i ++ ) {
@@ -85,12 +90,13 @@ class UniformsGroup extends UniformBuffer {
8590
}
8691

8792
uniform.offset = ( offset / this.bytesPerElement );
88-
8993
offset += ( uniform.itemSize * this.bytesPerElement );
9094

9195
}
9296

93-
return Math.ceil( offset / GPU_CHUNK_BYTES ) * GPU_CHUNK_BYTES;
97+
this._byteLength = Math.ceil( offset / GPU_CHUNK_BYTES ) * GPU_CHUNK_BYTES;
98+
99+
return this._byteLength;
94100

95101
}
96102

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

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@ let id = 0;
44

55
class NodeUniformsGroup extends UniformsGroup {
66

7-
constructor( name, groupNode ) {
7+
constructor( name, groupNode, commonUniformBuffer = null ) {
88

99
super( name );
1010

1111
this.id = id ++;
1212
this.groupNode = groupNode;
1313

1414
this.isNodeUniformsGroup = true;
15+
this.commonUniformBuffer = commonUniformBuffer;
16+
this._isCommon = null;
1517

1618
}
1719

@@ -21,6 +23,47 @@ class NodeUniformsGroup extends UniformsGroup {
2123

2224
}
2325

26+
allocateCommon() {
27+
28+
if ( this._isCommon === null ) {
29+
30+
this._isCommon = false;
31+
32+
if ( this.commonUniformBuffer !== null ) {
33+
34+
const buffer = this.commonUniformBuffer.allocate( this.byteLength );
35+
36+
if ( buffer ) {
37+
38+
this._buffer = buffer;
39+
this._isCommon = true;
40+
41+
}
42+
43+
}
44+
45+
}
46+
47+
return this._isCommon;
48+
49+
}
50+
51+
get buffer() {
52+
53+
if ( this._buffer === null ) {
54+
55+
if ( ! this.allocateCommon() ) {
56+
57+
return super.buffer;
58+
59+
}
60+
61+
}
62+
63+
return this._buffer;
64+
65+
}
66+
2467
getNodes() {
2568

2669
const nodes = [];

examples/jsm/renderers/webgpu/WebGPUBackend.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { GPUFeatureName, GPUTextureFormat, GPULoadOp, GPUStoreOp, GPUIndexFormat
66

77
import WGSLNodeBuilder from './nodes/WGSLNodeBuilder.js';
88
import Backend from '../common/Backend.js';
9+
import CommonUniformBuffer from '../common/CommonUniformBuffer.js';
910

1011
import { DepthFormat, WebGPUCoordinateSystem } from 'three';
1112

@@ -55,6 +56,7 @@ class WebGPUBackend extends Backend {
5556
this.pipelineUtils = new WebGPUPipelineUtils( this );
5657
this.textureUtils = new WebGPUTextureUtils( this );
5758
this.occludedResolveCache = new Map();
59+
this.commonUniformBuffer = null;
5860

5961
}
6062

@@ -494,8 +496,12 @@ class WebGPUBackend extends Backend {
494496

495497
}
496498

499+
this.bindingUtils.endPass();
500+
497501
this.device.queue.submit( [ renderContextData.encoder.finish() ] );
498502

503+
//this.device.queue.onSubmittedWorkDone().then( () => { performance.mark( 'render-end' ); } );
504+
499505
//
500506

501507
if ( renderContext.textures !== null ) {
@@ -770,6 +776,9 @@ class WebGPUBackend extends Backend {
770776
const groupData = this.get( computeGroup );
771777

772778
groupData.passEncoderGPU.end();
779+
780+
this.bindingUtils.endPass();
781+
773782
this.device.queue.submit( [ groupData.cmdEncoderGPU.finish() ] );
774783

775784
}
@@ -1035,7 +1044,20 @@ class WebGPUBackend extends Backend {
10351044

10361045
createNodeBuilder( object, renderer, scene = null ) {
10371046

1038-
return new WGSLNodeBuilder( object, renderer, scene );
1047+
if ( this.commonUniformBuffer === null ) {
1048+
1049+
const alignment = this.device.limits.minUniformBufferOffsetAlignment;
1050+
const size = this.renderer.commonBufferSize;
1051+
1052+
if ( size > 0 ) {
1053+
1054+
this.commonUniformBuffer = new CommonUniformBuffer( 256 * size, alignment );
1055+
1056+
}
1057+
1058+
}
1059+
1060+
return new WGSLNodeBuilder( object, renderer, scene, this.commonUniformBuffer );
10391061

10401062
}
10411063

examples/jsm/renderers/webgpu/nodes/WGSLNodeBuilder.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,14 +118,16 @@ fn threejs_repeatWrapping( uv : vec2<f32>, dimension : vec2<u32> ) -> vec2<u32>
118118

119119
class WGSLNodeBuilder extends NodeBuilder {
120120

121-
constructor( object, renderer, scene = null ) {
121+
constructor( object, renderer, scene = null, commonUniformBuffer = null ) {
122122

123123
super( object, renderer, new WGSLNodeParser(), scene );
124124

125125
this.uniformGroups = {};
126126

127127
this.builtins = {};
128128

129+
this.commonUniformBuffer = commonUniformBuffer;
130+
129131
}
130132

131133
needsColorSpaceToLinear( texture ) {
@@ -391,7 +393,7 @@ class WGSLNodeBuilder extends NodeBuilder {
391393

392394
if ( uniformsGroup === undefined ) {
393395

394-
uniformsGroup = new NodeUniformsGroup( groupName, group );
396+
uniformsGroup = new NodeUniformsGroup( groupName, group, this.commonUniformBuffer );
395397
uniformsGroup.setVisibility( gpuShaderStageLib[ shaderStage ] );
396398

397399
uniformsStage[ groupName ] = uniformsGroup;

examples/jsm/renderers/webgpu/utils/WebGPUBindingUtils.js

Lines changed: 79 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,32 @@ class WebGPUBindingUtils {
99

1010
this.backend = backend;
1111

12+
this.lowwaterMark = Infinity;
13+
this.highwaterMark = 0;
14+
15+
this.commonBufferGPU = null;
16+
17+
}
18+
19+
getCommonBuffer( commonUniformBuffer ) {
20+
21+
let bufferGPU = this.commonBufferGPU;
22+
23+
if ( bufferGPU === null ) {
24+
25+
bufferGPU = this.backend.device.createBuffer( {
26+
label: 'bindingBuffer_common',
27+
size: commonUniformBuffer.byteLength,
28+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
29+
} );
30+
31+
this.commonBufferGPU = bufferGPU;
32+
this.commonUniformBuffer = commonUniformBuffer;
33+
34+
}
35+
36+
return bufferGPU
37+
1238
}
1339

1440
createBindingsLayout( bindings ) {
@@ -128,10 +154,18 @@ class WebGPUBindingUtils {
128154
const backend = this.backend;
129155
const device = backend.device;
130156

131-
const buffer = binding.buffer;
132-
const bufferGPU = backend.get( binding ).buffer;
157+
if ( binding.isNodeUniformsGroup && binding.allocateCommon() ) {
158+
159+
const buffer = binding.buffer;
133160

134-
device.queue.writeBuffer( bufferGPU, 0, buffer, 0 );
161+
this.lowwaterMark = Math.min( this.lowwaterMark, buffer.byteOffset );
162+
this.highwaterMark = Math.max( this.highwaterMark, buffer.byteOffset + buffer.byteLength );
163+
164+
} else {
165+
166+
const bufferGPU = backend.get( binding ).buffer;
167+
device.queue.writeBuffer( bufferGPU, 0, binding.buffer, 0 );
168+
}
135169

136170
}
137171

@@ -149,23 +183,42 @@ class WebGPUBindingUtils {
149183

150184
const bindingData = backend.get( binding );
151185

152-
if ( bindingData.buffer === undefined ) {
186+
let resource;
153187

154-
const byteLength = binding.byteLength;
188+
if ( binding.isNodeUniformsGroup && binding.allocateCommon() ) {
155189

156-
const usage = GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST;
190+
const buffer = binding.buffer;
157191

158-
const bufferGPU = device.createBuffer( {
159-
label: 'bindingBuffer_' + binding.name,
160-
size: byteLength,
161-
usage: usage
162-
} );
192+
resource = {
193+
label: 'bindingBufferCommon_' + binding.name,
194+
buffer: this.getCommonBuffer( binding.commonUniformBuffer ),
195+
offset: buffer.byteOffset,
196+
size: buffer.byteLength
197+
};
163198

164-
bindingData.buffer = bufferGPU;
199+
} else {
200+
201+
if ( bindingData.buffer === undefined ) {
202+
203+
const byteLength = binding.byteLength;
204+
205+
const usage = GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST;
206+
207+
const bufferGPU = device.createBuffer( {
208+
label: 'bindingBuffer_' + binding.name,
209+
size: byteLength,
210+
usage: usage
211+
} );
212+
213+
bindingData.buffer = bufferGPU;
214+
215+
}
216+
217+
resource = { buffer: bindingData.buffer };
165218

166219
}
167220

168-
entriesGPU.push( { binding: bindingPoint, resource: { buffer: bindingData.buffer } } );
221+
entriesGPU.push( { binding: bindingPoint, resource } );
169222

170223
} else if ( binding.isStorageBuffer ) {
171224

@@ -239,6 +292,19 @@ class WebGPUBindingUtils {
239292

240293
}
241294

295+
endPass() {
296+
297+
const device = this.backend.device;
298+
299+
if ( this.commonBufferGPU === null || this.lowwaterMark === Infinity ) return;
300+
301+
device.queue.writeBuffer( this.commonBufferGPU, this.lowwaterMark, this.commonUniformBuffer.arrayBuffer, this.lowwaterMark );
302+
303+
this.lowwaterMark = Infinity;
304+
this.highwaterMark = 0;
305+
306+
}
307+
242308
}
243309

244310
export default WebGPUBindingUtils;

0 commit comments

Comments
 (0)