Limit HLG to 4.926x SDR
HLG is universally too bright on basically every single platform that
supports HDR. Fix this for Android.
Bug: 362510107
Flag: com.android.graphics.surfaceflinger.flags.begone_bright_hlg
Test: HLG playback
Change-Id: I5d464c016be62b11f6a3cc1ab228e14d198afb15
diff --git a/libs/ui/include_types/ui/HdrRenderTypeUtils.h b/libs/ui/include_types/ui/HdrRenderTypeUtils.h
index b0af878..70c50f0 100644
--- a/libs/ui/include_types/ui/HdrRenderTypeUtils.h
+++ b/libs/ui/include_types/ui/HdrRenderTypeUtils.h
@@ -61,4 +61,24 @@
return HdrRenderType::SDR;
}
-} // namespace android
\ No newline at end of file
+/**
+ * Returns the maximum headroom allowed for this content under "idealized"
+ * display conditions (low surround luminance, high-enough display brightness).
+ *
+ * TODO: take into account hdr metadata, but square it with the fact that some
+ * HLG content has CTA.861-3 metadata
+ */
+inline float getIdealizedMaxHeadroom(ui::Dataspace dataspace) {
+ const auto transfer = dataspace & HAL_DATASPACE_TRANSFER_MASK;
+
+ switch (transfer) {
+ case HAL_DATASPACE_TRANSFER_ST2084:
+ return 10000.0f / 203.0f;
+ case HAL_DATASPACE_TRANSFER_HLG:
+ return 1000.0f / 203.0f;
+ default:
+ return 1.0f;
+ }
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index f6d9a1a..bb01946 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -26,6 +26,7 @@
#include <ui/FloatRect.h>
#include <ui/HdrRenderTypeUtils.h>
#include <cstdint>
+#include <limits>
#include "system/graphics-base-v1.0.h"
#include <com_android_graphics_libgui_flags.h>
@@ -398,11 +399,22 @@
// For hdr content, treat the white point as the display brightness - HDR content should not be
// boosted or dimmed.
// If the layer explicitly requests to disable dimming, then don't dim either.
- if (hdrRenderType == HdrRenderType::GENERIC_HDR ||
- getOutput().getState().displayBrightnessNits == getOutput().getState().sdrWhitePointNits ||
- getOutput().getState().displayBrightnessNits == 0.f || !layerFEState->dimmingEnabled) {
+ if (getOutput().getState().displayBrightnessNits == getOutput().getState().sdrWhitePointNits ||
+ getOutput().getState().displayBrightnessNits <= 0.f || !layerFEState->dimmingEnabled) {
state.dimmingRatio = 1.f;
state.whitePointNits = getOutput().getState().displayBrightnessNits;
+ } else if (hdrRenderType == HdrRenderType::GENERIC_HDR) {
+ float deviceHeadroom = getOutput().getState().displayBrightnessNits /
+ getOutput().getState().sdrWhitePointNits;
+ float idealizedMaxHeadroom = deviceHeadroom;
+
+ if (FlagManager::getInstance().begone_bright_hlg()) {
+ idealizedMaxHeadroom =
+ std::min(idealizedMaxHeadroom, getIdealizedMaxHeadroom(state.dataspace));
+ }
+
+ state.dimmingRatio = std::min(idealizedMaxHeadroom / deviceHeadroom, 1.0f);
+ state.whitePointNits = getOutput().getState().displayBrightnessNits * state.dimmingRatio;
} else {
float layerBrightnessNits = getOutput().getState().sdrWhitePointNits;
// RANGE_EXTENDED can "self-promote" to HDR, but is still rendered for a particular
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 37b35f2..6499001 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3201,7 +3201,15 @@
snapshot.desiredHdrSdrRatio < 1.f
? std::numeric_limits<float>::infinity()
: snapshot.desiredHdrSdrRatio;
- info.mergeDesiredRatio(desiredHdrSdrRatio);
+
+ float desiredRatio = desiredHdrSdrRatio;
+ if (FlagManager::getInstance().begone_bright_hlg() &&
+ desiredHdrSdrRatio ==
+ std::numeric_limits<float>::infinity()) {
+ desiredRatio = getIdealizedMaxHeadroom(snapshot.dataspace);
+ }
+
+ info.mergeDesiredRatio(desiredRatio);
info.numberOfHdrLayers++;
const auto displayFrame = outputLayer->getState().displayFrame;
const int32_t area =
diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp
index b56ee01..a1b53ee 100644
--- a/services/surfaceflinger/common/FlagManager.cpp
+++ b/services/surfaceflinger/common/FlagManager.cpp
@@ -160,6 +160,7 @@
DUMP_READ_ONLY_FLAG(connected_display_hdr);
DUMP_READ_ONLY_FLAG(deprecate_frame_tracker);
DUMP_READ_ONLY_FLAG(skip_invisible_windows_in_input);
+ DUMP_READ_ONLY_FLAG(begone_bright_hlg);
#undef DUMP_READ_ONLY_FLAG
#undef DUMP_SERVER_FLAG
@@ -268,6 +269,7 @@
FLAG_MANAGER_READ_ONLY_FLAG(connected_display_hdr, "");
FLAG_MANAGER_READ_ONLY_FLAG(deprecate_frame_tracker, "");
FLAG_MANAGER_READ_ONLY_FLAG(skip_invisible_windows_in_input, "");
+FLAG_MANAGER_READ_ONLY_FLAG(begone_bright_hlg, "debug.sf.begone_bright_hlg");
/// Trunk stable server flags ///
FLAG_MANAGER_SERVER_FLAG(refresh_rate_overlay_on_external_display, "")
diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h
index 9086537..c1d88ce 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -98,6 +98,7 @@
bool connected_display_hdr() const;
bool deprecate_frame_tracker() const;
bool skip_invisible_windows_in_input() const;
+ bool begone_bright_hlg() const;
protected:
// overridden for unit tests
diff --git a/services/surfaceflinger/surfaceflinger_flags_new.aconfig b/services/surfaceflinger/surfaceflinger_flags_new.aconfig
index d4250bc..1188435 100644
--- a/services/surfaceflinger/surfaceflinger_flags_new.aconfig
+++ b/services/surfaceflinger/surfaceflinger_flags_new.aconfig
@@ -35,6 +35,14 @@
} # arr_surfacecontrol_setframerate_api
flag {
+ name: "begone_bright_hlg"
+ namespace: "core_graphics"
+ description: "Caps HLG brightness relative to SDR"
+ bug: "362510107"
+ is_fixed_read_only: true
+} # begone_bright_hlg
+
+flag {
name: "ce_fence_promise"
namespace: "window_surfaces"
description: "Moves logic for buffer release fences into LayerFE"