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

Commit ca8c8e6e authored by Oleg Petšjonkin's avatar Oleg Petšjonkin Committed by Android (Google) Code Review
Browse files

Merge "LowPower mode config for vrr displays" into main

parents 187aa9c3 d261b761
Loading
Loading
Loading
Loading
+20 −5
Original line number Diff line number Diff line
@@ -20,6 +20,10 @@ import android.annotation.Nullable;
import android.content.res.Resources;

import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;

import java.util.Collections;
import java.util.List;

/**
 * RefreshRates config for display
@@ -58,12 +62,17 @@ public class RefreshRateData {
     */
    public final int defaultRefreshRateInHbmSunlight;

    public final List<SupportedModeData> lowPowerSupportedModes;

    @VisibleForTesting
    public RefreshRateData(int defaultRefreshRate, int defaultPeakRefreshRate,
            int defaultRefreshRateInHbmHdr, int defaultRefreshRateInHbmSunlight) {
            int defaultRefreshRateInHbmHdr, int defaultRefreshRateInHbmSunlight,
            List<SupportedModeData> lowPowerSupportedModes) {
        this.defaultRefreshRate = defaultRefreshRate;
        this.defaultPeakRefreshRate = defaultPeakRefreshRate;
        this.defaultRefreshRateInHbmHdr = defaultRefreshRateInHbmHdr;
        this.defaultRefreshRateInHbmSunlight = defaultRefreshRateInHbmSunlight;
        this.lowPowerSupportedModes = Collections.unmodifiableList(lowPowerSupportedModes);
    }


