DisplayPowerController uses max desired SDR/HDR ratio

When an application requests a smaller max designed SDR/HDR ratio than
what is supported by the system, DisplayPowerController should clamp to
the smallest ratio bigger than 1.0.

Bug: 267350616
Test: SilkFX test app
Change-Id: I933ca05c1f336ee2102489bbc850d42bcf612c4c
This commit is contained in:
Alec Mouri
2023-02-08 00:54:57 +00:00
parent 84bf2e3a0f
commit cddccb61f2
8 changed files with 151 additions and 38 deletions

View File

@@ -42,10 +42,13 @@ public abstract class SurfaceControlHdrLayerInfoListener {
* @param maxH The height of the HDR layer with the largest area
* @param flags Additional metadata flags, currently always 0
* TODO(b/182312559): Add some flags
* @param maxDesiredHdrSdrRatio The max desired HDR/SDR ratio. Unbounded if the ratio is
* positive infinity.
*
* @hide */
* @hide
*/
public abstract void onHdrInfoChanged(IBinder displayToken, int numberOfHdrLayers,
int maxW, int maxH, int flags);
int maxW, int maxH, int flags, float maxDesiredHdrSdrRatio);
/**
* Registers this as an HDR info listener on the provided display

View File

@@ -42,12 +42,12 @@ struct SurfaceControlHdrLayerInfoListener : public gui::BnHdrLayerInfoListener {
LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&mVm) != JNI_OK, "Failed to GetJavaVm");
}
binder::Status onHdrLayerInfoChanged(int numberOfHdrLayers, int maxW, int maxH,
int flags) override {
binder::Status onHdrLayerInfoChanged(int numberOfHdrLayers, int maxW, int maxH, int flags,
float maxDesiredHdrSdrRatio) override {
JNIEnv* env = requireEnv();
env->CallVoidMethod(mListener, gListenerClassInfo.mOnHdrInfoChanged, mDisplayToken,
numberOfHdrLayers, maxW, maxH, flags);
numberOfHdrLayers, maxW, maxH, flags, maxDesiredHdrSdrRatio);
if (env->ExceptionCheck()) {
ALOGE("SurfaceControlHdrLayerInfoListener.onHdrInfoChanged() failed.");
@@ -129,7 +129,7 @@ int register_android_view_SurfaceControlHdrLayerInfoListener(JNIEnv* env) {
jclass clazz = env->FindClass("android/view/SurfaceControlHdrLayerInfoListener");
gListenerClassInfo.mClass = MakeGlobalRefOrDie(env, clazz);
gListenerClassInfo.mOnHdrInfoChanged =
env->GetMethodID(clazz, "onHdrInfoChanged", "(Landroid/os/IBinder;IIII)V");
env->GetMethodID(clazz, "onHdrInfoChanged", "(Landroid/os/IBinder;IIIIF)V");
return 0;
}

View File

@@ -851,11 +851,12 @@ public class DisplayDeviceConfig {
}
/**
* Calculate the HDR brightness for the specified SDR brightenss.
* Calculate the HDR brightness for the specified SDR brightenss, restricted by the
* maxDesiredHdrSdrRatio (the ratio between the HDR luminance and SDR luminance)
*
* @return the HDR brightness or BRIGHTNESS_INVALID when no mapping exists.
*/
public float getHdrBrightnessFromSdr(float brightness) {
public float getHdrBrightnessFromSdr(float brightness, float maxDesiredHdrSdrRatio) {
if (mSdrToHdrRatioSpline == null) {
return PowerManager.BRIGHTNESS_INVALID;
}
@@ -866,7 +867,7 @@ public class DisplayDeviceConfig {
return PowerManager.BRIGHTNESS_INVALID;
}
float ratio = mSdrToHdrRatioSpline.interpolate(nits);
float ratio = Math.min(mSdrToHdrRatioSpline.interpolate(nits), maxDesiredHdrSdrRatio);
float hdrNits = nits * ratio;
if (mNitsToBacklightSpline == null) {
return PowerManager.BRIGHTNESS_INVALID;

View File

@@ -966,8 +966,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mDisplayDeviceConfig.getHighBrightnessModeData(),
new HighBrightnessModeController.HdrBrightnessDeviceConfig() {
@Override
public float getHdrBrightnessFromSdr(float sdrBrightness) {
return mDisplayDeviceConfig.getHdrBrightnessFromSdr(sdrBrightness);
public float getHdrBrightnessFromSdr(
float sdrBrightness, float maxDesiredHdrSdrRatio) {
return mDisplayDeviceConfig.getHdrBrightnessFromSdr(
sdrBrightness, maxDesiredHdrSdrRatio);
}
});
mBrightnessThrottler.resetThrottlingData(
@@ -2069,8 +2071,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
displayUniqueId, PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, hbmData,
new HighBrightnessModeController.HdrBrightnessDeviceConfig() {
@Override
public float getHdrBrightnessFromSdr(float sdrBrightness) {
return mDisplayDeviceConfig.getHdrBrightnessFromSdr(sdrBrightness);
public float getHdrBrightnessFromSdr(
float sdrBrightness, float maxDesiredHdrSdrRatio) {
return mDisplayDeviceConfig.getHdrBrightnessFromSdr(
sdrBrightness, maxDesiredHdrSdrRatio);
}
},
() -> {

View File

@@ -804,8 +804,10 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
mDisplayDeviceConfig.getHighBrightnessModeData(),
new HighBrightnessModeController.HdrBrightnessDeviceConfig() {
@Override
public float getHdrBrightnessFromSdr(float sdrBrightness) {
return mDisplayDeviceConfig.getHdrBrightnessFromSdr(sdrBrightness);
public float getHdrBrightnessFromSdr(
float sdrBrightness, float maxDesiredHdrSdrRatio) {
return mDisplayDeviceConfig.getHdrBrightnessFromSdr(
sdrBrightness, maxDesiredHdrSdrRatio);
}
});
mBrightnessThrottler.resetThrottlingData(
@@ -1776,8 +1778,10 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
displayUniqueId, PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, hbmData,
new HighBrightnessModeController.HdrBrightnessDeviceConfig() {
@Override
public float getHdrBrightnessFromSdr(float sdrBrightness) {
return mDisplayDeviceConfig.getHdrBrightnessFromSdr(sdrBrightness);
public float getHdrBrightnessFromSdr(
float sdrBrightness, float maxDesiredHdrSdrRatio) {
return mDisplayDeviceConfig.getHdrBrightnessFromSdr(
sdrBrightness, maxDesiredHdrSdrRatio);
}
},
() -> {

View File

@@ -61,8 +61,12 @@ class HighBrightnessModeController {
@VisibleForTesting
static final float HBM_TRANSITION_POINT_INVALID = Float.POSITIVE_INFINITY;
private static final float DEFAULT_MAX_DESIRED_HDR_SDR_RATIO = 1.0f;
public interface HdrBrightnessDeviceConfig {
float getHdrBrightnessFromSdr(float sdrBrightness);
// maxDesiredHdrSdrRatio will restrict the HDR brightness if the ratio is less than
// Float.POSITIVE_INFINITY
float getHdrBrightnessFromSdr(float sdrBrightness, float maxDesiredHdrSdrRatio);
}
private final float mBrightnessMin;
@@ -96,6 +100,9 @@ class HighBrightnessModeController {
private int mHbmMode = BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
private boolean mIsHdrLayerPresent = false;
// mMaxDesiredHdrSdrRatio should only be applied when there is a valid backlight->nits mapping
private float mMaxDesiredHdrSdrRatio = DEFAULT_MAX_DESIRED_HDR_SDR_RATIO;
private boolean mIsThermalStatusWithinLimit = true;
private boolean mIsBlockedByLowPowerMode = false;
private int mWidth;
@@ -177,7 +184,8 @@ class HighBrightnessModeController {
float getHdrBrightnessValue() {
if (mHdrBrightnessCfg != null) {
float hdrBrightness = mHdrBrightnessCfg.getHdrBrightnessFromSdr(mBrightness);
float hdrBrightness = mHdrBrightnessCfg.getHdrBrightnessFromSdr(
mBrightness, mMaxDesiredHdrSdrRatio);
if (hdrBrightness != PowerManager.BRIGHTNESS_INVALID) {
return hdrBrightness;
}
@@ -457,6 +465,7 @@ class HighBrightnessModeController {
+ ", isLuxHigh: " + mIsInAllowedAmbientRange
+ ", isHBMCurrentlyAllowed: " + isCurrentlyAllowed()
+ ", isHdrLayerPresent: " + mIsHdrLayerPresent
+ ", mMaxDesiredHdrSdrRatio: " + mMaxDesiredHdrSdrRatio
+ ", isAutoBrightnessEnabled: " + mIsAutoBrightnessEnabled
+ ", mIsTimeAvailable: " + mIsTimeAvailable
+ ", mIsInAllowedAmbientRange: " + mIsInAllowedAmbientRange
@@ -600,11 +609,25 @@ class HighBrightnessModeController {
class HdrListener extends SurfaceControlHdrLayerInfoListener {
@Override
public void onHdrInfoChanged(IBinder displayToken, int numberOfHdrLayers,
int maxW, int maxH, int flags) {
int maxW, int maxH, int flags, float maxDesiredHdrSdrRatio) {
mHandler.post(() -> {
mIsHdrLayerPresent = numberOfHdrLayers > 0
&& (float) (maxW * maxH) >= ((float) (mWidth * mHeight)
* mHbmData.minimumHdrPercentOfScreen);
final float candidateDesiredHdrSdrRatio =
mIsHdrLayerPresent && mHdrBrightnessCfg != null
? maxDesiredHdrSdrRatio
: DEFAULT_MAX_DESIRED_HDR_SDR_RATIO;
if (candidateDesiredHdrSdrRatio >= 1.0f) {
mMaxDesiredHdrSdrRatio = candidateDesiredHdrSdrRatio;
} else {
Slog.w(TAG, "Ignoring invalid desired HDR/SDR Ratio: "
+ candidateDesiredHdrSdrRatio);
mMaxDesiredHdrSdrRatio = DEFAULT_MAX_DESIRED_HDR_SDR_RATIO;
}
// Calling the brightness update so that we can recalculate
// brightness with HDR in mind.
onBrightnessChanged(mBrightness, mUnthrottledBrightness, mThrottlingReason);

View File

@@ -230,6 +230,18 @@ public final class DisplayDeviceConfigTest {
assertEquals(mDisplayDeviceConfig.getHostUsiVersion().getMajorVersion(), 2);
assertEquals(mDisplayDeviceConfig.getHostUsiVersion().getMinorVersion(), 0);
// Max desired Hdr/SDR ratio upper-bounds the HDR brightness.
assertEquals(1.0f,
mDisplayDeviceConfig.getHdrBrightnessFromSdr(0.62f, Float.POSITIVE_INFINITY),
ZERO_DELTA);
assertEquals(0.62f,
mDisplayDeviceConfig.getHdrBrightnessFromSdr(0.62f, 1.0f),
ZERO_DELTA);
assertEquals(0.77787f,
mDisplayDeviceConfig.getHdrBrightnessFromSdr(0.62f, 1.25f),
SMALL_DELTA);
// Todo: Add asserts for BrightnessThrottlingData, DensityMapping,
// HighBrightnessModeData AmbientLightSensor, RefreshRateLimitations and ProximitySensor.
}
@@ -361,6 +373,16 @@ public final class DisplayDeviceConfigTest {
+ "</refreshRate>\n"
+ "<thermalStatusLimit>light</thermalStatusLimit>\n"
+ "<allowInLowPowerMode>false</allowInLowPowerMode>\n"
+ "<sdrHdrRatioMap>\n"
+ "<point>\n"
+ "<sdrNits>2.000</sdrNits>\n"
+ "<hdrRatio>4.000</hdrRatio>\n"
+ "</point>\n"
+ "<point>\n"
+ "<sdrNits>500.0</sdrNits>\n"
+ "<hdrRatio>1.6</hdrRatio>\n"
+ "</point>\n"
+ "</sdrHdrRatioMap>\n"
+ "</highBrightnessMode>\n"
+ "<screenOffBrightnessSensor>\n"
+ "<type>sensor_12345</type>\n"

View File

@@ -29,6 +29,7 @@ import static com.android.server.display.DisplayDeviceConfig.HDR_PERCENT_OF_SCRE
import static com.android.server.display.HighBrightnessModeController.HBM_TRANSITION_POINT_INVALID;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.anyFloat;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
@@ -103,6 +104,7 @@ public class HighBrightnessModeControllerTest {
@Mock IThermalService mThermalServiceMock;
@Mock Injector mInjectorMock;
@Mock HighBrightnessModeController.HdrBrightnessDeviceConfig mHdrBrightnessDeviceConfigMock;
@Captor ArgumentCaptor<IThermalEventListener> mThermalEventListenerCaptor;
@@ -376,17 +378,48 @@ public class HighBrightnessModeControllerTest {
// ensure hdr doesn't turn on if layer is too small
hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
layerWidth, smallLayerHeight, 0 /*flags*/);
layerWidth, smallLayerHeight, 0 /*flags*/, 1.0f /*maxDesiredHdrSdrRatio*/);
advanceTime(0);
assertEquals(HIGH_BRIGHTNESS_MODE_OFF, hbmc.getHighBrightnessMode());
// Now check with layer larger than 50%
hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
layerWidth, largeLayerHeight, 0 /*flags*/);
layerWidth, largeLayerHeight, 0 /*flags*/, 1.0f /*maxDesiredHdrSdrRatio*/);
advanceTime(0);
assertEquals(HIGH_BRIGHTNESS_MODE_HDR, hbmc.getHighBrightnessMode());
}
@Test
public void testHdrRespectsMaxDesiredHdrSdrRatio() {
final HighBrightnessModeController hbmc = new TestHbmBuilder()
.setClock(new OffsettableClock())
.setHdrBrightnessConfig(mHdrBrightnessDeviceConfigMock)
.build();
// Passthrough return the max desired hdr/sdr ratio
when(mHdrBrightnessDeviceConfigMock.getHdrBrightnessFromSdr(anyFloat(), anyFloat()))
.thenAnswer(i -> i.getArgument(1));
hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/, 2.0f /*maxDesiredHdrSdrRatio*/);
advanceTime(0);
assertEquals(2.0f, hbmc.getHdrBrightnessValue(), EPSILON);
// The hdr ratio cannot be less than 1.
hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/, 0.5f /*maxDesiredHdrSdrRatio*/);
advanceTime(0);
assertEquals(1.0f, hbmc.getHdrBrightnessValue(), EPSILON);
// The hdr ratio can be as much as positive infinity
hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/,
Float.POSITIVE_INFINITY /*maxDesiredHdrSdrRatio*/);
advanceTime(0);
assertEquals(Float.POSITIVE_INFINITY, hbmc.getHdrBrightnessValue(), 0.0);
}
@Test
public void testHdrTrumpsSunlight() {
final HighBrightnessModeController hbmc = createDefaultHbm(new OffsettableClock());
@@ -400,7 +433,7 @@ public class HighBrightnessModeControllerTest {
// turn on hdr
hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/);
DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/, 1.0f /*maxDesiredHdrSdrRatio*/);
advanceTime(0);
assertEquals(HIGH_BRIGHTNESS_MODE_HDR, hbmc.getHighBrightnessMode());
assertEquals(TRANSITION_POINT, hbmc.getCurrentBrightnessMax(), EPSILON);
@@ -412,14 +445,14 @@ public class HighBrightnessModeControllerTest {
// Check limit when HBM is off
hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/);
DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/, 1.0f /*maxDesiredHdrSdrRatio*/);
advanceTime(0);
assertEquals(HIGH_BRIGHTNESS_MODE_HDR, hbmc.getHighBrightnessMode());
assertEquals(TRANSITION_POINT, hbmc.getCurrentBrightnessMax(), EPSILON);
// Check limit with HBM is set to HDR
hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 0 /*numberOfHdrLayers*/,
DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/);
DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/, 1.0f /*maxDesiredHdrSdrRatio*/);
advanceTime(0);
assertEquals(HIGH_BRIGHTNESS_MODE_OFF, hbmc.getHighBrightnessMode());
assertEquals(TRANSITION_POINT, hbmc.getCurrentBrightnessMax(), EPSILON);
@@ -430,7 +463,7 @@ public class HighBrightnessModeControllerTest {
final HighBrightnessModeController hbmc = createDefaultHbm(new OffsettableClock());
hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/);
DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/, 1.0f /*maxDesiredHdrSdrRatio*/);
advanceTime(0);
assertEquals(HIGH_BRIGHTNESS_MODE_HDR, hbmc.getHighBrightnessMode());
@@ -473,7 +506,7 @@ public class HighBrightnessModeControllerTest {
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
hbmcOnBrightnessChanged(hbmc, TRANSITION_POINT);
hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/);
DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/, 1.0f /*maxDesiredHdrSdrRatio*/);
advanceTime(0);
assertEquals(HIGH_BRIGHTNESS_MODE_HDR, hbmc.getHighBrightnessMode());
@@ -483,7 +516,7 @@ public class HighBrightnessModeControllerTest {
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN));
hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 0 /*numberOfHdrLayers*/,
0, 0, 0 /*flags*/);
0, 0, 0 /*flags*/, 1.0f /*maxDesiredHdrSdrRatio*/);
advanceTime(0);
// Verify Stats HBM_OFF
@@ -517,7 +550,7 @@ public class HighBrightnessModeControllerTest {
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
hbmcOnBrightnessChanged(hbmc, DEFAULT_MIN);
hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/);
DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/, 1.0f /*maxDesiredHdrSdrRatio*/);
advanceTime(0);
assertEquals(HIGH_BRIGHTNESS_MODE_HDR, hbmc.getHighBrightnessMode());
@@ -657,7 +690,7 @@ public class HighBrightnessModeControllerTest {
eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN));
hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/);
DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/, 1.0f /*maxDesiredHdrSdrRatio*/);
advanceTime(0);
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
@@ -696,19 +729,42 @@ public class HighBrightnessModeControllerTest {
assertEquals(hbmMode, hbmc.getHighBrightnessMode());
}
private class TestHbmBuilder {
OffsettableClock mClock;
HighBrightnessModeController.HdrBrightnessDeviceConfig mHdrBrightnessCfg;
TestHbmBuilder setClock(OffsettableClock clock) {
mClock = clock;
return this;
}
TestHbmBuilder setHdrBrightnessConfig(
HighBrightnessModeController.HdrBrightnessDeviceConfig hdrBrightnessCfg
) {
mHdrBrightnessCfg = hdrBrightnessCfg;
return this;
}
HighBrightnessModeController build() {
initHandler(mClock);
if (mHighBrightnessModeMetadata == null) {
mHighBrightnessModeMetadata = new HighBrightnessModeMetadata();
}
return new HighBrightnessModeController(mInjectorMock, mHandler, DISPLAY_WIDTH,
DISPLAY_HEIGHT, mDisplayToken, mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX,
DEFAULT_HBM_DATA, mHdrBrightnessCfg, () -> {}, mHighBrightnessModeMetadata,
mContextSpy);
}
}
private HighBrightnessModeController createDefaultHbm() {
return createDefaultHbm(null);
return new TestHbmBuilder().build();
}
// Creates instance with standard initialization values.
private HighBrightnessModeController createDefaultHbm(OffsettableClock clock) {
initHandler(clock);
if (mHighBrightnessModeMetadata == null) {
mHighBrightnessModeMetadata = new HighBrightnessModeMetadata();
}
return new HighBrightnessModeController(mInjectorMock, mHandler, DISPLAY_WIDTH,
DISPLAY_HEIGHT, mDisplayToken, mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX,
DEFAULT_HBM_DATA, null, () -> {}, mHighBrightnessModeMetadata, mContextSpy);
return new TestHbmBuilder().setClock(clock).build();
}
private void initHandler(OffsettableClock clock) {