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

Commit 9714a08e authored by Oleg Petsjonkin's avatar Oleg Petsjonkin
Browse files

Default refresh rate for concurrent displays

Test: atest DisplayDeviceConfigTest
Bug: b/241308218
Change-Id: I92e69274d79778ba9625bcca0e3e8265c2daeb96
parent a3783bcb
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -337,6 +337,9 @@ public final class DisplayInfo implements Parcelable {
    @Nullable
    public DisplayShape displayShape;

    @Nullable
    public SurfaceControl.RefreshRateRange layoutLimitedRefreshRate;

    public static final @android.annotation.NonNull Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() {
        @Override
        public DisplayInfo createFromParcel(Parcel source) {
@@ -411,7 +414,8 @@ public final class DisplayInfo implements Parcelable {
                && brightnessDefault == other.brightnessDefault
                && Objects.equals(roundedCorners, other.roundedCorners)
                && installOrientation == other.installOrientation
                && Objects.equals(displayShape, other.displayShape);
                && Objects.equals(displayShape, other.displayShape)
                && Objects.equals(layoutLimitedRefreshRate, other.layoutLimitedRefreshRate);
    }

    @Override
@@ -466,6 +470,7 @@ public final class DisplayInfo implements Parcelable {
        roundedCorners = other.roundedCorners;
        installOrientation = other.installOrientation;
        displayShape = other.displayShape;
        layoutLimitedRefreshRate = other.layoutLimitedRefreshRate;
    }

    public void readFromParcel(Parcel source) {
@@ -526,6 +531,7 @@ public final class DisplayInfo implements Parcelable {
        }
        installOrientation = source.readInt();
        displayShape = source.readTypedObject(DisplayShape.CREATOR);
        layoutLimitedRefreshRate = source.readTypedObject(SurfaceControl.RefreshRateRange.CREATOR);
    }

    @Override
@@ -584,6 +590,7 @@ public final class DisplayInfo implements Parcelable {
        }
        dest.writeInt(installOrientation);
        dest.writeTypedObject(displayShape, flags);
        dest.writeTypedObject(layoutLimitedRefreshRate, flags);
    }

    @Override
@@ -843,6 +850,8 @@ public final class DisplayInfo implements Parcelable {
        sb.append(brightnessDefault);
        sb.append(", installOrientation ");
        sb.append(Surface.rotationToString(installOrientation));
        sb.append(", layoutLimitedRefreshRate ");
        sb.append(layoutLimitedRefreshRate);
        sb.append("}");
        return sb.toString();
    }
+30 −1
Original line number Diff line number Diff line
@@ -1692,7 +1692,7 @@ public final class SurfaceControl implements Parcelable {
     * Information about the min and max refresh rate DM would like to set the display to.
     * @hide
     */
    public static final class RefreshRateRange {
    public static final class RefreshRateRange implements Parcelable {
        public static final String TAG = "RefreshRateRange";

        // The tolerance within which we consider something approximately equals.
@@ -1761,6 +1761,35 @@ public final class SurfaceControl implements Parcelable {
            this.min = other.min;
            this.max = other.max;
        }

        /**
         * Writes the RefreshRateRange to parce
         *
         * @param dest parcel to write the transaction to
         */
        @Override
        public void writeToParcel(@NonNull Parcel dest, @WriteFlags int flags) {
            dest.writeFloat(min);
            dest.writeFloat(max);
        }

        @Override
        public int describeContents() {
            return 0;
        }

        public static final @NonNull Creator<RefreshRateRange> CREATOR =
                new Creator<RefreshRateRange>() {
                    @Override
                    public RefreshRateRange createFromParcel(Parcel in) {
                        return new RefreshRateRange(in.readFloat(), in.readFloat());
                    }

                    @Override
                    public RefreshRateRange[] newArray(int size) {
                        return new RefreshRateRange[size];
                    }
                };
    }

    /**
+1 −0
Original line number Diff line number Diff line
@@ -133,6 +133,7 @@ class DeviceStateToLayoutMap {
                    } else {
                        display.setPosition(POSITION_UNKNOWN);
                    }
                    display.setRefreshRateZoneId(d.getRefreshRateZoneId());
                }
            }
        } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
+42 −3
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import android.util.Pair;
import android.util.Slog;
import android.util.Spline;
import android.view.DisplayAddress;
import android.view.SurfaceControl;

import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
@@ -53,6 +54,7 @@ import com.android.server.display.config.NitsMap;
import com.android.server.display.config.Point;
import com.android.server.display.config.RefreshRateConfigs;
import com.android.server.display.config.RefreshRateRange;
import com.android.server.display.config.RefreshRateZone;
import com.android.server.display.config.SdrHdrRatioMap;
import com.android.server.display.config.SdrHdrRatioPoint;
import com.android.server.display.config.SensorDetails;
@@ -503,10 +505,10 @@ public class DisplayDeviceConfig {
    /**
     * Array of light sensor lux values to define our levels for auto backlight
     * brightness support.

     *
     * The N + 1 entries of this array define N control points defined in mBrightnessLevelsNits,
     * with first value always being 0 lux

     *
     * The control points must be strictly increasing.  Each control point
     * corresponds to an entry in the brightness backlight values arrays.
     * For example, if lux == level[1] (second element of the levels array)
@@ -515,7 +517,6 @@ public class DisplayDeviceConfig {
     *
     * Spline interpolation is used to determine the auto-brightness
     * backlight values for lux levels between these control points.
     *
     */
    private float[] mBrightnessLevelsLux;

@@ -619,6 +620,10 @@ public class DisplayDeviceConfig {
     */
    private int mDefaultLowBlockingZoneRefreshRate = DEFAULT_LOW_REFRESH_RATE;

    // Refresh rate profiles, currently only for concurrent mode profile and controlled by Layout
    private final Map<String, SurfaceControl.RefreshRateRange> mRefreshRateZoneProfiles =
            new HashMap<>();

    /**
     * The display uses different gamma curves for different refresh rates. It's hard for panel
     * vendors to tune the curves to have exact same brightness for different refresh rate. So
@@ -1353,6 +1358,23 @@ public class DisplayDeviceConfig {
        return mDefaultLowBlockingZoneRefreshRate;
    }

    /**
     * @return Refresh rate range for specific profile id or null
     */
    @Nullable
    public SurfaceControl.RefreshRateRange getRefreshRange(@Nullable String id) {
        if (TextUtils.isEmpty(id)) {
            return null;
        }
        return mRefreshRateZoneProfiles.get(id);
    }

    @NonNull
    @VisibleForTesting
    Map<String, SurfaceControl.RefreshRateRange> getRefreshRangeProfiles() {
        return mRefreshRateZoneProfiles;
    }

    /**
     * @return An array of lower display brightness thresholds. This, in combination with lower
     * ambient brightness thresholds help define buckets in which the refresh rate switching is not
@@ -1500,6 +1522,7 @@ public class DisplayDeviceConfig {
                + ", mDefaultHighBlockingZoneRefreshRate= " + mDefaultHighBlockingZoneRefreshRate
                + ", mDefaultPeakRefreshRate= " + mDefaultPeakRefreshRate
                + ", mDefaultRefreshRate= " + mDefaultRefreshRate
                + ", mRefreshRateZoneProfiles= " + mRefreshRateZoneProfiles
                + ", mLowDisplayBrightnessThresholds= "
                + Arrays.toString(mLowDisplayBrightnessThresholds)
                + ", mLowAmbientBrightnessThresholds= "
@@ -1828,6 +1851,7 @@ public class DisplayDeviceConfig {
        loadDefaultRefreshRate(refreshRateConfigs);
        loadLowerRefreshRateBlockingZones(lowerBlockingZoneConfig);
        loadHigherRefreshRateBlockingZones(higherBlockingZoneConfig);
        loadRefreshRateZoneProfiles(refreshRateConfigs);
    }

    private void loadPeakDefaultRefreshRate(RefreshRateConfigs refreshRateConfigs) {
@@ -1850,6 +1874,21 @@ public class DisplayDeviceConfig {
        }
    }

    /** Loads the refresh rate profiles. */
    private void loadRefreshRateZoneProfiles(RefreshRateConfigs refreshRateConfigs) {
        if (refreshRateConfigs == null) {
            return;
        }
        for (RefreshRateZone zone :
                refreshRateConfigs.getRefreshRateZoneProfiles().getRefreshRateZoneProfile()) {
            RefreshRateRange range = zone.getRefreshRateRange();
            mRefreshRateZoneProfiles.put(
                    zone.getId(),
                    new SurfaceControl.RefreshRateRange(
                            range.getMinimum().floatValue(), range.getMaximum().floatValue()));
        }
    }

    /**
     * Loads the refresh rate configurations pertaining to the upper blocking zones.
     */
+36 −11
Original line number Diff line number Diff line
@@ -159,7 +159,6 @@ public class DisplayModeDirector {
        mSupportedModesByDisplay = new SparseArray<>();
        mDefaultModeByDisplay = new SparseArray<>();
        mAppRequestObserver = new AppRequestObserver();
        mDisplayObserver = new DisplayObserver(context, handler);
        mDeviceConfig = injector.getDeviceConfig();
        mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
        mSettingsObserver = new SettingsObserver(context, handler);
@@ -170,6 +169,7 @@ public class DisplayModeDirector {
                updateVoteLocked(displayId, priority, vote);
            }
        };
        mDisplayObserver = new DisplayObserver(context, handler, ballotBox);
        mSensorObserver = new SensorObserver(context, ballotBox, injector);
        mSkinThermalStatusObserver = new SkinThermalStatusObserver(injector, ballotBox);
        mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler(),
@@ -1186,26 +1186,29 @@ public class DisplayModeDirector {
        // rest of low priority voters. It votes [0, max(PEAK, MIN)]
        public static final int PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE = 7;

        // For concurrent displays we want to limit refresh rate on all displays
        public static final int PRIORITY_LAYOUT_LIMITED_FRAME_RATE = 8;

        // LOW_POWER_MODE force the render frame rate to [0, 60HZ] if
        // Settings.Global.LOW_POWER_MODE is on.
        public static final int PRIORITY_LOW_POWER_MODE = 8;
        public static final int PRIORITY_LOW_POWER_MODE = 9;

        // PRIORITY_FLICKER_REFRESH_RATE_SWITCH votes for disabling refresh rate switching. If the
        // higher priority voters' result is a range, it will fix the rate to a single choice.
        // It's used to avoid refresh rate switches in certain conditions which may result in the
        // user seeing the display flickering when the switches occur.
        public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 9;
        public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 10;

        // Force display to [0, 60HZ] if skin temperature is at or above CRITICAL.
        public static final int PRIORITY_SKIN_TEMPERATURE = 10;
        public static final int PRIORITY_SKIN_TEMPERATURE = 11;

        // The proximity sensor needs the refresh rate to be locked in order to function, so this is
        // set to a high priority.
        public static final int PRIORITY_PROXIMITY = 11;
        public static final int PRIORITY_PROXIMITY = 12;

        // The Under-Display Fingerprint Sensor (UDFPS) needs the refresh rate to be locked in order
        // to function, so this needs to be the highest priority of all votes.
        public static final int PRIORITY_UDFPS = 12;
        public static final int PRIORITY_UDFPS = 13;

        // Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and
        // APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString.
@@ -1657,10 +1660,12 @@ public class DisplayModeDirector {
        // calling into us already holding its own lock.
        private final Context mContext;
        private final Handler mHandler;
        private final BallotBox mBallotBox;

        DisplayObserver(Context context, Handler handler) {
        DisplayObserver(Context context, Handler handler, BallotBox ballotBox) {
            mContext = context;
            mHandler = handler;
            mBallotBox = ballotBox;
        }

        public void observe() {
@@ -1689,7 +1694,9 @@ public class DisplayModeDirector {

        @Override
        public void onDisplayAdded(int displayId) {
            updateDisplayModes(displayId);
            DisplayInfo displayInfo = getDisplayInfo(displayId);
            updateDisplayModes(displayId, displayInfo);
            updateLayoutLimitedFrameRate(displayId, displayInfo);
        }

        @Override
@@ -1698,23 +1705,41 @@ public class DisplayModeDirector {
                mSupportedModesByDisplay.remove(displayId);
                mDefaultModeByDisplay.remove(displayId);
            }
            updateLayoutLimitedFrameRate(displayId, null);
        }

        @Override
        public void onDisplayChanged(int displayId) {
            updateDisplayModes(displayId);
            DisplayInfo displayInfo = getDisplayInfo(displayId);
            updateDisplayModes(displayId, displayInfo);
            updateLayoutLimitedFrameRate(displayId, displayInfo);
        }

        private void updateDisplayModes(int displayId) {
        @Nullable
        private DisplayInfo getDisplayInfo(int displayId) {
            Display d = mContext.getSystemService(DisplayManager.class).getDisplay(displayId);
            if (d == null) {
                // We can occasionally get a display added or changed event for a display that was
                // subsequently removed, which means this returns null. Check this case and bail
                // out early; if it gets re-attached we'll eventually get another call back for it.
                return;
                return null;
            }
            DisplayInfo info = new DisplayInfo();
            d.getDisplayInfo(info);
            return info;
        }

        private void updateLayoutLimitedFrameRate(int displayId, @Nullable DisplayInfo info) {
            Vote vote = info != null && info.layoutLimitedRefreshRate != null
                    ? Vote.forPhysicalRefreshRates(info.layoutLimitedRefreshRate.min,
                    info.layoutLimitedRefreshRate.max) : null;
            mBallotBox.vote(displayId, Vote.PRIORITY_LAYOUT_LIMITED_FRAME_RATE, vote);
        }

        private void updateDisplayModes(int displayId, @Nullable DisplayInfo info) {
            if (info == null) {
                return;
            }
            boolean changed = false;
            synchronized (mLock) {
                if (!Arrays.equals(mSupportedModesByDisplay.get(displayId), info.supportedModes)) {
Loading