Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice

Set screen refresh rate on Android 11

Discussion in 'Android' started by Prodigga, Oct 30, 2020.

  1. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    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:
    https://developer.android.com/guide/topics/media/frame-rate

    Of note is the section for games and other non-video apps:
    https://developer.android.com/guide/topics/media/frame-rate#games-non-video

    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.
     
    Last edited: Oct 30, 2020
  2. florianpenzkofer

    florianpenzkofer

    Unity Technologies

    Joined:
    Sep 2, 2014
    Posts:
    479
    Using "Optimized Frame Pacing" with Application.targetFrameRate=60 should switch the refresh rate to 60Hz.
     
  3. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    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.
     
  4. florianpenzkofer

    florianpenzkofer

    Unity Technologies

    Joined:
    Sep 2, 2014
    Posts:
    479
    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/is...-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.
     
  5. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    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.
     
  6. Cassanova99

    Cassanova99

    Joined:
    Oct 18, 2019
    Posts:
    1
    And if the display is set to 120Hz and the Application.targetFrameRate = 30? Will still change the refresh rate to 60Hz?
     
  7. florianpenzkofer

    florianpenzkofer

    Unity Technologies

    Joined:
    Sep 2, 2014
    Posts:
    479
    yes
     
  8. tarasrng

    tarasrng

    Joined:
    May 18, 2017
    Posts:
    11
    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?
     
  9. florianpenzkofer

    florianpenzkofer

    Unity Technologies

    Joined:
    Sep 2, 2014
    Posts:
    479
    Yes it sounds like a bug.
    Can you please report one with repro project and post the bug number here?
     
  10. ComRSMaster

    ComRSMaster

    Joined:
    May 23, 2021
    Posts:
    3
    Try this:

    1. Create file "MainActivity.java" in Assets folder.
    upload_2022-5-29_13-19-27.png

    2. Open this file and paste code:
    Code (CSharp):
    1. package com.*YOUR COMPANY NAME*.*YOUR PRODUCT NAME*;
    2. import com.unity3d.player.UnityPlayerActivity;
    3. import android.os.Bundle;
    4. import android.os.Build;
    5. import android.view.Display;
    6. import android.view.Window;
    7. import android.view.WindowManager;
    8. public class MainActivity extends UnityPlayerActivity {
    9.   protected void onCreate(Bundle savedInstanceState) {
    10.     super.onCreate(savedInstanceState);
    11.     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    12.             Window w = getWindow();
    13.             WindowManager.LayoutParams p = w.getAttributes();
    14.             Display.Mode[] modes = getDisplay().getSupportedModes();
    15.             //find display mode with max hz
    16.             int maxMode = 0;
    17.             float maxHZ = 60f;
    18.             for(Display.Mode m:modes) {
    19.                 if (maxHZ < m.getRefreshRate()) {
    20.                     maxHZ = m.getRefreshRate();
    21.                     maxMode = m.getModeId();
    22.                 }
    23.             }
    24.             p.preferredDisplayModeId = maxMode;
    25.             w.setAttributes(p);
    26.         }
    27.   }
    28. }
    3. Change *YOUR COMPANY NAME* and *YOUR PRODUCT NAME* to Company Name and Product Name from Project Settings -> Player.
    upload_2022-5-29_13-22-45.png
    4. Go to Project Settings -> Player -> Publishing Settings. Tick "Custom Main Manifest".
    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".
    upload_2022-5-29_13-30-50.png

    7. Be sure to call "Application.targetFrameRate = Screen.currentResolution.refreshRate;" in any script!

    Update: fixed bug in Android 12.
     
    Last edited: Aug 17, 2022
    Stardog likes this.
  11. florianpenzkofer

    florianpenzkofer

    Unity Technologies

    Joined:
    Sep 2, 2014
    Posts:
    479
  12. Korczu

    Korczu

    Joined:
    Apr 4, 2020
    Posts:
    10
    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?
     
  13. atasayin1

    atasayin1

    Joined:
    Nov 18, 2020
    Posts:
    8
    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
     
    weiping-toh, Stardog and MohamedTun like this.
  14. MohamedTun

    MohamedTun

    Joined:
    May 13, 2021
    Posts:
    37
    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 !!