1. Useless knowledge

A: ProMotion and LTPO. ProMotion is the dynamic refresh rate support that appears after iOS supports 120Hz, that is, different screen refresh rates are used in different scenes, so as to improve experience and reduce battery consumption.

LTPO(Low-Temperature Polycrystalline oxide) allows the display to dynamically change the refresh rate of the screen, and was pioneered in Samsung S20 Ultra, OPPO Find X3, and OnePlus 9 Pro. But in fact, people have different skills in LTPO, which leads to the problem we will talk about later.

For example, in LTPO 1.0, most of the implementation was just hard to lock the refresh rate of 60Hz/120Hz according to the scenario, while in LTPO 2.0, major manufacturers upgraded the adaptive strategy, for example, the most common upgrade is sliding frequency conversion:

Of course, in addition to the most common sliders, LTPO 2.0 May also have different up-and-down strategies for animation, video, text input, application switching, etc. The reasons for these are as follows:

  • Apple ProMotion is a unified scheme based on official implementation;
  • Android LTPO is based on the realization of Android OEM’s self-tuning after the supplier hardware;

The above information is from “Does LTPO Really Save Power? – One Plus LTPO 2.0 Hands-on Experience”.

This is the main reason why Flutter needs to be adapted separately on Android and iOS.

Second, the Android

First of all, we know that the adaptive screen refresh rate is self-adjusted by OEM. That is to say, in theory, as an App, there is no need to do any adaptation, because it just follows Android, and Android itself also uses Skia rendering.

The OnePlus 7 Pro’s 90Hz Refresh Rate Doesn’t Support Every App is quoted in The article “The OnePlus 7 Pro’s Refresh Rate Doesn’t Support Every App”.

– The 90 FPS mode for onePlus 7 Pro is only 60 FPS for some apps. The adb shell Settings put global oneplus_screen_refresh_rate 0 command is required. By contrast, Pixel 4 can render a 90fps Flutter App without any changes.

The problem was that onePlus didn’t support 90 FPS at first, and the community responded by communicating with OnePlus:

  • In order to balance performance and power consumption, the OnePlus 7 Pro uses its own frame rate control logic based on Android. Generally, the screen will work at a high frame rate, but in some scenarios, the system will cut back to a low frame rate, and due to the introduction of this mechanism, There may be problems with the system forcing the screen to run at a low frame rate when the App expects it to run at a high frame rate.

  • How to set FPS via App? If your application needs to set the frame rate, first get the list of modes currently supported by the screen via getSupportedModes(), then iterate through the list and assign the preferredDisplayModeId to the window based on the modeId that found the resolution and refresh rate you want to use.

Therefore, based on the solution to this problem, the community put forward the flutter_displaymode plug-in, which mainly provides support for obtaining display. Mode and setting preferredDisplayModeId. Used to temporarily fix refresh rate issues like those on the OnePlus 7 Pro.

/// On OnePlus 7 Pro:
/// #1 1080x2340 @ 60Hz
/// #2 1080x2340 @ 90Hz
/// #3 1440x3120 @ 90Hz
/// #4 1440x3120 @ 60Hz
/// On OnePlus 8 Pro:
/// #1 1080x2376 @ 60Hz
/// #2 1440x3168 @ 120Hz
/// #3 1440x3168 @ 60Hz
/// #4 1080x2376 @ 120Hz
Copy the code

So what’s a PreferredDisplayModeId? From the official SetFramerate-vs-preferredDisplayModeid:

WindowManager. LayoutParams. PreferredDisplayModeId is App to platform set up a way of frame rate, because sometimes the App just want to change the refresh rate, but I don’t need to change the other display modes such as resolution, etc. A similar setup is setFrameRate(), which makes it easier to use setFrameRate() instead of preferredDisplayModeId because setFrameRate() automatically matches modes with a particular frame rate in the display mode list.

So why not just use setFrameRate? One of them is because it’s a very high Target API.

PS: There is a great guy about Flutter. In fact, he has been working on this issue for a long time as AlexV525 of GDE. He is also involved in the maintenance of the plugin above. Also congratulations to 🎉 big man for getting Google Open Source Peer Bonus Winners in 2022 🏆.

However, the onplus 9 Pro has LTPO and ColorOS installed, and the previous ADB command is invalid on the new ColorOS. Don’t worry, this is actually an official bug. The issue was fixed after ColorOS 11_A.06, which means the plugin can still work.

Now, nearly two years have passed, the problem can only be solved temporarily by plug-ins, because the official attitude does not seem to support embedding in this way:

  • A Flutter should hand over refresh rate control to OS. A Flutter should not hardcode a single refresh rate.
  • Solutions to OEM problems like the Flutter Engine are best solved by plug-ins rather than by Flutter Engine;