@@ -71,9 +80,10 @@ public class RefreshRateData {
    public String toString() {
        return "RefreshRateData {"
                + "defaultRefreshRate: " + defaultRefreshRate
                + "defaultPeakRefreshRate: " + defaultPeakRefreshRate
                + "defaultRefreshRateInHbmHdr: " + defaultRefreshRateInHbmHdr
                + "defaultRefreshRateInHbmSunlight: " + defaultRefreshRateInHbmSunlight
                + ", defaultPeakRefreshRate: " + defaultPeakRefreshRate
                + ", defaultRefreshRateInHbmHdr: " + defaultRefreshRateInHbmHdr
                + ", defaultRefreshRateInHbmSunlight: " + defaultRefreshRateInHbmSunlight
                + ", lowPowerSupportedModes=" + lowPowerSupportedModes
                + "} ";
    }

@@ -90,8 +100,13 @@ public class RefreshRateData {
        int defaultRefreshRateInHbmSunlight = loadDefaultRefreshRateInHbmSunlight(
                refreshRateConfigs, resources);

        NonNegativeFloatToFloatMap modes =
                refreshRateConfigs == null ? null : refreshRateConfigs.getLowPowerSupportedModes();
        List<SupportedModeData> lowPowerSupportedModes = SupportedModeData.load(modes);

        return new RefreshRateData(defaultRefreshRate, defaultPeakRefreshRate,
                defaultRefreshRateInHbmHdr, defaultRefreshRateInHbmSunlight);
                defaultRefreshRateInHbmHdr, defaultRefreshRateInHbmSunlight,
                lowPowerSupportedModes);
    }

    private static int loadDefaultRefreshRate(
+4 −20
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@ import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.display.feature.DisplayManagerFlags;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@@ -42,7 +41,7 @@ public class SensorData {
    public final String name;
    public final float minRefreshRate;
    public final float maxRefreshRate;
    public final List<SupportedMode> supportedModes;
    public final List<SupportedModeData> supportedModes;

    @VisibleForTesting
    public SensorData() {
@@ -61,7 +60,7 @@ public class SensorData {

    @VisibleForTesting
    public SensorData(String type, String name, float minRefreshRate, float maxRefreshRate,
            List<SupportedMode> supportedModes) {
            List<SupportedModeData> supportedModes) {
        this.type = type;
        this.name = name;
        this.minRefreshRate = minRefreshRate;
@@ -214,26 +213,11 @@ public class SensorData {
            minRefreshRate = rr.getMinimum().floatValue();
            maxRefreshRate = rr.getMaximum().floatValue();
        }
        ArrayList<SupportedMode> supportedModes = new ArrayList<>();
        NonNegativeFloatToFloatMap configSupportedModes = sensorDetails.getSupportedModes();
        if (configSupportedModes != null) {
            for (NonNegativeFloatToFloatPoint supportedMode : configSupportedModes.getPoint()) {
                supportedModes.add(new SupportedMode(supportedMode.getFirst().floatValue(),
                        supportedMode.getSecond().floatValue()));
            }
        }
        List<SupportedModeData> supportedModes = SupportedModeData.load(
                sensorDetails.getSupportedModes());

        return new SensorData(sensorDetails.getType(), sensorDetails.getName(), minRefreshRate,
                maxRefreshRate, supportedModes);
    }

    public static class SupportedMode {
        public final float refreshRate;
        public final float vsyncRate;

        public SupportedMode(float refreshRate, float vsyncRate) {
            this.refreshRate = refreshRate;
            this.vsyncRate = vsyncRate;
        }
    }
}
+54 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.display.config;

import android.annotation.Nullable;

import java.util.ArrayList;
import java.util.List;

/**
 * Supported display mode data. Display mode is uniquely identified by refreshRate-vsync pair
 */
public class SupportedModeData {
    public final float refreshRate;
    public final float vsyncRate;

    public SupportedModeData(float refreshRate, float vsyncRate) {
        this.refreshRate = refreshRate;
        this.vsyncRate = vsyncRate;
    }

    @Override
    public String toString() {
        return "SupportedModeData{"
                + "refreshRate= " + refreshRate
                + ", vsyncRate= " + vsyncRate
                + '}';
    }

    static List<SupportedModeData> load(@Nullable NonNegativeFloatToFloatMap configMap) {
        ArrayList<SupportedModeData> supportedModes = new ArrayList<>();
        if (configMap != null) {
            for (NonNegativeFloatToFloatPoint supportedMode : configMap.getPoint()) {
                supportedModes.add(new SupportedModeData(supportedMode.getFirst().floatValue(),
                        supportedMode.getSecond().floatValue()));
            }
        }
        return supportedModes;
    }
}
+55 −22
Original line number Diff line number Diff line
@@ -78,6 +78,7 @@ import com.android.server.LocalServices;
import com.android.server.display.DisplayDeviceConfig;
import com.android.server.display.config.IdleScreenRefreshRateTimeoutLuxThresholdPoint;
import com.android.server.display.config.RefreshRateData;
import com.android.server.display.config.SupportedModeData;
import com.android.server.display.feature.DeviceConfigParameterProvider;
import com.android.server.display.feature.DisplayManagerFlags;
import com.android.server.display.utils.AmbientFilter;
@@ -451,15 +452,6 @@ public class DisplayModeDirector {
        return config != null && config.isVrrSupportEnabled();
    }

    private boolean isVrrSupportedByAnyDisplayLocked() {
        for (int i = 0; i < mDisplayDeviceConfigByDisplay.size(); i++) {
            if (mDisplayDeviceConfigByDisplay.valueAt(i).isVrrSupportEnabled()) {
                return true;
            }
        }
        return false;
    }

    /**
     * Sets the desiredDisplayModeSpecsListener for changes to display mode and refresh rate ranges.
     */
@@ -939,18 +931,44 @@ public class DisplayModeDirector {
        private final Uri mMatchContentFrameRateSetting =
                Settings.Secure.getUriFor(Settings.Secure.MATCH_CONTENT_FRAME_RATE);

        private final boolean mVsynLowPowerVoteEnabled;
        private final boolean mVsyncLowPowerVoteEnabled;
        private final boolean mPeakRefreshRatePhysicalLimitEnabled;

        private final Context mContext;
        private final Handler mHandler;
        private float mDefaultPeakRefreshRate;
        private float mDefaultRefreshRate;
        private boolean mIsLowPower = false;

        private final DisplayManager.DisplayListener mDisplayListener =
                new DisplayManager.DisplayListener() {
                    @Override
                    public void onDisplayAdded(int displayId) {
                        synchronized (mLock) {
                            updateLowPowerModeAllowedModesLocked();
                        }
                    }

                    @Override
                    public void onDisplayRemoved(int displayId) {
                        mVotesStorage.updateVote(displayId, Vote.PRIORITY_LOW_POWER_MODE_MODES,
                                null);
                    }

                    @Override
                    public void onDisplayChanged(int displayId) {
                        synchronized (mLock) {
                            updateLowPowerModeAllowedModesLocked();
                        }
                    }
                };

        SettingsObserver(@NonNull Context context, @NonNull Handler handler,
                DisplayManagerFlags flags) {
            super(handler);
            mContext = context;
            mVsynLowPowerVoteEnabled = flags.isVsyncLowPowerVoteEnabled();
            mHandler = handler;
            mVsyncLowPowerVoteEnabled = flags.isVsyncLowPowerVoteEnabled();
            mPeakRefreshRatePhysicalLimitEnabled = flags.isPeakRefreshRatePhysicalLimitEnabled();
            // We don't want to load from the DeviceConfig while constructing since this leads to
            // a spike in the latency of DisplayManagerService startup. This happens because
@@ -983,6 +1001,7 @@ public class DisplayModeDirector {
                    UserHandle.USER_SYSTEM);
            cr.registerContentObserver(mMatchContentFrameRateSetting, false /*notifyDescendants*/,
                    this);
            mInjector.registerDisplayListener(mDisplayListener, mHandler);

            float deviceConfigDefaultPeakRefresh =
                    mConfigParameterProvider.getPeakRefreshRateDefault();
@@ -995,6 +1014,7 @@ public class DisplayModeDirector {
                updateLowPowerModeSettingLocked();
                updateModeSwitchingTypeSettingLocked();
            }

        }

        public void setDefaultRefreshRate(float refreshRate) {
@@ -1061,23 +1081,36 @@ public class DisplayModeDirector {
        }

        private void updateLowPowerModeSettingLocked() {
            boolean inLowPowerMode = Settings.Global.getInt(mContext.getContentResolver(),
            mIsLowPower = Settings.Global.getInt(mContext.getContentResolver(),
                    Settings.Global.LOW_POWER_MODE, 0 /*default*/) != 0;
            final Vote vote;
            if (inLowPowerMode && mVsynLowPowerVoteEnabled && isVrrSupportedByAnyDisplayLocked()) {
                vote = Vote.forSupportedRefreshRates(List.of(
                        new SupportedRefreshRatesVote.RefreshRates(/* peakRefreshRate= */ 60f,
                                /* vsyncRate= */ 240f),
                        new SupportedRefreshRatesVote.RefreshRates(/* peakRefreshRate= */ 60f,
                                /* vsyncRate= */ 60f)
                ));
            } else if (inLowPowerMode) {
            if (mIsLowPower) {
                vote = Vote.forRenderFrameRates(0f, 60f);
            } else {
                vote = null;
            }
            mVotesStorage.updateGlobalVote(Vote.PRIORITY_LOW_POWER_MODE, vote);
            mBrightnessObserver.onLowPowerModeEnabledLocked(inLowPowerMode);
            mVotesStorage.updateGlobalVote(Vote.PRIORITY_LOW_POWER_MODE_RENDER_RATE, vote);
            mBrightnessObserver.onLowPowerModeEnabledLocked(mIsLowPower);
            updateLowPowerModeAllowedModesLocked();
        }

        private void updateLowPowerModeAllowedModesLocked() {
            if (!mVsyncLowPowerVoteEnabled) {
                return;
            }
            if (mIsLowPower) {
                for (int i = 0; i < mDisplayDeviceConfigByDisplay.size(); i++) {
                    DisplayDeviceConfig config = mDisplayDeviceConfigByDisplay.valueAt(i);
                    List<SupportedModeData> supportedModes = config
                            .getRefreshRateData().lowPowerSupportedModes;
                    mVotesStorage.updateVote(
                            mDisplayDeviceConfigByDisplay.keyAt(i),
                            Vote.PRIORITY_LOW_POWER_MODE_MODES,
                            Vote.forSupportedRefreshRates(supportedModes));
                }
            } else {
                mVotesStorage.removeAllVotesForPriority(Vote.PRIORITY_LOW_POWER_MODE_MODES);
            }
        }

        /**
+27 −10
Original line number Diff line number Diff line
@@ -18,6 +18,9 @@ package com.android.server.display.mode;

import android.annotation.NonNull;

import com.android.server.display.config.SupportedModeData;

import java.util.ArrayList;
import java.util.List;

interface Vote {
@@ -102,9 +105,15 @@ interface Vote {
    // For internal application to limit display modes to specific ids
    int PRIORITY_SYSTEM_REQUESTED_MODES = 14;

    // LOW_POWER_MODE force the render frame rate to [0, 60HZ] if
    // PRIORITY_LOW_POWER_MODE_MODES limits display modes to specific refreshRate-vsync pairs if
    // Settings.Global.LOW_POWER_MODE is on.
    // Lower priority that PRIORITY_LOW_POWER_MODE_RENDER_RATE and if discarded (due to other
    // higher priority votes), render rate limit can still apply
    int PRIORITY_LOW_POWER_MODE_MODES = 14;

    // PRIORITY_LOW_POWER_MODE_RENDER_RATE force the render frame rate to [0, 60HZ] if
    // Settings.Global.LOW_POWER_MODE is on.
    int PRIORITY_LOW_POWER_MODE = 15;
    int PRIORITY_LOW_POWER_MODE_RENDER_RATE = 15;

    // 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.
@@ -177,22 +186,26 @@ interface Vote {
        return new BaseModeRefreshRateVote(baseModeRefreshRate);
    }

    static Vote forSupportedRefreshRates(
            List<SupportedRefreshRatesVote.RefreshRates> refreshRates) {
        return new SupportedRefreshRatesVote(refreshRates);
    static Vote forSupportedRefreshRates(List<SupportedModeData> supportedModes) {
        if (supportedModes.isEmpty()) {
            return null;
        }
        List<SupportedRefreshRatesVote.RefreshRates> rates = new ArrayList<>();
        for (SupportedModeData data : supportedModes) {
            rates.add(new SupportedRefreshRatesVote.RefreshRates(data.refreshRate, data.vsyncRate));
        }
        return new SupportedRefreshRatesVote(rates);
    }

    static Vote forSupportedModes(List<Integer> modeIds) {
        return new SupportedModesVote(modeIds);
    }



    static Vote forSupportedRefreshRatesAndDisableSwitching(
            List<SupportedRefreshRatesVote.RefreshRates> supportedRefreshRates) {
        return new CombinedVote(
                List.of(forDisableRefreshRateSwitching(),
                        forSupportedRefreshRates(supportedRefreshRates)));
                        new SupportedRefreshRatesVote(supportedRefreshRates)));
    }

    static String priorityToString(int priority) {
@@ -213,8 +226,10 @@ interface Vote {
                return "PRIORITY_HIGH_BRIGHTNESS_MODE";
            case PRIORITY_PROXIMITY:
                return "PRIORITY_PROXIMITY";
            case PRIORITY_LOW_POWER_MODE:
                return "PRIORITY_LOW_POWER_MODE";
            case PRIORITY_LOW_POWER_MODE_MODES:
                return "PRIORITY_LOW_POWER_MODE_MODES";
            case PRIORITY_LOW_POWER_MODE_RENDER_RATE:
                return "PRIORITY_LOW_POWER_MODE_RENDER_RATE";
            case PRIORITY_SKIN_TEMPERATURE:
                return "PRIORITY_SKIN_TEMPERATURE";
            case PRIORITY_UDFPS:
@@ -227,6 +242,8 @@ interface Vote {
                return "PRIORITY_LIMIT_MODE";
            case PRIORITY_SYNCHRONIZED_REFRESH_RATE:
                return "PRIORITY_SYNCHRONIZED_REFRESH_RATE";
            case PRIORITY_USER_SETTING_PEAK_REFRESH_RATE:
                return "PRIORITY_USER_SETTING_PEAK_REFRESH_RATE";
            case PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE:
                return "PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE";
            case PRIORITY_AUTH_OPTIMIZER_RENDER_FRAME_RATE:
Loading