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

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

Merge "Introducing HDRClamper" into main

parents a41ed506 161958d2
Loading
Loading
Loading
Loading
+20 −3
Original line number Diff line number Diff line
@@ -17,9 +17,11 @@
package com.android.server.display;

import android.hardware.display.BrightnessInfo;
import android.os.Handler;
import android.os.IBinder;
import android.provider.DeviceConfigInterface;

import com.android.server.display.brightness.clamper.HdrClamper;
import com.android.server.display.feature.DeviceConfigParameterProvider;

import java.io.PrintWriter;
@@ -31,23 +33,30 @@ class BrightnessRangeController {
    private final NormalBrightnessModeController mNormalBrightnessModeController =
            new NormalBrightnessModeController();

    private final HdrClamper mHdrClamper;

    private final Runnable mModeChangeCallback;
    private final boolean mUseNbmController;

    private final boolean mUseHdrClamper;


    BrightnessRangeController(HighBrightnessModeController hbmController,
            Runnable modeChangeCallback, DisplayDeviceConfig displayDeviceConfig) {
            Runnable modeChangeCallback, DisplayDeviceConfig displayDeviceConfig, Handler handler) {
        this(hbmController, modeChangeCallback, displayDeviceConfig,
                new HdrClamper(modeChangeCallback::run, new Handler(handler.getLooper())),
                new DeviceConfigParameterProvider(DeviceConfigInterface.REAL));
    }

    BrightnessRangeController(HighBrightnessModeController hbmController,
            Runnable modeChangeCallback, DisplayDeviceConfig displayDeviceConfig,
            DeviceConfigParameterProvider configParameterProvider) {
            HdrClamper hdrClamper, DeviceConfigParameterProvider configParameterProvider) {
        mHbmController = hbmController;
        mModeChangeCallback = modeChangeCallback;
        mUseNbmController = configParameterProvider.isNormalBrightnessControllerFeatureEnabled();
        mUseHdrClamper = false;
        mNormalBrightnessModeController.resetNbmData(displayDeviceConfig.getLuxThrottlingData());
        mHdrClamper = hdrClamper;
    }

    void dump(PrintWriter pw) {
@@ -63,6 +72,9 @@ class BrightnessRangeController {
                () -> mNormalBrightnessModeController.onAmbientLuxChange(ambientLux),
                () -> mHbmController.onAmbientLuxChange(ambientLux)
        );
        if (mUseHdrClamper) {
            mHdrClamper.onAmbientLuxChange(ambientLux);
        }
    }

    float getNormalBrightnessMax() {
@@ -118,7 +130,8 @@ class BrightnessRangeController {
    }

    float getHdrBrightnessValue() {
        return mHbmController.getHdrBrightnessValue();
        float hdrBrightness =  mHbmController.getHdrBrightnessValue();
        return Math.min(hdrBrightness, mHdrClamper.getMaxBrightness());
    }

    float getTransitionPoint() {
@@ -138,4 +151,8 @@ class BrightnessRangeController {
            hbmChangesFunc.run();
        }
    }

    public float getHdrTransitionRate() {
        return mHdrClamper.getTransitionRate();
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -677,7 +677,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
        HighBrightnessModeController hbmController = createHbmControllerLocked(modeChangeCallback);

        mBrightnessRangeController = new BrightnessRangeController(hbmController,
                modeChangeCallback, mDisplayDeviceConfig);
                modeChangeCallback, mDisplayDeviceConfig, mHandler);

        mBrightnessThrottler = createBrightnessThrottlerLocked();

+16 −2
Original line number Diff line number Diff line
@@ -539,8 +539,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
                modeChangeCallback);
        mBrightnessThrottler = createBrightnessThrottlerLocked();

        mBrightnessRangeController = new BrightnessRangeController(hbmController,
                modeChangeCallback, mDisplayDeviceConfig);
        mBrightnessRangeController = mInjector.getBrightnessRangeController(hbmController,
                modeChangeCallback, mDisplayDeviceConfig, mHandler);

        mDisplayBrightnessController =
                new DisplayBrightnessController(context, null,
@@ -1497,6 +1497,9 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
            // allowed range.
            float animateValue = clampScreenBrightness(brightnessState);

            // custom transition duration
            float customTransitionRate = -1f;

            // If there are any HDR layers on the screen, we have a special brightness value that we
            // use instead. We still preserve the calculated brightness for Standard Dynamic Range
            // (SDR) layers, but the main brightness value will be the one for HDR.
@@ -1511,6 +1514,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
                // We want to scale HDR brightness level with the SDR level, we also need to restore
                // SDR brightness immediately when entering dim or low power mode.
                animateValue = mBrightnessRangeController.getHdrBrightnessValue();
                customTransitionRate = mBrightnessRangeController.getHdrTransitionRate();
            }

            final float currentBrightness = mPowerState.getScreenBrightness();
@@ -1523,6 +1527,9 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
                        || !isDisplayContentVisible || brightnessIsTemporary) {
                    animateScreenBrightness(animateValue, sdrAnimateValue,
                            SCREEN_ANIMATION_RATE_MINIMUM);
                } else if (customTransitionRate > 0) {
                    animateScreenBrightness(animateValue, sdrAnimateValue,
                            customTransitionRate);
                } else {
                    boolean isIncreasing = animateValue > currentBrightness;
                    final float rampSpeed;
@@ -2968,6 +2975,13 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
                    hbmChangeCallback, hbmMetadata, context);
        }

        BrightnessRangeController getBrightnessRangeController(
                HighBrightnessModeController hbmController, Runnable modeChangeCallback,
                DisplayDeviceConfig displayDeviceConfig, Handler handler) {
            return new BrightnessRangeController(hbmController,
                    modeChangeCallback, displayDeviceConfig, handler);
        }

        DisplayWhiteBalanceController getDisplayWhiteBalanceController(Handler handler,
                SensorManager sensorManager, Resources resources) {
            return DisplayWhiteBalanceFactory.create(handler,
+132 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.brightness.clamper;

import android.os.Handler;
import android.os.PowerManager;

import com.android.internal.annotations.VisibleForTesting;

import java.util.HashMap;
import java.util.Map;

public class HdrClamper {

    private final Configuration mConfiguration = new Configuration();

    private final BrightnessClamperController.ClamperChangeListener mClamperChangeListener;

    private final Handler mHandler;

    private final Runnable mDebouncer;

    private float mMaxBrightness = PowerManager.BRIGHTNESS_MAX;

    // brightness change speed, in units per seconds,
    private float mTransitionRate = -1f;

    private float mDesiredMaxBrightness = PowerManager.BRIGHTNESS_MAX;

    private float mDesiredTransitionDuration = -1; // in seconds

    public HdrClamper(BrightnessClamperController.ClamperChangeListener clamperChangeListener,
            Handler handler) {
        mClamperChangeListener = clamperChangeListener;
        mHandler = handler;
        mDebouncer = () -> {
            mTransitionRate = Math.abs((mMaxBrightness - mDesiredMaxBrightness)
                    / mDesiredTransitionDuration);
            mMaxBrightness = mDesiredMaxBrightness;
            mClamperChangeListener.onChanged();
        };
    }

    // Called in same looper: mHandler.getLooper()
    public float getMaxBrightness() {
        return mMaxBrightness;
    }

    // Called in same looper: mHandler.getLooper()
    public float getTransitionRate() {
        return mTransitionRate;
    }


    /**
     * Updates brightness cap in response to ambient lux change.
     * Called by ABC in same looper: mHandler.getLooper()
     */
    public void onAmbientLuxChange(float ambientLux) {
        float expectedMaxBrightness = findBrightnessLimit(ambientLux);
        if (mMaxBrightness == expectedMaxBrightness) {
            mDesiredMaxBrightness = mMaxBrightness;
            mDesiredTransitionDuration = -1;
            mTransitionRate = -1f;
            mHandler.removeCallbacks(mDebouncer);
        } else if (mDesiredMaxBrightness != expectedMaxBrightness) {
            mDesiredMaxBrightness = expectedMaxBrightness;
            long debounceTime;
            if (mDesiredMaxBrightness > mMaxBrightness) {
                debounceTime = mConfiguration.mIncreaseConfig.mDebounceTimeMillis;
                mDesiredTransitionDuration =
                        (float) mConfiguration.mIncreaseConfig.mTransitionTimeMillis / 1000;
            } else {
                debounceTime = mConfiguration.mDecreaseConfig.mDebounceTimeMillis;
                mDesiredTransitionDuration =
                        (float) mConfiguration.mDecreaseConfig.mTransitionTimeMillis / 1000;
            }

            mHandler.removeCallbacks(mDebouncer);
            mHandler.postDelayed(mDebouncer, debounceTime);
        }
    }

    @VisibleForTesting
    Configuration getConfiguration() {
        return mConfiguration;
    }

    private float findBrightnessLimit(float ambientLux) {
        float foundAmbientBoundary = Float.MAX_VALUE;
        float foundMaxBrightness = PowerManager.BRIGHTNESS_MAX;
        for (Map.Entry<Float, Float> brightnessPoint :
                mConfiguration.mMaxBrightnessLimits.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;
    }

    @VisibleForTesting
    static class Configuration {
        final Map<Float, Float> mMaxBrightnessLimits = new HashMap<>();
        final TransitionConfiguration mIncreaseConfig = new TransitionConfiguration();

        final TransitionConfiguration mDecreaseConfig = new TransitionConfiguration();
    }

    @VisibleForTesting
    static class TransitionConfiguration {
        long mDebounceTimeMillis;

        long mTransitionTimeMillis;
    }
}
+50 −3
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import android.content.res.Resources;
import android.hardware.Sensor;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.display.BrightnessInfo;
import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks;
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
import android.os.Handler;
@@ -67,7 +68,9 @@ import com.android.server.LocalServices;
import com.android.server.am.BatteryStatsService;
import com.android.server.display.RampAnimator.DualRampAnimator;
import com.android.server.display.brightness.BrightnessEvent;
import com.android.server.display.brightness.clamper.HdrClamper;
import com.android.server.display.color.ColorDisplayService;
import com.android.server.display.feature.DeviceConfigParameterProvider;
import com.android.server.display.layout.Layout;
import com.android.server.display.whitebalance.DisplayWhiteBalanceController;
import com.android.server.policy.WindowManagerPolicy;
@@ -1175,6 +1178,26 @@ public final class DisplayPowerController2Test {
        verify(mHolder.displayPowerState, times(1)).stop();
    }

    @Test
    public void testRampRateForHdrContent() {
        float clampedBrightness = 0.6f;
        float transitionRate = 35.5f;

        DisplayPowerRequest dpr = new DisplayPowerRequest();
        when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
        when(mHolder.hbmController.getHighBrightnessMode()).thenReturn(
                BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR);
        when(mHolder.hbmController.getHdrBrightnessValue()).thenReturn(PowerManager.BRIGHTNESS_MAX);
        when(mHolder.hdrClamper.getMaxBrightness()).thenReturn(clampedBrightness);
        when(mHolder.hdrClamper.getTransitionRate()).thenReturn(transitionRate);

        mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
        advanceTime(1); // Run updatePowerState

        verify(mHolder.animator, atLeastOnce()).animateTo(eq(clampedBrightness), anyFloat(),
                eq(transitionRate));
    }

    /**
     * Creates a mock and registers it to {@link LocalServices}.
     */
@@ -1270,12 +1293,16 @@ public final class DisplayPowerController2Test {
        final ScreenOffBrightnessSensorController screenOffBrightnessSensorController =
                mock(ScreenOffBrightnessSensorController.class);
        final HighBrightnessModeController hbmController = mock(HighBrightnessModeController.class);
        final HdrClamper hdrClamper = mock(HdrClamper.class);
        final DeviceConfigParameterProvider deviceConfigParameterProvider =
                mock(DeviceConfigParameterProvider.class);

        when(hbmController.getCurrentBrightnessMax()).thenReturn(PowerManager.BRIGHTNESS_MAX);

        TestInjector injector = spy(new TestInjector(displayPowerState, animator,
                automaticBrightnessController, wakelockController, brightnessMappingStrategy,
                hysteresisLevels, screenOffBrightnessSensorController, hbmController));
                hysteresisLevels, screenOffBrightnessSensorController, hbmController, hdrClamper,
                deviceConfigParameterProvider));

        final LogicalDisplay display = mock(LogicalDisplay.class);
        final DisplayDevice device = mock(DisplayDevice.class);
@@ -1293,7 +1320,7 @@ public final class DisplayPowerController2Test {

        return new DisplayPowerControllerHolder(dpc, display, displayPowerState, brightnessSetting,
                animator, automaticBrightnessController, wakelockController,
                screenOffBrightnessSensorController, hbmController, hbmMetadata,
                screenOffBrightnessSensorController, hbmController, hdrClamper, hbmMetadata,
                brightnessMappingStrategy, injector);
    }

@@ -1311,6 +1338,8 @@ public final class DisplayPowerController2Test {
        public final WakelockController wakelockController;
        public final ScreenOffBrightnessSensorController screenOffBrightnessSensorController;
        public final HighBrightnessModeController hbmController;

        public final HdrClamper hdrClamper;
        public final HighBrightnessModeMetadata hbmMetadata;
        public final BrightnessMappingStrategy brightnessMappingStrategy;
        public final DisplayPowerController2.Injector injector;
@@ -1322,6 +1351,7 @@ public final class DisplayPowerController2Test {
                WakelockController wakelockController,
                ScreenOffBrightnessSensorController screenOffBrightnessSensorController,
                HighBrightnessModeController hbmController,
                HdrClamper hdrClamper,
                HighBrightnessModeMetadata hbmMetadata,
                BrightnessMappingStrategy brightnessMappingStrategy,
                DisplayPowerController2.Injector injector) {
@@ -1334,6 +1364,7 @@ public final class DisplayPowerController2Test {
            this.wakelockController = wakelockController;
            this.screenOffBrightnessSensorController = screenOffBrightnessSensorController;
            this.hbmController = hbmController;
            this.hdrClamper = hdrClamper;
            this.hbmMetadata = hbmMetadata;
            this.brightnessMappingStrategy = brightnessMappingStrategy;
            this.injector = injector;
@@ -1350,13 +1381,19 @@ public final class DisplayPowerController2Test {
        private final ScreenOffBrightnessSensorController mScreenOffBrightnessSensorController;
        private final HighBrightnessModeController mHighBrightnessModeController;

        private final HdrClamper mHdrClamper;

        private final DeviceConfigParameterProvider mDeviceConfigParameterProvider;

        TestInjector(DisplayPowerState dps, DualRampAnimator<DisplayPowerState> animator,
                AutomaticBrightnessController automaticBrightnessController,
                WakelockController wakelockController,
                BrightnessMappingStrategy brightnessMappingStrategy,
                HysteresisLevels hysteresisLevels,
                ScreenOffBrightnessSensorController screenOffBrightnessSensorController,
                HighBrightnessModeController highBrightnessModeController) {
                HighBrightnessModeController highBrightnessModeController,
                HdrClamper hdrClamper,
                DeviceConfigParameterProvider deviceConfigParameterProvider) {
            mDisplayPowerState = dps;
            mAnimator = animator;
            mAutomaticBrightnessController = automaticBrightnessController;
@@ -1365,6 +1402,8 @@ public final class DisplayPowerController2Test {
            mHysteresisLevels = hysteresisLevels;
            mScreenOffBrightnessSensorController = screenOffBrightnessSensorController;
            mHighBrightnessModeController = highBrightnessModeController;
            mHdrClamper = hdrClamper;
            mDeviceConfigParameterProvider = deviceConfigParameterProvider;
        }

        @Override
@@ -1470,6 +1509,14 @@ public final class DisplayPowerController2Test {
            return mHighBrightnessModeController;
        }

        @Override
        BrightnessRangeController getBrightnessRangeController(
                HighBrightnessModeController hbmController, Runnable modeChangeCallback,
                DisplayDeviceConfig displayDeviceConfig, Handler handler) {
            return new BrightnessRangeController(hbmController, modeChangeCallback,
                    displayDeviceConfig, mHdrClamper, mDeviceConfigParameterProvider);
        }

        @Override
        DisplayWhiteBalanceController getDisplayWhiteBalanceController(Handler handler,
                SensorManager sensorManager, Resources resources) {
Loading