Rendering without using requestAnimationFrame for the main loop?

Hi there,

We made a webgl build using 5.3.0, and we are getting this error when our game loads up. It doesn’t crash our game, but our frame rate definitely is lowered.

Looks like you are rendering without using requestAnimationFrame for the main loop. You should use 0 for the frame rate in emscripten_set_main_loop in order to use requestAnimationFrame, as that can greatly improve your frame rates!

Anyone has a clue as to how to fix this?

Thank you.

1 Like

Are you using Application.targetFrameRate to lower the FPS? If yes, then this message is expected.

6 Likes

Yep, we added #if !UNITY_WEBGL for our FPS lock, and now the error is gone. Thank you!

3 Likes

Is there any actual harm setting the application framerate for WebGL apps? If we only want our game to run at (for example) 30fps will this cause issues? (for WebGL builds in general)

6 Likes

I also got this because I set the framerate through a script for WebGL as we’re targeting different platforms.
So why is this an error? Is this doing any harm??

1 Like

The backstory here is that in web browsers, there are two JavaScript APIs that could be used to implement animation: requestAnimationFrame() and setTimeout() (there’s also setInterval() which is essentially the same as setTimeout(), and also setImmediate(), which unfortunately had trouble ever getting standardized).

From the perspective of the browsers, requestAnimationFrame() is superior in comparison to setTimeout() when implementing animation, since requestAnimationFrame() hints towards the browser that the update ticks intend to perform continuously animated rendering for two reasons:

  • requestAnimationFrame() firing rate can match display’s refresh rate (30Hz/60Hz/90Hz/120Hz/144Hz are all possible, depending on what kind of gaming display one is running on, though last I checked, only Firefox implemented these rates, Chrome using fixed 60fps even if desktop was set to 120Hz). With setTimeout() one cannot know the display refresh rate, and has to guess/choose fixed 60Hz.
  • rAF() calls are also synced to display’s vsync interval, giving smoother animation since there is a smaller chance that vsync intervals would be missed. setTimeout() is used on the web for arbitrary/general timers, and browser cannot deduce that those would need to be vsync locked.
  • rAF() calls hint to the browser that the callbacks are about rendering animation, so when the tab is not visible, browsers can optimize power usage e.g. by stopping rAF() callbacks until tab comes back to foreground. In general, rAF()s do not run when page is on the background or browser is minimized.

In Unity, if Application FPS is set to 60, then rAF() is used to render. If any other FPS setting is used, then setTimeout() ticks are used to implement the custom FPS timer, since rAF() only works for 60fps.

However because of the way how setTimeout()s are not scheduled with respect to display vsync like rAF() is, using setTimeout() to animate results in stuttering animation in browser. This is what the message "You should use 0 for the frame rate in emscripten_set_main_loop in order to use requestAnimationFrame, as that can greatly improve your frame rates!" is about. The message originates from the Emscripten compiler that Unity uses, so it unfortunately reads a bit off from the perspective of Unity project settings UIs.

If you want to render at a lower rate than 60fps, then there is no harm about this message. If you want to render at native display refresh rate, then you should set the FPS setting to 60. Using a value like 30 should be ok, although using a value like 59fps will probably yield horribly stuttering animation compared to 60.

As a sidenote, there may be a possibility to get smoother animation rates from rAF() by decimating the calls, i.e. 60fps/2=30fps, 60fps/3=20fps, 60fps/4=15fps… though this has not been extensively experimented with yet. (If you’d like, you can manually intercept requestAnimationFrame() implementation in JS code before the Unity app is loaded to experiment with this kind of decimation)

11 Likes

Thats a detailed answer jukka. So what would be the BEST (getting the highest vsynced FPS) value to set for target frame rate in Unity for a webgl build?
This page from manual suggests -1:
https://docs.unity3d.com/Manual/webgl-performance.html
You seem to say 60…

1 Like

@jukka_j any answer on what the recommended setting for webgl builds? -1 or 60?

2 Likes

The problem with 60fps for webgl is PCs will punch up their GPU fans (!) which is unusual for browser content and indeed I am sure Safari will complain whatever (Apple hates web apps).
30 fps seems to lead to choppy frame rates in chrome though I need more testing.

A solution for easing browser-strain would be good…

Getting red messages in console logs isn’t ideal…

3 Likes

Waiting for the canonical answer to this for webgl builds in the latest versions of Unity.

Should we use:
Application.targetFrameRate = 0
Application.targetFrameRate = 60
Application.targetFrameRate = -1

or avoid it altogether?

2 Likes

The default setting Application.targetFrameRate = -1 is the best, it will give vsynced 60hz updates as long as the performance is adequate.

4 Likes