Browse Source

Backend: Introduce `createUniformBuffer()` (#33373)

sunag 3 months ago
parent
commit
deffab61b9

+ 21 - 3
examples/jsm/inspector/tabs/Timeline.js

@@ -1044,11 +1044,29 @@ class Timeline extends Tab {
 			case 'updateBindings': {
 
 				const bindGroup = args[ 0 ];
-				const details = { group: bindGroup.name || 'unknown' };
 
-				if ( bindGroup.bindings ) {
+				const details = {
+					group: bindGroup.name || 'unknown',
+					count: bindGroup.bindings.length
+				};
+
+				return details;
+
+			}
+
+			case 'createUniformBuffer':
+			case 'destroyUniformBuffer': {
+
+				const binding = args[ 0 ];
+
+				const details = {
+					group: binding.groupNode.name || 'unknown',
+					size: binding.byteLength + ' bytes'
+				};
+
+				if ( binding.name !== details.group ) {
 
-					details.count = bindGroup.bindings.length;
+					details.name = binding.name;
 
 				}
 

+ 16 - 0
src/renderers/common/Backend.js

@@ -389,6 +389,22 @@ class Backend {
 	 */
 	createStorageAttribute( /*attribute*/ ) { }
 
+	/**
+	 * Creates a uniform buffer.
+	 *
+	 * @abstract
+	 * @param {Buffer} uniformBuffer - The uniform buffer.
+	 */
+	createUniformBuffer( /*uniformBuffer*/ ) { }
+
+	/**
+	 * Destroys a uniform buffer.
+	 *
+	 * @abstract
+	 * @param {Buffer} uniformBuffer - The uniform buffer.
+	 */
+	destroyUniformBuffer( /*uniformBuffer*/ ) { }
+
 	/**
 	 * Updates the GPU buffer of a shader attribute.
 	 *

+ 74 - 32
src/renderers/common/Bindings.js

@@ -77,39 +77,39 @@ class Bindings extends DataMap {
 	 */
 	getForRender( renderObject ) {
 
-		const bindings = renderObject.getBindings();
+		return this._getBindings( renderObject, renderObject.getBindings() );
 
-		for ( const bindGroup of bindings ) {
+	}
 
-			const groupData = this.get( bindGroup );
+	/**
+	 * Returns the bind groups for the given compute node.
+	 *
+	 * @param {Node} computeNode - The compute node.
+	 * @return {Array<BindGroup>} The bind groups.
+	 */
+	getForCompute( computeNode ) {
 
-			if ( groupData.bindGroup === undefined ) {
+		return this._getBindings( computeNode, this.nodes.getForCompute( computeNode ).bindings );
 
-				// each object defines an array of bindings (ubos, textures, samplers etc.)
+	}
 
-				this._init( bindGroup );
+	_getBindings( object, bindings ) {
 
-				this.backend.createBindings( bindGroup, bindings, 0 );
+		const data = this.get( object );
 
-				groupData.bindGroup = bindGroup;
+		if ( data.bindings !== bindings ) {
 
-			}
+			if ( data.bindings !== undefined ) {
 
-		}
+				this._updateBindingsUsage( data.bindings, - 1 );
 
-		return bindings;
+			}
 
-	}
+			this._updateBindingsUsage( bindings, 1 );
 
-	/**
-	 * Returns the bind groups for the given compute node.
-	 *
-	 * @param {Node} computeNode - The compute node.
-	 * @return {Array<BindGroup>} The bind groups.
-	 */
-	getForCompute( computeNode ) {
+			data.bindings = bindings;
 
-		const bindings = this.nodes.getForCompute( computeNode ).bindings;
+		}
 
 		for ( const bindGroup of bindings ) {
 
@@ -160,14 +160,7 @@ class Bindings extends DataMap {
 	 */
 	deleteForCompute( computeNode ) {
 
-		const bindings = this.nodes.getForCompute( computeNode ).bindings;
-
-		for ( const bindGroup of bindings ) {
-
-			this.backend.deleteBindGroupData( bindGroup );
-			this.delete( bindGroup );
-
-		}
+		this._deleteBindings( computeNode );
 
 	}
 
@@ -178,12 +171,57 @@ class Bindings extends DataMap {
 	 */
 	deleteForRender( renderObject ) {
 
-		const bindings = renderObject.getBindings();
+		this._deleteBindings( renderObject );
+
+	}
+
+	_deleteBindings( object ) {
+
+		const data = this.get( object );
+
+		if ( data.bindings !== undefined ) {
+
+			this._updateBindingsUsage( data.bindings, - 1 );
+
+			data.bindings = undefined;
+
+		}
+
+	}
+
+	_updateBindingsUsage( bindings, delta ) {
 
 		for ( const bindGroup of bindings ) {
 
-			this.backend.deleteBindGroupData( bindGroup );
-			this.delete( bindGroup );
+			const groupData = this.get( bindGroup );
+
+			groupData.usedTimes = ( groupData.usedTimes || 0 ) + delta;
+
+			for ( const binding of bindGroup.bindings ) {
+
+				if ( binding.isUniformBuffer ) {
+
+					const bindingData = this.get( binding );
+
+					bindingData.usedTimes = ( bindingData.usedTimes || 0 ) + delta;
+
+					if ( bindingData.usedTimes === 0 ) {
+
+						this.backend.destroyUniformBuffer( binding );
+						this.delete( binding );
+
+					}
+
+				}
+
+			}
+
+			if ( groupData.usedTimes === 0 ) {
+
+				this.backend.deleteBindGroupData( bindGroup );
+				this.delete( bindGroup );
+
+			}
 
 		}
 
@@ -213,7 +251,11 @@ class Bindings extends DataMap {
 
 		for ( const binding of bindGroup.bindings ) {
 
-			if ( binding.isSampledTexture ) {
+			if ( binding.isUniformBuffer ) {
+
+				this.backend.createUniformBuffer( binding );
+
+			} else if ( binding.isSampledTexture ) {
 
 				this.textures.updateTexture( binding.texture );
 

+ 40 - 19
src/renderers/webgl-fallback/WebGLBackend.js

@@ -1834,24 +1834,9 @@ class WebGLBackend extends Backend {
 			if ( binding.isUniformsGroup || binding.isUniformBuffer ) {
 
 				const array = binding.buffer;
-				let { bufferGPU } = this.get( array );
+				const bufferGPU = map.bufferGPU;
 
-				if ( bufferGPU === undefined ) {
-
-					// create
-
-					bufferGPU = gl.createBuffer();
-
-					gl.bindBuffer( gl.UNIFORM_BUFFER, bufferGPU );
-					gl.bufferData( gl.UNIFORM_BUFFER, array.byteLength, gl.DYNAMIC_DRAW );
-
-					this.set( array, { bufferGPU } );
-
-				} else {
-
-					gl.bindBuffer( gl.UNIFORM_BUFFER, bufferGPU );
-
-				}
+				gl.bindBuffer( gl.UNIFORM_BUFFER, bufferGPU );
 
 				// update
 
@@ -1883,8 +1868,6 @@ class WebGLBackend extends Backend {
 
 				}
 
-				map.bufferGPU = bufferGPU;
-
 				this.set( binding, map );
 
 			} else if ( binding.isSampledTexture ) {
@@ -1951,6 +1934,44 @@ class WebGLBackend extends Backend {
 
 	// attributes
 
+	/**
+	 * Creates a uniform buffer.
+	 *
+	 * @param {Buffer} uniformBuffer - The uniform buffer.
+	 */
+	createUniformBuffer( uniformBuffer ) {
+
+		const uniformBufferData = this.get( uniformBuffer );
+
+		if ( uniformBufferData.bufferGPU === undefined ) {
+
+			const gl = this.gl;
+			const array = uniformBuffer.buffer;
+
+			uniformBufferData.bufferGPU = gl.createBuffer();
+
+			gl.bindBuffer( gl.UNIFORM_BUFFER, uniformBufferData.bufferGPU );
+			gl.bufferData( gl.UNIFORM_BUFFER, array.byteLength, gl.DYNAMIC_DRAW );
+
+		}
+
+	}
+
+	/**
+	 * Destroys the GPU data for the given uniform buffer.
+	 *
+	 * @param {Buffer} uniformBuffer - The uniform buffer.
+	 */
+	destroyUniformBuffer( uniformBuffer ) {
+
+		const uniformBufferData = this.get( uniformBuffer );
+
+		this.gl.deleteBuffer( uniformBufferData.bufferGPU );
+
+		this.delete( uniformBuffer );
+
+	}
+
 	/**
 	 * Creates the GPU buffer of an indexed shader attribute.
 	 *

+ 65 - 1
src/renderers/webgpu/WebGPUBackend.js

@@ -2,7 +2,7 @@
 import 'https://greggman.github.io/webgpu-avoid-redundant-state-setting/webgpu-check-redundant-state-setting.js';
 //*/
 
-import { GPUFeatureName, GPULoadOp, GPUStoreOp, GPUIndexFormat, GPUTextureViewDimension, GPUFeatureMap } from './utils/WebGPUConstants.js';
+import { GPUFeatureName, GPULoadOp, GPUStoreOp, GPUIndexFormat, GPUTextureViewDimension, GPUFeatureMap, GPUShaderStage } from './utils/WebGPUConstants.js';
 
 import WGSLNodeBuilder from './nodes/WGSLNodeBuilder.js';
 import Backend from '../common/Backend.js';
@@ -2178,6 +2178,70 @@ class WebGPUBackend extends Backend {
 
 	// bindings
 
+	/**
+	 * Creates a uniform buffer.
+	 *
+	 * @param {Buffer} uniformBuffer - The uniform buffer.
+	 */
+	createUniformBuffer( uniformBuffer ) {
+
+		const uniformBufferData = this.get( uniformBuffer );
+
+		if ( uniformBufferData.buffer === undefined ) {
+
+			const byteLength = uniformBuffer.byteLength;
+
+			const usage = GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST;
+
+			const visibilities = [];
+
+			if ( uniformBuffer.visibility & GPUShaderStage.VERTEX ) {
+
+				visibilities.push( 'vertex' );
+
+			}
+
+			if ( uniformBuffer.visibility & GPUShaderStage.FRAGMENT ) {
+
+				visibilities.push( 'fragment' );
+
+			}
+
+			if ( uniformBuffer.visibility & GPUShaderStage.COMPUTE ) {
+
+				visibilities.push( 'compute' );
+
+			}
+
+			const bufferVisibility = `(${visibilities.join( ',' )})`;
+
+			const bufferGPU = this.device.createBuffer( {
+				label: `bindingBuffer${uniformBuffer.id}_${uniformBuffer.name}_${bufferVisibility}`,
+				size: byteLength,
+				usage: usage
+			} );
+
+			uniformBufferData.buffer = bufferGPU;
+
+		}
+
+	}
+
+	/**
+	 * Destroys the GPU data for the given uniform buffer.
+	 *
+	 * @param {Buffer} uniformBuffer - The uniform buffer.
+	 */
+	destroyUniformBuffer( uniformBuffer ) {
+
+		const uniformBufferData = this.get( uniformBuffer );
+
+		uniformBufferData.buffer.destroy();
+
+		this.delete( uniformBuffer );
+
+	}
+
 	/**
 	 * Creates bindings from the given bind group definition.
 	 *

+ 0 - 37
src/renderers/webgpu/utils/WebGPUBindingUtils.js

@@ -283,43 +283,6 @@ class WebGPUBindingUtils {
 
 				const bindingData = backend.get( binding );
 
-				if ( bindingData.buffer === undefined ) {
-
-					const byteLength = binding.byteLength;
-
-					const usage = GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST;
-
-					const visibilities = [];
-					if ( binding.visibility & GPUShaderStage.VERTEX ) {
-
-						visibilities.push( 'vertex' );
-
-					}
-
-					if ( binding.visibility & GPUShaderStage.FRAGMENT ) {
-
-						visibilities.push( 'fragment' );
-
-					}
-
-					if ( binding.visibility & GPUShaderStage.COMPUTE ) {
-
-						visibilities.push( 'compute' );
-
-					}
-
-					const bufferVisibility = `(${visibilities.join( ',' )})`;
-
-					const bufferGPU = device.createBuffer( {
-						label: `bindingBuffer${binding.id}_${binding.name}_${bufferVisibility}`,
-						size: byteLength,
-						usage: usage
-					} );
-
-					bindingData.buffer = bufferGPU;
-
-				}
-
 				entriesGPU.push( { binding: bindingPoint, resource: { buffer: bindingData.buffer } } );
 
 			} else if ( binding.isStorageBuffer ) {

粤ICP备19079148号