Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aa47a682 authored by Ady Abraham's avatar Ady Abraham
Browse files

Use setFrameRate for high refresh rate deny list

Add visibility to SurfaceFlinger into the high refresh rate deny list
and let SurfaceFlinger handle it. Previously WM was setting the
preferredDisplayModeId on the denied app's window. The old way prevented
SurfaceFlinger to use the frame rate override feature as it didn't
know that a specific app is causing the refresh rate spec to be limited.

With this change, SurfaceFlinger will limit the display refresh rate
based on the high refresh rate deny list, and if possible, will use the
frame rate override feature to change the display rate to a multiple,
allowing other animations to be smooth while the denied app remains in
the low refresh rate.

Bug: 170502573
Test: manual
Change-Id: Ib75a3c229cea298b65aa56dc1c1b20ca016059c4
Merged-In: Ib75a3c229cea298b65aa56dc1c1b20ca016059c4
parent 9ce7fe21
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -547,16 +547,17 @@ public final class DisplayInfo implements Parcelable {
     * Returns the id of the "default" mode with the given refresh rate, or {@code 0} if no suitable
     * mode could be found.
     */
    public int findDefaultModeByRefreshRate(float refreshRate) {
    @Nullable
    public Display.Mode findDefaultModeByRefreshRate(float refreshRate) {
        Display.Mode[] modes = supportedModes;
        Display.Mode defaultMode = getDefaultMode();
        for (int i = 0; i < modes.length; i++) {
            if (modes[i].matches(
                    defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), refreshRate)) {
                return modes[i].getModeId();
                return modes[i];
            }
        }
        return 0;
        return null;
    }

    /**
+9 −0
Original line number Diff line number Diff line
@@ -217,6 +217,15 @@ public class Surface implements Parcelable {
     */
    public static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1;

    /**
     * This surface belongs to an app on the High Refresh Rate Deny list, and needs the display
     * to operate at the exact frame rate.
     *
     * This is used internally by the platform and should not be used by apps.
     * @hide
     */
    public static final int FRAME_RATE_COMPATIBILITY_EXACT = 100;

    /**
     * Create an empty surface, which will later be filled in by readFromParcel().
     * @hide
+1 −1
Original line number Diff line number Diff line
@@ -1357,7 +1357,7 @@ public final class DisplayManagerService extends SystemService {
                // Scan supported modes returned by display.getInfo() to find a mode with the same
                // size as the default display mode but with the specified refresh rate instead.
                requestedModeId = display.getDisplayInfoLocked().findDefaultModeByRefreshRate(
                        requestedRefreshRate);
                        requestedRefreshRate).getModeId();
            }
            mDisplayModeDirector.getAppRequestObserver().setAppRequestedMode(
                    displayId, requestedModeId);
+18 −8
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@ import android.view.DisplayInfo;
 */
class RefreshRatePolicy {

    private final int mLowRefreshRateId;
    private final Mode mLowRefreshRateMode;
    private final ArraySet<String> mNonHighRefreshRatePackages = new ArraySet<>();
    private final HighRefreshRateDenylist mHighRefreshRateDenylist;
    private final WindowManagerService mWmService;
@@ -56,7 +56,7 @@ class RefreshRatePolicy {

    RefreshRatePolicy(WindowManagerService wmService, DisplayInfo displayInfo,
            HighRefreshRateDenylist denylist) {
        mLowRefreshRateId = findLowRefreshRateModeId(displayInfo);
        mLowRefreshRateMode = findLowRefreshRateMode(displayInfo);
        mHighRefreshRateDenylist = denylist;
        mWmService = wmService;
    }
@@ -65,7 +65,7 @@ class RefreshRatePolicy {
     * Finds the mode id with the lowest refresh rate which is >= 60hz and same resolution as the
     * default mode.
     */
    private int findLowRefreshRateModeId(DisplayInfo displayInfo) {
    private Mode findLowRefreshRateMode(DisplayInfo displayInfo) {
        Mode mode = displayInfo.getDefaultMode();
        float[] refreshRates = displayInfo.getDefaultRefreshRates();
        float bestRefreshRate = mode.getRefreshRate();
@@ -104,13 +104,9 @@ class RefreshRatePolicy {

        // If app is using Camera, force it to default (lower) refresh rate.
        if (mNonHighRefreshRatePackages.contains(packageName)) {
            return mLowRefreshRateId;
            return mLowRefreshRateMode.getModeId();
        }

        // If app is denylisted using higher refresh rate, return default (lower) refresh rate
        if (mHighRefreshRateDenylist.isDenylisted(packageName)) {
            return mLowRefreshRateId;
        }
        return 0;
    }

@@ -137,4 +133,18 @@ class RefreshRatePolicy {
        }
        return LAYER_PRIORITY_UNSET;
    }

    float getPreferredRefreshRate(WindowState w) {
        // If app is animating, it's not able to control refresh rate because we want the animation
        // to run in default refresh rate.
        if (w.isAnimating(TRANSITION | PARENTS)) {
            return 0;
        }

        final String packageName = w.getOwningPackage();
        if (mHighRefreshRateDenylist.isDenylisted(packageName)) {
            return mLowRefreshRateMode.getRefreshRate();
        }
        return 0;
    }
}
+18 −3
Original line number Diff line number Diff line
@@ -233,6 +233,7 @@ import android.view.InputWindowHandle;
import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
import android.view.Surface;
import android.view.Surface.Rotation;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
@@ -730,6 +731,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
     */
    int mFrameRateSelectionPriority = RefreshRatePolicy.LAYER_PRIORITY_UNSET;

    /**
     * This is the frame rate which is passed to SurfaceFlinger if the window is part of the
     * high refresh rate deny list. The variable is cached, so we do not send too many updates to
     * SF.
     */
    float mDenyListFrameRate = 0f;

    static final int BLAST_TIMEOUT_DURATION = 5000; /* milliseconds */

    private final WindowProcessController mWpcForDisplayAreaConfigChanges;
@@ -5233,7 +5241,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
        return (mAttrs.flags & FLAG_BLUR_BEHIND) != 0 && mOwnerCanUseBackgroundBlur;
    }


    /**
     * Notifies SF about the priority of the window, if it changed. SF then uses this information
     * to decide which window's desired rendering rate should have a priority when deciding about
@@ -5242,13 +5249,21 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
     */
    @VisibleForTesting
    void updateFrameRateSelectionPriorityIfNeeded() {
        final int priority = getDisplayContent().getDisplayPolicy().getRefreshRatePolicy()
                .calculatePriority(this);
        RefreshRatePolicy refreshRatePolicy =
                getDisplayContent().getDisplayPolicy().getRefreshRatePolicy();
        final int priority = refreshRatePolicy.calculatePriority(this);
        if (mFrameRateSelectionPriority != priority) {
            mFrameRateSelectionPriority = priority;
            getPendingTransaction().setFrameRateSelectionPriority(mSurfaceControl,
                    mFrameRateSelectionPriority);
        }

        final float refreshRate = refreshRatePolicy.getPreferredRefreshRate(this);
        if (mDenyListFrameRate != refreshRate) {
            mDenyListFrameRate = refreshRate;
            getPendingTransaction().setFrameRate(
                    mSurfaceControl, mDenyListFrameRate, Surface.FRAME_RATE_COMPATIBILITY_EXACT);
        }
    }

    private void updateGlobalScaleIfNeeded() {
Loading