Merge "SF: VSyncDispatchTimerQueueEntry::update should not skip a frame" into main
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/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index cab1a60..966ec95 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -984,7 +984,7 @@
         return generatedFlaggedService(test_flags, kBinderNdkUnitTestServiceFlagged);
     }
 
-    ABinderProcess_setThreadPoolMaxThreadCount(1);  // to receive death notifications/callbacks
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
     ABinderProcess_startThreadPool();
 
     return RUN_ALL_TESTS();
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 7564c26..1e0aacd 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -611,6 +611,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;
@@ -774,6 +778,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 83c2b7f..4f1356b 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1808,6 +1808,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 920310e..0fedea7 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -209,7 +209,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,
@@ -248,7 +248,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 88a2c34..2888826 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/libs/renderengine/skia/filters/KawaseBlurFilter.cpp b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp
index 5c9820c..09f09a6 100644
--- a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp
+++ b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp
@@ -111,7 +111,7 @@
     constexpr int kSampleCount = 1;
     constexpr bool kMipmapped = false;
     constexpr SkSurfaceProps* kProps = nullptr;
-    sk_sp<SkSurface> surface = SkSurfaces::RenderTarget(context, skgpu::Budgeted::kYes, scaledInfo,
+    sk_sp<SkSurface> surface = SkSurfaces::RenderTarget(context, skgpu::Budgeted::kNo, scaledInfo,
                                                         kSampleCount, kTopLeft_GrSurfaceOrigin,
                                                         kProps, kMipmapped, input->isProtected());
     LOG_ALWAYS_FATAL_IF(!surface, "%s: Failed to create surface for blurring!", __func__);
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index 3ef9e69..ea06cf6 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -381,6 +381,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 2cf4c1b..cb0e2a1 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;
@@ -606,7 +606,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/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index 9c4f7a5..9745452 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -327,7 +327,8 @@
             mLayerVote.type != LayerHistory::LayerVoteType::ExplicitDefault) {
             ATRACE_FORMAT_INSTANT("Vote %s", ftl::enum_string(mLayerVote.type).c_str());
             ALOGV("%s voted %d", mName.c_str(), static_cast<int>(mLayerVote.type));
-            votes.push_back(mLayerVote);
+            votes.push_back({mLayerVote.type, mLayerVote.fps, mLayerVote.seamlessness,
+                             FrameRateCategory::Default, mLayerVote.categorySmoothSwitchOnly});
         }
 
         return votes;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d354e4b..5bb5508 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3111,6 +3111,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) {
@@ -3121,7 +3122,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);
@@ -5559,6 +5560,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;
@@ -5744,6 +5750,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);
diff --git a/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp b/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp
index 299e8aa..0adf0b6 100644
--- a/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp
@@ -114,7 +114,10 @@
     EXPECT_TRUE(mFlagManager.add_sf_skipped_frames_to_trace());
 }
 
-TEST_F(FlagManagerTest, returnsOverrideFalse) {
+// disabling this test since we need to use a unique flag for this test,
+// but we only one server flag currently. Re-enable once we have a new flag
+// and change this test to use a unique flag.
+TEST_F(FlagManagerTest, DISABLED_returnsOverrideFalse) {
     mFlagManager.markBootCompleted();
 
     SET_FLAG_FOR_TEST(flags::refresh_rate_overlay_on_external_display, true);
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index bc06a31..9b8ff42 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -646,7 +646,7 @@
     // Second LayerRequirement is the frame rate specification
     EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[1].vote);
     EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[1].desiredRefreshRate);
-    EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[1].frameRateCategory);
+    EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[1].frameRateCategory);
 
     // layer became inactive, but the vote stays
     setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
diff --git a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
index 9fe9ee8..c1fa6ac 100644
--- a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
@@ -213,7 +213,8 @@
 TEST_F(LayerInfoTest, getRefreshRateVote_explicitVoteWithCategory) {
     LayerInfo::LayerVote vote = {.type = LayerHistory::LayerVoteType::ExplicitDefault,
                                  .fps = 20_Hz,
-                                 .category = FrameRateCategory::High};
+                                 .category = FrameRateCategory::High,
+                                 .categorySmoothSwitchOnly = true};
     layerInfo.setLayerVote(vote);
 
     auto actualVotes =
@@ -221,10 +222,12 @@
     ASSERT_EQ(actualVotes.size(), 2u);
     ASSERT_EQ(actualVotes[0].type, LayerHistory::LayerVoteType::ExplicitCategory);
     ASSERT_EQ(actualVotes[0].category, vote.category);
+    ASSERT_TRUE(actualVotes[0].categorySmoothSwitchOnly);
     ASSERT_EQ(actualVotes[1].type, vote.type);
     ASSERT_EQ(actualVotes[1].fps, vote.fps);
     ASSERT_EQ(actualVotes[1].seamlessness, vote.seamlessness);
-    ASSERT_EQ(actualVotes[1].category, vote.category);
+    ASSERT_EQ(actualVotes[1].category, FrameRateCategory::Default);
+    ASSERT_TRUE(actualVotes[1].categorySmoothSwitchOnly);
 }
 
 TEST_F(LayerInfoTest, getRefreshRateVote_explicitCategory) {