Add support for restricting HDR headroom for video

This is needed for allowing apps to vote for HDR headroom restrictions
for SurfaceView and SurfaceControl

Bug: 323964760
Test: manually poking at test app
Test: SurfaceViewTests
Test: SurfaceControlTest
Test: ASurfaceControlTest
Change-Id: Ie886e67879525462d49fdedc535aea659d69321a
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index cce2e46..321737e 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -528,9 +528,8 @@
 
 /**
  * Sets the desired extended range brightness for the layer. This only applies for layers whose
- * dataspace has RANGE_EXTENDED set on it.
- *
- * Available since API level 34.
+ * dataspace has RANGE_EXTENDED set on it. See: ASurfaceTransaction_setDesiredHdrHeadroom, prefer
+ * using this API for formats that encode an HDR/SDR ratio as part of generating the buffer.
  *
  * @param surface_control The layer whose extended range brightness is being specified
  * @param currentBufferRatio The current hdr/sdr ratio of the current buffer as represented as
@@ -564,6 +563,12 @@
  *                     determined entirely by the dataspace being used (ie, typically SDR
  *                     however PQ or HLG transfer functions will still result in HDR)
  *
+ *                     When called after ASurfaceTransaction_setDesiredHdrHeadroom, the
+ *                     desiredRatio will override the desiredHeadroom provided by
+ *                     ASurfaceTransaction_setDesiredHdrHeadroom. Conversely, when called before
+ *                     ASurfaceTransaction_setDesiredHdrHeadroom, the desiredHeadroom provided by
+ *.                    ASurfaceTransaction_setDesiredHdrHeadroom will override the desiredRatio.
+ *
  *                     Must be finite && >= 1.0f
  *
  * Available since API level 34.
@@ -574,6 +579,45 @@
                                             float desiredRatio) __INTRODUCED_IN(__ANDROID_API_U__);
 
 /**
+ * Sets the desired hdr headroom for the layer. See: ASurfaceTransaction_setExtendedRangeBrightness,
+ * prefer using this API for formats that conform to HDR standards like HLG or HDR10, that do not
+ * communicate a HDR/SDR ratio as part of generating the buffer.
+ *
+ * @param surface_control The layer whose desired hdr headroom is being specified
+ *
+ * @param desiredHeadroom The desired hdr/sdr ratio as represented as peakHdrBrightnessInNits /
+ *                        targetSdrWhitePointInNits. This can be used to communicate the max
+ *                        desired brightness range of the panel. The system may not be able to, or
+ *                        may choose not to, deliver the requested range.
+ *
+ *                        While requesting a large desired ratio will result in the most
+ *                        dynamic range, voluntarily reducing the requested range can help
+ *                        improve battery life as well as can improve quality by ensuring
+ *                        greater bit depth is allocated to the luminance range in use.
+ *
+ *                        Default value is 0.0f and indicates that the system will choose the best
+ *                        headroom for this surface control's content. Typically, this means that
+ *                        HLG/PQ encoded content will be displayed with some HDR headroom greater
+ *                        than 1.0.
+ *
+ *                        When called after ASurfaceTransaction_setExtendedRangeBrightness, the
+ *                        desiredHeadroom will override the desiredRatio provided by
+ *                        ASurfaceTransaction_setExtendedRangeBrightness. Conversely, when called
+ *                        before ASurfaceTransaction_setExtendedRangeBrightness, the desiredRatio
+ *                        provided by ASurfaceTransaction_setExtendedRangeBrightness will override
+ *                        the desiredHeadroom.
+ *
+ *                        Must be finite && >= 1.0f or 0.0f to indicate there is no desired
+ *                        headroom.
+ *
+ * Available since API level 35.
+ */
+void ASurfaceTransaction_setDesiredHdrHeadroom(ASurfaceTransaction* transaction,
+                                               ASurfaceControl* surface_control,
+                                               float desiredHeadroom)
+        __INTRODUCED_IN(__ANDROID_API_V__);
+
+/**
  * Same as ASurfaceTransaction_setFrameRateWithChangeStrategy(transaction, surface_control,
  * frameRate, compatibility, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS).
  *
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 38fab9c..9d7d304 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -605,6 +605,10 @@
         desiredHdrSdrRatio = other.desiredHdrSdrRatio;
         currentHdrSdrRatio = other.currentHdrSdrRatio;
     }
+    if (other.what & eDesiredHdrHeadroomChanged) {
+        what |= eDesiredHdrHeadroomChanged;
+        desiredHdrSdrRatio = other.desiredHdrSdrRatio;
+    }
     if (other.what & eCachingHintChanged) {
         what |= eCachingHintChanged;
         cachingHint = other.cachingHint;
@@ -768,6 +772,7 @@
     CHECK_DIFF(diff, eDataspaceChanged, other, dataspace);
     CHECK_DIFF2(diff, eExtendedRangeBrightnessChanged, other, currentHdrSdrRatio,
                 desiredHdrSdrRatio);
+    CHECK_DIFF(diff, eDesiredHdrHeadroomChanged, other, desiredHdrSdrRatio);
     CHECK_DIFF(diff, eCachingHintChanged, other, cachingHint);
     CHECK_DIFF(diff, eHdrMetadataChanged, other, hdrMetadata);
     if (other.what & eSurfaceDamageRegionChanged &&
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 8d18551..3a02c64 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1807,6 +1807,20 @@
     return *this;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDesiredHdrHeadroom(
+        const sp<SurfaceControl>& sc, float desiredRatio) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eDesiredHdrHeadroomChanged;
+    s->desiredHdrSdrRatio = desiredRatio;
+
+    registerSurfaceControlForCallback(sc);
+    return *this;
+}
+
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCachingHint(
         const sp<SurfaceControl>& sc, gui::CachingHint cachingHint) {
     layer_state_t* s = getLayerState(sc);
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 6b8e824..9350c95 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -206,7 +206,7 @@
         eBackgroundBlurRadiusChanged = 0x80'00000000,
         eProducerDisconnect = 0x100'00000000,
         eFixedTransformHintChanged = 0x200'00000000,
-        /* unused 0x400'00000000, */
+        eDesiredHdrHeadroomChanged = 0x400'00000000,
         eBlurRegionsChanged = 0x800'00000000,
         eAutoRefreshChanged = 0x1000'00000000,
         eStretchChanged = 0x2000'00000000,
