Composition strategy prediction: Make broader predictions.

As of recently we have begun speculating on the composition
strategy in cases where we expect GL composition to be present.
This enables us to gain back main thread time by running
chooseCompositionStrategy (sometimes a long call to HWC)
in parallel with GL composition itself. Currently this is only
enabled when no geometry changes. Unfortunately this doesn't
help us a lot, since most of the cases where we have jank
and issues with SF runtime are around animations. In this
CL we try and expand the heuristic to cover more cases,
including app launch. Now we expect that if we are sending the
same output layers to HWC in the same order, and all we have
changed is geometry, then the composition strategy will remain
stable. We implement by hashing a subset of the values
sent to HWC and detecting changes.

Test: Existing tests pass. Play with phone lots, no mispredictions
Bug: 230617082
Change-Id: I1f41e2cc67b1b55780e1bf6e837d766b4c186161
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index feca71c..1362cff 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -801,6 +801,7 @@
     bool includeGeometry = refreshArgs.updatingGeometryThisFrame;
     uint32_t z = 0;
     bool overrideZ = false;
+    uint64_t outputLayerHash = 0;
     for (auto* layer : getOutputLayersOrderedByZ()) {
         if (layer == peekThroughLayer) {
             // No longer needed, although it should not show up again, so
@@ -827,6 +828,10 @@
                     constexpr bool isPeekingThrough = true;
                     peekThroughLayer->writeStateToHWC(includeGeometry, false, z++, overrideZ,
                                                       isPeekingThrough);
+                    outputLayerHash ^= android::hashCombine(
+                            reinterpret_cast<uint64_t>(&peekThroughLayer->getLayerFE()),
+                            z, includeGeometry, overrideZ, isPeekingThrough,
+                            peekThroughLayer->requiresClientComposition());
                 }
 
                 previousOverride = overrideInfo.buffer->getBuffer();
@@ -835,7 +840,14 @@
 
         constexpr bool isPeekingThrough = false;
         layer->writeStateToHWC(includeGeometry, skipLayer, z++, overrideZ, isPeekingThrough);
+        if (!skipLayer) {
+            outputLayerHash ^= android::hashCombine(
+                    reinterpret_cast<uint64_t>(&layer->getLayerFE()),
+                    z, includeGeometry, overrideZ, isPeekingThrough,
+                    layer->requiresClientComposition());
+        }
     }
+    editState().outputLayerHash = outputLayerHash;
 }
 
 compositionengine::OutputLayer* Output::findLayerRequestingBackgroundComposition() const {
@@ -1550,6 +1562,10 @@
 }
 
 bool Output::canPredictCompositionStrategy(const CompositionRefreshArgs& refreshArgs) {
+    uint64_t lastOutputLayerHash = getState().lastOutputLayerHash;
+    uint64_t outputLayerHash = getState().outputLayerHash;
+    editState().lastOutputLayerHash = outputLayerHash;
+
     if (!getState().isEnabled || !mHwComposerAsyncWorker) {
         ALOGV("canPredictCompositionStrategy disabled");
         return false;
@@ -1570,6 +1586,11 @@
         return false;
     }
 
+    if (lastOutputLayerHash != outputLayerHash) {
+        ALOGV("canPredictCompositionStrategy output layers changed");
+        return false;
+    }
+
     // If no layer uses clientComposition, then don't predict composition strategy
     // because we have less work to do in parallel.
     if (!anyLayersRequireClientComposition()) {
@@ -1577,12 +1598,7 @@
         return false;
     }
 
-    if (!refreshArgs.updatingOutputGeometryThisFrame) {
-        return true;
-    }
-
-    ALOGV("canPredictCompositionStrategy updatingOutputGeometryThisFrame");
-    return false;
+    return true;
 }
 
 bool Output::anyLayersRequireClientComposition() const {