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

Commit 8982d22e authored by Long Ling's avatar Long Ling
Browse files

display: support display config items for sdr and hdr blending

Support newly added interpolation type for nitsMap, sdrHdrRatioMap
and minimumHdrPercentOfScreen for sdr and hdr blending.

Bug: 196171661
Change-Id: Ic9832f49d701e520f587972a2fba2bd182cbd7a0
parent f7ff96dd
Loading
Loading
Loading
Loading
+141 −4
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@ import android.util.Slog;
import android.util.Spline;
import android.view.DisplayAddress;

import com.android.internal.annotations.VisibleForTesting;

import com.android.internal.R;
import com.android.internal.display.BrightnessSynchronizer;
import com.android.server.display.config.BrightnessThresholds;
@@ -40,9 +42,12 @@ import com.android.server.display.config.DisplayConfiguration;
import com.android.server.display.config.DisplayQuirks;
import com.android.server.display.config.HbmTiming;
import com.android.server.display.config.HighBrightnessMode;
import com.android.server.display.config.Interpolation;
import com.android.server.display.config.NitsMap;
import com.android.server.display.config.Point;
import com.android.server.display.config.RefreshRateRange;
import com.android.server.display.config.SdrHdrRatioMap;
import com.android.server.display.config.SdrHdrRatioPoint;
import com.android.server.display.config.SensorDetails;
import com.android.server.display.config.ThermalStatus;
import com.android.server.display.config.ThermalThrottling;
@@ -70,6 +75,7 @@ import javax.xml.datatype.DatatypeConfigurationException;
 */
public class DisplayDeviceConfig {
    private static final String TAG = "DisplayDeviceConfig";
    private static final boolean DEBUG = false;