@@ -245,7 +245,8 @@
             layer_state_t::eSidebandStreamChanged | layer_state_t::eSurfaceDamageRegionChanged |
             layer_state_t::eTransformToDisplayInverseChanged |
             layer_state_t::eTransparentRegionChanged |
-            layer_state_t::eExtendedRangeBrightnessChanged;
+            layer_state_t::eExtendedRangeBrightnessChanged |
+            layer_state_t::eDesiredHdrHeadroomChanged;
 
     // Content updates.
     static constexpr uint64_t CONTENT_CHANGES = layer_state_t::BUFFER_CHANGES |
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 14e3dd5..7118883 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -594,6 +594,7 @@
         Transaction& setDataspace(const sp<SurfaceControl>& sc, ui::Dataspace dataspace);
         Transaction& setExtendedRangeBrightness(const sp<SurfaceControl>& sc,
                                                 float currentBufferRatio, float desiredRatio);
+        Transaction& setDesiredHdrHeadroom(const sp<SurfaceControl>& sc, float desiredRatio);
         Transaction& setCachingHint(const sp<SurfaceControl>& sc, gui::CachingHint cachingHint);
         Transaction& setHdrMetadata(const sp<SurfaceControl>& sc, const HdrMetadata& hdrMetadata);
         Transaction& setSurfaceDamageRegion(const sp<SurfaceControl>& sc,
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index 38974a2..8b200a2 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -380,6 +380,9 @@
         currentHdrSdrRatio = requested.currentHdrSdrRatio;
         desiredHdrSdrRatio = requested.desiredHdrSdrRatio;
     }
+    if (forceUpdate || requested.what & layer_state_t::eDesiredHdrHeadroomChanged) {
+        desiredHdrSdrRatio = requested.desiredHdrSdrRatio;
+    }
     if (forceUpdate || requested.what & layer_state_t::eCachingHintChanged) {
         cachingHint = requested.cachingHint;
     }
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index 209df79..b72588a 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -98,7 +98,7 @@
     z = 0;
     layerStack = ui::DEFAULT_LAYER_STACK;
     transformToDisplayInverse = false;
-    desiredHdrSdrRatio = 1.f;
+    desiredHdrSdrRatio = -1.f;
     currentHdrSdrRatio = 1.f;
     dataspaceRequested = false;
     hdrMetadata.validTypes = 0;
@@ -603,7 +603,8 @@
             layer_state_t::eShadowRadiusChanged | layer_state_t::eFixedTransformHintChanged |
             layer_state_t::eTrustedOverlayChanged | layer_state_t::eStretchChanged |
             layer_state_t::eBufferCropChanged | layer_state_t::eDestinationFrameChanged |