In this respect, the processing ideas and decision-making feel is quite different from iOS, probably due to platform constraints.

In fact, the implementation logic of LTPO varies greatly from vendor to vendor. For example, onePlus 10Pro will selectively compress or discard some redundant instructions in LTPO rendering.

We know that Flutter renders widgets onto the Surface. In this respect, Flutter is similar to Google Map using SurfaceView and OpenGL. After testing Google Map on these devices, No special Settings like Flutter can only run at 60hz render.

Is it another “whitelist model” for the OEM to have the right to decide on the tuned LTPO whether to allow the App to use a higher refresh rate, even if the App requires a higher refresh rate?

So if you want the Surface to run at 90/120 Hz on some special devices, you need to use preferredDisplayModeId or setFrameRate, as long as the manufacturer doesn’t lock the frame rate.

Some phone manufacturers, for the sake of “dragon training” and temperature control, have their own “frame stabilization” policies, even forcing the frame rate to lock and display false frame rates.

The final result of discussion #78117 is that Flutter does not adapt specifically to these manufacturers. If necessary, you can use a third-party plugin to solve this problem. Of course, in my tests, the current refresh rate of most devices is normal.

There was also a bug with the early IntelliJ plugin for Flutter. Even though the application was running at 90 FPS, the Android Studio/IntelliJ plugin for Flutter gave 60 FPS. Of course this problem was solved in the follow-up #4289.

As an added bonus, manufacturers will also check if SurfaceView/TextureView is more than halfway across the screen, as this may indicate that you are watching a video or playing a game, which may also decrease the frame rate.

Finally, if you are curious about the refresh rate code of Flutter on Android, check out vsync_waiter. Cc, vsync_waiter_android.cc, android_display.cc

Third, the iOS

Back on iOS, ProMotion is not supported in the same way as native, because the official adaptation of ProMotion is mentioned in “Refresh Rate Optimization” at the beginning of ProMotion:

There is no need to change the App for these refresh rate changes if the following default frameworks are used:

  • UIKit
  • SwiftUI
  • SpriteKit
  • CAAnimation

However, Flutter does not use native controls provided by the system, so the following parameters need to be configured in the info.plist file to enable support for CADisplayLink and CAAnimation above 120Hz:

<key>CADisableMinimumFrameDurationOnPhone</key><true/>
Copy the code

Dev /go/variable… As you can see from the reply to Issue #90675, the official decision is to use the #29797 implementation first, by adjusting the content related to vsync_waiter_ios.mm to achieve high spawn support:

- (void)setMaxRefreshRateIfEnabled { NSNumber* minimumFrameRateDisabled = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CADisableMinimumFrameDurationOnPhone"]; if (! minimumFrameRateDisabled) { return; } double maxFrameRate = fmax([DisplayLinkManager displayRefreshRate], 60); double minFrameRate = fmax(maxFrameRate / 2, 60); If (@available(iOS 15.0, *)) {display_link_.get(). PreferredFrameRateRange = CAFrameRateRangeMake(minFrameRate, maxFrameRate, maxFrameRate); } else if (@ the available (iOS 10.0, *)) {display_link_. The get (). PreferredFramesPerSecond = maxFrameRate; }}Copy the code
  • By default, the frame rate will be set to 60;
  • Set to the maximum refresh rate supported by the display on devices that support ProMotion;
  • In iOS 15 and later, the frame rate range is also added, where preferred and Max are the maximum values supported by the screen, and min is 1/2 of the maximum value.

A more flexible implementation like #29692 was discussed earlier, which explored allowing the Flutter Engine to choose its own frame rate based on the rendering and usage scenarios because the community felt that: For the average user, it doesn’t make sense to let developers choose the right refresh without knowing the platform, performance, etc., so Engine adaptation is the way forward.

Based on community, of course, now desperately want Flutter to get the ability of 120 hz, the preceding CADisableMinimumFrameDurationOnPhone temporarily preferred to solve the dilemma, this is also how iOS official advocate.

It is also worth mentioning that Apple has fixed a bug that causes ProMotion in iOS 15.4, because ProMontion was not fully open to third-party support before, but after iOS 15.4, IOS automatically enables a 120Hz refresh rate for all custom animation content in your App, so the magic happens:

  • On iOS 15.4, the App can be compatible with 120Hz animation;
  • Prior to iOS 15.4, some animations supported ProMotion;

Four, the last

As you can see, for now, high brushes are still a challenge for Flutter. As an independent rendering engine, this is a problem that Flutter cannot escape.

  • You don’t need to make any adjustments on Android. If you encounter a particular device or system, flutter_displayMode is recommended.
  • You can add it on iOSCADisableMinimumFrameDurationOnPhoneTo rough it out and wait# 29797The combined release of relevant content;

Finally, if you have any information or ideas about high brush, please leave a comment and discuss.