diff --git a/examples/jsm/inspector/tabs/Timeline.js b/examples/jsm/inspector/tabs/Timeline.js index 9874dc5cdab886..25e20e50dbd451 100644 --- a/examples/jsm/inspector/tabs/Timeline.js +++ b/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; } diff --git a/src/nodes/display/PassNode.js b/src/nodes/display/PassNode.js index a75f1fd4f9f0cb..7fbe603fc60cd5 100644 --- a/src/nodes/display/PassNode.js +++ b/src/nodes/display/PassNode.js @@ -251,14 +251,22 @@ class PassNode extends TempNode { */ this._height = 1; - const depthTexture = new DepthTexture(); - depthTexture.isRenderTargetTexture = true; - //depthTexture.type = FloatType; - depthTexture.name = 'depth'; - const renderTarget = new RenderTarget( this._width * this._pixelRatio, this._height * this._pixelRatio, { type: HalfFloatType, ...options, } ); renderTarget.texture.name = 'output'; - renderTarget.depthTexture = depthTexture; + + let depthTexture = null; + + if ( this.scope === PassNode.DEPTH || options.depthBuffer !== false ) { + + depthTexture = new DepthTexture(); + depthTexture.isRenderTargetTexture = true; + //depthTexture.type = FloatType; + depthTexture.name = 'depth'; + + renderTarget.depthTexture = depthTexture; + + } + /** * The pass's render target. @@ -310,13 +318,18 @@ class PassNode extends TempNode { * A dictionary holding the internal result textures. * * @private - * @type {Object} + * @type {{ output: Texture, depth?: DepthTexture }} */ this._textures = { - output: renderTarget.texture, - depth: depthTexture + output: renderTarget.texture }; + if ( depthTexture !== null ) { + + this._textures.depth = depthTexture; + + } + /** * A dictionary holding the internal texture nodes. * @@ -757,7 +770,7 @@ class PassNode extends TempNode { this.renderTarget.texture.type = renderer.getOutputBufferType(); - if ( renderer.reversedDepthBuffer === true ) { + if ( renderer.reversedDepthBuffer === true && this.renderTarget.depthTexture !== null ) { this.renderTarget.depthTexture.type = FloatType; diff --git a/src/renderers/common/Backend.js b/src/renderers/common/Backend.js index faf3d77a86bfec..c0631941e33b35 100644 --- a/src/renderers/common/Backend.js +++ b/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. * diff --git a/src/renderers/common/Bindings.js b/src/renderers/common/Bindings.js index 3ccc9191836b40..fdce475f38385a 100644 --- a/src/renderers/common/Bindings.js +++ b/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} 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} 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 ); diff --git a/src/renderers/common/Textures.js b/src/renderers/common/Textures.js index 32c4b07b42f53d..51d13d1cf3b0ef 100644 --- a/src/renderers/common/Textures.js +++ b/src/renderers/common/Textures.js @@ -78,24 +78,30 @@ class Textures extends DataMap { const mipWidth = size.width >> activeMipmapLevel; const mipHeight = size.height >> activeMipmapLevel; - let depthTexture = renderTarget.depthTexture || depthTextureMips[ activeMipmapLevel ]; const useDepthTexture = renderTarget.depthBuffer === true || renderTarget.stencilBuffer === true; + let depthTexture = null; let textureNeedsUpdate = false; - if ( depthTexture === undefined && useDepthTexture ) { + if ( useDepthTexture ) { - depthTexture = new DepthTexture(); + depthTexture = renderTarget.depthTexture || depthTextureMips[ activeMipmapLevel ]; - depthTexture.format = renderTarget.stencilBuffer ? DepthStencilFormat : DepthFormat; - depthTexture.type = renderTarget.stencilBuffer ? UnsignedInt248Type : UnsignedIntType; // FloatType - depthTexture.image.width = mipWidth; - depthTexture.image.height = mipHeight; - depthTexture.image.depth = size.depth; - depthTexture.renderTarget = renderTarget; - depthTexture.isArrayTexture = renderTarget.multiview === true && size.depth > 1; + if ( depthTexture === undefined ) { - depthTextureMips[ activeMipmapLevel ] = depthTexture; + depthTexture = new DepthTexture(); + + depthTexture.format = renderTarget.stencilBuffer ? DepthStencilFormat : DepthFormat; + depthTexture.type = renderTarget.stencilBuffer ? UnsignedInt248Type : UnsignedIntType; // FloatType + depthTexture.image.width = mipWidth; + depthTexture.image.height = mipHeight; + depthTexture.image.depth = size.depth; + depthTexture.renderTarget = renderTarget; + depthTexture.isArrayTexture = renderTarget.multiview === true && size.depth > 1; + + depthTextureMips[ activeMipmapLevel ] = depthTexture; + + } } diff --git a/src/renderers/webgl-fallback/WebGLBackend.js b/src/renderers/webgl-fallback/WebGLBackend.js index dc73ec3de0501a..f63ee32669d2f0 100644 --- a/src/renderers/webgl-fallback/WebGLBackend.js +++ b/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. * diff --git a/src/renderers/webgpu/WebGPUBackend.js b/src/renderers/webgpu/WebGPUBackend.js index 0320d99d03572c..6d9bdfa2e1a5bb 100644 --- a/src/renderers/webgpu/WebGPUBackend.js +++ b/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. * diff --git a/src/renderers/webgpu/utils/WebGPUBindingUtils.js b/src/renderers/webgpu/utils/WebGPUBindingUtils.js index 2f9488d22deacc..7871c35c99ad18 100644 --- a/src/renderers/webgpu/utils/WebGPUBindingUtils.js +++ b/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 ) {