|
@@ -1120,44 +1120,59 @@ class WebGPUBackend extends Backend {
|
|
const renderContextData = this.get( renderContext );
|
|
const renderContextData = this.get( renderContext );
|
|
|
|
|
|
const size = 2 * BigInt64Array.BYTES_PER_ELEMENT;
|
|
const size = 2 * BigInt64Array.BYTES_PER_ELEMENT;
|
|
- const resolveBuffer = this.device.createBuffer( {
|
|
|
|
- size,
|
|
|
|
- usage: GPUBufferUsage.QUERY_RESOLVE | GPUBufferUsage.COPY_SRC,
|
|
|
|
- } );
|
|
|
|
|
|
|
|
- const resultBuffer = this.device.createBuffer( {
|
|
|
|
- size,
|
|
|
|
- usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,
|
|
|
|
- } );
|
|
|
|
|
|
+ if ( renderContextData.currentTimestampQueryBuffers === undefined ) {
|
|
|
|
+
|
|
|
|
+ renderContextData.currentTimestampQueryBuffers = {
|
|
|
|
+ resolveBuffer: this.device.createBuffer({
|
|
|
|
+ label: 'timestamp resolve buffer',
|
|
|
|
+ size: size,
|
|
|
|
+ usage: GPUBufferUsage.QUERY_RESOLVE | GPUBufferUsage.COPY_SRC,
|
|
|
|
+ }),
|
|
|
|
+ resultBuffer: this.device.createBuffer({
|
|
|
|
+ label: 'timestamp result buffer',
|
|
|
|
+ size: size,
|
|
|
|
+ usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,
|
|
|
|
+ }),
|
|
|
|
+ isMappingPending: false,
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const { resolveBuffer, resultBuffer, isMappingPending } = renderContextData.currentTimestampQueryBuffers
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ if ( isMappingPending === true ) return;
|
|
|
|
|
|
encoder.resolveQuerySet( renderContextData.timeStampQuerySet, 0, 2, resolveBuffer, 0 );
|
|
encoder.resolveQuerySet( renderContextData.timeStampQuerySet, 0, 2, resolveBuffer, 0 );
|
|
encoder.copyBufferToBuffer( resolveBuffer, 0, resultBuffer, 0, size );
|
|
encoder.copyBufferToBuffer( resolveBuffer, 0, resultBuffer, 0, size );
|
|
|
|
|
|
- renderContextData.currentTimestampQueryBuffer = resultBuffer;
|
|
|
|
-
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- async resolveTimestampAsync(renderContext, type = 'render') {
|
|
|
|
- if (!this.hasFeature(GPUFeatureName.TimestampQuery) || !this.trackTimestamp) return;
|
|
|
|
|
|
+ async resolveTimestampAsync( renderContext, type = 'render' ) {
|
|
|
|
+
|
|
|
|
+ if ( ! this.hasFeature( GPUFeatureName.TimestampQuery ) || ! this.trackTimestamp ) return;
|
|
|
|
|
|
const renderContextData = this.get(renderContext);
|
|
const renderContextData = this.get(renderContext);
|
|
- const { currentTimestampQueryBuffer } = renderContextData;
|
|
|
|
-
|
|
|
|
- if (currentTimestampQueryBuffer === undefined) return;
|
|
|
|
-
|
|
|
|
- const buffer = currentTimestampQueryBuffer;
|
|
|
|
-
|
|
|
|
- try {
|
|
|
|
- await buffer.mapAsync(GPUMapMode.READ);
|
|
|
|
- const times = new BigUint64Array(buffer.getMappedRange());
|
|
|
|
- const duration = Number(times[1] - times[0]) / 1000000;
|
|
|
|
- this.renderer.info.updateTimestamp(type, duration);
|
|
|
|
- } catch (error) {
|
|
|
|
- console.error(`Error mapping buffer: ${error}`);
|
|
|
|
- // Optionally handle the error, e.g., re-queue the buffer or skip it
|
|
|
|
- } finally {
|
|
|
|
- buffer.unmap();
|
|
|
|
- }
|
|
|
|
|
|
+
|
|
|
|
+ if ( renderContextData.currentTimestampQueryBuffers === undefined ) return;
|
|
|
|
+
|
|
|
|
+ const { resultBuffer, isMappingPending } = renderContextData.currentTimestampQueryBuffers;
|
|
|
|
+
|
|
|
|
+ if ( isMappingPending === true ) return;
|
|
|
|
+
|
|
|
|
+ renderContextData.currentTimestampQueryBuffers.isMappingPending = true;
|
|
|
|
+
|
|
|
|
+ await resultBuffer.mapAsync( GPUMapMode.READ );
|
|
|
|
+
|
|
|
|
+ const times = new BigUint64Array( resultBuffer.getMappedRange() );
|
|
|
|
+ const duration = Number( times[ 1 ] - times[ 0 ] ) / 1000000;
|
|
|
|
+
|
|
|
|
+ this.renderer.info.updateTimestamp( type, duration );
|
|
|
|
+ resultBuffer.unmap();
|
|
|
|
+
|
|
|
|
+ renderContextData.currentTimestampQueryBuffers.isMappingPending = false;
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|