Supply extra brightness parameters to RenderEngine
A future CL will update the HLG->SDR tonemapping algorithm to consider
current display brightness, as recommended by BT2100.
In preparation for this:
* Fix an issue where maxLuminance was using the current display
brightness if supplied from DisplayManager instead of the max luminance
* Add currentDisplayBrightnessNits to the RenderEngine interface to
support the current brightness
* Plumb current display brightness all the way to libtonemap, where
nothing uses it (yet)
Bug: 206035964
Test: libcompositionengine_test
Change-Id: I3e9f0fdb23fbb08c50e4733e5a16bcd20948d750
diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h
index b4cab39..2c51ccd 100644
--- a/libs/renderengine/include/renderengine/DisplaySettings.h
+++ b/libs/renderengine/include/renderengine/DisplaySettings.h
@@ -43,6 +43,9 @@
// Maximum luminance pulled from the display's HDR capabilities.
float maxLuminance = 1.0f;
+ // Current luminance of the display
+ float currentLuminanceNits = -1.f;
+
// Output dataspace that will be populated if wide color gamut is used, or
// DataSpace::UNKNOWN otherwise.
ui::Dataspace outputDataspace = ui::Dataspace::UNKNOWN;
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index cc90946..063ce67 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -656,6 +656,7 @@
parameters.layerDimmingRatio, 1.f));
return createLinearEffectShader(parameters.shader, effect, runtimeEffect, colorTransform,
parameters.display.maxLuminance,
+ parameters.display.currentLuminanceNits,
parameters.layer.source.buffer.maxLuminanceNits);
}
return parameters.shader;
diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp
index 36305ae..6077c2e 100644
--- a/libs/renderengine/skia/filters/LinearEffect.cpp
+++ b/libs/renderengine/skia/filters/LinearEffect.cpp
@@ -44,14 +44,15 @@
const shaders::LinearEffect& linearEffect,
sk_sp<SkRuntimeEffect> runtimeEffect,
const mat4& colorTransform, float maxDisplayLuminance,
- float maxLuminance) {
+ float currentDisplayLuminanceNits, float maxLuminance) {
ATRACE_CALL();
SkRuntimeShaderBuilder effectBuilder(runtimeEffect);
effectBuilder.child("child") = shader;
- const auto uniforms = shaders::buildLinearEffectUniforms(linearEffect, colorTransform,
- maxDisplayLuminance, maxLuminance);
+ const auto uniforms =
+ shaders::buildLinearEffectUniforms(linearEffect, colorTransform, maxDisplayLuminance,
+ currentDisplayLuminanceNits, maxLuminance);
for (const auto& uniform : uniforms) {
effectBuilder.uniform(uniform.name.c_str()).set(uniform.value.data(), uniform.value.size());
diff --git a/libs/renderengine/skia/filters/LinearEffect.h b/libs/renderengine/skia/filters/LinearEffect.h
index 8eb6670..e0a556b 100644
--- a/libs/renderengine/skia/filters/LinearEffect.h
+++ b/libs/renderengine/skia/filters/LinearEffect.h
@@ -37,13 +37,14 @@
// matrix transforming from linear XYZ to linear RGB immediately before OETF.
// We also provide additional HDR metadata upon creating the shader:
// * The max display luminance is the max luminance of the physical display in nits
+// * The current luminance of the physical display in nits
// * The max luminance is provided as the max luminance for the buffer, either from the SMPTE 2086
// or as the max light level from the CTA 861.3 standard.
sk_sp<SkShader> createLinearEffectShader(sk_sp<SkShader> inputShader,
const shaders::LinearEffect& linearEffect,
sk_sp<SkRuntimeEffect> runtimeEffect,
const mat4& colorTransform, float maxDisplayLuminance,
- float maxLuminance);
+ float currentDisplayLuminanceNits, float maxLuminance);
} // namespace skia
} // namespace renderengine
} // namespace android
diff --git a/libs/shaders/include/shaders/shaders.h b/libs/shaders/include/shaders/shaders.h
index 712a27a..43828cc 100644
--- a/libs/shaders/include/shaders/shaders.h
+++ b/libs/shaders/include/shaders/shaders.h
@@ -100,6 +100,7 @@
std::vector<tonemap::ShaderUniform> buildLinearEffectUniforms(const LinearEffect& linearEffect,
const mat4& colorTransform,
float maxDisplayLuminance,
+ float currentDisplayLuminanceNits,
float maxLuminance);
} // namespace android::shaders
diff --git a/libs/shaders/shaders.cpp b/libs/shaders/shaders.cpp
index 6019c4a..4d88d5d 100644
--- a/libs/shaders/shaders.cpp
+++ b/libs/shaders/shaders.cpp
@@ -463,6 +463,7 @@
std::vector<tonemap::ShaderUniform> buildLinearEffectUniforms(const LinearEffect& linearEffect,
const mat4& colorTransform,
float maxDisplayLuminance,
+ float currentDisplayLuminanceNits,
float maxLuminance) {
std::vector<tonemap::ShaderUniform> uniforms;
if (linearEffect.inputDataspace == linearEffect.outputDataspace) {
@@ -480,6 +481,7 @@
}
tonemap::Metadata metadata{.displayMaxLuminance = maxDisplayLuminance,
+ .currentDisplayLuminanceNits = currentDisplayLuminanceNits,
// If the input luminance is unknown, use display luminance (aka,
// no-op any luminance changes)
// This will be the case for eg screenshots in addition to
diff --git a/libs/tonemap/include/tonemap/tonemap.h b/libs/tonemap/include/tonemap/tonemap.h
index bd7b72d..6233e6c 100644
--- a/libs/tonemap/include/tonemap/tonemap.h
+++ b/libs/tonemap/include/tonemap/tonemap.h
@@ -42,7 +42,11 @@
// This metadata should not be used for manipulating the source code of the shader program directly,
// as otherwise caching by other system of these shaders may break.
struct Metadata {
+ // The maximum luminance of the display in nits
float displayMaxLuminance = 0.0;
+ // The current luminance of the display in nits
+ float currentDisplayLuminanceNits = 0.0;
+ // The maximum luminance of the content in nits
float contentMaxLuminance = 0.0;
};
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 192ee04..162d84e 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1059,9 +1059,11 @@
// If we have a valid current display brightness use that, otherwise fall back to the
// display's max desired
- clientCompositionDisplay.maxLuminance = outputState.displayBrightnessNits > 0.f
+ clientCompositionDisplay.currentLuminanceNits = outputState.displayBrightnessNits > 0.f
? outputState.displayBrightnessNits
: mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
+ clientCompositionDisplay.maxLuminance =
+ mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
clientCompositionDisplay.targetLuminanceNits = outputState.clientTargetWhitePointNits;
// Compute the global color transform matrix.
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index f7c7533..c2235a2 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -3069,6 +3069,8 @@
static constexpr float kDefaultMaxLuminance = 0.9f;
static constexpr float kDefaultAvgLuminance = 0.7f;
static constexpr float kDefaultMinLuminance = 0.1f;
+ static constexpr float kUnknownLuminance = -1.f;
+ static constexpr float kDisplayLuminance = 80.f;
static constexpr float kClientTargetLuminanceNits = 200.f;
static const Rect kDefaultOutputFrame;
@@ -3101,6 +3103,7 @@
const mat4 OutputComposeSurfacesTest::kDefaultColorTransformMat{mat4() * 0.5f};
const compositionengine::CompositionRefreshArgs OutputComposeSurfacesTest::kDefaultRefreshArgs;
const Region OutputComposeSurfacesTest::kDebugRegion{Rect{100, 101, 102, 103}};
+
const HdrCapabilities OutputComposeSurfacesTest::
kHdrCapabilities{{},
OutputComposeSurfacesTest::kDefaultMaxLuminance,
@@ -3403,6 +3406,14 @@
auto andIfUsesHdr(bool used) {
EXPECT_CALL(*getInstance()->mDisplayColorProfile, hasWideColorGamut())
.WillOnce(Return(used));
+ return nextState<OutputWithDisplayBrightnessNits>();
+ }
+ };
+
+ struct OutputWithDisplayBrightnessNits
+ : public CallOrderStateMachineHelper<TestType, OutputWithDisplayBrightnessNits> {
+ auto withDisplayBrightnessNits(float nits) {
+ getInstance()->mOutput.mState.displayBrightnessNits = nits;
return nextState<SkipColorTransformState>();
}
};
@@ -3434,11 +3445,34 @@
TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrMixedComposition) {
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(true)
+ .withDisplayBrightnessNits(kUnknownLuminance)
.andIfSkipColorTransform(false)
- .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
- kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
- kDefaultOutputOrientationFlags,
- kClientTargetLuminanceNits})
+ .thenExpectDisplaySettingsUsed({.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDefaultMaxLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = mat4(),
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits})
+ .execute()
+ .expectAFenceWasReturned();
+}
+
+TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings,
+ forHdrMixedCompositionWithDisplayBrightness) {
+ verify().ifMixedCompositionIs(true)
+ .andIfUsesHdr(true)
+ .withDisplayBrightnessNits(kDisplayLuminance)
+ .andIfSkipColorTransform(false)
+ .thenExpectDisplaySettingsUsed({.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = mat4(),
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits})
.execute()
.expectAFenceWasReturned();
}
@@ -3446,11 +3480,16 @@
TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrMixedComposition) {
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(false)
+ .withDisplayBrightnessNits(kUnknownLuminance)
.andIfSkipColorTransform(false)
- .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
- kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
- kDefaultOutputOrientationFlags,
- kClientTargetLuminanceNits})
+ .thenExpectDisplaySettingsUsed({.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDefaultMaxLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = mat4(),
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits})
.execute()
.expectAFenceWasReturned();
}
@@ -3458,11 +3497,16 @@
TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrOnlyClientComposition) {
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(true)
+ .withDisplayBrightnessNits(kUnknownLuminance)
.andIfSkipColorTransform(false)
- .thenExpectDisplaySettingsUsed(
- {kDefaultOutputDestinationClip, kDefaultOutputViewport, kDefaultMaxLuminance,
- kDefaultOutputDataspace, kDefaultColorTransformMat,
- kDefaultOutputOrientationFlags, kClientTargetLuminanceNits})
+ .thenExpectDisplaySettingsUsed({.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDefaultMaxLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = kDefaultColorTransformMat,
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits})
.execute()
.expectAFenceWasReturned();
}
@@ -3470,11 +3514,16 @@
TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrOnlyClientComposition) {
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(false)
+ .withDisplayBrightnessNits(kUnknownLuminance)
.andIfSkipColorTransform(false)
- .thenExpectDisplaySettingsUsed(
- {kDefaultOutputDestinationClip, kDefaultOutputViewport, kDefaultMaxLuminance,
- kDefaultOutputDataspace, kDefaultColorTransformMat,
- kDefaultOutputOrientationFlags, kClientTargetLuminanceNits})
+ .thenExpectDisplaySettingsUsed({.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDefaultMaxLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = kDefaultColorTransformMat,
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits})
.execute()
.expectAFenceWasReturned();
}
@@ -3483,11 +3532,16 @@
usesExpectedDisplaySettingsForHdrOnlyClientCompositionWithSkipClientTransform) {
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(true)
+ .withDisplayBrightnessNits(kUnknownLuminance)
.andIfSkipColorTransform(true)
- .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
- kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
- kDefaultOutputOrientationFlags,
- kClientTargetLuminanceNits})
+ .thenExpectDisplaySettingsUsed({.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDefaultMaxLuminance,
+ .outputDataspace = kDefaultOutputDataspace,
+ .colorTransform = mat4(),
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits})
.execute()
.expectAFenceWasReturned();
}