Set screen refresh rate on Android 11

Hello

I updated my pixel device to Android 11 and suddenly things were really ‘laggy’ and ‘stuttery’.

I use vsync to match the screen refresh rate. I can enable refresh rate overlay in my developer settings and can see that the display is running at 90hz.

In the profiler, I can see that the game is rendering at 90fps. But this is very taxing, and we frequently ‘miss the target’ and can see that Unity will have to drop to 60hz for one frame. This results in very large stutters as the game recovers.

The alternative is to disable vsync and use Application.targetFrameRate and set that to 60. But this appears really stuttery, because it is out of sync with the displays refresh rate (which is still 90hz). I can enable ‘battery saving mode’ which forces the refresh rate to 60hz and everything now looks buttery smooth.

In either case (targetFrameRate or vsync), we would need the functionality to set the display refresh rate down to 60hz for a smooth experience.

Here is the API to change that:

Of note is the section for games and other non-video apps:

I would like to ask the device to render at 60hz. But there is now way to do that.

I tried the following:
Screen.SetResolution(Screen.width,Screen.height,true, 60);

But it has no effect.

Using “Optimized Frame Pacing” with Application.targetFrameRate=60 should switch the refresh rate to 60Hz.

Hey Florian, thanks for the reply, just tried this now. Set vsync off (0), target frame rate 60, optimised frame pacing enabled. I can confirm this works - the overlay shows 60 as the refresh rate. Thanks!

I always thought vsync was a more reliable way to set a target frame rate instead of Application.targetFrameRate which is less accurate and can cause stutters. Or does ‘optimise frame pacing’ ‘over-rule’ that? Should I use ‘vsync = 1’ for iOS and ‘target frame rate = 60 + OFP’ for android? This idea stems from a lot of stuff I have read from Tautvydas-Zilys, who is doing some great frame-time related work here. He has made a couple of comments where he recommends vsync over targetFrameRate. He mentioned it is better on PC, but I just assumed that applies to mobile too, I could be wrong.

On Android Application.targetFrameRate=60 should give you the same results as vsync=1 (on devices with 60Hz display).
So as long as you are using a targetFrameRate such as 60, 30, 20, 15 … (for 60Hz) you should not get any additional stutter on mobile.

“Optimized Frame Pacing” always picks the closest possible target frame rate, so e.g. for an “odd” framerate such as 37 we would use 30.

As part of the Android work for Tautvydas’ “deltaTime” changes we also changed the behavior of vsync on Android to match iOS. This means that the vsync setting will be ignored in Unity 2021 and later and it’s always treated as vsync=0, so targetFrameRate should be used. We expect that this will work well with future true variable refresh rate displays on mobile.

Unity’s Android already used the vsync timestamp from Android’s Choreographer API when possible for more stable deltaTime.
So the improvement you will get in 2021 are smaller on Android compared to some other platforms. But issues like https://issuetracker.unity3d.com/issues/android-time-dot-unscaleddeltatime-does-not-match-time-dot-deltatime-when-timescale-is-1 are be fixed.

“Optimized Frame Pacing” uses Google’s “Swappy” (https://android.googlesource.com/platform/frameworks/opt/gamesdk/+/refs/heads/master/src/swappy/).
It does frame pacing but it also does adjust the refresh rate if possible. E.g. on a Galaxy S20 with Display set to 120Hz it would change the refresh rate to 60Hz when Application.targetFrameRate=60).
We are currently not using Swappy’s “auto mode”, which would dynamically adjust the target frame rate based on CPU and GPU times.

Btw there are still some known issues with Swappy on old devices (Android 5.1 and older). We are looking into those.

Thanks for the detailed breakdown! This is some great information to have. It may be worth the documentation team putting together a page on frame rate control differences between all the platforms. There is a lot of black box magic and it isn’t easy (or quick - you need to do lots of builds) to figure out what’s actually happening.

Anyway thanks again, much appreciated.

And if the display is set to 120Hz and the Application.targetFrameRate = 30? Will still change the refresh rate to 60Hz?

yes

