It’s not always desirable to render a project at the highest frame rate possible, for a variety of reasons, especially on mobile platforms. Historically, Unity developers have used Application.targetFrameRate or Vsync count to throttle the rendering speed of Unity. This approach impacts not just rendering but the frequency at which every part of Unity runs. The new on-demand rendering API allows you to decouple the rendering frequency from the player loop frequency.
On-demand rendering allows you to skip rendering frames while still running the rest of the player loop at a high frequency. This can be especially useful on mobile; bypassing rendering can bring significant performance and power savings, while still allowing the application to be responsive to touch events.
Here are some example scenarios of when you may want to lower the frame rate:
Everywhere! On-demand rendering works on Unity 2019.3 with every supported platform (see the system requirements) and rendering API (built-in render pipeline, Universal Render Pipeline and High Definition Render Pipeline).
The on-demand rendering API consists of only three properties in the namespace UnityEngine.Rendering.
OnDemandRendering.renderFrameInterval
This is the most important part. It allows you to get or set the render frame interval, which is a dividing factor of Application.targetFrameRate or QualitySettings.vSyncCount, to define the new frame rate. For example, if you set Application.targetFrameRate to 60 and OnDemandRendering.renderFrameInterval to 2, only every other frame will render, yielding a frame rate of 30 fps.
OnDemandRendering.effectiveFrameRate
This property gives you an estimate of the frame rate that your application will render at. The estimate is determined using the values of OnDemandRendering.renderFrameInterval, Application.targetFrameRate, QualitySettings.vSyncCount and the display refresh rate. But bear in mind that this is an estimate and not a guarantee; your application may render more slowly if the CPU is bogged down by work from other things such as scripts, physics, networking, etc.
OnDemandRendering.willThisFrameRender
This simply tells you if the current frame will be rendered to the screen. You can use non-rendered frames to do some additional CPU-intensive work such as heavy math operations, loading assets or spawning prefabs.
Here is a simple example showing how on-demand rendering could be used in a menu to render at 20 fps unless there is input.
using UnityEngine; using UnityEngine.Rendering; public class Menu : MonoBehaviour { // Start is called before the first frame update void Start() { QualitySettings.vSyncCount = 0; Application.targetFrameRate = 60; // When the Menu starts, set the rendering to target 20fps OnDemandRendering.renderFrameInterval = 3; } // Update is called once per frame void Update() { if (Input.GetMouseButton(0) || (Input.touchCount > 0)) { // If the mouse button or touch detected render at 60 FPS (every frame). OnDemandRendering.renderFrameInterval = 1; } else { // If there is no mouse and no touch input then we can go back to 20 FPS (every 3 frames). OnDemandRendering.renderFrameInterval = 3; } } }
Here is an example project demonstrating how on-demand rendering can be used in a variety of situations.
Let us know in the forums how on-demand rendering is working for you. We’ve tested it on Windows, macOS, WebGL, iOS, and Android, both in the Unity Editor and with Standalone players, but we’re always open to more feedback.
Is this article helpful for you?
Thank you for your feedback!