How on-demand rendering can improve mobile performance

February 7, 2020 David Rogers

 

What is on-demand rendering?

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.

Why would I use on-demand rendering?

Here are some example scenarios of when you may want to lower the frame rate:

  1. Menus (e.g., the application entry point or a pause menu): Menus tend to be relatively simple Scenes and as such do not need to render at full speed. If you render menus at a lower frame rate, you will still receive input during a frame that is not rendered, allowing you to reduce power consumption and to keep the device temperature from rising to a point where the CPU frequency may be throttled, while keeping a smooth UI interaction.
  2. Turn-based games (e.g., chess): Turn-based games have periods of low activity when users think about their next move or wait for other users to make their move. During such times, you can lower the frame rate to prevent unnecessary power usage and prolong the battery life.
  3. Static content: You can lower the frame rate in applications where the content is static for much of the time, such as automotive user interface (UI).
  4. Performance management: If you want to manage power usage and device thermals to maximize battery life and prevent CPU throttling, particularly if you are using the Adaptive Performance package, you can adjust the rendering speed.
  5. Machine learning or AI applications: Reducing the amount of work the CPU devotes to rendering may give you a little bit of a performance boost for the heavy processing that is the central focus of your application.

Where is it supported?

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).

How do I use on-demand rendering?

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.

What else do I need to know?

  • Even though frames will not be rendered as often, events will be sent to scripts at a normal pace. This means that you may receive input during a frame that is not rendered. To prevent the appearance of input lag we recommend that you call OnDemandRendering.renderFrameInterval = 1 for the duration of the input to keep buttons, movement, etc. responsive.
  • Situations that are very heavy on scripting, physics, animation, etc. but are not rendering will not benefit from using on-demand rendering. The results may appear choppy and with negligible reduction in CPU and power usage.

Example

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.

Are you using on-demand rendering?

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.

Previous Article
Higher fidelity and smoother frame rates with Adaptive Performance
Higher fidelity and smoother frame rates with Adaptive Performance

See how Unity makes it easier to develop performant mobile games.

No More Articles