    public static final float HIGH_BRIGHTNESS_MODE_UNSUPPORTED = Float.NaN;

@@ -86,6 +92,9 @@ public class DisplayDeviceConfig {
    private static final String NO_SUFFIX_FORMAT = "%d";
    private static final long STABLE_FLAG = 1L << 62;

    private static final int INTERPOLATION_DEFAULT = 0;
    private static final int INTERPOLATION_LINEAR = 1;

    // Float.NaN (used as invalid for brightness) cannot be stored in config.xml
    // so -2 is used instead
    private static final float INVALID_BRIGHTNESS_IN_CONFIG = -2f;
@@ -99,6 +108,9 @@ public class DisplayDeviceConfig {
    // Length of the ambient light horizon used to calculate short-term estimate of ambient light.
    private static final int AMBIENT_LIGHT_SHORT_HORIZON_MILLIS = 2000;

    @VisibleForTesting
    static final float HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT = 0.5f;

    private final Context mContext;

    // The details of the ambient light sensor associated with this display.
@@ -114,6 +126,7 @@ public class DisplayDeviceConfig {
    // config.xml. These are the raw values and just used for the dumpsys
    private float[] mRawNits;
    private float[] mRawBacklight;
    private int mInterpolationType;

    // These arrays are calculated from the raw arrays, but clamped to contain values equal to and
    // between mBacklightMinimum and mBacklightMaximum. These three arrays should all be the same
@@ -142,6 +155,7 @@ public class DisplayDeviceConfig {
    private Spline mBrightnessToBacklightSpline;
    private Spline mBacklightToBrightnessSpline;
    private Spline mBacklightToNitsSpline;
    private Spline mNitsToBacklightSpline;
    private List<String> mQuirks;
    private boolean mIsHighBrightnessModeEnabled = false;
    private HighBrightnessModeData mHbmData;
@@ -149,6 +163,7 @@ public class DisplayDeviceConfig {
    private String mLoadedFrom = null;

    private BrightnessThrottlingData mBrightnessThrottlingData;
    private Spline mSdrToHdrRatioSpline;

    private DisplayDeviceConfig(Context context) {
        mContext = context;
@@ -332,6 +347,45 @@ public class DisplayDeviceConfig {
        return mBacklightToNitsSpline.interpolate(backlight);
    }

    /**
     * Calculate the HDR brightness for the specified SDR brightenss.
     *
     * @return the HDR brightness or BRIGHTNESS_INVALID when no mapping exists.
     */
    public float getHdrBrightnessFromSdr(float brightness) {
        if (mSdrToHdrRatioSpline == null) {
            return PowerManager.BRIGHTNESS_INVALID;
        }

        float backlight = getBacklightFromBrightness(brightness);
        float nits = getNitsFromBacklight(backlight);
        if (nits == NITS_INVALID) {
            return PowerManager.BRIGHTNESS_INVALID;
        }

        float ratio = mSdrToHdrRatioSpline.interpolate(nits);
        float hdrNits = nits * ratio;
        if (mNitsToBacklightSpline == null) {
            return PowerManager.BRIGHTNESS_INVALID;
        }

        float hdrBacklight = mNitsToBacklightSpline.interpolate(hdrNits);
        hdrBacklight = Math.max(mBacklightMinimum, Math.min(mBacklightMaximum, hdrBacklight));
        float hdrBrightness = mBacklightToBrightnessSpline.interpolate(hdrBacklight);

        if (DEBUG) {
            Slog.d(TAG, "getHdrBrightnessFromSdr: sdr brightness " + brightness
                + " backlight " + backlight
                + " nits " + nits
                + " ratio " + ratio
                + " hdrNits " + hdrNits
                + " hdrBacklight " + hdrBacklight
                + " hdrBrightness " + hdrBrightness
                );
        }
        return hdrBrightness;
    }

    /**
     * Return an array of equal length to backlight and nits, that covers the entire system
     * brightness range of 0.0-1.0.
@@ -444,15 +498,18 @@ public class DisplayDeviceConfig {
                + ", mNits=" + Arrays.toString(mNits)
                + ", mRawBacklight=" + Arrays.toString(mRawBacklight)
                + ", mRawNits=" + Arrays.toString(mRawNits)
                + ", mInterpolationType=" + mInterpolationType
                + ", mBrightness=" + Arrays.toString(mBrightness)
                + ", mBrightnessToBacklightSpline=" + mBrightnessToBacklightSpline
                + ", mBacklightToBrightnessSpline=" + mBacklightToBrightnessSpline
                + ", mNitsToBacklightSpline=" + mNitsToBacklightSpline
                + ", mBacklightMinimum=" + mBacklightMinimum
                + ", mBacklightMaximum=" + mBacklightMaximum
                + ", mBrightnessDefault=" + mBrightnessDefault
                + ", mQuirks=" + mQuirks
                + ", isHbmEnabled=" + mIsHighBrightnessModeEnabled
                + ", mHbmData=" + mHbmData
                + ", mSdrToHdrRatioSpline=" + mSdrToHdrRatioSpline
                + ", mBrightnessThrottlingData=" + mBrightnessThrottlingData
                + ", mBrightnessRampFastDecrease=" + mBrightnessRampFastDecrease
                + ", mBrightnessRampFastIncrease=" + mBrightnessRampFastIncrease
@@ -653,6 +710,7 @@ public class DisplayDeviceConfig {
        float[] nits = new float[size];
        float[] backlight = new float[size];

        mInterpolationType = convertInterpolationType(map.getInterpolation());
        int i = 0;
        for (Point point : points) {
            nits[i] = point.getNits().floatValue();
@@ -678,6 +736,40 @@ public class DisplayDeviceConfig {
        constrainNitsAndBacklightArrays();
    }

    private Spline loadSdrHdrRatioMap(HighBrightnessMode hbmConfig) {
        final SdrHdrRatioMap sdrHdrRatioMap = hbmConfig.getSdrHdrRatioMap_all();

        if (sdrHdrRatioMap == null) {
            return null;
        }

        final List<SdrHdrRatioPoint> points = sdrHdrRatioMap.getPoint();
        final int size = points.size();
        if (size <= 0) {
            return null;
        }

        float[] nits = new float[size];
        float[] ratios = new float[size];

        int i = 0;
        for (SdrHdrRatioPoint point : points) {
            nits[i] = point.getSdrNits().floatValue();
            if (i > 0) {
                if (nits[i] < nits[i - 1]) {
                    Slog.e(TAG, "sdrHdrRatioMap must be non-decreasing, ignoring rest "
                                + " of configuration. nits: " + nits[i] + " < "
                                + nits[i - 1]);
                    return null;
                }
            }
            ratios[i] = point.getHdrRatio().floatValue();
            ++i;
        }

        return Spline.createSpline(nits, ratios);
    }

    private void loadBrightnessThrottlingMap(DisplayConfiguration config) {
        final ThermalThrottling throttlingConfig = config.getThermalThrottling();
        if (throttlingConfig == null) {
@@ -823,9 +915,18 @@ public class DisplayDeviceConfig {
                    mBacklight[mBacklight.length - 1],
                    PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, mBacklight[i]);
        }
        mBrightnessToBacklightSpline = Spline.createSpline(mBrightness, mBacklight);
        mBacklightToBrightnessSpline = Spline.createSpline(mBacklight, mBrightness);
        mBacklightToNitsSpline = Spline.createSpline(mBacklight, mNits);
        mBrightnessToBacklightSpline = mInterpolationType == INTERPOLATION_LINEAR
            ? Spline.createLinearSpline(mBrightness, mBacklight)
            : Spline.createSpline(mBrightness, mBacklight);
        mBacklightToBrightnessSpline = mInterpolationType == INTERPOLATION_LINEAR
            ? Spline.createLinearSpline(mBacklight, mBrightness)
            : Spline.createSpline(mBacklight, mBrightness);
        mBacklightToNitsSpline = mInterpolationType == INTERPOLATION_LINEAR
            ? Spline.createLinearSpline(mBacklight, mNits)
            : Spline.createSpline(mBacklight, mNits);
        mNitsToBacklightSpline = mInterpolationType == INTERPOLATION_LINEAR
            ? Spline.createLinearSpline(mNits, mBacklight)
            : Spline.createSpline(mNits, mBacklight);
    }

    private void loadQuirks(DisplayConfiguration config) {
@@ -862,6 +963,20 @@ public class DisplayDeviceConfig {
                mRefreshRateLimitations.add(new RefreshRateLimitation(
                        DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE, min, max));
            }
            BigDecimal minHdrPctOfScreen = hbm.getMinimumHdrPercentOfScreen_all();
            if (minHdrPctOfScreen != null) {
                mHbmData.minimumHdrPercentOfScreen = minHdrPctOfScreen.floatValue();
                if (mHbmData.minimumHdrPercentOfScreen > 1
                        || mHbmData.minimumHdrPercentOfScreen < 0) {
                    Slog.w(TAG, "Invalid minimum HDR percent of screen: "
                                    + String.valueOf(mHbmData.minimumHdrPercentOfScreen));
                    mHbmData.minimumHdrPercentOfScreen = HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT;
                }
            } else {
                mHbmData.minimumHdrPercentOfScreen = HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT;
            }

            mSdrToHdrRatioSpline = loadSdrHdrRatioMap(hbm);
        }
    }

@@ -1024,6 +1139,21 @@ public class DisplayDeviceConfig {
        }
    }

    private int convertInterpolationType(Interpolation value) {
        if (value == null) {
            return INTERPOLATION_DEFAULT;
        }
        switch (value) {
            case _default:
                return INTERPOLATION_DEFAULT;
            case linear:
                return INTERPOLATION_LINEAR;
            default:
                Slog.wtf(TAG, "Unexpected Interpolation Type: " + value);
                return INTERPOLATION_DEFAULT;
        }
    }

    private void loadAmbientHorizonFromDdc(DisplayConfiguration config) {
        final BigInteger configLongHorizon = config.getAmbientLightHorizonLong();
        if (configLongHorizon != null) {
@@ -1088,11 +1218,15 @@ public class DisplayDeviceConfig {
        /** Minimum time that HBM can be on before being enabled. */
        public long timeMinMillis;

        /** Minimum HDR video size to enter high brightness mode */
        public float minimumHdrPercentOfScreen;

        HighBrightnessModeData() {}

        HighBrightnessModeData(float minimumLux, float transitionPoint, long timeWindowMillis,
                long timeMaxMillis, long timeMinMillis,
                @PowerManager.ThermalStatus int thermalStatusLimit, boolean allowInLowPowerMode) {
                @PowerManager.ThermalStatus int thermalStatusLimit, boolean allowInLowPowerMode,
                float minimumHdrPercentOfScreen) {
            this.minimumLux = minimumLux;
            this.transitionPoint = transitionPoint;
            this.timeWindowMillis = timeWindowMillis;
@@ -1100,6 +1234,7 @@ public class DisplayDeviceConfig {
            this.timeMinMillis = timeMinMillis;
            this.thermalStatusLimit = thermalStatusLimit;
            this.allowInLowPowerMode = allowInLowPowerMode;
            this.minimumHdrPercentOfScreen = minimumHdrPercentOfScreen;
        }

        /**
@@ -1114,6 +1249,7 @@ public class DisplayDeviceConfig {
            other.transitionPoint = transitionPoint;
            other.thermalStatusLimit = thermalStatusLimit;
            other.allowInLowPowerMode = allowInLowPowerMode;
            other.minimumHdrPercentOfScreen = minimumHdrPercentOfScreen;
        }

        @Override
@@ -1126,6 +1262,7 @@ public class DisplayDeviceConfig {
                    + ", timeMin: " + timeMinMillis + "ms"
                    + ", thermalStatusLimit: " + thermalStatusLimit
                    + ", allowInLowPowerMode: " + allowInLowPowerMode
                    + ", minimumHdrPercentOfScreen: " + minimumHdrPercentOfScreen
                    + "} ";
        }
    }
+13 −1
Original line number Diff line number Diff line
@@ -831,7 +831,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
        setUpAutoBrightness(mContext.getResources(), mHandler);
        reloadReduceBrightColours();
        mHbmController.resetHbmData(info.width, info.height, token, info.uniqueId,
                mDisplayDeviceConfig.getHighBrightnessModeData());
                mDisplayDeviceConfig.getHighBrightnessModeData(),
                new HighBrightnessModeController.HdrBrightnessDeviceConfig() {
                    @Override
                    public float getHdrBrightnessFromSdr(float sdrBrightness) {
                        return mDisplayDeviceConfig.getHdrBrightnessFromSdr(sdrBrightness);
                    }
                });
        mBrightnessThrottler.resetThrottlingData(
                mDisplayDeviceConfig.getBrightnessThrottlingData());
    }
@@ -1697,6 +1703,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
        final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
        return new HighBrightnessModeController(mHandler, info.width, info.height, displayToken,
                displayUniqueId, PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, hbmData,
                new HighBrightnessModeController.HdrBrightnessDeviceConfig() {
                    @Override
                    public float getHdrBrightnessFromSdr(float sdrBrightness) {
                        return mDisplayDeviceConfig.getHdrBrightnessFromSdr(sdrBrightness);
                    }
                },
                () -> {
                    sendUpdatePowerStateLocked();
                    postBrightnessChangeRunnable();
+22 −10
Original line number Diff line number Diff line
@@ -58,11 +58,13 @@ class HighBrightnessModeController {

    private static final boolean DEBUG = false;

    private static final float HDR_PERCENT_OF_SCREEN_REQUIRED = 0.50f;

    @VisibleForTesting
    static final float HBM_TRANSITION_POINT_INVALID = Float.POSITIVE_INFINITY;

    public interface HdrBrightnessDeviceConfig {
        float getHdrBrightnessFromSdr(float sdrBrightness);
    }

    private final float mBrightnessMin;
    private final float mBrightnessMax;
    private final Handler mHandler;
@@ -76,6 +78,7 @@ class HighBrightnessModeController {

    private HdrListener mHdrListener;
    private HighBrightnessModeData mHbmData;
    private HdrBrightnessDeviceConfig mHdrBrightnessCfg;
    private IBinder mRegisteredDisplayToken;

    private boolean mIsInAllowedAmbientRange = false;
@@ -115,16 +118,17 @@ class HighBrightnessModeController {

    HighBrightnessModeController(Handler handler, int width, int height, IBinder displayToken,
            String displayUniqueId, float brightnessMin, float brightnessMax,
            HighBrightnessModeData hbmData, Runnable hbmChangeCallback, Context context) {
            HighBrightnessModeData hbmData, HdrBrightnessDeviceConfig hdrBrightnessCfg,
            Runnable hbmChangeCallback, Context context) {
        this(new Injector(), handler, width, height, displayToken, displayUniqueId, brightnessMin,
            brightnessMax, hbmData, hbmChangeCallback, context);
            brightnessMax, hbmData, hdrBrightnessCfg, hbmChangeCallback, context);
    }

    @VisibleForTesting
    HighBrightnessModeController(Injector injector, Handler handler, int width, int height,
            IBinder displayToken, String displayUniqueId, float brightnessMin, float brightnessMax,
            HighBrightnessModeData hbmData, Runnable hbmChangeCallback,
            Context context) {
            HighBrightnessModeData hbmData, HdrBrightnessDeviceConfig hdrBrightnessCfg,
            Runnable hbmChangeCallback, Context context) {
        mInjector = injector;
        mContext = context;
        mClock = injector.getClock();
@@ -138,7 +142,7 @@ class HighBrightnessModeController {
        mRecalcRunnable = this::recalculateTimeAllowance;
        mHdrListener = new HdrListener();

        resetHbmData(width, height, displayToken, displayUniqueId, hbmData);
        resetHbmData(width, height, displayToken, displayUniqueId, hbmData, hdrBrightnessCfg);
    }

    void setAutoBrightnessEnabled(int state) {
@@ -178,6 +182,13 @@ class HighBrightnessModeController {
    }

    float getHdrBrightnessValue() {
        if (mHdrBrightnessCfg != null) {
            float hdrBrightness = mHdrBrightnessCfg.getHdrBrightnessFromSdr(mBrightness);
            if (hdrBrightness != PowerManager.BRIGHTNESS_INVALID) {
                return hdrBrightness;
            }
        }

        // For HDR brightness, we take the current brightness and scale it to the max. The reason
        // we do this is because we want brightness to go to HBM max when it would normally go
        // to normal max, meaning it should not wait to go to 10000 lux (or whatever the transition
@@ -250,10 +261,11 @@ class HighBrightnessModeController {
    }

    void resetHbmData(int width, int height, IBinder displayToken, String displayUniqueId,
            HighBrightnessModeData hbmData) {
            HighBrightnessModeData hbmData, HdrBrightnessDeviceConfig hdrBrightnessCfg) {
        mWidth = width;
        mHeight = height;
        mHbmData = hbmData;
        mHdrBrightnessCfg = hdrBrightnessCfg;
        mDisplayStatsId = displayUniqueId.hashCode();

        unregisterHdrListener();
@@ -598,8 +610,8 @@ class HighBrightnessModeController {
                int maxW, int maxH, int flags) {
            mHandler.post(() -> {
                mIsHdrLayerPresent = numberOfHdrLayers > 0
                        && (float) (maxW * maxH)
                                >= ((float) (mWidth * mHeight) * HDR_PERCENT_OF_SCREEN_REQUIRED);
                        && (float) (maxW * maxH) >= ((float) (mWidth * mHeight)
                                   * mHbmData.minimumHdrPercentOfScreen);
                // Calling the brightness update so that we can recalculate
                // brightness with HDR in mind.
                onBrightnessChanged(mBrightness, mUnthrottledBrightness, mThrottlingReason);
+8 −4
Original line number Diff line number Diff line
@@ -22,11 +22,14 @@ import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR;
import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT;


import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED;
import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED;
import static com.android.server.display.AutomaticBrightnessController
                                                      .AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE;

import static com.android.server.display.DisplayDeviceConfig.HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT;

import static com.android.server.display.HighBrightnessModeController.HBM_TRANSITION_POINT_INVALID;

import static org.junit.Assert.assertEquals;
@@ -111,7 +114,8 @@ public class HighBrightnessModeControllerTest {
    private static final HighBrightnessModeData DEFAULT_HBM_DATA =
            new HighBrightnessModeData(MINIMUM_LUX, TRANSITION_POINT, TIME_WINDOW_MILLIS,
                    TIME_ALLOWED_IN_WINDOW_MILLIS, TIME_MINIMUM_AVAILABLE_TO_ENABLE_MILLIS,
                    THERMAL_STATUS_LIMIT, ALLOW_IN_LOW_POWER_MODE);
                    THERMAL_STATUS_LIMIT, ALLOW_IN_LOW_POWER_MODE,
                    HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT);

    @Before
    public void setUp() {
@@ -136,7 +140,7 @@ public class HighBrightnessModeControllerTest {
        initHandler(null);
        final HighBrightnessModeController hbmc = new HighBrightnessModeController(
                mInjectorMock, mHandler, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayToken,
                mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, () -> {}, mContextSpy);
                mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, null, () -> {}, mContextSpy);
        assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF);
        assertEquals(hbmc.getTransitionPoint(), HBM_TRANSITION_POINT_INVALID, 0.0f);
    }
@@ -146,7 +150,7 @@ public class HighBrightnessModeControllerTest {
        initHandler(null);
        final HighBrightnessModeController hbmc = new HighBrightnessModeController(
                mInjectorMock, mHandler, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayToken,
                mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, () -> {}, mContextSpy);
                mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, null, () -> {}, mContextSpy);
        hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
        hbmc.onAmbientLuxChange(MINIMUM_LUX - 1); // below allowed range
        assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF);
@@ -679,7 +683,7 @@ public class HighBrightnessModeControllerTest {
        initHandler(clock);
        return new HighBrightnessModeController(mInjectorMock, mHandler, DISPLAY_WIDTH,
                DISPLAY_HEIGHT, mDisplayToken, mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX,
                DEFAULT_HBM_DATA, () -> {}, mContextSpy);
                DEFAULT_HBM_DATA, null, () -> {}, mContextSpy);
    }

    private void initHandler(OffsettableClock clock) {