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

Commit a2a7cee3 authored by Chris Kuiper's avatar Chris Kuiper Committed by Android (Google) Code Review
Browse files

Merge "DisplayManager: Switch RampAnimator to ramp in HLG space."

parents 00e99e74 b9530fba
Loading
Loading
Loading
Loading
+83 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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;

import android.util.MathUtils;

/**
 * Utility class providing functions to convert between linear and perceptual gamma space.
 *
 * Internally, this implements the Hybrid Log Gamma electro-optical transfer function, which is a
 * slight improvement to the typical gamma transfer function for displays whose max brightness
 * exceeds the 120 nit reference point, but doesn't set a specific reference brightness like the PQ
 * function does.
 *
 * Note that this transfer function is only valid if the display's backlight value is a linear
 * control. If it's calibrated to be something non-linear, then a different transfer function
 * should be used.
 *
 * Note: This code is based on the same class in the com.android.settingslib.display package.
 */
public class BrightnessUtils {

    // Hybrid Log Gamma constant values
    private static final float R = 0.5f;
    private static final float A = 0.17883277f;
    private static final float B = 0.28466892f;
    private static final float C = 0.55991073f;

    /**
     * A function for converting from the gamma space into the linear space.
     *
     * @param val The value in the gamma space [0 .. 1.0]
     * @return The corresponding value in the linear space [0 .. 1.0].
     */
    public static final float convertGammaToLinear(float val) {
        final float ret;
        if (val <= R) {
            ret = MathUtils.sq(val / R);
        } else {
            ret = MathUtils.exp((val - C) / A) + B;
        }

        // HLG is normalized to the range [0, 12], ensure that value is within that range,
        // it shouldn't be out of bounds.
        final float normalizedRet = MathUtils.constrain(ret, 0, 12);

        // Re-normalize to the range [0, 1]
        // in order to derive the correct setting value.
        return normalizedRet / 12;
    }

    /**
     * A function for converting from the linear space into the gamma space.
     *
     * @param val The value in linear space [0 .. 1.0]
     * @return The corresponding value in gamma space [0 .. 1.0]
     */
    public static final float convertLinearToGamma(float val) {
        // For some reason, HLG normalizes to the range [0, 12] rather than [0, 1]
        final float normalizedVal = val * 12;
        final float ret;
        if (normalizedVal <= 1f) {
            ret = MathUtils.sqrt(normalizedVal) * R;
        } else {
            ret = A * MathUtils.log(normalizedVal - B) + C;
        }
        return ret;
    }
}
+13 −7
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@ import android.view.Choreographer;
/**
 * A custom animator that progressively updates a property value at
 * a given variable rate until it reaches a particular target value.
 * The ramping at the given rate is done in the perceptual space using
 * the HLG transfer functions.
 */
class RampAnimator<T> {
    private final T mObject;
@@ -57,7 +59,9 @@ class RampAnimator<T> {
     * @param rate The convergence rate in units per second, or 0 to set the value immediately.
     * @return True if the target differs from the previous target.
     */
    public boolean animateTo(float target, float rate) {
    public boolean animateTo(float targetLinear, float rate) {
        // Convert the target from the linear into the HLG space.
        final float target = BrightnessUtils.convertLinearToGamma(targetLinear);

        // Immediately jump to the target the first time.
        if (mFirstTime || rate <= 0) {
@@ -156,7 +160,9 @@ class RampAnimator<T> {
            final float oldCurrentValue = mCurrentValue;
            mCurrentValue = mAnimatedValue;
            if (oldCurrentValue != mCurrentValue) {
                mProperty.setValue(mObject, mCurrentValue);
                // Convert value from HLG into linear space for the property.
                final float linearCurrentVal = BrightnessUtils.convertGammaToLinear(mCurrentValue);
                mProperty.setValue(mObject, linearCurrentVal);
            }
            if (mTargetValue != mCurrentValue) {
                postAnimationCallback();
@@ -201,14 +207,14 @@ class RampAnimator<T> {
         * If this is the first time the property is being set or if the rate is 0,
         * the value jumps directly to the target.
         *
         * @param firstTarget The first target value.
         * @param secondTarget The second target value.
         * @param linearFirstTarget The first target value in linear space.
         * @param linearSecondTarget The second target value in linear space.
         * @param rate The convergence rate in units per second, or 0 to set the value immediately.
         * @return True if either target differs from the previous target.
         */
        public boolean animateTo(float firstTarget, float secondTarget, float rate) {
            final boolean firstRetval = mFirst.animateTo(firstTarget, rate);
            final boolean secondRetval = mSecond.animateTo(secondTarget, rate);
        public boolean animateTo(float linearFirstTarget, float linearSecondTarget, float rate) {
            final boolean firstRetval = mFirst.animateTo(linearFirstTarget, rate);
            final boolean secondRetval = mSecond.animateTo(linearSecondTarget, rate);
            return firstRetval && secondRetval;
        }