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

Commit 4f14640b authored by petsjonkin's avatar petsjonkin
Browse files

Moving HDR logic from HDRClamper to HDRModifier

HDRModifier now can apply bightness cap on ambient lux changes
This also fixes the bug: when switching ON hdr content cap should be applied instantly
This also fixes the bug: HDR capping works only when Adaptive Brightness ON

Bug: b/353474430 b/330433294 b/322445088
Test: atest HdrModidierTest
Flag: com.android.server.display.feature.flags.new_hdr_brightness_modifier
Change-Id: Ia6b7f0d922f1f7ba65c6abb941e1cc4905a8470f
parent 1d3f49a3
Loading
Loading
Loading
Loading
+7 −4
Original line number Diff line number Diff line
@@ -99,6 +99,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.function.Function;

import javax.xml.datatype.DatatypeConfigurationException;

@@ -1798,15 +1799,17 @@ public class DisplayDeviceConfig {
                loadThermalThrottlingConfig(config);
                loadPowerThrottlingConfigData(config);
                // Backlight and evenDimmer data should be loaded for HbmData
                mHbmData = HighBrightnessModeData.loadHighBrightnessModeData(config, (hbm) -> {
                Function<HighBrightnessMode, Float> transitionPointProvider = (hbm) -> {
                    float transitionPointBacklightScale = hbm.getTransitionPoint_all().floatValue();
                    if (transitionPointBacklightScale >= mBacklightMaximum) {
                        throw new IllegalArgumentException("HBM transition point invalid. "
                                + mHbmData.transitionPoint + " is not less than "
                                + transitionPointBacklightScale + " is not less than "
                                + mBacklightMaximum);
                    }
                    return  getBrightnessFromBacklight(transitionPointBacklightScale);
                });
                };
                mHbmData = HighBrightnessModeData.loadHighBrightnessModeData(config,
                        transitionPointProvider);
                if (mHbmData.isHighBrightnessModeEnabled && mHbmData.refreshRateLimit != null) {
                    // TODO(b/331650248): cleanup, DMD can use mHbmData.refreshRateLimit
                    mRefreshRateLimitations.add(new RefreshRateLimitation(
@@ -1830,7 +1833,7 @@ public class DisplayDeviceConfig {
                loadRefreshRateSetting(config);
                loadScreenOffBrightnessSensorValueToLuxFromDdc(config);
                loadUsiVersion(config);
                mHdrBrightnessData = HdrBrightnessData.loadConfig(config);
                mHdrBrightnessData = HdrBrightnessData.loadConfig(config, transitionPointProvider);
                loadBrightnessCapForWearBedtimeMode(config);
                loadIdleScreenRefreshRateTimeoutConfigs(config);
                mVrrSupportEnabled = config.getSupportsVrr();
+4 −3
Original line number Diff line number Diff line
@@ -271,8 +271,9 @@ public class BrightnessClamperController {
            ModifiersAggregatedState state2) {
        return !BrightnessSynchronizer.floatEquals(state1.mMaxDesiredHdrRatio,
                state2.mMaxDesiredHdrRatio)
                || state1.mSdrHdrRatioSpline != state2.mSdrHdrRatioSpline
                || state1.mHdrHbmEnabled != state2.mHdrHbmEnabled;
                || !BrightnessSynchronizer.floatEquals(state1.mMaxHdrBrightness,
                state2.mMaxHdrBrightness)
                || state1.mSdrHdrRatioSpline != state2.mSdrHdrRatioSpline;
    }

    private void start() {
@@ -470,8 +471,8 @@ public class BrightnessClamperController {
     */
    public static class ModifiersAggregatedState {
        float mMaxDesiredHdrRatio = HdrBrightnessModifier.DEFAULT_MAX_HDR_SDR_RATIO;
        float mMaxHdrBrightness = PowerManager.BRIGHTNESS_MAX;
        @Nullable
        Spline mSdrHdrRatioSpline = null;
        boolean mHdrHbmEnabled = false;
    }
}
+119 −13
Original line number Diff line number Diff line
@@ -16,11 +16,15 @@

package com.android.server.display.brightness.clamper;

import static com.android.server.display.DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET;
import static com.android.server.display.brightness.clamper.LightSensorController.INVALID_LUX;

import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.hardware.display.DisplayManagerInternal;
import android.os.Handler;
import android.os.IBinder;
import android.os.PowerManager;
import android.view.SurfaceControlHdrLayerInfoListener;

import com.android.internal.annotations.VisibleForTesting;
@@ -30,6 +34,7 @@ import com.android.server.display.DisplayDeviceConfig;
import com.android.server.display.config.HdrBrightnessData;

import java.io.PrintWriter;
import java.util.Map;

public class HdrBrightnessModifier implements BrightnessStateModifier,
        BrightnessClamperController.DisplayDeviceDataListener,
@@ -53,20 +58,32 @@ public class HdrBrightnessModifier implements BrightnessStateModifier,
    private final Handler mHandler;
    private final BrightnessClamperController.ClamperChangeListener mClamperChangeListener;
    private final Injector mInjector;
    private final Runnable mDebouncer;

    private IBinder mRegisteredDisplayToken;

    private float mScreenSize;
    private float mHdrLayerSize = DEFAULT_HDR_LAYER_SIZE;
    private HdrBrightnessData mHdrBrightnessData;
    private DisplayDeviceConfig mDisplayDeviceConfig;
    @Nullable
    private HdrBrightnessData mHdrBrightnessData;
    private float mScreenSize;

    private float mMaxDesiredHdrRatio = DEFAULT_MAX_HDR_SDR_RATIO;
    private float mHdrLayerSize = DEFAULT_HDR_LAYER_SIZE;

    private float mAmbientLux = INVALID_LUX;

    private Mode mMode = Mode.NO_HDR;
    // The maximum brightness allowed for current lux
    private float mMaxBrightness = PowerManager.BRIGHTNESS_MAX;
    private float mPendingMaxBrightness = PowerManager.BRIGHTNESS_MAX;
    // brightness change speed, in units per seconds. Applied only on ambient lux changes
    private float mTransitionRate = CUSTOM_ANIMATION_RATE_NOT_SET;
    private float mPendingTransitionRate = CUSTOM_ANIMATION_RATE_NOT_SET;

    HdrBrightnessModifier(Handler handler,
            BrightnessClamperController.ClamperChangeListener clamperChangeListener,
            BrightnessClamperController.DisplayDeviceData displayData) {
        this(handler, clamperChangeListener, new Injector(), displayData);
        this(new Handler(handler.getLooper()), clamperChangeListener, new Injector(), displayData);
    }

    @VisibleForTesting
@@ -77,6 +94,11 @@ public class HdrBrightnessModifier implements BrightnessStateModifier,
        mHandler = handler;
        mClamperChangeListener = clamperChangeListener;
        mInjector = injector;
        mDebouncer = () -> {
            mTransitionRate = mPendingTransitionRate;
            mMaxBrightness = mPendingMaxBrightness;
            mClamperChangeListener.onChanged();
        };
        onDisplayChanged(displayData);
    }

@@ -90,33 +112,60 @@ public class HdrBrightnessModifier implements BrightnessStateModifier,
        if (mMode == Mode.NO_HDR) {
            return;
        }

        float hdrBrightness = mDisplayDeviceConfig.getHdrBrightnessFromSdr(
                stateBuilder.getBrightness(), mMaxDesiredHdrRatio,
                mHdrBrightnessData.sdrToHdrRatioSpline);
        float maxBrightness = getMaxBrightness(mMode, mMaxBrightness, mHdrBrightnessData);
        hdrBrightness = Math.min(hdrBrightness, maxBrightness);

        stateBuilder.setHdrBrightness(hdrBrightness);
        stateBuilder.setCustomAnimationRate(mTransitionRate);
        // transition rate applied, reset
        mTransitionRate = CUSTOM_ANIMATION_RATE_NOT_SET;
    }

    @Override
    public void dump(PrintWriter printWriter) {
        // noop
    public void dump(PrintWriter pw) {
        pw.println("HdrBrightnessModifier:");
        pw.println("  mHdrBrightnessData=" + mHdrBrightnessData);
        pw.println("  mScreenSize=" + mScreenSize);
        pw.println("  mMaxDesiredHdrRatio=" + mMaxDesiredHdrRatio);
        pw.println("  mHdrLayerSize=" + mHdrLayerSize);
        pw.println("  mAmbientLux=" + mAmbientLux);
        pw.println("  mMode=" + mMode);
        pw.println("  mMaxBrightness=" + mMaxBrightness);
        pw.println("  mPendingMaxBrightness=" + mPendingMaxBrightness);
        pw.println("  mTransitionRate=" + mTransitionRate);
        pw.println("  mPendingTransitionRate=" + mPendingTransitionRate);
        pw.println("  mHdrListener registered=" + (mRegisteredDisplayToken != null));
    }

    // Called in DisplayControllerHandler
    @Override
    public void stop() {
        unregisterHdrListener();
        mHandler.removeCallbacksAndMessages(null);
    }


    // Called in DisplayControllerHandler
    @Override
    public boolean shouldListenToLightSensor() {
        return false;
        return hasBrightnessLimits();
    }

    // Called in DisplayControllerHandler
    @Override
    public void setAmbientLux(float lux) {
        // noop
        mAmbientLux = lux;
        if (!hasBrightnessLimits()) {
            return;
        }
        float desiredMaxBrightness = findBrightnessLimit(mHdrBrightnessData, lux);
        if (mMode == Mode.NO_HDR) {
            mMaxBrightness = desiredMaxBrightness;
        } else {
            scheduleMaxBrightnessUpdate(desiredMaxBrightness, mHdrBrightnessData);
        }
    }

    @Override
@@ -125,15 +174,44 @@ public class HdrBrightnessModifier implements BrightnessStateModifier,
                displayData.mHeight, displayData.mDisplayDeviceConfig));
    }

    // Called in DisplayControllerHandler
    // Called in DisplayControllerHandler, when any modifier state changes
    @Override
    public void applyStateChange(
            BrightnessClamperController.ModifiersAggregatedState aggregatedState) {
        if (mMode != Mode.NO_HDR) {
        if (mMode != Mode.NO_HDR && mHdrBrightnessData != null) {
            aggregatedState.mMaxDesiredHdrRatio = mMaxDesiredHdrRatio;
            aggregatedState.mSdrHdrRatioSpline = mHdrBrightnessData.sdrToHdrRatioSpline;
            aggregatedState.mHdrHbmEnabled = (mMode == Mode.HBM_HDR);
            aggregatedState.mMaxHdrBrightness = getMaxBrightness(
                    mMode, mMaxBrightness, mHdrBrightnessData);
        }
    }

    private boolean hasBrightnessLimits() {
        return mHdrBrightnessData != null && !mHdrBrightnessData.maxBrightnessLimits.isEmpty();
    }

    private void scheduleMaxBrightnessUpdate(float desiredMaxBrightness, HdrBrightnessData data) {
        if (mMaxBrightness == desiredMaxBrightness) {
            mPendingMaxBrightness = mMaxBrightness;
            mPendingTransitionRate = -1f;
            mTransitionRate = -1f;
            mHandler.removeCallbacks(mDebouncer);
        } else if (mPendingMaxBrightness != desiredMaxBrightness) {
            mPendingMaxBrightness = desiredMaxBrightness;
            long debounceTime;
            if (mPendingMaxBrightness > mMaxBrightness) {
                debounceTime = data.brightnessIncreaseDebounceMillis;
                mPendingTransitionRate = data.screenBrightnessRampIncrease;
            } else {
                debounceTime = data.brightnessDecreaseDebounceMillis;
                mPendingTransitionRate = data.screenBrightnessRampDecrease;
            }

            mHandler.removeCallbacks(mDebouncer);
            mHandler.postDelayed(mDebouncer, debounceTime);
        }
        // do nothing if expectedMaxBrightness == mDesiredMaxBrightness
        // && expectedMaxBrightness != mMaxBrightness
    }

    // Called in DisplayControllerHandler
@@ -168,6 +246,8 @@ public class HdrBrightnessModifier implements BrightnessStateModifier,
        mMaxDesiredHdrRatio = maxDesiredHdrRatio;

        if (needToNotifyChange) {
            // data or hdr layer changed, reset custom transition rate
            mTransitionRate = CUSTOM_ANIMATION_RATE_NOT_SET;
            mClamperChangeListener.onChanged();
        }
    }
@@ -190,6 +270,32 @@ public class HdrBrightnessModifier implements BrightnessStateModifier,
        return Mode.HBM_HDR;
    }

    private float getMaxBrightness(Mode mode, float maxBrightness, HdrBrightnessData data) {
        if (mode == Mode.NBM_HDR) {
            return Math.min(data.hbmTransitionPoint, maxBrightness);
        } else if (mode == Mode.HBM_HDR) {
            return maxBrightness;
        } else {
            return PowerManager.BRIGHTNESS_MAX;
        }
    }

    // Called in DisplayControllerHandler
    private float findBrightnessLimit(HdrBrightnessData data, float ambientLux) {
        float foundAmbientBoundary = Float.MAX_VALUE;
        float foundMaxBrightness = PowerManager.BRIGHTNESS_MAX;
        for (Map.Entry<Float, Float> brightnessPoint :
                data.maxBrightnessLimits.entrySet()) {
            float ambientBoundary = brightnessPoint.getKey();
            // find ambient lux upper boundary closest to current ambient lux
            if (ambientBoundary > ambientLux && ambientBoundary < foundAmbientBoundary) {
                foundMaxBrightness = brightnessPoint.getValue();
                foundAmbientBoundary = ambientBoundary;
            }
        }
        return foundMaxBrightness;
    }

    // Called in DisplayControllerHandler
    private void onHdrInfoChanged(float hdrLayerSize, float maxDesiredHdrSdrRatio) {
        mHdrLayerSize = hdrLayerSize;
+35 −6
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.display.config;
import static com.android.server.display.config.HighBrightnessModeData.HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT;

import android.annotation.Nullable;
import android.os.PowerManager;
import android.util.Spline;

import com.android.internal.annotations.VisibleForTesting;
@@ -29,6 +30,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

/**
 * Brightness config for HDR content
@@ -48,9 +50,9 @@ import java.util.Map;
 *             </point>
 *         </brightnessMap>
 *         <brightnessIncreaseDebounceMillis>1000</brightnessIncreaseDebounceMillis>
 *         <brightnessIncreaseDurationMillis>10000</brightnessIncreaseDurationMillis>
 *         <screenBrightnessRampIncrease>0.04</brightnessIncreaseDurationMillis>
 *         <brightnessDecreaseDebounceMillis>13000</brightnessDecreaseDebounceMillis>
 *         <brightnessDecreaseDurationMillis>10000</brightnessDecreaseDurationMillis>
 *         <screenBrightnessRampDecrease>0.03</brightnessDecreaseDurationMillis>
 *         <minimumHdrPercentOfScreenForNbm>0.2</minimumHdrPercentOfScreenForNbm>
 *         <minimumHdrPercentOfScreenForHbm>0.5</minimumHdrPercentOfScreenForHbm>
 *         <allowInLowPowerMode>true</allowInLowPowerMode>
@@ -98,6 +100,11 @@ public class HdrBrightnessData {
     */
    public final float screenBrightnessRampDecrease;

    /**
     * Brightness level at which we transition from normal to high-brightness
     */
    public final float hbmTransitionPoint;

    /**
     * Min Hdr layer size to start hdr brightness boost up to high brightness mode transition point
     */
@@ -123,6 +130,7 @@ public class HdrBrightnessData {
    public HdrBrightnessData(Map<Float, Float> maxBrightnessLimits,
            long brightnessIncreaseDebounceMillis, float screenBrightnessRampIncrease,
            long brightnessDecreaseDebounceMillis, float screenBrightnessRampDecrease,
            float hbmTransitionPoint,
            float minimumHdrPercentOfScreenForNbm, float minimumHdrPercentOfScreenForHbm,
            boolean allowInLowPowerMode, @Nullable Spline sdrToHdrRatioSpline) {
        this.maxBrightnessLimits = maxBrightnessLimits;
@@ -130,6 +138,7 @@ public class HdrBrightnessData {
        this.screenBrightnessRampIncrease = screenBrightnessRampIncrease;
        this.brightnessDecreaseDebounceMillis = brightnessDecreaseDebounceMillis;
        this.screenBrightnessRampDecrease = screenBrightnessRampDecrease;
        this.hbmTransitionPoint = hbmTransitionPoint;
        this.minimumHdrPercentOfScreenForNbm = minimumHdrPercentOfScreenForNbm;
        this.minimumHdrPercentOfScreenForHbm = minimumHdrPercentOfScreenForHbm;
        this.allowInLowPowerMode = allowInLowPowerMode;
@@ -144,6 +153,7 @@ public class HdrBrightnessData {
                + ", mScreenBrightnessRampIncrease: " + screenBrightnessRampIncrease
                + ", mBrightnessDecreaseDebounceMillis: " + brightnessDecreaseDebounceMillis
                + ", mScreenBrightnessRampDecrease: " + screenBrightnessRampDecrease
                + ", transitionPoint: " + hbmTransitionPoint
                + ", minimumHdrPercentOfScreenForNbm: " + minimumHdrPercentOfScreenForNbm
                + ", minimumHdrPercentOfScreenForHbm: " + minimumHdrPercentOfScreenForHbm
                + ", allowInLowPowerMode: " + allowInLowPowerMode
@@ -155,10 +165,12 @@ public class HdrBrightnessData {
     * Loads HdrBrightnessData from DisplayConfiguration
     */
    @Nullable
    public static HdrBrightnessData loadConfig(DisplayConfiguration config) {
    public static HdrBrightnessData loadConfig(DisplayConfiguration config,
            Function<HighBrightnessMode, Float> transitionPointProvider) {
        HighBrightnessMode hbmConfig = config.getHighBrightnessMode();
        HdrBrightnessConfig hdrConfig = config.getHdrBrightnessConfig();
        if (hdrConfig == null) {
            return getFallbackData(config.getHighBrightnessMode());
            return getFallbackData(hbmConfig, transitionPointProvider);
        }

        List<NonNegativeFloatToFloatPoint> points = hdrConfig.getBrightnessMap().getPoint();
@@ -169,22 +181,38 @@ public class HdrBrightnessData {

        float minHdrPercentForHbm = hdrConfig.getMinimumHdrPercentOfScreenForHbm() != null
                ? hdrConfig.getMinimumHdrPercentOfScreenForHbm().floatValue()
                : getFallbackHdrPercent(config.getHighBrightnessMode());
                : getFallbackHdrPercent(hbmConfig);

        float minHdrPercentForNbm = hdrConfig.getMinimumHdrPercentOfScreenForNbm() != null
                ? hdrConfig.getMinimumHdrPercentOfScreenForNbm().floatValue() : minHdrPercentForHbm;

        if (minHdrPercentForNbm > minHdrPercentForHbm) {
            throw new IllegalArgumentException(
                    "minHdrPercentForHbm should be >= minHdrPercentForNbm");
        }

        return new HdrBrightnessData(brightnessLimits,
                hdrConfig.getBrightnessIncreaseDebounceMillis().longValue(),
                hdrConfig.getScreenBrightnessRampIncrease().floatValue(),
                hdrConfig.getBrightnessDecreaseDebounceMillis().longValue(),
                hdrConfig.getScreenBrightnessRampDecrease().floatValue(),
                getTransitionPoint(hbmConfig, transitionPointProvider),
                minHdrPercentForNbm, minHdrPercentForHbm, hdrConfig.getAllowInLowPowerMode(),
                getSdrHdrRatioSpline(hdrConfig, config.getHighBrightnessMode()));
    }

    private static float getTransitionPoint(@Nullable HighBrightnessMode hbm,
            Function<HighBrightnessMode, Float> transitionPointProvider) {
        if (hbm == null) {
            return PowerManager.BRIGHTNESS_MAX;
        } else {
            return transitionPointProvider.apply(hbm);
        }
    }

    @Nullable
    private static HdrBrightnessData getFallbackData(HighBrightnessMode hbm) {
    private static HdrBrightnessData getFallbackData(@Nullable HighBrightnessMode hbm,
            Function<HighBrightnessMode, Float> transitionPointProvider) {
        if (hbm == null) {
            return null;
        }
@@ -193,6 +221,7 @@ public class HdrBrightnessData {
        return new HdrBrightnessData(Collections.emptyMap(),
                0, DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET,
                0, DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET,
                getTransitionPoint(hbm, transitionPointProvider),
                fallbackPercent, fallbackPercent, false, fallbackSpline);
    }

+2 −1
Original line number Diff line number Diff line
@@ -353,7 +353,8 @@ public class BrightnessClamperControllerTest {
    public void test_notifiesExternalListener_aggregatedStateChanged() {
        doAnswer((invocation) -> {
            ModifiersAggregatedState argument = invocation.getArgument(0);
            argument.mHdrHbmEnabled = true;
            // we need to do changes in AggregatedState to trigger onChange
            argument.mMaxHdrBrightness = 0.5f;
            return null;
        }).when(mMockStatefulModifier).applyStateChange(any());
        mTestInjector.mCapturedChangeListener.onChanged();
Loading