From 6ec855e8fc904861e54c5d5315182b5bfce4ca4f Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Sat, 25 Jan 2025 10:38:00 +0100 Subject: [PATCH 1/5] WebGPURenderer: Only use HalfFloatType for the framebuffer target if necessary. --- src/renderers/common/Backend.js | 11 +++++++++++ src/renderers/common/Renderer.js | 13 ++++++++++--- src/renderers/webgpu/WebGPUBackend.js | 13 ++++++++++++- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/renderers/common/Backend.js b/src/renderers/common/Backend.js index 028b74463d26eb..b6b9e0dab68f0d 100644 --- a/src/renderers/common/Backend.js +++ b/src/renderers/common/Backend.js @@ -588,6 +588,17 @@ class Backend { } + /** + * Returns `true` if the backend requires a framebuffer target with type `HalfFloat`. + * + * @return {Boolean} Whether the backend requires a framebuffer target with type `HalfFloat` or not. + */ + needsHalfFloatFrameBufferTarget() { + + return false; + + } + /** * Sets a dictionary for the given object into the * internal data structure. diff --git a/src/renderers/common/Renderer.js b/src/renderers/common/Renderer.js index 6463696ff0c625..6190f6131fcfb9 100644 --- a/src/renderers/common/Renderer.js +++ b/src/renderers/common/Renderer.js @@ -26,7 +26,7 @@ import { Matrix4 } from '../../math/Matrix4.js'; import { Vector2 } from '../../math/Vector2.js'; import { Vector4 } from '../../math/Vector4.js'; import { RenderTarget } from '../../core/RenderTarget.js'; -import { DoubleSide, BackSide, FrontSide, SRGBColorSpace, NoToneMapping, LinearFilter, LinearSRGBColorSpace, HalfFloatType, RGBAFormat, PCFShadowMap } from '../../constants.js'; +import { DoubleSide, BackSide, FrontSide, SRGBColorSpace, NoToneMapping, LinearFilter, LinearSRGBColorSpace, HalfFloatType, RGBAFormat, PCFShadowMap, UnsignedByteType } from '../../constants.js'; /** @module Renderer **/ @@ -1121,14 +1121,21 @@ class Renderer { const { width, height } = this.getDrawingBufferSize( _drawingBufferSize ); const { depth, stencil } = this; + // to improve performance we only want to use HalfFloatType if necessary + // HalfFloatType is required when a) tone mapping is used or b) the backend specifically requests it + + const type = ( useToneMapping || this.backend.needsHalfFloatFrameBufferTarget() ) ? HalfFloatType : UnsignedByteType; + let frameBufferTarget = this._frameBufferTarget; - if ( frameBufferTarget === null ) { + if ( frameBufferTarget === null || this._frameBufferTarget.texture.type !== type ) { + + if ( frameBufferTarget !== null ) frameBufferTarget.dispose(); frameBufferTarget = new RenderTarget( width, height, { depthBuffer: depth, stencilBuffer: stencil, - type: HalfFloatType, // FloatType + type: type, format: RGBAFormat, colorSpace: LinearSRGBColorSpace, generateMipmaps: false, diff --git a/src/renderers/webgpu/WebGPUBackend.js b/src/renderers/webgpu/WebGPUBackend.js index da44414d90327f..4b961f7c151ca0 100644 --- a/src/renderers/webgpu/WebGPUBackend.js +++ b/src/renderers/webgpu/WebGPUBackend.js @@ -13,7 +13,7 @@ import WebGPUBindingUtils from './utils/WebGPUBindingUtils.js'; import WebGPUPipelineUtils from './utils/WebGPUPipelineUtils.js'; import WebGPUTextureUtils from './utils/WebGPUTextureUtils.js'; -import { WebGPUCoordinateSystem } from '../../constants.js'; +import { HalfFloatType, WebGPUCoordinateSystem } from '../../constants.js'; import WebGPUTimestampQueryPool from './utils/WebGPUTimestampQueryPool.js'; /** @@ -279,6 +279,17 @@ class WebGPUBackend extends Backend { } + /** + * Returns `true` if the backend requires a framebuffer target with type `HalfFloat`. + * + * @return {Boolean} Whether the backend requires a framebuffer target with type `HalfFloat` or not. + */ + needsHalfFloatFrameBufferTarget() { + + return ( this.parameters.outputType === HalfFloatType ); + + } + /** * Returns the default render pass descriptor. * From e11b4695d85f0f09afd13cb16515d94c6706f721 Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Sat, 25 Jan 2025 10:46:40 +0100 Subject: [PATCH 2/5] Examples: Add tone mapping to custom lights demo. --- examples/webgpu_lights_custom.html | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/webgpu_lights_custom.html b/examples/webgpu_lights_custom.html index afbe5b5dfe5fc1..398695edc4e75a 100644 --- a/examples/webgpu_lights_custom.html +++ b/examples/webgpu_lights_custom.html @@ -113,6 +113,7 @@ renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); renderer.setAnimationLoop( animate ); + renderer.toneMapping = THREE.LinearToneMapping; document.body.appendChild( renderer.domElement ); // controls From ce13b860b6811e0bf3fbab1af8f13eb2ef1ebff8 Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Sun, 26 Jan 2025 17:04:11 +0100 Subject: [PATCH 3/5] Renderer: Avoid ping-pong effect with framebuffer targets. --- src/renderers/common/Renderer.js | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/renderers/common/Renderer.js b/src/renderers/common/Renderer.js index 6190f6131fcfb9..9b0befabf913a4 100644 --- a/src/renderers/common/Renderer.js +++ b/src/renderers/common/Renderer.js @@ -445,13 +445,14 @@ class Renderer { this._transparentSort = null; /** - * The framebuffer target. + * A map that holds a framebuffer target for each render + * target type. * * @private - * @type {RenderTarget?} + * @type {Map} * @default null */ - this._frameBufferTarget = null; + this._frameBufferTargetMap = new Map(); const alphaClear = this.alpha === true ? 0 : 1; @@ -1126,11 +1127,9 @@ class Renderer { const type = ( useToneMapping || this.backend.needsHalfFloatFrameBufferTarget() ) ? HalfFloatType : UnsignedByteType; - let frameBufferTarget = this._frameBufferTarget; - - if ( frameBufferTarget === null || this._frameBufferTarget.texture.type !== type ) { + let frameBufferTarget = this._frameBufferTargetMap.get( type ); - if ( frameBufferTarget !== null ) frameBufferTarget.dispose(); + if ( frameBufferTarget === undefined ) { frameBufferTarget = new RenderTarget( width, height, { depthBuffer: depth, @@ -1146,7 +1145,7 @@ class Renderer { frameBufferTarget.isPostProcessingRenderTarget = true; - this._frameBufferTarget = frameBufferTarget; + this._frameBufferTargetMap.set( type, frameBufferTarget ); } @@ -2033,6 +2032,14 @@ class Renderer { this._renderContexts.dispose(); this._textures.dispose(); + for ( const renderTarget of this._frameBufferTargetMap.values() ) { + + renderTarget.dispose(); + + } + + this._frameBufferTargetMap.clear(); + Object.values( this.backend.timestampQueryPool ).forEach( queryPool => { if ( queryPool !== null ) queryPool.dispose(); From 443a718ab79da09b0ce1408fae8c95e5b525ad48 Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Sun, 26 Jan 2025 17:15:09 +0100 Subject: [PATCH 4/5] Renderer: Clean up. --- src/renderers/common/Renderer.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/renderers/common/Renderer.js b/src/renderers/common/Renderer.js index 9b0befabf913a4..b8a36ef1ea8fbc 100644 --- a/src/renderers/common/Renderer.js +++ b/src/renderers/common/Renderer.js @@ -450,7 +450,6 @@ class Renderer { * * @private * @type {Map} - * @default null */ this._frameBufferTargetMap = new Map(); From 9539e31696112177ad5c9aab707994450d79367f Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Mon, 27 Jan 2025 22:10:01 +0100 Subject: [PATCH 5/5] Backend: Move `outputType` check. --- src/renderers/common/Backend.js | 4 ++-- src/renderers/webgpu/WebGPUBackend.js | 13 +------------ 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/src/renderers/common/Backend.js b/src/renderers/common/Backend.js index b6b9e0dab68f0d..8b42632d2997a0 100644 --- a/src/renderers/common/Backend.js +++ b/src/renderers/common/Backend.js @@ -4,7 +4,7 @@ let _color4 = null; import Color4 from './Color4.js'; import { Vector2 } from '../../math/Vector2.js'; import { createCanvasElement, warnOnce } from '../../utils.js'; -import { REVISION } from '../../constants.js'; +import { HalfFloatType, REVISION } from '../../constants.js'; /** * Most of the rendering related logic is implemented in the @@ -595,7 +595,7 @@ class Backend { */ needsHalfFloatFrameBufferTarget() { - return false; + return ( this.parameters.outputType === HalfFloatType ); } diff --git a/src/renderers/webgpu/WebGPUBackend.js b/src/renderers/webgpu/WebGPUBackend.js index 4b961f7c151ca0..da44414d90327f 100644 --- a/src/renderers/webgpu/WebGPUBackend.js +++ b/src/renderers/webgpu/WebGPUBackend.js @@ -13,7 +13,7 @@ import WebGPUBindingUtils from './utils/WebGPUBindingUtils.js'; import WebGPUPipelineUtils from './utils/WebGPUPipelineUtils.js'; import WebGPUTextureUtils from './utils/WebGPUTextureUtils.js'; -import { HalfFloatType, WebGPUCoordinateSystem } from '../../constants.js'; +import { WebGPUCoordinateSystem } from '../../constants.js'; import WebGPUTimestampQueryPool from './utils/WebGPUTimestampQueryPool.js'; /** @@ -279,17 +279,6 @@ class WebGPUBackend extends Backend { } - /** - * Returns `true` if the backend requires a framebuffer target with type `HalfFloat`. - * - * @return {Boolean} Whether the backend requires a framebuffer target with type `HalfFloat` or not. - */ - needsHalfFloatFrameBufferTarget() { - - return ( this.parameters.outputType === HalfFloatType ); - - } - /** * Returns the default render pass descriptor. *