Stopping render loop and then immediately running it again causes double frames

Hello,
I suspect it’s an edge case scenario, but I’ll still give it a try.

In our code there happened a situation when stopRenderLoop and runRenderLoop were called within the same JS event loop, i.e. almost immediately one after another:

engine.stopRenderLoop(renderSceneFunction);
// some synchronous code
engine.runRenderLoop(renderSceneFunction);

This caused renderSceneFunction to be called twice per frame, i.e. the “first” render loop wasn’t actually stopped.

Here’s a PG,

where render function is called N times in 1 second of rendering (renderCount variable),
but if you comment out the stopRenderLoop/runRenderLoop calls it becomes ~ N/2.

I think the change was introduced here Cancel any pending animation frames on stopRenderLoop by carolhmj · Pull Request #14102 · BabylonJS/Babylon.js · GitHub (v6.14.2).
The reason is that _renderLoop and runRenderLoop methods both schedule another frame in this particular case:

_renderLoop() {
    // ...
    someRenderFunction();
        // inside `renderFunction` there's a call to `stopRenderLoop`:
        engine.stopRenderLoop(someRenderFunction);
            // inside stopRenderLoop this flag is reset
            this._renderingQueueLaunched = false;
            // and _activeRenderLoops array is emptied
            this._activeRenderLoops.splice(/*...*/);
        // some synchronous code here, then still inside `renderFunction` render loop is resumed
        engine.runRenderLoop(someRenderFunction);
            // inside this function _activeRenderLoops array is filled
            this._activeRenderLoops.push(renderFunction);
            // and new frame is scheduled
            this._frameHandler = this._queueNewFrame(/*...*/);
    // END of `someRenderFunction`
    // but this _renderLoop isn't over yet, it now checks for _activeRenderLoops which is not empty anymore
    if (this._activeRenderLoops.length > 0)
        // and then also schedules another frame
        this._frameHandler = this._queueNewFrame(/*...*/);

Previously this._renderingQueueLaunched wasn’t set to false by stopRenderLoop so new frame was only scheduled once.

I’d appreciate any input on that.

Thank you :pray:

1 Like

I am working on it ASAP, sorry you did not have an answer before.

1 Like

Will be fixed by fix cancel render loop by sebavan · Pull Request #14868 · BabylonJS/Babylon.js · GitHub but need a bit more checks

2 Likes

Thank you very much :pray: