Scene performance using UniversalCamera quickly deteriorates and eventually crashes when gamepad attached

This seems to be a bug in Babylon, hope any of you can validate and reproduce…

When using the UniversalCamera with camera.attachControl(...) set and a gamepad attached (I’m using a Thrustmaster HOTAS Warthog, but any gamepad should work) , the FPS will eventually start to drop (after about 1 minute on my MBP M1 Max).

Repro: Babylon.js Playground (make sure to wait at least 1-2 minutes and check the FPS counter in the bottom right)

Screenshot 2024-10-30 at 16.17.48

From looking at the source code, I think the reason is that _checkGamepadStatus() is being called twice on every frame:
Once in GamepadSceneComponent._beforeCameraUpdate() and then again in `GamepadManager._checkGamepadsStatus().

This wouldn’t be so bad if it was called twice on every frame, but since _checkGamepadsStatus() adds itself to run again on the next frame, this means that every subsequent frame _checkGamepadsStatus() is being called one additional time. After ten seconds at 60hz, that means that frame 601 would be calling the same function 602 times in a single frame, causing serious slowdown.

Can anyone verify?

Interesting catch. I wonder why it hasn’t popped up so far.

Yes, it seems like the recursive call in the _checkGamepadsStatus is not really needed. Watch to submit a PR?

Thanks for verifying @RaananW!

I’d be happy to submit a PR… but before I do that I wanted to understand a bit better why this is happening now, even though we’ve been using Babylon with a Gamepad attached for several years now with no issues.

Since you understand the Babylon internals betters, could it be that this commit caused the doubling up of calls (related issue)? Maybe the _scene check existed to prevent it in the first place?

If that’s the case, would removing the recursive call effectively revert #13798?

Looking at my unanswered question here - GamepadManager: Fixed issue where providing scene object to constructor would prevent status updates by PolygonalSun · Pull Request #13798 · BabylonJS/Babylon.js · GitHub , I still wonder if there is a better way to do that.

Following the entire process, the scene component is only added once scene.gamepadManager is referenced. Until then the scene component is not registered. So if you just create a gamepad manager yourself, it is possible that scene will be undefined. I guess it would make more sense to remove the scene component’s loop and leave the other one. No reason to do both. I can try digging deeper tomorrow, but this is most certainly an issue.

Right, exactly.

So then I’d be more than happy to open a PR to remove the _checkGamepadsStatus() call in gamepadSceneComponent (Babylon.js/packages/dev/core/src/Gamepads/gamepadSceneComponent.ts at master · BabylonJS/Babylon.js · GitHub). However, that raises another question… since that scene component doesn’t really seem to do anything else, does it make the entire component obsolete?

I’ll wait for you to analyze the situation, but definitely happy to contribute in whatever direction you think is best to solve this.

we can’t remove the component due to back-compat, but we can most certainly remove the _checkGamepadsStatus call in it. I’m still trying to follow up the history of this to be sure we are not breaking anything, but I am 99% sure this would solve the entire issue while keeping it working as expected.

Sounds good! I opened a PR here: fix(Gamepads): duplicate gamepad status check causing each frame to double up calls by foxxyz · Pull Request #15761 · BabylonJS/Babylon.js · GitHub

2 Likes