-            layer_state_t::eDimmingEnabledChanged | layer_state_t::eExtendedRangeBrightnessChanged;
+            layer_state_t::eDimmingEnabledChanged | layer_state_t::eExtendedRangeBrightnessChanged |
+            layer_state_t::eDesiredHdrHeadroomChanged;
     if (changedFlags & deniedChanges) {
         ATRACE_FORMAT_INSTANT("%s: false [has denied changes flags 0x%" PRIx64 "]", __func__,
                               s.what & deniedChanges);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 219a8e2..736fec6 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -3395,6 +3395,14 @@
     return true;
 }
 
+bool Layer::setDesiredHdrHeadroom(float desiredRatio) {
+    if (mDrawingState.desiredHdrSdrRatio == desiredRatio) return false;
+    mDrawingState.desiredHdrSdrRatio = desiredRatio;
+    mDrawingState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
 bool Layer::setCachingHint(gui::CachingHint cachingHint) {
     if (mDrawingState.cachingHint == cachingHint) return false;
     mDrawingState.cachingHint = cachingHint;
@@ -3991,6 +3999,13 @@
         }
     }
 
+    if (s.what & layer_state_t::eDesiredHdrHeadroomChanged) {
+        if (mDrawingState.desiredHdrSdrRatio != s.desiredHdrSdrRatio) {
+            ATRACE_FORMAT_INSTANT("%s: false [eDesiredHdrHeadroomChanged changed]", __func__);
+            return false;
+        }
+    }
+
     return true;
 }
 
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index dfd57c6..0ceecec 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -233,7 +233,7 @@
         bool autoRefresh = false;
         bool dimmingEnabled = true;
         float currentHdrSdrRatio = 1.f;
-        float desiredHdrSdrRatio = 1.f;
+        float desiredHdrSdrRatio = -1.f;
         gui::CachingHint cachingHint = gui::CachingHint::Enabled;
         int64_t latchedVsyncId = 0;
         bool useVsyncIdForRefreshRateSelection = false;
@@ -317,6 +317,7 @@
     void setDesiredPresentTime(nsecs_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/);
     bool setDataspace(ui::Dataspace /*dataspace*/);
     bool setExtendedRangeBrightness(float currentBufferRatio, float desiredRatio);
+    bool setDesiredHdrHeadroom(float desiredRatio);
     bool setCachingHint(gui::CachingHint cachingHint);
     bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/);
     bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/);
@@ -546,7 +547,7 @@
         sp<IBinder> mReleaseBufferEndpoint;
 
         bool mFrameLatencyNeeded{false};
-        float mDesiredHdrSdrRatio = 1.f;
+        float mDesiredHdrSdrRatio = -1.f;
     };
 
     BufferInfo mBufferInfo;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7626fe7..1a40bc2 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3119,6 +3119,7 @@
         for (auto& [compositionDisplay, listener] : hdrInfoListeners) {
             HdrLayerInfoReporter::HdrLayerInfo info;
             int32_t maxArea = 0;
+
             auto updateInfoFn =
                     [&](const std::shared_ptr<compositionengine::Display>& compositionDisplay,
                         const frontend::LayerSnapshot& snapshot, const sp<LayerFE>& layerFe) {
@@ -3129,7 +3130,7 @@
                                         compositionDisplay->getOutputLayerForLayer(layerFe);
                                 if (outputLayer) {
                                     const float desiredHdrSdrRatio =
-                                            snapshot.desiredHdrSdrRatio <= 1.f
+                                            snapshot.desiredHdrSdrRatio < 1.f
                                             ? std::numeric_limits<float>::infinity()
                                             : snapshot.desiredHdrSdrRatio;
                                     info.mergeDesiredRatio(desiredHdrSdrRatio);
@@ -5415,6 +5416,11 @@
             flags |= eTraversalNeeded;
         }
     }
+    if (what & layer_state_t::eDesiredHdrHeadroomChanged) {
+        if (layer->setDesiredHdrHeadroom(s.desiredHdrSdrRatio)) {
+            flags |= eTraversalNeeded;
+        }
+    }
     if (what & layer_state_t::eCachingHintChanged) {
         if (layer->setCachingHint(s.cachingHint)) {
             flags |= eTraversalNeeded;
@@ -5600,6 +5606,11 @@
             flags |= eTraversalNeeded;
         }
     }
+    if (what & layer_state_t::eDesiredHdrHeadroomChanged) {
+        if (layer->setDesiredHdrHeadroom(s.desiredHdrSdrRatio)) {
+            flags |= eTraversalNeeded;
+        }
+    }
     if (what & layer_state_t::eBufferChanged) {
         std::optional<ui::Transform::RotationFlags> transformHint = std::nullopt;
         frontend::LayerSnapshot* snapshot = mLayerSnapshotBuilder.getSnapshot(layer->sequence);