From e4c4a5106e259facafead80019c83e18113fdc32 Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Thu, 2 Jan 2025 11:20:48 +0100 Subject: [PATCH] WebGPURenderer: Reduce memory churn when using chain maps. --- src/renderers/common/Lighting.js | 12 +++++++----- src/renderers/common/RenderBundles.js | 12 +++++++++--- src/renderers/common/RenderContexts.js | 17 ++++++++++------- src/renderers/common/RenderLists.js | 12 +++++++++--- src/renderers/common/RenderObjects.js | 16 +++++++++------- src/renderers/common/nodes/Nodes.js | 20 ++++++++++++++------ 6 files changed, 58 insertions(+), 31 deletions(-) diff --git a/src/renderers/common/Lighting.js b/src/renderers/common/Lighting.js index a92f22aad1f01e..8b48bf6cd24c96 100644 --- a/src/renderers/common/Lighting.js +++ b/src/renderers/common/Lighting.js @@ -2,6 +2,7 @@ import { LightsNode } from '../../nodes/Nodes.js'; import ChainMap from './ChainMap.js'; const _defaultLights = /*@__PURE__*/ new LightsNode(); +const _chainKeys = []; /** * This renderer module manages the lights nodes which are unique @@ -49,19 +50,20 @@ class Lighting extends ChainMap { if ( scene.isQuadMesh ) return _defaultLights; - // tiled lighting + _chainKeys[ 0 ] = scene; + _chainKeys[ 1 ] = camera; - const keys = [ scene, camera ]; - - let node = this.get( keys ); + let node = this.get( _chainKeys ); if ( node === undefined ) { node = this.createNode(); - this.set( keys, node ); + this.set( _chainKeys, node ); } + _chainKeys.length = 0; + return node; } diff --git a/src/renderers/common/RenderBundles.js b/src/renderers/common/RenderBundles.js index a53a7250de2913..25f90a7261b4ab 100644 --- a/src/renderers/common/RenderBundles.js +++ b/src/renderers/common/RenderBundles.js @@ -1,6 +1,8 @@ import ChainMap from './ChainMap.js'; import RenderBundle from './RenderBundle.js'; +const _chainKeys = []; + /** * This renderer module manages render bundles. * @@ -32,17 +34,21 @@ class RenderBundles { get( bundleGroup, camera ) { const bundles = this.bundles; - const keys = [ bundleGroup, camera ]; - let bundle = bundles.get( keys ); + _chainKeys[ 0 ] = bundleGroup; + _chainKeys[ 1 ] = camera; + + let bundle = bundles.get( _chainKeys ); if ( bundle === undefined ) { bundle = new RenderBundle( bundleGroup, camera ); - bundles.set( keys, bundle ); + bundles.set( _chainKeys, bundle ); } + _chainKeys.length = 0; + return bundle; } diff --git a/src/renderers/common/RenderContexts.js b/src/renderers/common/RenderContexts.js index 83fb5216c320e0..32c36c059b6ef5 100644 --- a/src/renderers/common/RenderContexts.js +++ b/src/renderers/common/RenderContexts.js @@ -1,6 +1,8 @@ import ChainMap from './ChainMap.js'; import RenderContext from './RenderContext.js'; +const _chainKeys = []; + /** * This module manages the render contexts of the renderer. * @@ -33,13 +35,12 @@ class RenderContexts { */ get( scene = null, camera = null, renderTarget = null ) { - const chainKey = []; - if ( scene !== null ) chainKey.push( scene ); - if ( camera !== null ) chainKey.push( camera ); + if ( scene !== null ) _chainKeys.push( scene ); + if ( camera !== null ) _chainKeys.push( camera ); - if ( chainKey.length === 0 ) { + if ( _chainKeys.length === 0 ) { - chainKey.push( { id: 'default' } ); + _chainKeys.push( { id: 'default' } ); } @@ -61,16 +62,18 @@ class RenderContexts { const chainMap = this.getChainMap( attachmentState ); - let renderState = chainMap.get( chainKey ); + let renderState = chainMap.get( _chainKeys ); if ( renderState === undefined ) { renderState = new RenderContext(); - chainMap.set( chainKey, renderState ); + chainMap.set( _chainKeys, renderState ); } + _chainKeys.length = 0; + if ( renderTarget !== null ) renderState.sampleCount = renderTarget.samples === 0 ? 1 : renderTarget.samples; return renderState; diff --git a/src/renderers/common/RenderLists.js b/src/renderers/common/RenderLists.js index 57a334418c04df..1818d25e0156a6 100644 --- a/src/renderers/common/RenderLists.js +++ b/src/renderers/common/RenderLists.js @@ -1,6 +1,8 @@ import ChainMap from './ChainMap.js'; import RenderList from './RenderList.js'; +const _chainKeys = []; + /** * This renderer module manages the render lists which are unique * per scene and camera combination. @@ -42,17 +44,21 @@ class RenderLists { get( scene, camera ) { const lists = this.lists; - const keys = [ scene, camera ]; - let list = lists.get( keys ); + _chainKeys[ 0 ] = scene; + _chainKeys[ 1 ] = camera; + + let list = lists.get( _chainKeys ); if ( list === undefined ) { list = new RenderList( this.lighting, scene, camera ); - lists.set( keys, list ); + lists.set( _chainKeys, list ); } + _chainKeys.length = 0; + return list; } diff --git a/src/renderers/common/RenderObjects.js b/src/renderers/common/RenderObjects.js index 2379883a91a57a..b9ffe747681f2a 100644 --- a/src/renderers/common/RenderObjects.js +++ b/src/renderers/common/RenderObjects.js @@ -1,7 +1,7 @@ import ChainMap from './ChainMap.js'; import RenderObject from './RenderObject.js'; -const _chainArray = []; +const _chainKeys = []; /** * This module manages the render objects of the renderer. @@ -92,18 +92,18 @@ class RenderObjects { const chainMap = this.getChainMap( passId ); // reuse chainArray - _chainArray[ 0 ] = object; - _chainArray[ 1 ] = material; - _chainArray[ 2 ] = renderContext; - _chainArray[ 3 ] = lightsNode; + _chainKeys[ 0 ] = object; + _chainKeys[ 1 ] = material; + _chainKeys[ 2 ] = renderContext; + _chainKeys[ 3 ] = lightsNode; - let renderObject = chainMap.get( _chainArray ); + let renderObject = chainMap.get( _chainKeys ); if ( renderObject === undefined ) { renderObject = this.createRenderObject( this.nodes, this.geometries, this.renderer, object, material, scene, camera, lightsNode, renderContext, clippingContext, passId ); - chainMap.set( _chainArray, renderObject ); + chainMap.set( _chainKeys, renderObject ); } else { @@ -133,6 +133,8 @@ class RenderObjects { } + _chainKeys.length = 0; + return renderObject; } diff --git a/src/renderers/common/nodes/Nodes.js b/src/renderers/common/nodes/Nodes.js index 16a1163bd047cc..07a74bd4b99d06 100644 --- a/src/renderers/common/nodes/Nodes.js +++ b/src/renderers/common/nodes/Nodes.js @@ -9,6 +9,7 @@ import { CubeUVReflectionMapping, EquirectangularReflectionMapping, Equirectangu import { hashArray } from '../../../nodes/core/NodeUtils.js'; const _outputNodeMap = new WeakMap(); +const _chainKeys = []; /** * This renderer module manages node-related objects and is the @@ -136,10 +137,13 @@ class Nodes extends DataMap { // other groups are updated just when groupNode.needsUpdate is true - const groupChain = [ groupNode, nodeUniformsGroup ]; + _chainKeys[ 0 ] = groupNode; + _chainKeys[ 1 ] = nodeUniformsGroup; - let groupData = this.groupsData.get( groupChain ); - if ( groupData === undefined ) this.groupsData.set( groupChain, groupData = {} ); + let groupData = this.groupsData.get( _chainKeys ); + if ( groupData === undefined ) this.groupsData.set( _chainKeys, groupData = {} ); + + _chainKeys.length = 0; if ( groupData.version !== groupNode.version ) { @@ -382,10 +386,12 @@ class Nodes extends DataMap { */ getCacheKey( scene, lightsNode ) { - const chain = [ scene, lightsNode ]; + _chainKeys[ 0 ] = scene; + _chainKeys[ 1 ] = lightsNode; + const callId = this.renderer.info.calls; - let cacheKeyData = this.callHashCache.get( chain ); + let cacheKeyData = this.callHashCache.get( _chainKeys ); if ( cacheKeyData === undefined || cacheKeyData.callId !== callId ) { @@ -405,10 +411,12 @@ class Nodes extends DataMap { cacheKey: hashArray( values ) }; - this.callHashCache.set( chain, cacheKeyData ); + this.callHashCache.set( _chainKeys, cacheKeyData ); } + _chainKeys.length = 0; + return cacheKeyData.cacheKey; }