I’m experiencing just the same issue mentioned in this topic, but “Optimized Frame Pacing” doesn’t help.
Testing on Samsung Galaxy Note 20 Ultra.
Setting Application.targetFrameRate = 60; (vsync is off) results in slightly noticeable jittering (from time to time) when display setting is adaptive (120 hz)
After setting the Display refresh rate to 60 the game runs perfectly smooth.
Setting Application.targetFrameRate = 120 obviously fixes the issue as well.
Using Unity 2021.2.12f1.
@florianpenzkofer could it be some bug or I am missing something?

Yes it sounds like a bug.
Can you please report one with repro project and post the bug number here?

Try this:

1. Create file “MainActivity.java” in Assets folder.
8164832--1062107--upload_2022-5-29_13-19-27.png

2. Open this file and paste code:

package com.*YOUR COMPANY NAME*.*YOUR PRODUCT NAME*;
import com.unity3d.player.UnityPlayerActivity;
import android.os.Bundle;
import android.os.Build;
import android.view.Display;
import android.view.Window;
import android.view.WindowManager;
public class MainActivity extends UnityPlayerActivity {
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            Window w = getWindow();
            WindowManager.LayoutParams p = w.getAttributes();
            Display.Mode[] modes = getDisplay().getSupportedModes();
            //find display mode with max hz
            int maxMode = 0;
            float maxHZ = 60f;
            for(Display.Mode m:modes) {
                if (maxHZ < m.getRefreshRate()) {
                    maxHZ = m.getRefreshRate();
                    maxMode = m.getModeId();
                }
            }
            p.preferredDisplayModeId = maxMode;
            w.setAttributes(p);
        }
  }
}

3. Change YOUR COMPANY NAME and YOUR PRODUCT NAME to Company Name and Product Name from Project Settings → Player.
8164832--1062113--upload_2022-5-29_13-22-45.png
4. Go to Project Settings → Player → Publishing Settings. Tick “Custom Main Manifest”.
8164832--1062116--upload_2022-5-29_13-24-17.png

5. Open file “AndroidManifest.xml” in “*Assets\Plugins\Android*”.
6. Change android:name=“com.unity3d.player.UnityPlayerActivity” to android:name=“com.YOUR COMPANY NAME.YOUR PRODUCT NAME.MainActivity”.

7. Be sure to call “Application.targetFrameRate = Screen.currentResolution.refreshRate;” in any script!
Update: fixed bug in Android 12.

1 Like

Pleas follow the steps here to report a bug and post the case number in this thread. Unity QA: Building quality with passion

Maybe that’s stupid quesiton. But what do you mean by it?

And why to include it in any script? Why not to call it only on scene load?

I’m still struggling with this problem. Does anyone open an issue, if so whats the ID number?

I have tried the MainActivity trial and nothing happened. Here are the some frame results:

if Application.targetFrameRate = 60 and Optimized Frame Pacing is disable

  • 60 hz phones → 60 fps
  • 90 hz phones → 45 fps
  • 120 hz phones → 60 fps
  • 144 hz phones → 72 fps

if Application.targetFrameRate = 61 and Optimized Frame Pacing is disable

  • 60 hz phones → 60 fps
  • 90 hz phones → 90 fps
  • 120 hz phones → 60 fps
  • 144 hz phones → 72 fps

if Application.targetFrameRate = 60 and Optimized Frame Pacing is enable

  • 60 hz phones → 60 fps
  • 90 hz phones → 45 fps
  • 120 hz phones → 60 fps
  • 144 hz phones → 50 fps

if Application.targetFrameRate = 61 and Optimized Frame Pacing is enable

  • 60 hz phones → 60 fps
  • 90 hz phones → 45 fps
  • 120 hz phones → 60 fps
  • 144 hz phones → 50 fps
3 Likes

I’m Also facing the exact same problem in the new unity 2022LTS and looks like no one from unity seems to care however in unity 2021LTS I can achieve 60 fps but the frame rate is not stable at all idon’t know how to fix it !!. the only solution that i’m thinking right now is to set the device screen refresh to 60 like if you use energy save mode or in the android settings directly from unity through java but it looks a lot complex and i don’t think if it’s even achievable !!