Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Renderer: Call ID #27101

Merged
merged 12 commits into from
Nov 4, 2023
31 changes: 10 additions & 21 deletions examples/jsm/renderers/common/Animation.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,39 @@
class Animation {

constructor() {
constructor( nodes, info ) {

this.nodes = null;
this.nodes = nodes;
this.info = info;

this.animationLoop = null;
this.requestId = null;

this.isAnimating = false;

this.context = self;
this._init();

}

start() {

if ( this.isAnimating === true || this.animationLoop === null || this.nodes === null ) return;

this.isAnimating = true;
_init() {

const update = ( time, frame ) => {

this.requestId = self.requestAnimationFrame( update );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually... is this correct that this function is called every frame using rAF even if animationLoop isn't set? /ping @sunag

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was intentional, nodeFrame.update() cannot be called in render() to work correctly, this fix cases where no animationLoop was added.

Copy link
Contributor

@LeviPesin LeviPesin Jan 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why it cannot be called there?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to know what frame we are in to trigger NodeUpdateType.FRAME frame events, otherwise we will only have NodeUpdateType.RENDER call events. The frame counter makes sure which frame is in order to avoid duplicate events.


this.nodes.nodeFrame.update();

this.animationLoop( time, frame );
this.info.frame = this.nodes.nodeFrame.frameId;

if ( this.animationLoop !== null ) this.animationLoop( time, frame );

};

this.requestId = self.requestAnimationFrame( update );
update();

}

stop() {
dispose() {

self.cancelAnimationFrame( this.requestId );

this.isAnimating = false;

}

setAnimationLoop( callback ) {
Expand All @@ -47,12 +42,6 @@ class Animation {

}

setNodes( nodes ) {

this.nodes = nodes;

}

}

export default Animation;
6 changes: 3 additions & 3 deletions examples/jsm/renderers/common/Bindings.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,15 +101,15 @@ class Bindings extends DataMap {
const { backend } = this;

const updateMap = this.updateMap;
const frame = this.info.render.frame;
const callId = this.info.calls;

let needsBindingsUpdate = false;

// iterate over all bindings and check if buffer updates or a new binding group is required

for ( const binding of bindings ) {

const isUpdated = updateMap.get( binding ) === frame;
const isUpdated = updateMap.get( binding ) === callId;

if ( isUpdated ) continue;

Expand Down Expand Up @@ -137,7 +137,7 @@ class Bindings extends DataMap {

}

updateMap.set( binding, frame );
updateMap.set( binding, callId );

}

Expand Down
8 changes: 4 additions & 4 deletions examples/jsm/renderers/common/Geometries.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class Geometries extends DataMap {
this.info = info;

this.wireframes = new WeakMap();
this.attributeFrame = new WeakMap();
this.attributeCall = new WeakMap();

}

Expand Down Expand Up @@ -162,13 +162,13 @@ class Geometries extends DataMap {

updateAttribute( attribute, type ) {

const frame = this.info.render.frame;
const callId = this.info.render.calls;

if ( this.attributeFrame.get( attribute ) !== frame ) {
if ( this.attributeCall.get( attribute ) !== callId ) {

this.attributes.update( attribute, type );

this.attributeFrame.set( attribute, frame );
this.attributeCall.set( attribute, callId );

}

Expand Down
14 changes: 12 additions & 2 deletions examples/jsm/renderers/common/Info.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,21 @@ class Info {

this.autoReset = true;

this.frame = 0;
this.calls = 0;

this.render = {
frame: 0,
calls: 0,
drawCalls: 0,
triangles: 0,
points: 0,
lines: 0
};

this.compute = {
calls: 0
};

this.memory = {
geometries: 0,
textures: 0
Expand Down Expand Up @@ -60,7 +67,10 @@ class Info {

this.reset();

this.render.frame = 0;
this.calls = 0;

this.render.calls = 0;
this.compute.calls = 0;

this.memory.geometries = 0;
this.memory.textures = 0;
Expand Down
40 changes: 24 additions & 16 deletions examples/jsm/renderers/common/Renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class Renderer {
this._attributes = null;
this._geometries = null;
this._nodes = null;
this._animation = null;
this._bindings = null;
this._objects = null;
this._pipelines = null;
Expand All @@ -70,8 +71,6 @@ class Renderer {
this._textures = null;
this._background = null;

this._animation = new Animation();

this._currentRenderContext = null;
this._lastRenderContext = null;

Expand Down Expand Up @@ -136,6 +135,7 @@ class Renderer {
}

this._nodes = new Nodes( this, backend );
this._animation = new Animation( this._nodes, this.info );
this._attributes = new Attributes( backend );
this._background = new Background( this, this._nodes );
this._geometries = new Geometries( this._attributes, this.info );
Expand All @@ -148,9 +148,6 @@ class Renderer {

//

this._animation.setNodes( this._nodes );
this._animation.start();

this._initialized = true;

resolve();
Expand Down Expand Up @@ -197,8 +194,13 @@ class Renderer {
this._currentRenderContext = renderContext;
this._currentRenderObjectFunction = this._renderObjectFunction || this.renderObject;

//

nodeFrame.renderId ++;

this.info.calls ++;
this.info.render.calls ++;

//

const coordinateSystem = this.coordinateSystem;
Expand All @@ -213,16 +215,12 @@ class Renderer {

//

if ( this._animation.isAnimating === false ) nodeFrame.update();

if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld();

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

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

this.info.render.frame ++;

//

let viewport = this._viewport;
Expand Down Expand Up @@ -361,15 +359,11 @@ class Renderer {

}

setAnimationLoop( callback ) {

if ( this._initialized === false ) this.init();
async setAnimationLoop( callback ) {

const animation = this._animation;

animation.setAnimationLoop( callback );
if ( this._initialized === false ) await this.init();

( callback === null ) ? animation.stop() : animation.start();
this._animation.setAnimationLoop( callback );

}

Expand Down Expand Up @@ -621,6 +615,7 @@ class Renderer {

this.info.dispose();

this._animation.dispose();
this._objects.dispose();
this._properties.dispose();
this._pipelines.dispose();
Expand Down Expand Up @@ -665,12 +660,25 @@ class Renderer {

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

//

this.info.calls ++;
this.info.compute.calls ++;

//

const backend = this.backend;
const pipelines = this._pipelines;
const bindings = this._bindings;
const nodes = this._nodes;
const computeList = Array.isArray( computeNodes ) ? computeNodes : [ computeNodes ];

if ( computeList[ 0 ] === undefined || computeList[ 0 ].isComputeNode !== true ) {

throw new Error( 'THREE.Renderer: .compute() expects a ComputeNode.' );

}

backend.beginCompute( computeNodes );

for ( const computeNode of computeList ) {
Expand Down
12 changes: 6 additions & 6 deletions examples/jsm/renderers/common/nodes/Nodes.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class Nodes extends DataMap {
this.backend = backend;
this.nodeFrame = new NodeFrame();
this.nodeBuilderCache = new Map();
this.frameHashCache = new ChainMap();
this.callHashCache = new ChainMap();

}

Expand Down Expand Up @@ -148,11 +148,11 @@ class Nodes extends DataMap {
getCacheKey( scene, lightsNode ) {

const chain = [ scene, lightsNode ];
const frameId = this.nodeFrame.frameId;
const callId = this.renderer.info.calls;

let cacheKeyData = this.frameHashCache.get( chain );
let cacheKeyData = this.callHashCache.get( chain );

if ( cacheKeyData === undefined || cacheKeyData.frameId !== frameId ) {
if ( cacheKeyData === undefined || cacheKeyData.callId !== callId ) {

const environmentNode = this.getEnvironmentNode( scene );
const fogNode = this.getFogNode( scene );
Expand All @@ -166,11 +166,11 @@ class Nodes extends DataMap {
if ( toneMappingNode ) cacheKey.push( toneMappingNode.getCacheKey() );

cacheKeyData = {
frameId,
callId,
cacheKey: cacheKey.join( ',' )
};

this.frameHashCache.set( chain, cacheKeyData );
this.callHashCache.set( chain, cacheKeyData );

}

Expand Down
Binary file modified examples/screenshots/webgpu_instance_points.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/screenshots/webgpu_lines_fat.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/screenshots/webgpu_particles.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 1 addition & 3 deletions examples/webgpu_clearcoat.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
let group;

init();
animate();

function init() {

Expand Down Expand Up @@ -187,6 +186,7 @@
renderer = new WebGPURenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setAnimationLoop( animate );
container.appendChild( renderer.domElement );

//
Expand Down Expand Up @@ -227,8 +227,6 @@

function animate() {

requestAnimationFrame( animate );

render();

stats.update();
Expand Down
11 changes: 9 additions & 2 deletions examples/webgpu_compute_texture_pingpong.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
let pingTexture, pongTexture;
let material;
let phase = true;
let lastUpdate = - 1;

const seed = uniform( new THREE.Vector2() );

init();
Expand Down Expand Up @@ -184,14 +186,19 @@

function render() {

// reset every 200 frames
const time = performance.now();
const seconds = Math.floor( time / 1000 );

// reset every second

if ( renderer.info.render.frame % 200 === 0 ) {
if ( phase && seconds !== lastUpdate ) {

seed.value.set( Math.random(), Math.random() );

renderer.compute( computeInitNode );

lastUpdate = seconds;

}

// compute step
Expand Down
4 changes: 1 addition & 3 deletions examples/webgpu_instance_points.html
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
let insetHeight;

init();
animate();

function init() {

Expand All @@ -69,6 +68,7 @@
renderer = new WebGPURenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setAnimationLoop( animate );
document.body.appendChild( renderer.domElement );

scene = new THREE.Scene();
Expand Down Expand Up @@ -161,8 +161,6 @@

function animate() {

requestAnimationFrame( animate );

stats.update();

// main scene
Expand Down