Sfoglia il codice sorgente

WebGPURenderer: More descriptor usage. (#33529)

Michael Herzog 1 mese fa
parent
commit
52d84fb78e

+ 38 - 19
src/renderers/webgpu/WebGPUBackend.js

@@ -17,8 +17,11 @@ import { WebGPUCoordinateSystem, TimestampQuery, REVISION, HalfFloatType, Compat
 import WebGPUTimestampQueryPool from './utils/WebGPUTimestampQueryPool.js';
 import { error } from '../../utils.js';
 
+import GPUBufferDescriptor from './descriptors/GPUBufferDescriptor.js';
 import GPUCommandEncoderDescriptor from './descriptors/GPUCommandEncoderDescriptor.js';
 import GPUComputePassDescriptor from './descriptors/GPUComputePassDescriptor.js';
+import GPUQuerySetDescriptor from './descriptors/GPUQuerySetDescriptor.js';
+import GPUShaderModuleDescriptor from './descriptors/GPUShaderModuleDescriptor.js';
 import GPURenderPassColorAttachment from './descriptors/GPURenderPassColorAttachment.js';
 import GPURenderPassDepthStencilAttachment from './descriptors/GPURenderPassDepthStencilAttachment.js';
 import GPURenderPassDescriptor from './descriptors/GPURenderPassDescriptor.js';
@@ -28,8 +31,11 @@ import GPUTextureViewDescriptor from './descriptors/GPUTextureViewDescriptor.js'
 import GPUExtent3D from './descriptors/GPUExtent3D.js';
 
 const _clearValue = { r: 0, g: 0, b: 0, a: 1 };
+const _bufferDescriptor = new GPUBufferDescriptor();
 const _commandEncoderDescriptor = new GPUCommandEncoderDescriptor();
 const _computePassDescriptor = new GPUComputePassDescriptor();
+const _querySetDescriptor = new GPUQuerySetDescriptor();
+const _shaderModuleDescriptor = new GPUShaderModuleDescriptor();
 const _renderPassTimestampWrites = new GPURenderPassTimestampWrites();
 const _texelCopyTextureInfoSrc = new GPUTexelCopyTextureInfo();
 const _texelCopyTextureInfoDst = new GPUTexelCopyTextureInfo();
@@ -693,7 +699,13 @@ class WebGPUBackend extends Backend {
 
 			//
 
-			occlusionQuerySet = device.createQuerySet( { type: 'occlusion', count: occlusionQueryCount, label: `occlusionQuerySet_${ renderContext.id }` } );
+			_querySetDescriptor.label = `occlusionQuerySet_${ renderContext.id }`;
+			_querySetDescriptor.type = 'occlusion';
+			_querySetDescriptor.count = occlusionQueryCount;
+
+			occlusionQuerySet = device.createQuerySet( _querySetDescriptor );
+
+			_querySetDescriptor.reset();
 
 			renderContextData.occlusionQuerySet = occlusionQuerySet;
 			renderContextData.occlusionQueryIndex = 0;
@@ -1122,12 +1134,12 @@ class WebGPUBackend extends Backend {
 
 			if ( queryResolveBuffer === undefined ) {
 
-				queryResolveBuffer = this.device.createBuffer(
-					{
-						size: bufferSize,
-						usage: GPUBufferUsage.QUERY_RESOLVE | GPUBufferUsage.COPY_SRC
-					}
-				);
+				_bufferDescriptor.size = bufferSize;
+				_bufferDescriptor.usage = GPUBufferUsage.QUERY_RESOLVE | GPUBufferUsage.COPY_SRC;
+
+				queryResolveBuffer = this.device.createBuffer( _bufferDescriptor );
+
+				_bufferDescriptor.reset();
 
 				this.occludedResolveCache.set( bufferSize, queryResolveBuffer );
 
@@ -1135,12 +1147,12 @@ class WebGPUBackend extends Backend {
 
 			//
 
-			const readBuffer = this.device.createBuffer(
-				{
-					size: bufferSize,
-					usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
-				}
-			);
+			_bufferDescriptor.size = bufferSize;
+			_bufferDescriptor.usage = GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ;
+
+			const readBuffer = this.device.createBuffer( _bufferDescriptor );
+
+			_bufferDescriptor.reset();
 
 			// two buffers required here - WebGPU doesn't allow usage of QUERY_RESOLVE & MAP_READ to be combined
 			renderContextData.encoder.resolveQuerySet( renderContextData.occlusionQuerySet, 0, occlusionQueryCount, queryResolveBuffer, 0 );
@@ -2152,11 +2164,16 @@ class WebGPUBackend extends Backend {
 
 		const programGPU = this.get( program );
 
+		_shaderModuleDescriptor.label = program.stage + ( program.name !== '' ? `_${ program.name }` : '' );
+		_shaderModuleDescriptor.code = program.code;
+
 		programGPU.module = {
-			module: this.device.createShaderModule( { code: program.code, label: program.stage + ( program.name !== '' ? `_${ program.name }` : '' ) } ),
+			module: this.device.createShaderModule( _shaderModuleDescriptor ),
 			entryPoint: 'main'
 		};
 
+		_shaderModuleDescriptor.reset();
+
 	}
 
 	/**
@@ -2288,11 +2305,13 @@ class WebGPUBackend extends Backend {
 
 			const bufferVisibility = `(${visibilities.join( ',' )})`;
 
-			const bufferGPU = this.device.createBuffer( {
-				label: `bindingBuffer${uniformBuffer.id}_${uniformBuffer.name}_${bufferVisibility}`,
-				size: byteLength,
-				usage: usage
-			} );
+			_bufferDescriptor.label = `bindingBuffer${uniformBuffer.id}_${uniformBuffer.name}_${bufferVisibility}`;
+			_bufferDescriptor.size = byteLength;
+			_bufferDescriptor.usage = usage;
+
+			const bufferGPU = this.device.createBuffer( _bufferDescriptor );
+
+			_bufferDescriptor.reset();
 
 			uniformBufferData.buffer = bufferGPU;
 

+ 48 - 0
src/renderers/webgpu/descriptors/GPUBindGroupDescriptor.js

@@ -0,0 +1,48 @@
+/**
+ * Reusable descriptor for `GPUDevice.createBindGroup()`.
+ *
+ * @private
+ */
+class GPUBindGroupDescriptor {
+
+	constructor() {
+
+		/**
+		 * The label of the bind group.
+		 *
+		 * @type {string}
+		 */
+		this.label = '';
+
+		/**
+		 * The bind group layout the bind group conforms to.
+		 *
+		 * @type {?GPUBindGroupLayout}
+		 * @default null
+		 */
+		this.layout = null;
+
+		/**
+		 * The bind group entries.
+		 *
+		 * @type {Array<Object>}
+		 */
+		this.entries = [];
+
+	}
+
+	/**
+	 * Resets the descriptor to its default state. The internal `entries` array
+	 * is emptied without releasing its backing storage.
+	 */
+	reset() {
+
+		this.label = '';
+		this.layout = null;
+		this.entries.length = 0;
+
+	}
+
+}
+
+export default GPUBindGroupDescriptor;

+ 57 - 0
src/renderers/webgpu/descriptors/GPUBufferDescriptor.js

@@ -0,0 +1,57 @@
+/**
+ * Reusable descriptor for `GPUDevice.createBuffer()`.
+ *
+ * @private
+ */
+class GPUBufferDescriptor {
+
+	constructor() {
+
+		/**
+		 * The label of the buffer.
+		 *
+		 * @type {string}
+		 */
+		this.label = '';
+
+		/**
+		 * The size of the buffer in bytes.
+		 *
+		 * @type {number}
+		 * @default 0
+		 */
+		this.size = 0;
+
+		/**
+		 * The allowed usages for the buffer.
+		 *
+		 * @type {number}
+		 * @default 0
+		 */
+		this.usage = 0;
+
+		/**
+		 * Whether the buffer is in the mapped state at creation.
+		 *
+		 * @type {boolean}
+		 * @default false
+		 */
+		this.mappedAtCreation = false;
+
+	}
+
+	/**
+	 * Resets the descriptor to its default state.
+	 */
+	reset() {
+
+		this.label = '';
+		this.size = 0;
+		this.usage = 0;
+		this.mappedAtCreation = false;
+
+	}
+
+}
+
+export default GPUBufferDescriptor;

+ 48 - 0
src/renderers/webgpu/descriptors/GPUComputePipelineDescriptor.js

@@ -0,0 +1,48 @@
+/**
+ * Reusable descriptor for `GPUDevice.createComputePipeline()`.
+ *
+ * @private
+ */
+class GPUComputePipelineDescriptor {
+
+	constructor() {
+
+		/**
+		 * The label of the compute pipeline.
+		 *
+		 * @type {string}
+		 */
+		this.label = '';
+
+		/**
+		 * The pipeline layout the pipeline conforms to, or `'auto'`.
+		 *
+		 * @type {?GPUPipelineLayout|string}
+		 * @default null
+		 */
+		this.layout = null;
+
+		/**
+		 * The programmable compute stage.
+		 *
+		 * @type {?Object}
+		 * @default null
+		 */
+		this.compute = null;
+
+	}
+
+	/**
+	 * Resets the descriptor to its default state.
+	 */
+	reset() {
+
+		this.label = '';
+		this.layout = null;
+		this.compute = null;
+
+	}
+
+}
+
+export default GPUComputePipelineDescriptor;

+ 39 - 0
src/renderers/webgpu/descriptors/GPUPipelineLayoutDescriptor.js

@@ -0,0 +1,39 @@
+/**
+ * Reusable descriptor for `GPUDevice.createPipelineLayout()`.
+ *
+ * @private
+ */
+class GPUPipelineLayoutDescriptor {
+
+	constructor() {
+
+		/**
+		 * The label of the pipeline layout.
+		 *
+		 * @type {string}
+		 */
+		this.label = '';
+
+		/**
+		 * The set of bind group layouts the pipeline layout describes.
+		 *
+		 * @type {?Array<?GPUBindGroupLayout>}
+		 * @default null
+		 */
+		this.bindGroupLayouts = null;
+
+	}
+
+	/**
+	 * Resets the descriptor to its default state.
+	 */
+	reset() {
+
+		this.label = '';
+		this.bindGroupLayouts = null;
+
+	}
+
+}
+
+export default GPUPipelineLayoutDescriptor;

+ 47 - 0
src/renderers/webgpu/descriptors/GPUQuerySetDescriptor.js

@@ -0,0 +1,47 @@
+/**
+ * Reusable descriptor for `GPUDevice.createQuerySet()`.
+ *
+ * @private
+ */
+class GPUQuerySetDescriptor {
+
+	constructor() {
+
+		/**
+		 * The label of the query set.
+		 *
+		 * @type {string}
+		 */
+		this.label = '';
+
+		/**
+		 * The type of queries managed by the set.
+		 *
+		 * @type {string|undefined}
+		 */
+		this.type = undefined;
+
+		/**
+		 * The number of queries managed by the set.
+		 *
+		 * @type {number}
+		 * @default 0
+		 */
+		this.count = 0;
+
+	}
+
+	/**
+	 * Resets the descriptor to its default state.
+	 */
+	reset() {
+
+		this.label = '';
+		this.type = undefined;
+		this.count = 0;
+
+	}
+
+}
+
+export default GPUQuerySetDescriptor;

+ 130 - 0
src/renderers/webgpu/descriptors/GPURenderPipelineDescriptor.js

@@ -0,0 +1,130 @@
+/**
+ * Reusable descriptor for `GPUDevice.createRenderPipeline()` and
+ * `createRenderPipelineAsync()`.
+ *
+ * @private
+ */
+class GPURenderPipelineDescriptor {
+
+	constructor() {
+
+		/**
+		 * The label of the render pipeline.
+		 *
+		 * @type {string}
+		 */
+		this.label = '';
+
+		/**
+		 * The pipeline layout the pipeline conforms to, or `'auto'`.
+		 *
+		 * @type {?GPUPipelineLayout|string}
+		 * @default null
+		 */
+		this.layout = null;
+
+		/**
+		 * The programmable vertex stage.
+		 *
+		 * @type {?Object}
+		 * @default null
+		 */
+		this.vertex = null;
+
+		/**
+		 * The primitive-assembly state.
+		 *
+		 * @type {Object}
+		 */
+		this.primitive = {};
+
+		/**
+		 * The depth/stencil state, omitted when the pipeline has no depth or stencil aspect.
+		 *
+		 * @type {Object|undefined}
+		 */
+		this.depthStencil = undefined;
+
+		/**
+		 * The multisample state.
+		 *
+		 * @type {GPUMultisampleState}
+		 */
+		this.multisample = new GPUMultisampleState();
+
+		/**
+		 * The programmable fragment stage. Omitted for vertex-only pipelines.
+		 *
+		 * @type {?Object}
+		 * @default null
+		 */
+		this.fragment = null;
+
+	}
+
+	/**
+	 * Resets the descriptor to its default state.
+	 */
+	reset() {
+
+		this.label = '';
+		this.layout = null;
+		this.vertex = null;
+		this.primitive = {};
+		this.depthStencil = undefined;
+		this.multisample.reset();
+		this.fragment = null;
+
+	}
+
+}
+
+/**
+ * Reusable nested state for `GPURenderPipelineDescriptor.multisample`.
+ *
+ * @private
+ */
+class GPUMultisampleState {
+
+	constructor() {
+
+		/**
+		 * The number of samples per pixel.
+		 *
+		 * @type {number}
+		 * @default 1
+		 */
+		this.count = 1;
+
+		/**
+		 * A bitmask determining which samples are written to.
+		 *
+		 * @type {number}
+		 * @default 0xFFFFFFFF
+		 */
+		this.mask = 0xFFFFFFFF;
+
+		/**
+		 * Whether a fragment's alpha channel is used to generate a sample coverage mask.
+		 *
+		 * @type {boolean}
+		 * @default false
+		 */
+		this.alphaToCoverageEnabled = false;
+
+	}
+
+	/**
+	 * Resets the state to its default values.
+	 */
+	reset() {
+
+		this.count = 1;
+		this.mask = 0xFFFFFFFF;
+		this.alphaToCoverageEnabled = false;
+
+	}
+
+}
+
+export default GPURenderPipelineDescriptor;

+ 119 - 0
src/renderers/webgpu/descriptors/GPUSamplerDescriptor.js

@@ -0,0 +1,119 @@
+/**
+ * Reusable descriptor for `GPUDevice.createSampler()`.
+ *
+ * @private
+ */
+class GPUSamplerDescriptor {
+
+	constructor() {
+
+		/**
+		 * The label of the sampler.
+		 *
+		 * @type {string}
+		 */
+		this.label = '';
+
+		/**
+		 * The address mode for the sampler's U coordinate.
+		 *
+		 * @type {string}
+		 * @default 'clamp-to-edge'
+		 */
+		this.addressModeU = 'clamp-to-edge';
+
+		/**
+		 * The address mode for the sampler's V coordinate.
+		 *
+		 * @type {string}
+		 * @default 'clamp-to-edge'
+		 */
+		this.addressModeV = 'clamp-to-edge';
+
+		/**
+		 * The address mode for the sampler's W coordinate.
+		 *
+		 * @type {string}
+		 * @default 'clamp-to-edge'
+		 */
+		this.addressModeW = 'clamp-to-edge';
+
+		/**
+		 * The magnification filter mode.
+		 *
+		 * @type {string}
+		 * @default 'nearest'
+		 */
+		this.magFilter = 'nearest';
+
+		/**
+		 * The minification filter mode.
+		 *
+		 * @type {string}
+		 * @default 'nearest'
+		 */
+		this.minFilter = 'nearest';
+
+		/**
+		 * The mipmap filter mode.
+		 *
+		 * @type {string}
+		 * @default 'nearest'
+		 */
+		this.mipmapFilter = 'nearest';
+
+		/**
+		 * The minimum level of detail used to sample.
+		 *
+		 * @type {number}
+		 * @default 0
+		 */
+		this.lodMinClamp = 0;
+
+		/**
+		 * The maximum level of detail used to sample.
+		 *
+		 * @type {number}
+		 * @default 32
+		 */
+		this.lodMaxClamp = 32;
+
+		/**
+		 * The compare function used by the sampler.
+		 *
+		 * @type {string|undefined}
+		 */
+		this.compare = undefined;
+
+		/**
+		 * The maximum allowed anisotropic filtering.
+		 *
+		 * @type {number}
+		 * @default 1
+		 */
+		this.maxAnisotropy = 1;
+
+	}
+
+	/**
+	 * Resets the descriptor to its default state.
+	 */
+	reset() {
+
+		this.label = '';
+		this.addressModeU = 'clamp-to-edge';
+		this.addressModeV = 'clamp-to-edge';
+		this.addressModeW = 'clamp-to-edge';
+		this.magFilter = 'nearest';
+		this.minFilter = 'nearest';
+		this.mipmapFilter = 'nearest';
+		this.lodMinClamp = 0;
+		this.lodMaxClamp = 32;
+		this.compare = undefined;
+		this.maxAnisotropy = 1;
+
+	}
+
+}
+
+export default GPUSamplerDescriptor;

+ 46 - 0
src/renderers/webgpu/descriptors/GPUShaderModuleDescriptor.js

@@ -0,0 +1,46 @@
+/**
+ * Reusable descriptor for `GPUDevice.createShaderModule()`.
+ *
+ * @private
+ */
+class GPUShaderModuleDescriptor {
+
+	constructor() {
+
+		/**
+		 * The label of the shader module.
+		 *
+		 * @type {string}
+		 */
+		this.label = '';
+
+		/**
+		 * The WGSL source code of the shader module.
+		 *
+		 * @type {string}
+		 */
+		this.code = '';
+
+		/**
+		 * Compilation hints that may help the implementation produce optimized code.
+		 *
+		 * @type {Array<Object>}
+		 */
+		this.compilationHints = [];
+
+	}
+
+	/**
+	 * Resets the descriptor to its default state.
+	 */
+	reset() {
+
+		this.label = '';
+		this.code = '';
+		this.compilationHints.length = 0;
+
+	}
+
+}
+
+export default GPUShaderModuleDescriptor;

+ 99 - 0
src/renderers/webgpu/descriptors/GPUTextureDescriptor.js

@@ -0,0 +1,99 @@
+/**
+ * Reusable descriptor for `GPUDevice.createTexture()`.
+ *
+ * @private
+ */
+class GPUTextureDescriptor {
+
+	constructor() {
+
+		/**
+		 * The label of the texture.
+		 *
+		 * @type {string}
+		 */
+		this.label = '';
+
+		/**
+		 * The size of the texture.
+		 *
+		 * @type {{width: number, height: number, depthOrArrayLayers: number}}
+		 */
+		this.size = { width: 0, height: 1, depthOrArrayLayers: 1 };
+
+		/**
+		 * The number of mip levels the texture will contain.
+		 *
+		 * @type {number}
+		 * @default 1
+		 */
+		this.mipLevelCount = 1;
+
+		/**
+		 * The sample count of the texture.
+		 *
+		 * @type {number}
+		 * @default 1
+		 */
+		this.sampleCount = 1;
+
+		/**
+		 * The dimension of the set of texel coordinates.
+		 *
+		 * @type {string}
+		 * @default '2d'
+		 */
+		this.dimension = '2d';
+
+		/**
+		 * The format of the texture.
+		 *
+		 * @type {string|undefined}
+		 */
+		this.format = undefined;
+
+		/**
+		 * The allowed usages for the texture.
+		 *
+		 * @type {number|undefined}
+		 */
+		this.usage = undefined;
+
+		/**
+		 * The formats that views of this texture may use.
+		 *
+		 * @type {Array<string>}
+		 */
+		this.viewFormats = [];
+
+		/**
+		 * The view dimension to use when binding the texture (compatibility mode).
+		 *
+		 * @type {string|undefined}
+		 */
+		this.textureBindingViewDimension = undefined;
+
+	}
+
+	/**
+	 * Resets the descriptor to its default state.
+	 */
+	reset() {
+
+		this.label = '';
+		this.size.width = 0;
+		this.size.height = 1;
+		this.size.depthOrArrayLayers = 1;
+		this.mipLevelCount = 1;
+		this.sampleCount = 1;
+		this.dimension = '2d';
+		this.format = undefined;
+		this.usage = undefined;
+		this.viewFormats.length = 0;
+		this.textureBindingViewDimension = undefined;
+
+	}
+
+}
+
+export default GPUTextureDescriptor;

+ 10 - 0
src/renderers/webgpu/descriptors/GPUTextureViewDescriptor.js

@@ -74,6 +74,15 @@ class GPUTextureViewDescriptor {
 		 */
 		this.arrayLayerCount = undefined;
 
+		/**
+		 * The component swizzle to apply when sampling the texture view.
+		 * Requires the `'texture-component-swizzle'` feature; ignored otherwise.
+		 *
+		 * @type {string}
+		 * @default 'rgba'
+		 */
+		this.swizzle = 'rgba';
+
 	}
 
 	/**
@@ -90,6 +99,7 @@ class GPUTextureViewDescriptor {
 		this.mipLevelCount = undefined;
 		this.baseArrayLayer = 0;
 		this.arrayLayerCount = undefined;
+		this.swizzle = 'rgba';
 
 	}
 

+ 24 - 16
src/renderers/webgpu/utils/WebGPUAttributeUtils.js

@@ -1,10 +1,12 @@
 import { GPUInputStepMode } from './WebGPUConstants.js';
 import { submit } from './WebGPUUtils.js';
+import GPUBufferDescriptor from '../descriptors/GPUBufferDescriptor.js';
 import GPUCommandEncoderDescriptor from '../descriptors/GPUCommandEncoderDescriptor.js';
 
 import { Float16BufferAttribute } from '../../../core/BufferAttribute.js';
 import { isTypedArray, error } from '../../../utils.js';
 
+const _bufferDescriptor = new GPUBufferDescriptor();
 const _commandEncoderDescriptor = new GPUCommandEncoderDescriptor();
 
 const typedArraysToVertexFormatPrefix = new Map( [
@@ -128,12 +130,14 @@ class WebGPUAttributeUtils {
 			const byteLength = array.byteLength;
 			const size = byteLength + ( ( 4 - ( byteLength % 4 ) ) % 4 );
 
-			buffer = device.createBuffer( {
-				label: bufferAttribute.name,
-				size: size,
-				usage: usage,
-				mappedAtCreation: true
-			} );
+			_bufferDescriptor.label = bufferAttribute.name;
+			_bufferDescriptor.size = size;
+			_bufferDescriptor.usage = usage;
+			_bufferDescriptor.mappedAtCreation = true;
+
+			buffer = device.createBuffer( _bufferDescriptor );
+
+			_bufferDescriptor.reset();
 
 			new array.constructor( buffer.getMappedRange() ).set( array );
 
@@ -355,11 +359,13 @@ class WebGPUAttributeUtils {
 			// initialize the GPU-side read copy buffer if it is not present
 			if ( readbackInfo.readBufferGPU === undefined ) {
 
-				readBufferGPU = device.createBuffer( {
-					label: `${ target.name }_readback`,
-					size: target.maxByteLength,
-					usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
-				} );
+				_bufferDescriptor.label = `${ target.name }_readback`;
+				_bufferDescriptor.size = target.maxByteLength;
+				_bufferDescriptor.usage = GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ;
+
+				readBufferGPU = device.createBuffer( _bufferDescriptor );
+
+				_bufferDescriptor.reset();
 
 				// release / dispose
 				const releaseCallback = () => {
@@ -400,11 +406,13 @@ class WebGPUAttributeUtils {
 		} else {
 
 			// create a new temp buffer for array buffers otherwise
-			readBufferGPU = device.createBuffer( {
-				label: `${ attribute.name }_readback`,
-				size: byteLength,
-				usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
-			} );
+			_bufferDescriptor.label = `${ attribute.name }_readback`;
+			_bufferDescriptor.size = byteLength;
+			_bufferDescriptor.usage = GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ;
+
+			readBufferGPU = device.createBuffer( _bufferDescriptor );
+
+			_bufferDescriptor.reset();
 
 		}
 

+ 31 - 21
src/renderers/webgpu/utils/WebGPUBindingUtils.js

@@ -8,8 +8,12 @@ import { NodeAccess } from '../../../nodes/core/constants.js';
 import { isTypedArray, error } from '../../../utils.js';
 import { hashString } from '../../../nodes/core/NodeUtils.js';
 
+import GPUBindGroupDescriptor from '../descriptors/GPUBindGroupDescriptor.js';
+import GPUBufferDescriptor from '../descriptors/GPUBufferDescriptor.js';
 import GPUTextureViewDescriptor from '../descriptors/GPUTextureViewDescriptor.js';
 
+const _bindGroupDescriptor = new GPUBindGroupDescriptor();
+const _bufferDescriptor = new GPUBufferDescriptor();
 const _viewDescriptor = new GPUTextureViewDescriptor();
 
 /**
@@ -248,21 +252,25 @@ class WebGPUBindingUtils {
 		const usage = GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST;
 		const index = data[ 0 ];
 
-		const buffer = device.createBuffer( {
-			label: 'bindingCameraIndex_' + index,
-			size: 16, // uint(4) * 4
-			usage: usage
-		} );
+		_bufferDescriptor.label = 'bindingCameraIndex_' + index;
+		_bufferDescriptor.size = 16; // uint(4) * 4
+		_bufferDescriptor.usage = usage;
+
+		const buffer = device.createBuffer( _bufferDescriptor );
+
+		_bufferDescriptor.reset();
 
 		device.queue.writeBuffer( buffer, 0, data, 0 );
 
-		const entries = [ { binding: 0, resource: { buffer } } ];
+		_bindGroupDescriptor.label = 'bindGroupCameraIndex_' + index;
+		_bindGroupDescriptor.layout = layoutGPU;
+		_bindGroupDescriptor.entries.push( { binding: 0, resource: { buffer } } );
+
+		const bindGroup = device.createBindGroup( _bindGroupDescriptor );
+
+		_bindGroupDescriptor.reset();
 
-		return device.createBindGroup( {
-			label: 'bindGroupCameraIndex_' + index,
-			layout: layoutGPU,
-			entries
-		} );
+		return bindGroup;
 
 	}
 
@@ -279,7 +287,9 @@ class WebGPUBindingUtils {
 		const device = backend.device;
 
 		let bindingPoint = 0;
-		const entriesGPU = [];
+
+		_bindGroupDescriptor.label = 'bindGroup_' + bindGroup.name;
+		_bindGroupDescriptor.layout = layoutGPU;
 
 		for ( const binding of bindGroup.bindings ) {
 
@@ -287,13 +297,13 @@ class WebGPUBindingUtils {
 
 				const bindingData = backend.get( binding );
 
-				entriesGPU.push( { binding: bindingPoint, resource: { buffer: bindingData.buffer } } );
+				_bindGroupDescriptor.entries.push( { binding: bindingPoint, resource: { buffer: bindingData.buffer } } );
 
 			} else if ( binding.isStorageBuffer ) {
 
 				const buffer = backend.get( binding.attribute ).buffer;
 
-				entriesGPU.push( { binding: bindingPoint, resource: { buffer: buffer } } );
+				_bindGroupDescriptor.entries.push( { binding: bindingPoint, resource: { buffer: buffer } } );
 
 			} else if ( binding.isSampledTexture ) {
 
@@ -360,13 +370,13 @@ class WebGPUBindingUtils {
 
 				}
 
-				entriesGPU.push( { binding: bindingPoint, resource: resourceGPU } );
+				_bindGroupDescriptor.entries.push( { binding: bindingPoint, resource: resourceGPU } );
 
 			} else if ( binding.isSampler ) {
 
 				const textureGPU = backend.get( binding.texture );
 
-				entriesGPU.push( { binding: bindingPoint, resource: textureGPU.sampler } );
+				_bindGroupDescriptor.entries.push( { binding: bindingPoint, resource: textureGPU.sampler } );
 
 			}
 
@@ -374,11 +384,11 @@ class WebGPUBindingUtils {
 
 		}
 
-		return device.createBindGroup( {
-			label: 'bindGroup_' + bindGroup.name,
-			layout: layoutGPU,
-			entries: entriesGPU
-		} );
+		const bindGroupGPU = device.createBindGroup( _bindGroupDescriptor );
+
+		_bindGroupDescriptor.reset();
+
+		return bindGroupGPU;
 
 	}
 

+ 39 - 24
src/renderers/webgpu/utils/WebGPUPipelineUtils.js

@@ -17,9 +17,15 @@ import {
 
 import { error, ReversedDepthFuncs, warn, warnOnce } from '../../../utils.js';
 
+import GPUComputePipelineDescriptor from '../descriptors/GPUComputePipelineDescriptor.js';
+import GPUPipelineLayoutDescriptor from '../descriptors/GPUPipelineLayoutDescriptor.js';
 import GPURenderBundleEncoderDescriptor from '../descriptors/GPURenderBundleEncoderDescriptor.js';
+import GPURenderPipelineDescriptor from '../descriptors/GPURenderPipelineDescriptor.js';
 
+const _computePipelineDescriptor = new GPUComputePipelineDescriptor();
+const _pipelineLayoutDescriptor = new GPUPipelineLayoutDescriptor();
 const _renderBundleEncoderDescriptor = new GPURenderBundleEncoderDescriptor();
+const _renderPipelineDescriptor = new GPURenderPipelineDescriptor();
 
 /**
  * A WebGPU backend utility module for managing pipelines.
@@ -222,20 +228,19 @@ class WebGPUPipelineUtils {
 
 		const sampleCount = this._getSampleCount( renderObject.context );
 
-		const pipelineDescriptor = {
-			label: `renderPipeline_${ material.name || material.type }_${ material.id }`,
-			vertex: Object.assign( {}, vertexModule, { buffers: vertexBuffers } ),
-			fragment: Object.assign( {}, fragmentModule, { targets } ),
-			primitive: primitiveState,
-			multisample: {
-				count: sampleCount,
-				alphaToCoverageEnabled: material.alphaToCoverage && sampleCount > 1
-			},
-			layout: device.createPipelineLayout( {
-				bindGroupLayouts
-			} )
-		};
+		_pipelineLayoutDescriptor.bindGroupLayouts = bindGroupLayouts;
 
+		const pipelineLayout = device.createPipelineLayout( _pipelineLayoutDescriptor );
+
+		_pipelineLayoutDescriptor.reset();
+
+		_renderPipelineDescriptor.label = `renderPipeline_${ material.name || material.type }_${ material.id }`;
+		_renderPipelineDescriptor.vertex = Object.assign( {}, vertexModule, { buffers: vertexBuffers } );
+		_renderPipelineDescriptor.fragment = Object.assign( {}, fragmentModule, { targets } );
+		_renderPipelineDescriptor.primitive = primitiveState;
+		_renderPipelineDescriptor.multisample.count = sampleCount;
+		_renderPipelineDescriptor.multisample.alphaToCoverageEnabled = material.alphaToCoverage && sampleCount > 1;
+		_renderPipelineDescriptor.layout = pipelineLayout;
 
 		const depthStencil = {};
 		const renderDepth = renderObject.context.depth;
@@ -268,7 +273,7 @@ class WebGPUPipelineUtils {
 
 			}
 
-			pipelineDescriptor.depthStencil = depthStencil;
+			_renderPipelineDescriptor.depthStencil = depthStencil;
 
 		}
 
@@ -280,11 +285,13 @@ class WebGPUPipelineUtils {
 			{ program: vertexProgram, module: vertexModule.module },
 			{ program: fragmentProgram, module: fragmentModule.module }
 		];
-		const pipelineLabel = pipelineDescriptor.label;
+		const pipelineLabel = _renderPipelineDescriptor.label;
 
 		if ( promises === null ) {
 
-			pipelineData.pipeline = device.createRenderPipeline( pipelineDescriptor );
+			pipelineData.pipeline = device.createRenderPipeline( _renderPipelineDescriptor );
+
+			_renderPipelineDescriptor.reset();
 
 			device.popErrorScope().then( ( err ) => {
 
@@ -310,7 +317,7 @@ class WebGPUPipelineUtils {
 
 					try {
 
-						pipelineData.pipeline = await device.createRenderPipelineAsync( pipelineDescriptor );
+						pipelineData.pipeline = await device.createRenderPipelineAsync( _renderPipelineDescriptor );
 
 					} catch ( err ) {
 
@@ -333,6 +340,8 @@ class WebGPUPipelineUtils {
 
 				} finally {
 
+					_renderPipelineDescriptor.reset();
+
 					// Guarantee resolution so `compileAsync`'s Promise.all cannot hang on an
 					// unexpected throw from any await above.
 					resolve();
@@ -409,13 +418,19 @@ class WebGPUPipelineUtils {
 
 		device.pushErrorScope( 'validation' );
 
-		pipelineGPU.pipeline = device.createComputePipeline( {
-			label: pipelineLabel,
-			compute: computeProgram,
-			layout: device.createPipelineLayout( {
-				bindGroupLayouts
-			} )
-		} );
+		_pipelineLayoutDescriptor.bindGroupLayouts = bindGroupLayouts;
+
+		const pipelineLayout = device.createPipelineLayout( _pipelineLayoutDescriptor );
+
+		_pipelineLayoutDescriptor.reset();
+
+		_computePipelineDescriptor.label = pipelineLabel;
+		_computePipelineDescriptor.compute = computeProgram;
+		_computePipelineDescriptor.layout = pipelineLayout;
+
+		pipelineGPU.pipeline = device.createComputePipeline( _computePipelineDescriptor );
+
+		_computePipelineDescriptor.reset();
 
 		device.popErrorScope().then( ( err ) => {
 

+ 77 - 53
src/renderers/webgpu/utils/WebGPUTexturePassUtils.js

@@ -1,16 +1,26 @@
 import DataMap from '../../common/DataMap.js';
 import { GPUFilterMode, GPULoadOp, GPUStoreOp } from './WebGPUConstants.js';
 import { submit } from './WebGPUUtils.js';
+import GPUBindGroupDescriptor from '../descriptors/GPUBindGroupDescriptor.js';
+import GPUBufferDescriptor from '../descriptors/GPUBufferDescriptor.js';
 import GPUCommandEncoderDescriptor from '../descriptors/GPUCommandEncoderDescriptor.js';
 import GPURenderBundleEncoderDescriptor from '../descriptors/GPURenderBundleEncoderDescriptor.js';
 import GPURenderPassColorAttachment from '../descriptors/GPURenderPassColorAttachment.js';
 import GPURenderPassDescriptor from '../descriptors/GPURenderPassDescriptor.js';
+import GPURenderPipelineDescriptor from '../descriptors/GPURenderPipelineDescriptor.js';
+import GPUShaderModuleDescriptor from '../descriptors/GPUShaderModuleDescriptor.js';
+import GPUTextureDescriptor from '../descriptors/GPUTextureDescriptor.js';
 import GPUTextureViewDescriptor from '../descriptors/GPUTextureViewDescriptor.js';
 
+const _bindGroupDescriptor = new GPUBindGroupDescriptor();
+const _bufferDescriptor = new GPUBufferDescriptor();
 const _commandEncoderDescriptor = new GPUCommandEncoderDescriptor();
 const _renderBundleEncoderDescriptor = new GPURenderBundleEncoderDescriptor();
 const _renderPassDescriptor = new GPURenderPassDescriptor();
+const _renderPipelineDescriptor = new GPURenderPipelineDescriptor();
 const _colorAttachment = new GPURenderPassColorAttachment();
+const _shaderModuleDescriptor = new GPUShaderModuleDescriptor();
+const _textureDescriptor = new GPUTextureDescriptor();
 const _viewDescriptor = new GPUTextureViewDescriptor();
 
 /**
@@ -130,20 +140,25 @@ fn main_cube( Varys: VarysStruct ) -> @location( 0 ) vec4<f32> {
 		 * flip uniform buffer
 		 * @type {GPUBuffer}
 		 */
-		this.flipUniformBuffer = device.createBuffer( {
-			size: 4,
-			usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
-		} );
+		_bufferDescriptor.size = 4;
+		_bufferDescriptor.usage = GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST;
+
+		this.flipUniformBuffer = device.createBuffer( _bufferDescriptor );
+
+		_bufferDescriptor.reset();
+
 		device.queue.writeBuffer( this.flipUniformBuffer, 0, new Uint32Array( [ 1 ] ) );
 
 		/**
 		 * no flip uniform buffer
 		 * @type {GPUBuffer}
 		 */
-		this.noFlipUniformBuffer = device.createBuffer( {
-			size: 4,
-			usage: GPUBufferUsage.UNIFORM
-		} );
+		_bufferDescriptor.size = 4;
+		_bufferDescriptor.usage = GPUBufferUsage.UNIFORM;
+
+		this.noFlipUniformBuffer = device.createBuffer( _bufferDescriptor );
+
+		_bufferDescriptor.reset();
 
 		/**
 		 * A cache for GPU render pipelines used for copy/transfer passes.
@@ -158,10 +173,12 @@ fn main_cube( Varys: VarysStruct ) -> @location( 0 ) vec4<f32> {
 		 *
 		 * @type {GPUShaderModule}
 		 */
-		this.mipmapShaderModule = device.createShaderModule( {
-			label: 'mipmap',
-			code: mipmapSource
-		} );
+		_shaderModuleDescriptor.label = 'mipmap';
+		_shaderModuleDescriptor.code = mipmapSource;
+
+		this.mipmapShaderModule = device.createShaderModule( _shaderModuleDescriptor );
+
+		_shaderModuleDescriptor.reset();
 
 	}
 
@@ -181,18 +198,18 @@ fn main_cube( Varys: VarysStruct ) -> @location( 0 ) vec4<f32> {
 
 		if ( pipeline === undefined ) {
 
-			pipeline = this.device.createRenderPipeline( {
-				label: `mipmap-${ format }-${ textureBindingViewDimension }`,
-				vertex: {
-					module: this.mipmapShaderModule,
-				},
-				fragment: {
-					module: this.mipmapShaderModule,
-					entryPoint: `main_${ textureBindingViewDimension.replace( '-', '_' ) }`,
-					targets: [ { format } ]
-				},
-				layout: 'auto'
-			} );
+			_renderPipelineDescriptor.label = `mipmap-${ format }-${ textureBindingViewDimension }`;
+			_renderPipelineDescriptor.vertex = { module: this.mipmapShaderModule };
+			_renderPipelineDescriptor.fragment = {
+				module: this.mipmapShaderModule,
+				entryPoint: `main_${ textureBindingViewDimension.replace( '-', '_' ) }`,
+				targets: [ { format } ]
+			};
+			_renderPipelineDescriptor.layout = 'auto';
+
+			pipeline = this.device.createRenderPipeline( _renderPipelineDescriptor );
+
+			_renderPipelineDescriptor.reset();
 
 			this.transferPipelines[ key ] = pipeline;
 
@@ -214,11 +231,14 @@ fn main_cube( Varys: VarysStruct ) -> @location( 0 ) vec4<f32> {
 		const format = textureGPUDescriptor.format;
 		const { width, height } = textureGPUDescriptor.size;
 
-		const tempTexture = this.device.createTexture( {
-			size: { width, height },
-			format,
-			usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING
-		} );
+		_textureDescriptor.size.width = width;
+		_textureDescriptor.size.height = height;
+		_textureDescriptor.format = format;
+		_textureDescriptor.usage = GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING;
+
+		const tempTexture = this.device.createTexture( _textureDescriptor );
+
+		_textureDescriptor.reset();
 
 		const copyTransferPipeline = this.getTransferPipeline( format, textureGPU.textureBindingViewDimension );
 		const flipTransferPipeline = this.getTransferPipeline( format, tempTexture.textureBindingViewDimension );
@@ -236,20 +256,22 @@ fn main_cube( Varys: VarysStruct ) -> @location( 0 ) vec4<f32> {
 
 			_viewDescriptor.reset();
 
-			const bindGroup = this.device.createBindGroup( {
-				layout: bindGroupLayout,
-				entries: [ {
-					binding: 0,
-					resource: this.flipYSampler
-				}, {
-					binding: 1,
-					resource: sourceView,
-				}, {
-					binding: 2,
-					resource: { buffer: flipY ? this.flipUniformBuffer : this.noFlipUniformBuffer }
-				} ]
+			_bindGroupDescriptor.layout = bindGroupLayout;
+			_bindGroupDescriptor.entries.push( {
+				binding: 0,
+				resource: this.flipYSampler
+			}, {
+				binding: 1,
+				resource: sourceView,
+			}, {
+				binding: 2,
+				resource: { buffer: flipY ? this.flipUniformBuffer : this.noFlipUniformBuffer }
 			} );
 
+			const bindGroup = this.device.createBindGroup( _bindGroupDescriptor );
+
+			_bindGroupDescriptor.reset();
+
 			_viewDescriptor.dimension = '2d';
 			_viewDescriptor.mipLevelCount = 1;
 			_viewDescriptor.baseArrayLayer = destinationArrayLayer;
@@ -344,20 +366,22 @@ fn main_cube( Varys: VarysStruct ) -> @location( 0 ) vec4<f32> {
 
 				_viewDescriptor.reset();
 
-				const bindGroup = this.device.createBindGroup( {
-					layout: bindGroupLayout,
-					entries: [ {
-						binding: 0,
-						resource: this.mipmapSampler
-					}, {
-						binding: 1,
-						resource: sourceView,
-					}, {
-						binding: 2,
-						resource: { buffer: this.noFlipUniformBuffer }
-					} ]
+				_bindGroupDescriptor.layout = bindGroupLayout;
+				_bindGroupDescriptor.entries.push( {
+					binding: 0,
+					resource: this.mipmapSampler
+				}, {
+					binding: 1,
+					resource: sourceView,
+				}, {
+					binding: 2,
+					resource: { buffer: this.noFlipUniformBuffer }
 				} );
 
+				const bindGroup = this.device.createBindGroup( _bindGroupDescriptor );
+
+				_bindGroupDescriptor.reset();
+
 				_viewDescriptor.dimension = '2d';
 				_viewDescriptor.baseMipLevel = baseMipLevel;
 				_viewDescriptor.mipLevelCount = 1;

+ 47 - 46
src/renderers/webgpu/utils/WebGPUTextureUtils.js

@@ -5,20 +5,26 @@ import { ColorManagement } from '../../../math/ColorManagement.js';
 
 import WebGPUTexturePassUtils from './WebGPUTexturePassUtils.js';
 import { submit } from './WebGPUUtils.js';
+import GPUBufferDescriptor from '../descriptors/GPUBufferDescriptor.js';
 import GPUCommandEncoderDescriptor from '../descriptors/GPUCommandEncoderDescriptor.js';
+import GPUSamplerDescriptor from '../descriptors/GPUSamplerDescriptor.js';
 import GPUTexelCopyTextureInfo from '../descriptors/GPUTexelCopyTextureInfo.js';
 import GPUTexelCopyBufferInfo from '../descriptors/GPUTexelCopyBufferInfo.js';
 import GPUTexelCopyBufferLayout from '../descriptors/GPUTexelCopyBufferLayout.js';
 import GPUCopyExternalImageSourceInfo from '../descriptors/GPUCopyExternalImageSourceInfo.js';
 import GPUCopyExternalImageDestInfo from '../descriptors/GPUCopyExternalImageDestInfo.js';
+import GPUTextureDescriptor from '../descriptors/GPUTextureDescriptor.js';
 import GPUExtent3D from '../descriptors/GPUExtent3D.js';
 
+const _bufferDescriptor = new GPUBufferDescriptor();
 const _commandEncoderDescriptor = new GPUCommandEncoderDescriptor();
+const _samplerDescriptor = new GPUSamplerDescriptor();
 const _texelCopyTextureInfo = new GPUTexelCopyTextureInfo();
 const _texelCopyBufferInfo = new GPUTexelCopyBufferInfo();
 const _texelCopyBufferLayout = new GPUTexelCopyBufferLayout();
 const _copyExternalImageSourceInfo = new GPUCopyExternalImageSourceInfo();
 const _copyExternalImageDestInfo = new GPUCopyExternalImageDestInfo();
+const _textureDescriptor = new GPUTextureDescriptor();
 const _extent3D = new GPUExtent3D();
 
 import {
@@ -159,40 +165,39 @@ class WebGPUTextureUtils {
 
 		if ( samplerData === undefined ) {
 
-			const samplerDescriptorGPU = {
-				addressModeU: this._convertAddressMode( texture.wrapS ),
-				addressModeV: this._convertAddressMode( texture.wrapT ),
-				addressModeW: this._convertAddressMode( texture.wrapR ),
-				magFilter: this._convertFilterMode( texture.magFilter ),
-				minFilter: this._convertFilterMode( texture.minFilter ),
-				mipmapFilter: this._convertMipmapFilterMode( texture.minFilter ),
-				maxAnisotropy: 1
-			};
+			_samplerDescriptor.addressModeU = this._convertAddressMode( texture.wrapS );
+			_samplerDescriptor.addressModeV = this._convertAddressMode( texture.wrapT );
+			_samplerDescriptor.addressModeW = this._convertAddressMode( texture.wrapR );
+			_samplerDescriptor.magFilter = this._convertFilterMode( texture.magFilter );
+			_samplerDescriptor.minFilter = this._convertFilterMode( texture.minFilter );
+			_samplerDescriptor.mipmapFilter = this._convertMipmapFilterMode( texture.minFilter );
 
 			// Depth textures without compare function must use non-filtering (nearest) sampling
 			if ( texture.isDepthTexture && ( texture.compareFunction === null || textureNode.compareNode === null ) ) {
 
-				samplerDescriptorGPU.magFilter = GPUFilterMode.Nearest;
-				samplerDescriptorGPU.minFilter = GPUFilterMode.Nearest;
-				samplerDescriptorGPU.mipmapFilter = GPUFilterMode.Nearest;
+				_samplerDescriptor.magFilter = GPUFilterMode.Nearest;
+				_samplerDescriptor.minFilter = GPUFilterMode.Nearest;
+				_samplerDescriptor.mipmapFilter = GPUFilterMode.Nearest;
 
 			}
 
 			// anisotropy can only be used when all filter modes are set to linear.
 
-			if ( samplerDescriptorGPU.magFilter === GPUFilterMode.Linear && samplerDescriptorGPU.minFilter === GPUFilterMode.Linear && samplerDescriptorGPU.mipmapFilter === GPUFilterMode.Linear ) {
+			if ( _samplerDescriptor.magFilter === GPUFilterMode.Linear && _samplerDescriptor.minFilter === GPUFilterMode.Linear && _samplerDescriptor.mipmapFilter === GPUFilterMode.Linear ) {
 
-				samplerDescriptorGPU.maxAnisotropy = texture.anisotropy;
+				_samplerDescriptor.maxAnisotropy = texture.anisotropy;
 
 			}
 
 			if ( texture.isDepthTexture && texture.compareFunction !== null && textureNode.compareNode !== null && backend.hasCompatibility( Compatibility.TEXTURE_COMPARE ) ) {
 
-				samplerDescriptorGPU.compare = _compareToWebGPU[ texture.compareFunction ];
+				_samplerDescriptor.compare = _compareToWebGPU[ texture.compareFunction ];
 
 			}
 
-			const sampler = backend.device.createSampler( samplerDescriptorGPU );
+			const sampler = backend.device.createSampler( _samplerDescriptor );
+
+			_samplerDescriptor.reset();
 
 			samplerData = { sampler, usedTimes: 0 };
 
@@ -325,19 +330,16 @@ class WebGPUTextureUtils {
 
 		}
 
-		const textureDescriptorGPU = {
-			label: texture.name,
-			size: {
-				width: width,
-				height: height,
-				depthOrArrayLayers: depth,
-			},
-			mipLevelCount: levels,
-			sampleCount: primarySamples,
-			dimension: dimension,
-			format: format,
-			usage: usage
-		};
+		const textureDescriptorGPU = new GPUTextureDescriptor();
+		textureDescriptorGPU.label = texture.name;
+		textureDescriptorGPU.size.width = width;
+		textureDescriptorGPU.size.height = height;
+		textureDescriptorGPU.size.depthOrArrayLayers = depth;
+		textureDescriptorGPU.mipLevelCount = levels;
+		textureDescriptorGPU.sampleCount = primarySamples;
+		textureDescriptorGPU.dimension = dimension;
+		textureDescriptorGPU.format = format;
+		textureDescriptorGPU.usage = usage;
 
 		// texture creation
 
@@ -447,17 +449,16 @@ class WebGPUTextureUtils {
 
 		if ( colorBuffer ) colorBuffer.destroy();
 
-		colorBuffer = backend.device.createTexture( {
-			label: 'colorBuffer',
-			size: {
-				width: width,
-				height: height,
-				depthOrArrayLayers: 1
-			},
-			sampleCount: backend.utils.getSampleCount( backend.renderer.currentSamples ),
-			format: backend.utils.getPreferredCanvasFormat(),
-			usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC
-		} );
+		_textureDescriptor.label = 'colorBuffer';
+		_textureDescriptor.size.width = width;
+		_textureDescriptor.size.height = height;
+		_textureDescriptor.sampleCount = backend.utils.getSampleCount( backend.renderer.currentSamples );
+		_textureDescriptor.format = backend.utils.getPreferredCanvasFormat();
+		_textureDescriptor.usage = GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC;
+
+		colorBuffer = backend.device.createTexture( _textureDescriptor );
+
+		_textureDescriptor.reset();
 
 		//
 
@@ -702,12 +703,12 @@ class WebGPUTextureUtils {
 		let bytesPerRow = width * bytesPerTexel;
 		bytesPerRow = Math.ceil( bytesPerRow / 256 ) * 256; // Align to 256 bytes
 
-		const readBuffer = device.createBuffer(
-			{
-				size: ( ( height - 1 ) * bytesPerRow ) + ( width * bytesPerTexel ), // see https://github.com/mrdoob/three.js/issues/31658#issuecomment-3229442010
-				usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
-			}
-		);
+		_bufferDescriptor.size = ( ( height - 1 ) * bytesPerRow ) + ( width * bytesPerTexel ); // see https://github.com/mrdoob/three.js/issues/31658#issuecomment-3229442010
+		_bufferDescriptor.usage = GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ;
+
+		const readBuffer = device.createBuffer( _bufferDescriptor );
+
+		_bufferDescriptor.reset();
 
 		const encoder = device.createCommandEncoder( _commandEncoderDescriptor );
 

+ 27 - 16
src/renderers/webgpu/utils/WebGPUTimestampQueryPool.js

@@ -1,9 +1,13 @@
 import { error, warnOnce } from '../../../utils.js';
 import TimestampQueryPool from '../../common/TimestampQueryPool.js';
 import { submit } from './WebGPUUtils.js';
+import GPUBufferDescriptor from '../descriptors/GPUBufferDescriptor.js';
 import GPUCommandEncoderDescriptor from '../descriptors/GPUCommandEncoderDescriptor.js';
+import GPUQuerySetDescriptor from '../descriptors/GPUQuerySetDescriptor.js';
 
+const _bufferDescriptor = new GPUBufferDescriptor();
 const _commandEncoderDescriptor = new GPUCommandEncoderDescriptor();
+const _querySetDescriptor = new GPUQuerySetDescriptor();
 
 /**
  * Manages a pool of WebGPU timestamp queries for performance measurement.
@@ -26,24 +30,31 @@ class WebGPUTimestampQueryPool extends TimestampQueryPool {
 		this.device = device;
 		this.type = type;
 
-		this.querySet = this.device.createQuerySet( {
-			type: 'timestamp',
-			count: this.maxQueries,
-			label: `queryset_global_timestamp_${type}`
-		} );
+		_querySetDescriptor.label = `queryset_global_timestamp_${type}`;
+		_querySetDescriptor.type = 'timestamp';
+		_querySetDescriptor.count = this.maxQueries;
+
+		this.querySet = this.device.createQuerySet( _querySetDescriptor );
+
+		_querySetDescriptor.reset();
 
 		const bufferSize = this.maxQueries * 8;
-		this.resolveBuffer = this.device.createBuffer( {
-			label: `buffer_timestamp_resolve_${type}`,
-			size: bufferSize,
-			usage: GPUBufferUsage.QUERY_RESOLVE | GPUBufferUsage.COPY_SRC
-		} );
-
-		this.resultBuffer = this.device.createBuffer( {
-			label: `buffer_timestamp_result_${type}`,
-			size: bufferSize,
-			usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
-		} );
+
+		_bufferDescriptor.label = `buffer_timestamp_resolve_${type}`;
+		_bufferDescriptor.size = bufferSize;
+		_bufferDescriptor.usage = GPUBufferUsage.QUERY_RESOLVE | GPUBufferUsage.COPY_SRC;
+
+		this.resolveBuffer = this.device.createBuffer( _bufferDescriptor );
+
+		_bufferDescriptor.reset();
+
+		_bufferDescriptor.label = `buffer_timestamp_result_${type}`;
+		_bufferDescriptor.size = bufferSize;
+		_bufferDescriptor.usage = GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ;
+
+		this.resultBuffer = this.device.createBuffer( _bufferDescriptor );
+
+		_bufferDescriptor.reset();
 
 	}
 

粤ICP备19079148号