From cb1a378040e47a143657a5ff9077d7e09b5a1539 Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Sat, 2 May 2026 13:29:26 +0200 Subject: [PATCH] WebGPURenderer: Optimize `submit()` calls. (#33513) --- src/renderers/webgpu/WebGPUBackend.js | 12 +++++------ .../webgpu/utils/WebGPUAttributeUtils.js | 3 ++- .../webgpu/utils/WebGPUTexturePassUtils.js | 5 +++-- .../webgpu/utils/WebGPUTextureUtils.js | 3 ++- .../webgpu/utils/WebGPUTimestampQueryPool.js | 3 ++- src/renderers/webgpu/utils/WebGPUUtils.js | 20 +++++++++++++++++++ 6 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/renderers/webgpu/WebGPUBackend.js b/src/renderers/webgpu/WebGPUBackend.js index df85e1862f79e7..0ffb056329cfb0 100644 --- a/src/renderers/webgpu/WebGPUBackend.js +++ b/src/renderers/webgpu/WebGPUBackend.js @@ -6,7 +6,7 @@ import { GPUFeatureName, GPULoadOp, GPUStoreOp, GPUIndexFormat, GPUTextureViewDi import WGSLNodeBuilder from './nodes/WGSLNodeBuilder.js'; import Backend from '../common/Backend.js'; -import WebGPUUtils from './utils/WebGPUUtils.js'; +import WebGPUUtils, { submit } from './utils/WebGPUUtils.js'; import WebGPUAttributeUtils from './utils/WebGPUAttributeUtils.js'; import WebGPUBindingUtils from './utils/WebGPUBindingUtils.js'; import WebGPUCapabilities from './utils/WebGPUCapabilities.js'; @@ -1105,7 +1105,7 @@ class WebGPUBackend extends Backend { } - this.device.queue.submit( [ renderContextData.encoder.finish() ] ); + submit( this.device, renderContextData.encoder.finish() ); // @@ -1378,7 +1378,7 @@ class WebGPUBackend extends Backend { currentPass.end(); - device.queue.submit( [ encoder.finish() ] ); + submit( device, encoder.finish() ); } @@ -1525,7 +1525,7 @@ class WebGPUBackend extends Backend { groupData.passEncoderGPU.end(); - this.device.queue.submit( [ groupData.cmdEncoderGPU.finish() ] ); + submit( this.device, groupData.cmdEncoderGPU.finish() ); } @@ -2490,7 +2490,7 @@ class WebGPUBackend extends Backend { ] ); - this.device.queue.submit( [ encoder.finish() ] ); + submit( this.device, encoder.finish() ); if ( dstLevel === 0 && dstTexture.generateMipmaps ) { @@ -2616,7 +2616,7 @@ class WebGPUBackend extends Backend { } else { - this.device.queue.submit( [ encoder.finish() ] ); + submit( this.device, encoder.finish() ); } diff --git a/src/renderers/webgpu/utils/WebGPUAttributeUtils.js b/src/renderers/webgpu/utils/WebGPUAttributeUtils.js index d6199ed3f42d05..7e4f208c0ed2b8 100644 --- a/src/renderers/webgpu/utils/WebGPUAttributeUtils.js +++ b/src/renderers/webgpu/utils/WebGPUAttributeUtils.js @@ -1,4 +1,5 @@ import { GPUInputStepMode } from './WebGPUConstants.js'; +import { submit } from './WebGPUUtils.js'; import { Float16BufferAttribute } from '../../../core/BufferAttribute.js'; import { isTypedArray, error } from '../../../utils.js'; @@ -418,7 +419,7 @@ class WebGPUAttributeUtils { ); const gpuCommands = cmdEncoder.finish(); - device.queue.submit( [ gpuCommands ] ); + submit( device, gpuCommands ); // map the data to the CPU await readBufferGPU.mapAsync( GPUMapMode.READ, 0, byteLength ); diff --git a/src/renderers/webgpu/utils/WebGPUTexturePassUtils.js b/src/renderers/webgpu/utils/WebGPUTexturePassUtils.js index ba7dc89b878f63..b76223858227a8 100644 --- a/src/renderers/webgpu/utils/WebGPUTexturePassUtils.js +++ b/src/renderers/webgpu/utils/WebGPUTexturePassUtils.js @@ -1,5 +1,6 @@ import DataMap from '../../common/DataMap.js'; import { GPUFilterMode, GPULoadOp, GPUStoreOp } from './WebGPUConstants.js'; +import { submit } from './WebGPUUtils.js'; /** * A WebGPU backend utility module used by {@link WebGPUTextureUtils}. @@ -259,7 +260,7 @@ fn main_cube( Varys: VarysStruct ) -> @location( 0 ) vec4 { pass( copyTransferPipeline, textureGPU, baseArrayLayer, tempTexture, 0, false ); pass( flipTransferPipeline, tempTexture, 0, textureGPU, baseArrayLayer, true ); - this.device.queue.submit( [ commandEncoder.finish() ] ); + submit( this.device, commandEncoder.finish() ); tempTexture.destroy(); @@ -281,7 +282,7 @@ fn main_cube( Varys: VarysStruct ) -> @location( 0 ) vec4 { this._mipmapRunBundles( commandEncoder, passes ); - if ( encoder === null ) this.device.queue.submit( [ commandEncoder.finish() ] ); + if ( encoder === null ) submit( this.device, commandEncoder.finish() ); textureData.layers = passes; diff --git a/src/renderers/webgpu/utils/WebGPUTextureUtils.js b/src/renderers/webgpu/utils/WebGPUTextureUtils.js index 3ef860a62f851b..9905bfb0433589 100644 --- a/src/renderers/webgpu/utils/WebGPUTextureUtils.js +++ b/src/renderers/webgpu/utils/WebGPUTextureUtils.js @@ -4,6 +4,7 @@ import { import { ColorManagement } from '../../../math/ColorManagement.js'; import WebGPUTexturePassUtils from './WebGPUTexturePassUtils.js'; +import { submit } from './WebGPUUtils.js'; import { ByteType, ShortType, @@ -708,7 +709,7 @@ class WebGPUTextureUtils { const typedArrayType = this._getTypedArrayType( format ); - device.queue.submit( [ encoder.finish() ] ); + submit( device, encoder.finish() ); await readBuffer.mapAsync( GPUMapMode.READ ); diff --git a/src/renderers/webgpu/utils/WebGPUTimestampQueryPool.js b/src/renderers/webgpu/utils/WebGPUTimestampQueryPool.js index 89ceaeadf66776..6d442588779379 100644 --- a/src/renderers/webgpu/utils/WebGPUTimestampQueryPool.js +++ b/src/renderers/webgpu/utils/WebGPUTimestampQueryPool.js @@ -1,5 +1,6 @@ import { error, warnOnce } from '../../../utils.js'; import TimestampQueryPool from '../../common/TimestampQueryPool.js'; +import { submit } from './WebGPUUtils.js'; /** * Manages a pool of WebGPU timestamp queries for performance measurement. @@ -155,7 +156,7 @@ class WebGPUTimestampQueryPool extends TimestampQueryPool { ); const commandBuffer = commandEncoder.finish(); - this.device.queue.submit( [ commandBuffer ] ); + submit( this.device, commandBuffer ); if ( this.resultBuffer.mapState !== 'unmapped' ) { diff --git a/src/renderers/webgpu/utils/WebGPUUtils.js b/src/renderers/webgpu/utils/WebGPUUtils.js index 9baee7b3f3d239..5a64a201a16744 100644 --- a/src/renderers/webgpu/utils/WebGPUUtils.js +++ b/src/renderers/webgpu/utils/WebGPUUtils.js @@ -1,6 +1,8 @@ import { HalfFloatType, UnsignedByteType } from '../../../constants.js'; import { GPUPrimitiveTopology, GPUTextureFormat } from './WebGPUConstants.js'; +const _commandList = [ null ]; + /** * A WebGPU backend utility module with common helpers. * @@ -266,4 +268,22 @@ class WebGPUUtils { } +/** + * Submits a single GPU command to the device queue using a shared, module-scoped + * array to avoid per-call array allocations. + * + * @private + * @param {GPUDevice} device - The GPU device. + * @param {GPUCommandBuffer} command - The command buffer to submit. + */ +export function submit( device, command ) { + + _commandList[ 0 ] = command; + + device.queue.submit( _commandList ); + + _commandList[ 0 ] = null; + +} + export default WebGPUUtils;