Loading services/core/java/com/android/server/display/BrightnessUtils.java 0 → 100644 +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; } } services/core/java/com/android/server/display/RampAnimator.java +13 −7 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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(); Loading Loading @@ -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; } Loading Loading
services/core/java/com/android/server/display/BrightnessUtils.java 0 → 100644 +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; } }
services/core/java/com/android/server/display/RampAnimator.java +13 −7 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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(); Loading Loading @@ -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; } Loading