Skip to content

Commit

Permalink
WebGPURenderer: Improve Infos logic (#27889)
Browse files Browse the repository at this point in the history
* improve info system on threejs

* cleanup and add stats-gl in example external

* fix bot warning

* remove unused dom
  • Loading branch information
RenaudRohlinger authored Mar 13, 2024
1 parent 93be183 commit f4a695c
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 95 deletions.
2 changes: 2 additions & 0 deletions examples/jsm/renderers/common/Animation.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ class Animation {

this.requestId = self.requestAnimationFrame( update );

if ( this.info.autoReset === true ) this.info.reset();

this.nodes.nodeFrame.update();

this.info.frame = this.nodes.nodeFrame.frameId;
Expand Down
30 changes: 11 additions & 19 deletions examples/jsm/renderers/common/Info.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,21 @@ class Info {
drawCalls: 0,
triangles: 0,
points: 0,
lines: 0
lines: 0,
timestamp: 0
};

this.compute = {
calls: 0,
computeCalls: 0
computeCalls: 0,
timestamp: 0
};

this.memory = {
geometries: 0,
textures: 0
};

this.timestamp = {
compute: 0,
render: 0
};

}

update( object, count, instanceCount ) {
Expand Down Expand Up @@ -62,26 +59,21 @@ class Info {

updateTimestamp( type, time ) {

this.timestamp[ type ] += time;

}

resetCompute() {

this.compute.computeCalls = 0;

this.timestamp.compute = 0;
this[ type ].timestamp += time;

}

reset() {

this.render.drawCalls = 0;
this.compute.computeCalls = 0;

this.render.triangles = 0;
this.render.points = 0;
this.render.lines = 0;

this.timestamp.render = 0;
this.render.timestamp = 0;
this.compute.timestamp = 0;

}

Expand All @@ -94,8 +86,8 @@ class Info {
this.render.calls = 0;
this.compute.calls = 0;

this.timestamp.compute = 0;
this.timestamp.render = 0;
this.render.timestamp = 0;
this.compute.timestamp = 0;
this.memory.geometries = 0;
this.memory.textures = 0;

Expand Down
7 changes: 2 additions & 5 deletions examples/jsm/renderers/common/Renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -312,9 +312,7 @@ class Renderer {

if ( this._initialized === false ) await this.init();

const renderContext = this._renderScene( scene, camera );

await this.backend.resolveTimestampAsync( renderContext, 'render' );
this._renderScene( scene, camera );

}

Expand Down Expand Up @@ -379,7 +377,6 @@ class Renderer {

if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld();

if ( this.info.autoReset === true ) this.info.reset();

//

Expand Down Expand Up @@ -509,6 +506,7 @@ class Renderer {
sceneRef.onAfterRender( this, scene, camera, renderTarget );

//
this.backend.resolveTimestampAsync( renderContext, 'render' );

return renderContext;

Expand Down Expand Up @@ -898,7 +896,6 @@ class Renderer {
const previousRenderId = nodeFrame.renderId;

//
if ( this.info.autoReset === true ) this.info.resetCompute();

this.info.calls ++;
this.info.compute.calls ++;
Expand Down
53 changes: 34 additions & 19 deletions examples/jsm/renderers/webgl/WebGLBackend.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,66 +73,81 @@ class WebGLBackend extends Backend {

const renderContextData = this.get( renderContext );

if ( this.queryRunning ) {

if ( ! renderContextData.queryQueue ) renderContextData.queryQueue = [];
renderContextData.queryQueue.push( renderContext );
return;

}

if ( renderContextData.activeQuery ) {

// End the previous query if it's still active
this.gl.endQuery( this.disjoint.TIME_ELAPSED_EXT );
this.gl.endQuery( this.disjoint.TIME_ELAPSED_EXT );
renderContextData.activeQuery = null;

}

renderContextData.activeQuery = this.gl.createQuery();

if ( renderContextData.activeQuery !== null ) {

this.gl.beginQuery( this.disjoint.TIME_ELAPSED_EXT, renderContextData.activeQuery );
this.gl.beginQuery( this.disjoint.TIME_ELAPSED_EXT, renderContextData.activeQuery );
this.queryRunning = true;

}


}

// timestamp utils

prepareTimestampBuffer( renderContext ) {
prepareTimestampBuffer( renderContext ) {

if ( ! this.disjoint || ! this.trackTimestamp ) return;

const renderContextData = this.get( renderContext );

if ( renderContextData.activeQuery ) {

this.gl.endQuery( this.disjoint.TIME_ELAPSED_EXT );
// Add the active query to the gpuQueries array and reset it
if ( renderContextData.gpuQueries === undefined ) renderContextData.gpuQueries = [];
renderContextData.gpuQueries.push( { query: renderContextData.activeQuery } );
renderContextData.activeQuery = null;
this.gl.endQuery( this.disjoint.TIME_ELAPSED_EXT );

if ( ! renderContextData.gpuQueries ) renderContextData.gpuQueries = [];
renderContextData.gpuQueries.push( { query: renderContextData.activeQuery } );
renderContextData.activeQuery = null;
this.queryRunning = false;

if ( renderContextData.queryQueue && renderContextData.queryQueue.length > 0 ) {

const nextRenderContext = renderContextData.queryQueue.shift();
this.initTimestampQuery( nextRenderContext );

}

}

}

async resolveTimestampAsync( renderContext, type = 'render' ) {
async resolveTimestampAsync( renderContext, type = 'render' ) {

if ( ! this.disjoint || ! this.trackTimestamp ) return;

const renderContextData = this.get( renderContext );

for ( let i = 0; i < renderContextData.gpuQueries.length; i ++ ) {
if ( ! renderContextData.gpuQueries ) renderContextData.gpuQueries = [];

const queryInfo = renderContextData.gpuQueries[ i ];
for ( let i = 0; i < renderContextData.gpuQueries.length; i ++ ) {

const available = this.gl.getQueryParameter( queryInfo.query, this.gl.QUERY_RESULT_AVAILABLE );
const disjoint = this.gl.getParameter( this.disjoint.GPU_DISJOINT_EXT );
const queryInfo = renderContextData.gpuQueries[ i ];
const available = this.gl.getQueryParameter( queryInfo.query, this.gl.QUERY_RESULT_AVAILABLE );
const disjoint = this.gl.getParameter( this.disjoint.GPU_DISJOINT_EXT );

if ( available && ! disjoint ) {
if ( available && ! disjoint ) {

const elapsed = this.gl.getQueryParameter( queryInfo.query, this.gl.QUERY_RESULT );
const duration = Number( elapsed ) / 1000000; // Convert nanoseconds to milliseconds

this.gl.deleteQuery( queryInfo.query );
renderContextData.gpuQueries.splice( i, 1 ); // Remove the processed query

i --;

this.renderer.info.updateTimestamp( type, duration );

}
Expand Down
46 changes: 22 additions & 24 deletions examples/jsm/renderers/webgpu/WebGPUBackend.js
Original file line number Diff line number Diff line change
Expand Up @@ -1049,9 +1049,11 @@ class WebGPUBackend extends Backend {
beginningOfPassWriteIndex: 0, // Write timestamp in index 0 when pass begins.
endOfPassWriteIndex: 1, // Write timestamp in index 1 when pass ends.
};

Object.assign( descriptor, {
timestampWrites,
} );

renderContextData.timeStampQuerySet = timeStampQuerySet;

}
Expand Down Expand Up @@ -1084,33 +1086,29 @@ class WebGPUBackend extends Backend {

}

async resolveTimestampAsync( renderContext, type = 'render' ) {

if ( ! this.hasFeature( GPUFeatureName.TimestampQuery ) || ! this.trackTimestamp ) return;

const renderContextData = this.get( renderContext );

// handle timestamp query results

async resolveTimestampAsync(renderContext, type = 'render') {
if (!this.hasFeature(GPUFeatureName.TimestampQuery) || !this.trackTimestamp) return;

const renderContextData = this.get(renderContext);
const { currentTimestampQueryBuffer } = renderContextData;

if ( currentTimestampQueryBuffer ) {

renderContextData.currentTimestampQueryBuffer = null;

await currentTimestampQueryBuffer.mapAsync( GPUMapMode.READ );

const times = new BigUint64Array( currentTimestampQueryBuffer.getMappedRange() );

const duration = Number( times[ 1 ] - times[ 0 ] ) / 1000000;
// console.log( `Compute ${type} duration: ${Number( times[ 1 ] - times[ 0 ] ) / 1000000}ms` );
this.renderer.info.updateTimestamp( type, duration );

currentTimestampQueryBuffer.unmap();

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();
}

}


// node builder

Expand Down
1 change: 1 addition & 0 deletions examples/tags.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
"webgl_materials_modified": [ "onBeforeCompile" ],
"webgl_raycaster_bvh": [ "external", "query", "bounds", "tree", "accelerate", "performance", "community", "extension", "plugin", "library", "three-mesh-bvh" ],
"webgl_renderer_pathtracer": [ "external", "raytracing", "pathtracing", "library", "plugin", "extension", "community", "three-gpu-pathtracer", "three-mesh-bvh" ],
"webgpu_compute_particles_snow": [ "external", "webgpu", "stats-gl" ],
"webgl_shadowmap_csm": [ "cascade" ],
"webgl_shadowmap_pcss": [ "soft" ],
"webgl_simple_gi": [ "global illumination" ],
Expand Down
8 changes: 2 additions & 6 deletions examples/webgpu_compute_particles.html
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,6 @@

//

renderer.info.autoReset = false;

renderer.compute( computeInit );

// click event
Expand Down Expand Up @@ -294,8 +292,8 @@

timestamps.innerHTML = `
Compute ${renderer.info.compute.computeCalls} pass in ${renderer.info.timestamp.compute.toFixed( 6 )}ms<br>
Draw ${renderer.info.render.drawCalls} pass in ${renderer.info.timestamp.render.toFixed( 6 )}ms`;
Compute ${renderer.info.compute.computeCalls} pass in ${renderer.info.compute.timestamp.toFixed( 6 )}ms<br>
Draw ${renderer.info.render.drawCalls} pass in ${renderer.info.render.timestamp.toFixed( 6 )}ms`;

}

Expand All @@ -305,8 +303,6 @@

}

renderer.info.resetCompute();
renderer.info.reset();

}

Expand Down
Loading

0 comments on commit f4a695c

Please sign in to comment.