Skip to content

Commit

Permalink
WebGPURenderer: Add Timestamp Queries WebGL fallback support (#27870)
Browse files Browse the repository at this point in the history
* add timestamp fallback support through EXT_disjoint_timer_query_webgl2

* Decrement i to ensure the next element is not skipped
  • Loading branch information
RenaudRohlinger authored Mar 6, 2024
1 parent a3bf320 commit ec8d19b
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 6 deletions.
2 changes: 1 addition & 1 deletion examples/jsm/renderers/common/Renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -889,6 +889,7 @@ class Renderer {
const previousRenderId = nodeFrame.renderId;

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

this.info.calls ++;
this.info.compute.calls ++;
Expand All @@ -897,7 +898,6 @@ class Renderer {
nodeFrame.renderId = this.info.calls;

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

const backend = this.backend;
const pipelines = this._pipelines;
Expand Down
86 changes: 84 additions & 2 deletions examples/jsm/renderers/webgl/WebGLBackend.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ class WebGLBackend extends Backend {
this.vaoCache = {};
this.transformFeedbackCache = {};
this.discard = false;
this.trackTimestamp = ( parameters.trackTimestamp === true );

this.extensions.get( 'EXT_color_buffer_float' );
this.disjoint = this.extensions.get( 'EXT_disjoint_timer_query_webgl2' );
this.parallel = this.extensions.get( 'KHR_parallel_shader_compile' );
this._currentContext = null;

Expand All @@ -64,6 +66,81 @@ class WebGLBackend extends Backend {

}


initTimestampQuery( renderContext ) {

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

const renderContextData = this.get( renderContext );

if ( renderContextData.activeQuery ) {

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

}

renderContextData.activeQuery = this.gl.createQuery();
if ( renderContextData.activeQuery !== null ) {

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

}


}

// timestamp utils

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;

}

}

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 ++ ) {

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 ) {

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

}

}

}

getContext() {

return this.gl;
Expand All @@ -78,6 +155,7 @@ class WebGLBackend extends Backend {
//

//
this.initTimestampQuery( renderContext );

renderContextData.previousContext = this._currentContext;
this._currentContext = renderContext;
Expand Down Expand Up @@ -219,6 +297,7 @@ class WebGLBackend extends Backend {

}

this.prepareTimestampBuffer( renderContext );

}

Expand Down Expand Up @@ -379,11 +458,12 @@ class WebGLBackend extends Backend {

}

beginCompute( /*computeGroup*/ ) {
beginCompute( computeGroup ) {

const gl = this.gl;

gl.bindFramebuffer( gl.FRAMEBUFFER, null );
this.initTimestampQuery( computeGroup );

}

Expand Down Expand Up @@ -456,14 +536,16 @@ class WebGLBackend extends Backend {

}

finishCompute( /*computeGroup*/ ) {
finishCompute( computeGroup ) {

const gl = this.gl;

this.discard = false;

gl.disable( gl.RASTERIZER_DISCARD );

this.prepareTimestampBuffer( computeGroup );

}

draw( renderObject, info ) {
Expand Down
1 change: 1 addition & 0 deletions examples/jsm/renderers/webgl/utils/WebGLConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ export const GLFeatureName = {
'WEBKIT_WEBGL_compressed_texture_pvrtc': 'texture-compression-pvrtc',
'WEBGL_compressed_texture_s3tc': 'texture-compression-bc',
'EXT_texture_compression_bptc': 'texture-compression-bptc',
'EXT_disjoint_timer_query_webgl2': 'timestamp-query',

};
4 changes: 2 additions & 2 deletions examples/webgpu_compute_particles.html
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,8 @@

timestamps.innerHTML = `
Compute ${renderer.info.compute.computeCalls} pass in ${renderer.info.timestamp.compute}ms<br>
Draw ${renderer.info.render.drawCalls} pass in ${renderer.info.timestamp.render}ms`;
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`;

}

Expand Down
38 changes: 37 additions & 1 deletion examples/webgpu_storage_buffer.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,32 @@
<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a>
<br />This example demonstrate the fetch of external element from a StorageBuffer.
<br /> Left canvas is using WebGPU Backend, right canvas is WebGL Backend.
<div id="timestamps" style="
position: absolute;
top: 60px;
left: 0;
padding: 10px;
background: rgba( 0, 0, 0, 0.5 );
color: #fff;
font-family: monospace;
font-size: 12px;
line-height: 1.5;
pointer-events: none;
text-align: left;
"></div>
<div id="timestamps_webgl" style="
position: absolute;
top: 60px;
right: 0;
padding: 10px;
background: rgba( 0, 0, 0, 0.5 );
color: #fff;
font-family: monospace;
font-size: 12px;
line-height: 1.5;
pointer-events: none;
text-align: left;
"></div>
</div>

<script type="importmap">
Expand All @@ -31,6 +57,11 @@
import WebGPURenderer from 'three/addons/renderers/webgpu/WebGPURenderer.js';
import StorageInstancedBufferAttribute from 'three/addons/renderers/common/StorageInstancedBufferAttribute.js';

const timestamps = {
webgpu: document.getElementById( 'timestamps' ),
webgl: document.getElementById( 'timestamps_webgl' )
};

// WebGPU Backend
init();

Expand Down Expand Up @@ -153,7 +184,7 @@
const plane = new THREE.Mesh( new THREE.PlaneGeometry( 1, 1 ), material );
scene.add( plane );

const renderer = new WebGPURenderer( { antialias: false, forceWebGL: forceWebGL } );
const renderer = new WebGPURenderer( { antialias: false, forceWebGL: forceWebGL, trackTimestamp: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth / 2, window.innerHeight );

Expand Down Expand Up @@ -184,6 +215,11 @@
await renderer.computeAsync( compute );
await renderer.renderAsync( scene, camera );

timestamps[ forceWebGL ? 'webgl' : 'webgpu' ].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`;

setTimeout( stepAnimation, 1000 );

};
Expand Down

0 comments on commit ec8d19b

Please sign in to comment.