SF: LayerSnapshotBuilder updates

- Adds support for framerate, gamemode, transformhint & input
- Fixes z-order traversal bug where a layer was visited twice.
- Compat fix, a layer cannot be root once its parented

Test: presubmit
Bug: 238781169
Change-Id: Ic33aa09b2c41fadd4872ca481b41f86400629fc8
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 0982077..d76faba 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -166,7 +166,8 @@
             .receivesInput = receivesInput(),
             .isSecure = isSecure(),
             .isPrimary = isPrimary(),
-            .rotationFlags = ui::Transform::toRotationFlags(mOrientation)};
+            .rotationFlags = ui::Transform::toRotationFlags(mOrientation),
+            .transformHint = getTransformHint()};
 }
 
 void DisplayDevice::setPowerMode(hal::PowerMode mode) {
diff --git a/services/surfaceflinger/FrontEnd/DisplayInfo.h b/services/surfaceflinger/FrontEnd/DisplayInfo.h
index 0c7b24a..6b9d7a2 100644
--- a/services/surfaceflinger/FrontEnd/DisplayInfo.h
+++ b/services/surfaceflinger/FrontEnd/DisplayInfo.h
@@ -16,6 +16,8 @@
 
 #pragma once
 
+#include <sstream>
+
 #include <gui/DisplayInfo.h>
 
 namespace android::surfaceflinger::frontend {
@@ -29,6 +31,16 @@
     // TODO(b/238781169) can eliminate once sPrimaryDisplayRotationFlags is removed.
     bool isPrimary;
     ui::Transform::RotationFlags rotationFlags;
+    ui::Transform::RotationFlags transformHint;
+    std::string getDebugString() const {
+        std::stringstream debug;
+        debug << "DisplayInfo {displayId=" << info.displayId << " lw=" << info.logicalWidth
+              << " lh=" << info.logicalHeight << " transform={" << transform.dsdx() << " ,"
+              << transform.dsdy() << " ," << transform.dtdx() << " ," << transform.dtdy()
+              << "} isSecure=" << isSecure << " isPrimary=" << isPrimary
+              << " rotationFlags=" << rotationFlags << " transformHint=" << transformHint << "}";
+        return debug.str();
+    }
 };
 
 } // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
index 514a642..678d36b 100644
--- a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
@@ -28,8 +28,8 @@
                         const std::pair<LayerHierarchy*, LayerHierarchy::Variant>& rhs) {
     auto lhsLayer = lhs.first->getLayer();
     auto rhsLayer = rhs.first->getLayer();
-    if (lhsLayer->layerStack != rhsLayer->layerStack) {
-        return lhsLayer->layerStack.id < rhsLayer->layerStack.id;
+    if (lhsLayer->layerStack.id != rhsLayer->layerStack.id) {
+        return lhsLayer->layerStack.id > rhsLayer->layerStack.id;
     }
     if (lhsLayer->z != rhsLayer->z) {
         return lhsLayer->z < rhsLayer->z;
@@ -75,11 +75,11 @@
     for (auto it = mChildren.begin(); it < mChildren.end(); it++) {
         auto& [child, childVariant] = *it;
         if (traverseThisLayer && child->getLayer()->z >= 0) {
+            traverseThisLayer = false;
             bool breakTraversal = !visitor(*this, traversalPath);
             if (breakTraversal) {
                 return;
             }
-            traverseThisLayer = false;
         }
         if (childVariant == LayerHierarchy::Variant::Detached) {
             continue;
diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.h b/services/surfaceflinger/FrontEnd/LayerHierarchy.h
index 8cdc240..ca8d301 100644
--- a/services/surfaceflinger/FrontEnd/LayerHierarchy.h
+++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.h
@@ -41,11 +41,13 @@
 // states.
 class LayerHierarchy {
 public:
-    enum Variant {
+    enum Variant : uint32_t {
         Attached,
         Detached,
         Relative,
         Mirror,
+        ftl_first = Attached,
+        ftl_last = Mirror,
     };
     // Represents a unique path to a node.
     struct TraversalPath {
diff --git a/services/surfaceflinger/FrontEnd/LayerLog.h b/services/surfaceflinger/FrontEnd/LayerLog.h
new file mode 100644
index 0000000..47e1e30
--- /dev/null
+++ b/services/surfaceflinger/FrontEnd/LayerLog.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+// Uncomment to trace layer updates for a single layer
+// #define LOG_LAYER 1
+
+#ifdef LOG_LAYER
+#define LLOGV(LAYER_ID, x, ...) \
+    ALOGV_IF(((LAYER_ID) == LOG_LAYER), "[%d] %s " x, LOG_LAYER, __func__, ##__VA_ARGS__);
+#else
+#define LLOGV(LAYER_ID, x, ...) ALOGV("[%d] %s " x, (LAYER_ID), __func__, ##__VA_ARGS__);
+#endif
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index d483a99..3a0540c 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -61,7 +61,7 @@
 }
 
 bool LayerSnapshot::hasBufferOrSidebandStream() const {
-    return ((sidebandStream != nullptr) || (buffer != nullptr));
+    return ((sidebandStream != nullptr) || (externalTexture != nullptr));
 }
 
 bool LayerSnapshot::drawShadows() const {
@@ -99,7 +99,7 @@
 
     // If the buffer has no alpha channel, then we are opaque
     if (hasBufferOrSidebandStream() &&
-        isOpaqueFormat(buffer ? buffer->getPixelFormat() : PIXEL_FORMAT_NONE)) {
+        isOpaqueFormat(externalTexture ? externalTexture->getPixelFormat() : PIXEL_FORMAT_NONE)) {
         return true;
     }
 
@@ -108,11 +108,7 @@
 }
 
 bool LayerSnapshot::isHiddenByPolicy() const {
-    if (CC_UNLIKELY(invalidTransform)) {
-        ALOGW("Hide layer %s because it has invalid transformation.", name.c_str());
-        return true;
-    }
-    return isHiddenByPolicyFromParent || isHiddenByPolicyFromRelativeParent;
+    return invalidTransform || isHiddenByPolicyFromParent || isHiddenByPolicyFromRelativeParent;
 }
 
 bool LayerSnapshot::getIsVisible() const {
@@ -128,19 +124,22 @@
 }
 
 std::string LayerSnapshot::getIsVisibleReason() const {
-    if (!hasSomethingToDraw()) {
-        return "!hasSomethingToDraw";
-    }
+    // not visible
+    if (!hasSomethingToDraw()) return "!hasSomethingToDraw";
+    if (invalidTransform) return "invalidTransform";
+    if (isHiddenByPolicyFromParent) return "hidden by parent or layer flag";
+    if (isHiddenByPolicyFromRelativeParent) return "hidden by relative parent";
+    if (color.a == 0.0f && !hasBlur()) return "alpha = 0 and no blur";
 
-    if (isHiddenByPolicy()) {
-        return "isHiddenByPolicy";
-    }
-
-    if (color.a > 0.0f || hasBlur()) {
-        return "";
-    }
-
-    return "alpha = 0 and !hasBlur";
+    // visible
+    std::stringstream reason;
+    if (sidebandStream != nullptr) reason << " sidebandStream";
+    if (externalTexture != nullptr) reason << " buffer";
+    if (fillsColor() || color.a > 0.0f) reason << " color{" << color << "}";
+    if (drawShadows()) reason << " shadowSettings.length=" << shadowSettings.length;
+    if (backgroundBlurRadius > 0) reason << " backgroundBlurRadius=" << backgroundBlurRadius;
+    if (blurRegions.size() > 0) reason << " blurRegions.size()=" << blurRegions.size();
+    return reason.str();
 }
 
 bool LayerSnapshot::canReceiveInput() const {
@@ -152,11 +151,16 @@
     return transformDet != 0 && !isinf(transformDet) && !isnan(transformDet);
 }
 
+bool LayerSnapshot::hasInputInfo() const {
+    return inputInfo.token != nullptr ||
+            inputInfo.inputConfig.test(gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL);
+}
+
 std::string LayerSnapshot::getDebugString() const {
-    return "Snapshot(" + base::StringPrintf("%p", this) + "){" + path.toString() + name +
-            " isHidden=" + std::to_string(isHiddenByPolicyFromParent) +
-            " isHiddenRelative=" + std::to_string(isHiddenByPolicyFromRelativeParent) +
-            " isVisible=" + std::to_string(isVisible) + " " + getIsVisibleReason() + "}";
+    std::stringstream debug;
+    debug << "Snapshot{" << path.toString() << name << " isVisible=" << isVisible << " {"
+          << getIsVisibleReason() << "} changes=" << changes.string() << "}";
+    return debug.str();
 }
 
 } // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
index d14bd3a..4512ade 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
@@ -20,6 +20,7 @@
 #include <renderengine/LayerSettings.h>
 #include "LayerHierarchy.h"
 #include "RequestedLayerState.h"
+#include "Scheduler/LayerInfo.h"
 #include "android-base/stringprintf.h"
 
 namespace android::surfaceflinger::frontend {
@@ -39,6 +40,10 @@
     }
 };
 
+struct ChildState {
+    bool hasValidFrameRate = false;
+};
+
 // LayerSnapshot stores Layer state used by CompositionEngine and RenderEngine. Composition
 // Engine uses a pointer to LayerSnapshot (as LayerFECompositionState*) and the LayerSettings
 // passed to Render Engine are created using properties stored on this struct.
@@ -59,6 +64,7 @@
     bool layerOpaqueFlagSet;
     RoundedCornerState roundedCorner;
     FloatRect transformedBounds;
+    Rect transformedBoundsWithoutTransparentRegion;
     renderengine::ShadowSettings shadowSettings;
     bool premultipliedAlpha;
     bool isHdrY410;
@@ -75,6 +81,10 @@
     ui::Transform localTransform;
     gui::DropInputMode dropInputMode;
     bool isTrustedOverlay;
+    gui::GameMode gameMode;
+    scheduler::LayerInfo::FrameRate frameRate;
+    ui::Transform::RotationFlags fixedTransformHint;
+    ChildState childState;
 
     static bool isOpaqueFormat(PixelFormat format);
     static bool isTransformValid(const ui::Transform& t);
@@ -91,6 +101,7 @@
     bool isHiddenByPolicy() const;
     std::string getDebugString() const;
     std::string getIsVisibleReason() const;
+    bool hasInputInfo() const;
 };
 
 } // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index bff12d7..40dffb9 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -24,6 +24,8 @@
 #include <numeric>
 #include "DisplayHardware/HWC2.h"
 #include "DisplayHardware/Hal.h"
+#include "LayerLog.h"
+#include "TimeStats/TimeStats.h"
 #include "ftl/small_map.h"
 
 namespace android::surfaceflinger::frontend {
@@ -250,6 +252,64 @@
     return blendMode;
 }
 
+void updateSurfaceDamage(const RequestedLayerState& requested, bool hasReadyFrame,
+                         bool forceFullDamage, Region& outSurfaceDamageRegion) {
+    if (!hasReadyFrame) {
+        outSurfaceDamageRegion.clear();
+        return;
+    }
+    if (forceFullDamage) {
+        outSurfaceDamageRegion = Region::INVALID_REGION;
+    } else {
+        outSurfaceDamageRegion = requested.surfaceDamageRegion;
+    }
+}
+
+void updateVisibility(LayerSnapshot& snapshot) {
+    snapshot.isVisible = snapshot.getIsVisible();
+
+    // TODO(b/238781169) we are ignoring this compat for now, since we will have
+    // to remove any optimization based on visibility.
+
+    // For compatibility reasons we let layers which can receive input
+    // receive input before they have actually submitted a buffer. Because
+    // of this we use canReceiveInput instead of isVisible to check the
+    // policy-visibility, ignoring the buffer state. However for layers with
+    // hasInputInfo()==false we can use the real visibility state.
+    // We are just using these layers for occlusion detection in
+    // InputDispatcher, and obviously if they aren't visible they can't occlude
+    // anything.
+    const bool visible =
+            (snapshot.inputInfo.token != nullptr) ? snapshot.canReceiveInput() : snapshot.isVisible;
+    snapshot.inputInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_VISIBLE, !visible);
+}
+
+bool needsInputInfo(const LayerSnapshot& snapshot, const RequestedLayerState& requested) {
+    if (requested.potentialCursor) {
+        return false;
+    }
+
+    if (snapshot.inputInfo.token != nullptr) {
+        return true;
+    }
+
+    if (snapshot.hasBufferOrSidebandStream()) {
+        return true;
+    }
+
+    return requested.windowInfoHandle &&
+            requested.windowInfoHandle->getInfo()->inputConfig.test(
+                    gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL);
+}
+
+void clearChanges(LayerSnapshot& snapshot) {
+    snapshot.changes.clear();
+    snapshot.contentDirty = false;
+    snapshot.hasReadyFrame = false;
+    snapshot.sidebandStreamHasFrame = false;
+    snapshot.surfaceDamage.clear();
+}
+
 } // namespace
 
 LayerSnapshot LayerSnapshotBuilder::getRootSnapshot() {
@@ -274,6 +334,9 @@
     snapshot.inputInfo.touchOcclusionMode = gui::TouchOcclusionMode::BLOCK_UNTRUSTED;
     snapshot.dropInputMode = gui::DropInputMode::NONE;
     snapshot.isTrustedOverlay = false;
+    snapshot.gameMode = gui::GameMode::Unsupported;
+    snapshot.frameRate = {};
+    snapshot.fixedTransformHint = ui::Transform::ROT_INVALID;
     return snapshot;
 }
 
@@ -285,16 +348,15 @@
 }
 
 bool LayerSnapshotBuilder::tryFastUpdate(const Args& args) {
-    if (args.forceUpdate) {
-        // force update requested, so skip the fast path
+    if (args.forceUpdate || args.displayChanges) {
+        // force update requested, or we have display changes, so skip the fast path
         return false;
     }
 
     if (args.layerLifecycleManager.getGlobalChanges().get() == 0) {
         // there are no changes, so just clear the change flags from before.
         for (auto& snapshot : mSnapshots) {
-            snapshot->changes.clear();
-            snapshot->contentDirty = false;
+            clearChanges(*snapshot);
         }
         return true;
     }
@@ -320,14 +382,14 @@
     // Walk through the snapshots, clearing previous change flags and updating the snapshots
     // if needed.
     for (auto& snapshot : mSnapshots) {
-        snapshot->changes.clear();
-        snapshot->contentDirty = false;
+        clearChanges(*snapshot);
         auto it = layersWithChanges.find(snapshot->path.id);
         if (it != layersWithChanges.end()) {
             ALOGV("%s fast path snapshot changes = %s", __func__,
                   mRootSnapshot.changes.string().c_str());
             LayerHierarchy::TraversalPath root = LayerHierarchy::TraversalPath::ROOT;
-            updateSnapshot(*snapshot, args, *it->second, mRootSnapshot, root);
+            updateSnapshot(*snapshot, args, *it->second, mRootSnapshot, root,
+                           /*newSnapshot=*/false);
         }
     }
     return true;
@@ -335,7 +397,6 @@
 
 void LayerSnapshotBuilder::updateSnapshots(const Args& args) {
     ATRACE_NAME("UpdateSnapshots");
-    ALOGV("%s updateSnapshots force = %s", __func__, std::to_string(args.forceUpdate).c_str());
     if (args.forceUpdate || args.displayChanges) {
         mRootSnapshot.geomLayerBounds = getMaxDisplayBounds(args.displays);
     }
@@ -352,7 +413,7 @@
     }
 
     sortSnapshotsByZ(args);
-    mRootSnapshot.changes.clear();
+    clearChanges(mRootSnapshot);
 
     // Destroy unreachable snapshots
     if (args.layerLifecycleManager.getDestroyedLayers().empty()) {
@@ -372,6 +433,7 @@
         }
 
         mIdToSnapshot.erase(traversalPath);
+        mSnapshots.back()->globalZ = it->get()->globalZ;
         std::iter_swap(it, mSnapshots.end() - 1);
         mSnapshots.erase(mSnapshots.end() - 1);
     }
@@ -384,12 +446,15 @@
     updateSnapshots(args);
 }
 
-void LayerSnapshotBuilder::updateSnapshotsInHierarchy(const Args& args,
-                                                      const LayerHierarchy& hierarchy,
-                                                      LayerHierarchy::TraversalPath& traversalPath,
-                                                      const LayerSnapshot& parentSnapshot) {
+const LayerSnapshot& LayerSnapshotBuilder::updateSnapshotsInHierarchy(
+        const Args& args, const LayerHierarchy& hierarchy,
+        LayerHierarchy::TraversalPath& traversalPath, const LayerSnapshot& parentSnapshot) {
     const RequestedLayerState* layer = hierarchy.getLayer();
-    LayerSnapshot* snapshot = getOrCreateSnapshot(traversalPath, *layer);
+    LayerSnapshot* snapshot = getSnapshot(traversalPath);
+    const bool newSnapshot = snapshot == nullptr;
+    if (newSnapshot) {
+        snapshot = createSnapshot(traversalPath, *layer);
+    }
     if (traversalPath.isRelative()) {
         bool parentIsRelative = traversalPath.variant == LayerHierarchy::Variant::Relative;
         updateRelativeState(*snapshot, parentSnapshot, parentIsRelative, args);
@@ -397,23 +462,18 @@
         if (traversalPath.isAttached()) {
             resetRelativeState(*snapshot);
         }
-        updateSnapshot(*snapshot, args, *layer, parentSnapshot, traversalPath);
-    }
-
-    // If layer is hidden by policy we can avoid update its children. If the visibility
-    // changed this update, then we still need to set the visibility on all the children.
-    if (snapshot->isHiddenByPolicy() &&
-        (!snapshot->changes.any(RequestedLayerState::Changes::Visibility |
-                                RequestedLayerState::Changes::Hierarchy))) {
-        return;
+        updateSnapshot(*snapshot, args, *layer, parentSnapshot, traversalPath, newSnapshot);
     }
 
     for (auto& [childHierarchy, variant] : hierarchy.mChildren) {
         LayerHierarchy::ScopedAddToTraversalPath addChildToPath(traversalPath,
                                                                 childHierarchy->getLayer()->id,
                                                                 variant);
-        updateSnapshotsInHierarchy(args, *childHierarchy, traversalPath, *snapshot);
+        const LayerSnapshot& childSnapshot =
+                updateSnapshotsInHierarchy(args, *childHierarchy, traversalPath, *snapshot);
+        updateChildState(*snapshot, childSnapshot, args);
     }
+    return *snapshot;
 }
 
 LayerSnapshot* LayerSnapshotBuilder::getSnapshot(uint32_t layerId) const {
@@ -429,22 +489,17 @@
     return it == mIdToSnapshot.end() ? nullptr : it->second;
 }
 
-LayerSnapshot* LayerSnapshotBuilder::getOrCreateSnapshot(const LayerHierarchy::TraversalPath& id,
-                                                         const RequestedLayerState& layer) {
-    auto snapshot = getSnapshot(id);
-    if (snapshot) {
-        return snapshot;
-    }
-
+LayerSnapshot* LayerSnapshotBuilder::createSnapshot(const LayerHierarchy::TraversalPath& id,
+                                                    const RequestedLayerState& layer) {
     mSnapshots.emplace_back(std::make_unique<LayerSnapshot>(layer, id));
-    snapshot = mSnapshots.back().get();
+    LayerSnapshot* snapshot = mSnapshots.back().get();
     snapshot->globalZ = static_cast<size_t>(mSnapshots.size()) - 1;
     mIdToSnapshot[id] = snapshot;
     return snapshot;
 }
 
 void LayerSnapshotBuilder::sortSnapshotsByZ(const Args& args) {
-    if (!args.forceUpdate &&
+    if (!mResortSnapshots && !args.forceUpdate &&
         !args.layerLifecycleManager.getGlobalChanges().any(
                 RequestedLayerState::Changes::Hierarchy |
                 RequestedLayerState::Changes::Visibility)) {
@@ -453,6 +508,8 @@
         return;
     }
 
+    mResortSnapshots = false;
+
     size_t globalZ = 0;
     args.root.traverseInZOrder(
             [this, &globalZ](const LayerHierarchy&,
@@ -467,7 +524,8 @@
                     return false;
                 }
 
-                if (snapshot->isVisible) {
+                if (snapshot->getIsVisible() || snapshot->hasInputInfo()) {
+                    updateVisibility(*snapshot);
                     size_t oldZ = snapshot->globalZ;
                     size_t newZ = globalZ++;
                     snapshot->globalZ = newZ;
@@ -475,16 +533,17 @@
                         return true;
                     }
                     mSnapshots[newZ]->globalZ = oldZ;
+                    LLOGV(snapshot->sequence, "Made visible z=%zu -> %zu %s", oldZ, newZ,
+                          snapshot->getDebugString().c_str());
                     std::iter_swap(mSnapshots.begin() + static_cast<ssize_t>(oldZ),
                                    mSnapshots.begin() + static_cast<ssize_t>(newZ));
                 }
-
                 return true;
             });
-
+    mNumInterestingSnapshots = (int)globalZ;
     while (globalZ < mSnapshots.size()) {
         mSnapshots[globalZ]->globalZ = globalZ;
-        mSnapshots[globalZ]->isVisible = false;
+        updateVisibility(*mSnapshots[globalZ]);
         globalZ++;
     }
 }
@@ -493,7 +552,8 @@
                                                const LayerSnapshot& parentSnapshot,
                                                bool parentIsRelative, const Args& args) {
     if (parentIsRelative) {
-        snapshot.isHiddenByPolicyFromRelativeParent = parentSnapshot.isHiddenByPolicyFromParent;
+        snapshot.isHiddenByPolicyFromRelativeParent =
+                parentSnapshot.isHiddenByPolicyFromParent || parentSnapshot.invalidTransform;
         if (args.includeMetadata) {
             snapshot.relativeLayerMetadata = parentSnapshot.layerMetadata;
         }
@@ -507,6 +567,38 @@
     snapshot.isVisible = snapshot.getIsVisible();
 }
 
+void LayerSnapshotBuilder::updateChildState(LayerSnapshot& snapshot,
+                                            const LayerSnapshot& childSnapshot, const Args& args) {
+    if (snapshot.childState.hasValidFrameRate) {
+        return;
+    }
+    if (args.forceUpdate || childSnapshot.changes.test(RequestedLayerState::Changes::FrameRate)) {
+        // We return whether this layer ot its children has a vote. We ignore ExactOrMultiple votes
+        // for the same reason we are allowing touch boost for those layers. See
+        // RefreshRateSelector::rankFrameRates for details.
+        using FrameRateCompatibility = scheduler::LayerInfo::FrameRateCompatibility;
+        const auto layerVotedWithDefaultCompatibility = childSnapshot.frameRate.rate.isValid() &&
+                childSnapshot.frameRate.type == FrameRateCompatibility::Default;
+        const auto layerVotedWithNoVote =
+                childSnapshot.frameRate.type == FrameRateCompatibility::NoVote;
+        const auto layerVotedWithExactCompatibility = childSnapshot.frameRate.rate.isValid() &&
+                childSnapshot.frameRate.type == FrameRateCompatibility::Exact;
+
+        snapshot.childState.hasValidFrameRate |= layerVotedWithDefaultCompatibility ||
+                layerVotedWithNoVote || layerVotedWithExactCompatibility;
+
+        // If we don't have a valid frame rate, but the children do, we set this
+        // layer as NoVote to allow the children to control the refresh rate
+        if (!snapshot.frameRate.rate.isValid() &&
+            snapshot.frameRate.type != FrameRateCompatibility::NoVote &&
+            snapshot.childState.hasValidFrameRate) {
+            snapshot.frameRate =
+                    scheduler::LayerInfo::FrameRate(Fps(), FrameRateCompatibility::NoVote);
+            snapshot.changes |= childSnapshot.changes & RequestedLayerState::Changes::FrameRate;
+        }
+    }
+}
+
 void LayerSnapshotBuilder::resetRelativeState(LayerSnapshot& snapshot) {
     snapshot.isHiddenByPolicyFromRelativeParent = false;
     snapshot.relativeLayerMetadata.mMap.clear();
@@ -523,27 +615,69 @@
 void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& args,
                                           const RequestedLayerState& requested,
                                           const LayerSnapshot& parentSnapshot,
-                                          const LayerHierarchy::TraversalPath& path) {
+                                          const LayerHierarchy::TraversalPath& path,
+                                          bool newSnapshot) {
     // Always update flags and visibility
     ftl::Flags<RequestedLayerState::Changes> parentChanges = parentSnapshot.changes &
             (RequestedLayerState::Changes::Hierarchy | RequestedLayerState::Changes::Geometry |
              RequestedLayerState::Changes::Visibility | RequestedLayerState::Changes::Metadata |
              RequestedLayerState::Changes::AffectsChildren);
     snapshot.changes = parentChanges | requested.changes;
-    snapshot.isHiddenByPolicyFromParent =
-            parentSnapshot.isHiddenByPolicyFromParent || requested.isHiddenByPolicy();
+    snapshot.isHiddenByPolicyFromParent = parentSnapshot.isHiddenByPolicyFromParent ||
+            parentSnapshot.invalidTransform || requested.isHiddenByPolicy();
     snapshot.contentDirty = requested.what & layer_state_t::CONTENT_DIRTY;
-    if (snapshot.isHiddenByPolicyFromParent) {
-        snapshot.isVisible = false;
-        return;
-    }
+    // TODO(b/238781169) scope down the changes to only buffer updates.
+    snapshot.hasReadyFrame =
+            (snapshot.contentDirty || requested.autoRefresh) && (requested.externalTexture);
+    // TODO(b/238781169) how is this used? ag/15523870
+    snapshot.sidebandStreamHasFrame = false;
+    updateSurfaceDamage(requested, snapshot.hasReadyFrame, args.forceFullDamage,
+                        snapshot.surfaceDamage);
 
+    const bool forceUpdate = newSnapshot || args.forceUpdate ||
+            snapshot.changes.any(RequestedLayerState::Changes::Visibility |
+                                 RequestedLayerState::Changes::Created);
     uint32_t displayRotationFlags =
             getDisplayRotationFlags(args.displays, snapshot.outputFilter.layerStack);
 
-    const bool forceUpdate = args.forceUpdate ||
-            snapshot.changes.any(RequestedLayerState::Changes::Visibility |
-                                 RequestedLayerState::Changes::Created);
+    // always update the buffer regardless of visibility
+    if (forceUpdate || requested.what & layer_state_t::BUFFER_CHANGES) {
+        snapshot.acquireFence =
+                (requested.externalTexture &&
+                 requested.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged))
+                ? requested.bufferData->acquireFence
+                : Fence::NO_FENCE;
+        snapshot.buffer =
+                requested.externalTexture ? requested.externalTexture->getBuffer() : nullptr;
+        snapshot.bufferSize = requested.getBufferSize(displayRotationFlags);
+        snapshot.geomBufferSize = snapshot.bufferSize;
+        snapshot.croppedBufferSize = requested.getCroppedBufferSize(snapshot.bufferSize);
+        snapshot.dataspace = requested.dataspace;
+        snapshot.externalTexture = requested.externalTexture;
+        snapshot.frameNumber = (requested.bufferData) ? requested.bufferData->frameNumber : 0;
+        snapshot.geomBufferTransform = requested.bufferTransform;
+        snapshot.geomBufferUsesDisplayInverseTransform = requested.transformToDisplayInverse;
+        snapshot.geomContentCrop = requested.getBufferCrop();
+        snapshot.geomUsesSourceCrop = snapshot.hasBufferOrSidebandStream();
+        snapshot.hasProtectedContent = requested.externalTexture &&
+                requested.externalTexture->getUsage() & GRALLOC_USAGE_PROTECTED;
+        snapshot.isHdrY410 = requested.dataspace == ui::Dataspace::BT2020_ITU_PQ &&
+                requested.api == NATIVE_WINDOW_API_MEDIA &&
+                requested.bufferData->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102;
+        snapshot.sidebandStream = requested.sidebandStream;
+        snapshot.transparentRegionHint = requested.transparentRegion;
+        snapshot.color.rgb = requested.getColor().rgb;
+    }
+
+    if (snapshot.isHiddenByPolicyFromParent && !newSnapshot) {
+        if (forceUpdate ||
+            snapshot.changes.any(RequestedLayerState::Changes::Hierarchy |
+                                 RequestedLayerState::Changes::Geometry |
+                                 RequestedLayerState::Changes::Input)) {
+            updateInput(snapshot, requested, parentSnapshot, path, args);
+        }
+        return;
+    }
 
     if (forceUpdate || snapshot.changes.any(RequestedLayerState::Changes::AffectsChildren)) {
         // If root layer, use the layer stack otherwise get the parent's layer stack.
@@ -567,6 +701,17 @@
             snapshot.colorTransform = requested.colorTransform;
             snapshot.colorTransformIsIdentity = !requested.hasColorTransform;
         }
+        snapshot.gameMode = requested.metadata.has(gui::METADATA_GAME_MODE)
+                ? requested.gameMode
+                : parentSnapshot.gameMode;
+        snapshot.frameRate = (requested.requestedFrameRate.rate.isValid() ||
+                              (requested.requestedFrameRate.type ==
+                               scheduler::LayerInfo::FrameRateCompatibility::NoVote))
+                ? requested.requestedFrameRate
+                : parentSnapshot.frameRate;
+        snapshot.fixedTransformHint = requested.fixedTransformHint != ui::Transform::ROT_INVALID
+                ? requested.fixedTransformHint
+                : parentSnapshot.fixedTransformHint;
     }
 
     if (forceUpdate || requested.changes.get() != 0) {
@@ -576,35 +721,11 @@
                 (requested.flags & layer_state_t::eLayerOpaque) == layer_state_t::eLayerOpaque;
     }
 
-    if (forceUpdate || requested.what & layer_state_t::BUFFER_CHANGES) {
-        snapshot.acquireFence =
-                (requested.bufferData) ? requested.bufferData->acquireFence : Fence::NO_FENCE;
-        snapshot.buffer =
-                requested.externalTexture ? requested.externalTexture->getBuffer() : nullptr;
-        snapshot.bufferSize = requested.getBufferSize(displayRotationFlags);
-        snapshot.geomBufferSize = snapshot.bufferSize;
-        snapshot.croppedBufferSize = requested.getCroppedBufferSize(snapshot.bufferSize);
-        snapshot.dataspace = requested.dataspace;
-        snapshot.externalTexture = requested.externalTexture;
-        snapshot.frameNumber = (requested.bufferData) ? requested.bufferData->frameNumber : 0;
-        snapshot.geomBufferTransform = requested.bufferTransform;
-        snapshot.geomBufferUsesDisplayInverseTransform = requested.transformToDisplayInverse;
-        snapshot.geomContentCrop = requested.getBufferCrop();
-        snapshot.geomUsesSourceCrop = snapshot.hasBufferOrSidebandStream();
-        snapshot.hasProtectedContent = requested.externalTexture &&
-                requested.externalTexture->getUsage() & GRALLOC_USAGE_PROTECTED;
-        snapshot.isHdrY410 = requested.dataspace == ui::Dataspace::BT2020_ITU_PQ &&
-                requested.api == NATIVE_WINDOW_API_MEDIA &&
-                requested.bufferData->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102;
-        snapshot.sidebandStream = requested.sidebandStream;
-        snapshot.surfaceDamage = requested.surfaceDamageRegion;
-        snapshot.transparentRegionHint = requested.transparentRegion;
-    }
-
     if (forceUpdate || snapshot.changes.any(RequestedLayerState::Changes::Content)) {
         snapshot.color.rgb = requested.getColor().rgb;
         snapshot.isColorspaceAgnostic = requested.colorSpaceAgnostic;
-        snapshot.backgroundBlurRadius = static_cast<int>(requested.backgroundBlurRadius);
+        snapshot.backgroundBlurRadius =
+                args.supportsBlur ? static_cast<int>(requested.backgroundBlurRadius) : 0;
         snapshot.blurRegions = requested.blurRegions;
         snapshot.hdrMetadata = requested.hdrMetadata;
     }
@@ -620,12 +741,7 @@
         snapshot.changes.any(RequestedLayerState::Changes::Hierarchy |
                              RequestedLayerState::Changes::Geometry |
                              RequestedLayerState::Changes::Input)) {
-        static frontend::DisplayInfo sDefaultInfo = {.isSecure = false};
-        const std::optional<frontend::DisplayInfo> displayInfo =
-                args.displays.get(snapshot.outputFilter.layerStack);
-        bool noValidDisplay = !displayInfo.has_value();
-        updateInput(snapshot, requested, parentSnapshot, displayInfo.value_or(sDefaultInfo),
-                    noValidDisplay, path);
+        updateInput(snapshot, requested, parentSnapshot, path, args);
     }
 
     // computed snapshot properties
@@ -636,12 +752,14 @@
     }
     snapshot.forceClientComposition = snapshot.isHdrY410 || snapshot.shadowSettings.length > 0 ||
             requested.blurRegions.size() > 0 || snapshot.stretchEffect.hasEffect();
-    snapshot.isVisible = snapshot.getIsVisible();
     snapshot.isOpaque = snapshot.isContentOpaque() && !snapshot.roundedCorner.hasRoundedCorners() &&
             snapshot.color.a == 1.f;
     snapshot.blendMode = getBlendMode(snapshot, requested);
-
-    ALOGV("%supdated [%d]%s changes parent:%s global:%s local:%s requested:%s %s from parent %s",
+    // TODO(b/238781169) pass this from flinger
+    // snapshot.fps;
+    // snapshot.metadata;
+    LLOGV(snapshot.sequence,
+          "%supdated [%d]%s changes parent:%s global:%s local:%s requested:%s %s from parent %s",
           args.forceUpdate ? "Force " : "", requested.id, requested.name.c_str(),
           parentSnapshot.changes.string().c_str(), snapshot.changes.string().c_str(),
           requested.changes.string().c_str(), std::to_string(requested.what).c_str(),
@@ -694,12 +812,35 @@
     snapshot.localTransform = requested.getTransform(displayRotationFlags);
     snapshot.localTransformInverse = snapshot.localTransform.inverse();
     snapshot.geomLayerTransform = parentSnapshot.geomLayerTransform * snapshot.localTransform;
+    const bool transformWasInvalid = snapshot.invalidTransform;
     snapshot.invalidTransform = !LayerSnapshot::isTransformValid(snapshot.geomLayerTransform);
     if (snapshot.invalidTransform) {
-        ALOGW("Resetting transform for %s because it has an invalid transformation.",
-              requested.getDebugStringShort().c_str());
+        auto& t = snapshot.geomLayerTransform;
+        auto& requestedT = requested.requestedTransform;
+        std::string transformDebug =
+                base::StringPrintf(" transform={%f,%f,%f,%f}  requestedTransform={%f,%f,%f,%f}",
+                                   t.dsdx(), t.dsdy(), t.dtdx(), t.dtdy(), requestedT.dsdx(),
+                                   requestedT.dsdy(), requestedT.dtdx(), requestedT.dtdy());
+        std::string bufferDebug;
+        if (requested.externalTexture) {
+            auto unRotBuffer = requested.getUnrotatedBufferSize(displayRotationFlags);
+            auto& destFrame = requested.destinationFrame;
+            bufferDebug = base::StringPrintf(" buffer={%d,%d}  displayRot=%d"
+                                             " destFrame={%d,%d,%d,%d} unRotBuffer={%d,%d}",
+                                             requested.externalTexture->getWidth(),
+                                             requested.externalTexture->getHeight(),
+                                             displayRotationFlags, destFrame.left, destFrame.top,
+                                             destFrame.right, destFrame.bottom,
+                                             unRotBuffer.getHeight(), unRotBuffer.getWidth());
+        }
+        ALOGW("Resetting transform for %s because it is invalid.%s%s",
+              snapshot.getDebugString().c_str(), transformDebug.c_str(), bufferDebug.c_str());
         snapshot.geomLayerTransform.reset();
     }
+    if (transformWasInvalid != snapshot.invalidTransform) {
+        // If transform is invalid, the layer will be hidden.
+        mResortSnapshots = true;
+    }
     snapshot.geomInverseLayerTransform = snapshot.geomLayerTransform.inverse();
 
     FloatRect parentBounds = parentSnapshot.geomLayerBounds;
@@ -711,12 +852,19 @@
     }
     snapshot.geomLayerBounds = snapshot.geomLayerBounds.intersect(parentBounds);
     snapshot.transformedBounds = snapshot.geomLayerTransform.transform(snapshot.geomLayerBounds);
+    const Rect geomLayerBoundsWithoutTransparentRegion =
+            RequestedLayerState::reduce(Rect(snapshot.geomLayerBounds),
+                                        requested.transparentRegion);
+    snapshot.transformedBoundsWithoutTransparentRegion =
+            snapshot.geomLayerTransform.transform(geomLayerBoundsWithoutTransparentRegion);
     snapshot.parentTransform = parentSnapshot.geomLayerTransform;
 
     // Subtract the transparent region and snap to the bounds
-    Rect bounds =
+    const Rect bounds =
             RequestedLayerState::reduce(snapshot.croppedBufferSize, requested.transparentRegion);
-    snapshot.cursorFrame = snapshot.geomLayerTransform.transform(bounds);
+    if (requested.potentialCursor) {
+        snapshot.cursorFrame = snapshot.geomLayerTransform.transform(bounds);
+    }
 
     // TODO(b/238781169) use dest vs src
     snapshot.bufferNeedsFiltering = snapshot.externalTexture &&
@@ -749,15 +897,28 @@
 void LayerSnapshotBuilder::updateInput(LayerSnapshot& snapshot,
                                        const RequestedLayerState& requested,
                                        const LayerSnapshot& parentSnapshot,
-                                       const frontend::DisplayInfo& displayInfo,
-                                       bool noValidDisplay,
-                                       const LayerHierarchy::TraversalPath& path) {
+                                       const LayerHierarchy::TraversalPath& path,
+                                       const Args& args) {
+    if (requested.windowInfoHandle) {
+        snapshot.inputInfo = *requested.windowInfoHandle->getInfo();
+    } else {
+        snapshot.inputInfo = {};
+    }
     snapshot.inputInfo.displayId = static_cast<int32_t>(snapshot.outputFilter.layerStack.id);
-    if (!requested.hasInputInfo()) {
-        snapshot.inputInfo.inputConfig = gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL;
+
+    if (!needsInputInfo(snapshot, requested)) {
         return;
     }
 
+    static frontend::DisplayInfo sDefaultInfo = {.isSecure = false};
+    const std::optional<frontend::DisplayInfo> displayInfoOpt =
+            args.displays.get(snapshot.outputFilter.layerStack);
+    bool noValidDisplay = !displayInfoOpt.has_value();
+    auto displayInfo = displayInfoOpt.value_or(sDefaultInfo);
+
+    if (!requested.windowInfoHandle) {
+        snapshot.inputInfo.inputConfig = gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL;
+    }
     fillInputFrameInfo(snapshot.inputInfo, displayInfo.transform, snapshot);
 
     if (noValidDisplay) {
@@ -766,17 +927,6 @@
         snapshot.inputInfo.inputConfig |= gui::WindowInfo::InputConfig::NOT_TOUCHABLE;
     }
 
-    // For compatibility reasons we let layers which can receive input
-    // receive input before they have actually submitted a buffer. Because
-    // of this we use canReceiveInput instead of isVisible to check the
-    // policy-visibility, ignoring the buffer state. However for layers with
-    // hasInputInfo()==false we can use the real visibility state.
-    // We are just using these layers for occlusion detection in
-    // InputDispatcher, and obviously if they aren't visible they can't occlude
-    // anything.
-    const bool visible = requested.hasInputInfo() ? snapshot.canReceiveInput() : snapshot.isVisible;
-    snapshot.inputInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_VISIBLE, !visible);
-
     snapshot.inputInfo.alpha = snapshot.color.a;
     snapshot.inputInfo.touchOcclusionMode = parentSnapshot.inputInfo.touchOcclusionMode;
     if (requested.dropInputMode == gui::DropInputMode::ALL ||
@@ -830,4 +980,28 @@
     return mSnapshots;
 }
 
+void LayerSnapshotBuilder::forEachVisibleSnapshot(const ConstVisitor& visitor) const {
+    for (int i = 0; i < mNumInterestingSnapshots; i++) {
+        LayerSnapshot& snapshot = *mSnapshots[(size_t)i];
+        if (!snapshot.isVisible) continue;
+        visitor(snapshot);
+    }
+}
+
+void LayerSnapshotBuilder::forEachVisibleSnapshot(const Visitor& visitor) {
+    for (int i = 0; i < mNumInterestingSnapshots; i++) {
+        std::unique_ptr<LayerSnapshot>& snapshot = mSnapshots.at((size_t)i);
+        if (!snapshot->isVisible) continue;
+        visitor(snapshot);
+    }
+}
+
+void LayerSnapshotBuilder::forEachInputSnapshot(const ConstVisitor& visitor) const {
+    for (int i = mNumInterestingSnapshots - 1; i >= 0; i--) {
+        LayerSnapshot& snapshot = *mSnapshots[(size_t)i];
+        if (!snapshot.hasInputInfo()) continue;
+        visitor(snapshot);
+    }
+}
+
 } // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
index 33b250c..abb7e66 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
@@ -44,6 +44,8 @@
         // Set to true if there were display changes since last update.
         bool displayChanges = false;
         const renderengine::ShadowSettings& globalShadowSettings;
+        bool supportsBlur = true;
+        bool forceFullDamage = false;
     };
     LayerSnapshotBuilder();
 
@@ -56,10 +58,22 @@
     // change flags.
     void update(const Args&);
     std::vector<std::unique_ptr<LayerSnapshot>>& getSnapshots();
+    LayerSnapshot* getSnapshot(uint32_t layerId) const;
+
+    typedef std::function<void(const LayerSnapshot& snapshot)> ConstVisitor;
+
+    // Visit each visible snapshot in z-order
+    void forEachVisibleSnapshot(const ConstVisitor& visitor) const;
+
+    typedef std::function<void(std::unique_ptr<LayerSnapshot>& snapshot)> Visitor;
+    // Visit each visible snapshot in z-order and move the snapshot if needed
+    void forEachVisibleSnapshot(const Visitor& visitor);
+
+    // Visit each snapshot interesting to input reverse z-order
+    void forEachInputSnapshot(const ConstVisitor& visitor) const;
 
 private:
     friend class LayerSnapshotTest;
-    LayerSnapshot* getSnapshot(uint32_t layerId) const;
     LayerSnapshot* getSnapshot(const LayerHierarchy::TraversalPath& id) const;
     static LayerSnapshot getRootSnapshot();
 
@@ -69,28 +83,29 @@
 
     void updateSnapshots(const Args& args);
 
-    void updateSnapshotsInHierarchy(const Args&, const LayerHierarchy& hierarchy,
-                                    LayerHierarchy::TraversalPath& traversalPath,
-                                    const LayerSnapshot& parentSnapshot);
-    void updateSnapshot(LayerSnapshot& snapshot, const Args& args, const RequestedLayerState&,
-                        const LayerSnapshot& parentSnapshot,
-                        const LayerHierarchy::TraversalPath& path);
+    const LayerSnapshot& updateSnapshotsInHierarchy(const Args&, const LayerHierarchy& hierarchy,
+                                                    LayerHierarchy::TraversalPath& traversalPath,
+                                                    const LayerSnapshot& parentSnapshot);
+    void updateSnapshot(LayerSnapshot&, const Args&, const RequestedLayerState&,
+                        const LayerSnapshot& parentSnapshot, const LayerHierarchy::TraversalPath&,
+                        bool newSnapshot);
     static void updateRelativeState(LayerSnapshot& snapshot, const LayerSnapshot& parentSnapshot,
                                     bool parentIsRelative, const Args& args);
     static void resetRelativeState(LayerSnapshot& snapshot);
     static void updateRoundedCorner(LayerSnapshot& snapshot, const RequestedLayerState& layerState,
                                     const LayerSnapshot& parentSnapshot);
-    static void updateLayerBounds(LayerSnapshot& snapshot, const RequestedLayerState& layerState,
-                                  const LayerSnapshot& parentSnapshot,
-                                  uint32_t displayRotationFlags);
+    void updateLayerBounds(LayerSnapshot& snapshot, const RequestedLayerState& layerState,
+                           const LayerSnapshot& parentSnapshot, uint32_t displayRotationFlags);
     static void updateShadows(LayerSnapshot& snapshot, const RequestedLayerState& requested,
                               const renderengine::ShadowSettings& globalShadowSettings);
     void updateInput(LayerSnapshot& snapshot, const RequestedLayerState& requested,
-                     const LayerSnapshot& parentSnapshot, const frontend::DisplayInfo& displayInfo,
-                     bool noValidDisplay, const LayerHierarchy::TraversalPath& path);
+                     const LayerSnapshot& parentSnapshot, const LayerHierarchy::TraversalPath& path,
+                     const Args& args);
     void sortSnapshotsByZ(const Args& args);
-    LayerSnapshot* getOrCreateSnapshot(const LayerHierarchy::TraversalPath& id,
-                                       const RequestedLayerState& layer);
+    LayerSnapshot* createSnapshot(const LayerHierarchy::TraversalPath& id,
+                                  const RequestedLayerState& layer);
+    void updateChildState(LayerSnapshot& snapshot, const LayerSnapshot& childSnapshot,
+                          const Args& args);
 
     struct TraversalPathHash {
         std::size_t operator()(const LayerHierarchy::TraversalPath& key) const {
@@ -105,6 +120,8 @@
             mIdToSnapshot;
     std::vector<std::unique_ptr<LayerSnapshot>> mSnapshots;
     LayerSnapshot mRootSnapshot;
+    bool mResortSnapshots = false;
+    int mNumInterestingSnapshots = 0;
 };
 
 } // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index dcc16e8..39bf07a 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -14,16 +14,18 @@
  * limitations under the License.
  */
 
-#include "FrontEnd/LayerCreationArgs.h"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 #undef LOG_TAG
 #define LOG_TAG "RequestedLayerState"
 
+#include <log/log.h>
 #include <private/android_filesystem_config.h>
 #include <sys/types.h>
 
 #include "Layer.h"
+#include "LayerCreationArgs.h"
 #include "LayerHandle.h"
+#include "LayerLog.h"
 #include "RequestedLayerState.h"
 
 namespace android::surfaceflinger::frontend {
@@ -47,7 +49,7 @@
 
 RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args)
       : id(args.sequence),
-        name(args.name),
+        name(args.name + "#" + std::to_string(args.sequence)),
         canBeRoot(args.addToRoot),
         layerCreationFlags(args.flags),
         textureName(args.textureName),
@@ -59,6 +61,9 @@
     changes |= RequestedLayerState::Changes::Metadata;
     handleAlive = true;
     parentId = LayerHandle::getLayerId(args.parentHandle.promote());
+    if (args.parentHandle != nullptr) {
+        canBeRoot = false;
+    }
     mirrorId = LayerHandle::getLayerId(args.mirrorLayerHandle.promote());
     if (mirrorId != UNASSIGNED_LAYER_ID) {
         changes |= RequestedLayerState::Changes::Mirror;
@@ -83,6 +88,7 @@
     } else {
         color.rgb = {0.0_hf, 0.0_hf, 0.0_hf};
     }
+    LLOGV(layerId, "Created %s flags=%d", getDebugString().c_str(), flags);
     color.a = 1.0f;
 
     crop.makeInvalid();
@@ -114,11 +120,14 @@
     defaultFrameRateCompatibility =
             static_cast<int8_t>(scheduler::LayerInfo::FrameRateCompatibility::Default);
     dataspace = ui::Dataspace::V0_SRGB;
+    gameMode = gui::GameMode::Unsupported;
+    requestedFrameRate = {};
 }
 
 void RequestedLayerState::merge(const ResolvedComposerState& resolvedComposerState) {
-    bool oldFlags = flags;
-    Rect oldBufferSize = getBufferSize(0);
+    const uint32_t oldFlags = flags;
+    const half oldAlpha = color.a;
+    const bool hadBufferOrSideStream = hasValidBuffer() || sidebandStream != nullptr;
     const layer_state_t& clientState = resolvedComposerState.state;
 
     uint64_t clientChanges = what | layer_state_t::diff(clientState);
@@ -127,14 +136,28 @@
 
     if (clientState.what & layer_state_t::eFlagsChanged) {
         if ((oldFlags ^ flags) & layer_state_t::eLayerHidden) {
-            changes |= RequestedLayerState::Changes::Visibility;
+            changes |= RequestedLayerState::Changes::Visibility |
+                    RequestedLayerState::Changes::VisibleRegion;
         }
         if ((oldFlags ^ flags) & layer_state_t::eIgnoreDestinationFrame) {
             changes |= RequestedLayerState::Changes::Geometry;
         }
     }
-    if (clientState.what & layer_state_t::eBufferChanged && oldBufferSize != getBufferSize(0)) {
-        changes |= RequestedLayerState::Changes::Geometry;
+    if (clientState.what &
+        (layer_state_t::eBufferChanged | layer_state_t::eSidebandStreamChanged)) {
+        const bool hasBufferOrSideStream = hasValidBuffer() || sidebandStream != nullptr;
+        if (hadBufferOrSideStream != hasBufferOrSideStream) {
+            changes |= RequestedLayerState::Changes::Geometry |
+                    RequestedLayerState::Changes::VisibleRegion |
+                    RequestedLayerState::Changes::Visibility | RequestedLayerState::Changes::Input |
+                    RequestedLayerState::Changes::Buffer;
+        }
+    }
+    if (what & (layer_state_t::eAlphaChanged)) {
+        if (oldAlpha == 0 || color.a == 0) {
+            changes |= RequestedLayerState::Changes::Visibility |
+                    RequestedLayerState::Changes::VisibleRegion;
+        }
     }
     if (clientChanges & layer_state_t::HIERARCHY_CHANGES)
         changes |= RequestedLayerState::Changes::Hierarchy;
@@ -144,7 +167,10 @@
         changes |= RequestedLayerState::Changes::Geometry;
     if (clientChanges & layer_state_t::AFFECTS_CHILDREN)
         changes |= RequestedLayerState::Changes::AffectsChildren;
-
+    if (clientChanges & layer_state_t::INPUT_CHANGES)
+        changes |= RequestedLayerState::Changes::Input;
+    if (clientChanges & layer_state_t::VISIBLE_REGION_CHANGES)
+        changes |= RequestedLayerState::Changes::VisibleRegion;
     if (clientState.what & layer_state_t::eColorTransformChanged) {
         static const mat4 identityMatrix = mat4();
         hasColorTransform = colorTransform != identityMatrix;
@@ -183,7 +209,6 @@
         wp<IBinder>& touchableRegionCropHandle =
                 windowInfoHandle->editInfo()->touchableRegionCropHandle;
         touchCropId = LayerHandle::getLayerId(touchableRegionCropHandle.promote());
-        changes |= RequestedLayerState::Changes::Input;
         touchableRegionCropHandle.clear();
     }
     if (clientState.what & layer_state_t::eStretchChanged) {
@@ -205,6 +230,27 @@
     if (clientState.what & layer_state_t::eMatrixChanged) {
         requestedTransform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
     }
+    if (clientState.what & layer_state_t::eMetadataChanged) {
+        const int32_t requestedGameMode =
+                clientState.metadata.getInt32(gui::METADATA_GAME_MODE, -1);
+        if (requestedGameMode != -1) {
+            // The transaction will be received on the Task layer and needs to be applied to all
+            // child layers.
+            if (static_cast<int32_t>(gameMode) != requestedGameMode) {
+                gameMode = static_cast<gui::GameMode>(requestedGameMode);
+                changes |= RequestedLayerState::Changes::AffectsChildren;
+            }
+        }
+    }
+    if (clientState.what & layer_state_t::eFrameRateChanged) {
+        const auto compatibility =
+                Layer::FrameRate::convertCompatibility(clientState.frameRateCompatibility);
+        const auto strategy = Layer::FrameRate::convertChangeFrameRateStrategy(
+                clientState.changeFrameRateStrategy);
+        requestedFrameRate =
+                Layer::FrameRate(Fps::fromValue(clientState.frameRate), compatibility, strategy);
+        changes |= RequestedLayerState::Changes::FrameRate;
+    }
 }
 
 ui::Size RequestedLayerState::getUnrotatedBufferSize(uint32_t displayRotationFlags) const {
@@ -368,7 +414,8 @@
 // If the relative parentid is unassigned, the layer will be considered relative but won't be
 // reachable.
 bool RequestedLayerState::hasValidRelativeParent() const {
-    return isRelativeOf && parentId != relativeParentId;
+    return isRelativeOf &&
+            (parentId != relativeParentId || relativeParentId == UNASSIGNED_LAYER_ID);
 }
 
 bool RequestedLayerState::hasInputInfo() const {
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.h b/services/surfaceflinger/FrontEnd/RequestedLayerState.h
index 95240d0..3a16531 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.h
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.h
@@ -20,6 +20,7 @@
 #include <ftl/flags.h>
 #include <gui/LayerState.h>
 #include <renderengine/ExternalTexture.h>
+#include "Scheduler/LayerInfo.h"
 
 #include "LayerCreationArgs.h"
 #include "TransactionState.h"
@@ -48,6 +49,9 @@
         Metadata = 1u << 10,
         Visibility = 1u << 11,
         AffectsChildren = 1u << 12,
+        FrameRate = 1u << 13,
+        VisibleRegion = 1u << 14,
+        Buffer = 1u << 15,
     };
     static Rect reduce(const Rect& win, const Region& exclude);
     RequestedLayerState(const LayerCreationArgs&);
@@ -91,6 +95,8 @@
     ui::Transform requestedTransform;
     std::shared_ptr<FenceTime> acquireFenceTime;
     std::shared_ptr<renderengine::ExternalTexture> externalTexture;
+    gui::GameMode gameMode;
+    scheduler::LayerInfo::FrameRate requestedFrameRate;
 
     // book keeping states
     bool handleAlive = true;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 0179d62..ba1d2c6 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -475,7 +475,8 @@
     snapshot->geomLayerTransform = getTransform();
     snapshot->geomInverseLayerTransform = snapshot->geomLayerTransform.inverse();
     snapshot->transparentRegionHint = getActiveTransparentRegion(drawingState);
-    snapshot->localTransformInverse = getActiveTransform(drawingState).inverse();
+    snapshot->localTransform = getActiveTransform(drawingState);
+    snapshot->localTransformInverse = snapshot->localTransform.inverse();
     snapshot->blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode);
     snapshot->alpha = alpha;
     snapshot->backgroundBlurRadius = drawingState.backgroundBlurRadius;
@@ -2595,6 +2596,8 @@
     mDrawingState = from->mDrawingState;
     // Skip callback info since they are not applicable for cloned layers.
     mDrawingState.releaseBufferListener = nullptr;
+    // TODO (b/238781169) currently broken for mirror layers because we do not
+    // track release fences for mirror layers composed on other displays
     mDrawingState.callbackHandles = {};
 }
 
diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
index 33c9440..783df28 100644
--- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
@@ -562,4 +562,83 @@
     hierarchyBuilder.getHierarchy().traverseInZOrder(checkTraversalPathIdVisitor);
 }
 
+TEST_F(LayerHierarchyTest, zorderRespectsLayerSequenceId) {
+    // remove default hierarchy
+    mLifecycleManager = LayerLifecycleManager();
+    createRootLayer(1);
+    createRootLayer(2);
+    createRootLayer(4);
+    createRootLayer(5);
+    createLayer(11, 1);
+    createLayer(51, 5);
+    createLayer(53, 5);
+
+    mLifecycleManager.commitChanges();
+    LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers());
+    UPDATE_AND_VERIFY(hierarchyBuilder);
+    std::vector<uint32_t> expectedTraversalPath = {1, 11, 2, 4, 5, 51, 53};
+    EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), expectedTraversalPath);
+
+    EXPECT_EQ(getTraversalPathInZOrder(hierarchyBuilder.getHierarchy()), expectedTraversalPath);
+    expectedTraversalPath = {};
+    EXPECT_EQ(getTraversalPath(hierarchyBuilder.getOffscreenHierarchy()), expectedTraversalPath);
+
+    // A new layer is added with a smaller sequence id. Make sure its sorted correctly. While
+    // sequence ids are always incremented, this scenario can happen when a layer is reparented.
+    createRootLayer(3);
+    createLayer(52, 5);
+
+    UPDATE_AND_VERIFY(hierarchyBuilder);
+    expectedTraversalPath = {1, 11, 2, 3, 4, 5, 51, 52, 53};
+    EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), expectedTraversalPath);
+    EXPECT_EQ(getTraversalPathInZOrder(hierarchyBuilder.getHierarchy()), expectedTraversalPath);
+    expectedTraversalPath = {};
+    EXPECT_EQ(getTraversalPath(hierarchyBuilder.getOffscreenHierarchy()), expectedTraversalPath);
+}
+
+TEST_F(LayerHierarchyTest, zorderRespectsLayerZ) {
+    // remove default hierarchy
+    mLifecycleManager = LayerLifecycleManager();
+    createRootLayer(1);
+    createLayer(11, 1);
+    createLayer(12, 1);
+    createLayer(13, 1);
+    setZ(11, -1);
+    setZ(12, 2);
+    setZ(13, 1);
+
+    mLifecycleManager.commitChanges();
+    LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers());
+    UPDATE_AND_VERIFY(hierarchyBuilder);
+    std::vector<uint32_t> expectedTraversalPath = {1, 11, 13, 12};
+    EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), expectedTraversalPath);
+
+    expectedTraversalPath = {11, 1, 13, 12};
+    EXPECT_EQ(getTraversalPathInZOrder(hierarchyBuilder.getHierarchy()), expectedTraversalPath);
+    expectedTraversalPath = {};
+    EXPECT_EQ(getTraversalPath(hierarchyBuilder.getOffscreenHierarchy()), expectedTraversalPath);
+}
+
+TEST_F(LayerHierarchyTest, zorderRespectsLayerStack) {
+    // remove default hierarchy
+    mLifecycleManager = LayerLifecycleManager();
+    createRootLayer(1);
+    createRootLayer(2);
+    createLayer(11, 1);
+    createLayer(21, 2);
+    setLayerStack(1, 20);
+    setLayerStack(2, 10);
+
+    mLifecycleManager.commitChanges();
+    LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers());
+    UPDATE_AND_VERIFY(hierarchyBuilder);
+    std::vector<uint32_t> expectedTraversalPath = {1, 11, 2, 21};
+    EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), expectedTraversalPath);
+
+    expectedTraversalPath = {1, 11, 2, 21};
+    EXPECT_EQ(getTraversalPathInZOrder(hierarchyBuilder.getHierarchy()), expectedTraversalPath);
+    expectedTraversalPath = {};
+    EXPECT_EQ(getTraversalPath(hierarchyBuilder.getOffscreenHierarchy()), expectedTraversalPath);
+}
+
 } // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
index 08727f2..1a82232 100644
--- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
+++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
@@ -245,6 +245,18 @@
         mLifecycleManager.applyTransactions(transactions);
     }
 
+    void setLayerStack(uint32_t id, int32_t layerStack) {
+        std::vector<TransactionState> transactions;
+        transactions.emplace_back();
+        transactions.back().states.push_back({});
+
+        transactions.back().states.front().state.what = layer_state_t::eLayerStackChanged;
+        transactions.back().states.front().state.surface = mHandles[id];
+        transactions.back().states.front().state.layerId = static_cast<int32_t>(id);
+        transactions.back().states.front().state.layerStack = ui::LayerStack::fromValue(layerStack);
+        mLifecycleManager.applyTransactions(transactions);
+    }
+
     LayerLifecycleManager mLifecycleManager;
     std::unordered_map<uint32_t, sp<LayerHandle>> mHandles;
 };
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 2441c06..e124342 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -38,6 +38,9 @@
 
 namespace android::surfaceflinger::frontend {
 
+using ftl::Flags;
+using namespace ftl::flag_operators;
+
 // To run test:
 /**
  mp :libsurfaceflinger_unittest && adb sync; adb shell \
@@ -88,14 +91,11 @@
         ASSERT_TRUE(expectedBuilder.getSnapshots().size() > 0);
         ASSERT_TRUE(actualBuilder.getSnapshots().size() > 0);
 
-        std::vector<std::unique_ptr<LayerSnapshot>>& snapshots = actualBuilder.getSnapshots();
         std::vector<uint32_t> actualVisibleLayerIdsInZOrder;
-        for (auto& snapshot : snapshots) {
-            if (!snapshot->isVisible) {
-                break;
-            }
-            actualVisibleLayerIdsInZOrder.push_back(snapshot->path.id);
-        }
+        actualBuilder.forEachVisibleSnapshot(
+                [&actualVisibleLayerIdsInZOrder](const LayerSnapshot& snapshot) {
+                    actualVisibleLayerIdsInZOrder.push_back(snapshot.path.id);
+                });
         EXPECT_EQ(expectedVisibleLayerIdsInZOrder, actualVisibleLayerIdsInZOrder);
     }
 
@@ -103,7 +103,6 @@
 
     LayerHierarchyBuilder mHierarchyBuilder{{}};
     LayerSnapshotBuilder mSnapshotBuilder;
-    std::unordered_map<uint32_t, sp<LayerHandle>> mHandles;
     display::DisplayMap<ui::LayerStack, frontend::DisplayInfo> mFrontEndDisplayInfos;
     renderengine::ShadowSettings globalShadowSettings;
     static const std::vector<uint32_t> STARTING_ZORDER;
@@ -257,4 +256,54 @@
     EXPECT_EQ(getSnapshot(1)->changes, RequestedLayerState::Changes::Content);
 }
 
+TEST_F(LayerSnapshotTest, GameMode) {
+    std::vector<TransactionState> transactions;
+    transactions.emplace_back();
+    transactions.back().states.push_back({});
+    transactions.back().states.front().state.what = layer_state_t::eMetadataChanged;
+    transactions.back().states.front().state.metadata = LayerMetadata();
+    transactions.back().states.front().state.metadata.setInt32(METADATA_GAME_MODE, 42);
+    transactions.back().states.front().state.surface = mHandles[1];
+    transactions.back().states.front().state.layerId = static_cast<int32_t>(1);
+    mLifecycleManager.applyTransactions(transactions);
+    UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+    EXPECT_EQ(static_cast<int32_t>(getSnapshot(1)->gameMode), 42);
+    EXPECT_EQ(static_cast<int32_t>(getSnapshot(11)->gameMode), 42);
+}
+
+TEST_F(LayerSnapshotTest, NoLayerVoteForParentWithChildVotes) {
+    // ROOT
+    // ├── 1
+    // │   ├── 11 (frame rate set)
+    // │   │   └── 111
+    // │   ├── 12
+    // │   │   ├── 121
+    // │   │   └── 122
+    // │   │       └── 1221
+    // │   └── 13
+    // └── 2
+
+    std::vector<TransactionState> transactions;
+    transactions.emplace_back();
+    transactions.back().states.push_back({});
+    transactions.back().states.front().state.what = layer_state_t::eFrameRateChanged;
+    transactions.back().states.front().state.frameRate = 90.0;
+    transactions.back().states.front().state.frameRateCompatibility =
+            ANATIVEWINDOW_FRAME_RATE_EXACT;
+    transactions.back().states.front().state.changeFrameRateStrategy =
+            ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS;
+    transactions.back().states.front().state.surface = mHandles[11];
+    transactions.back().states.front().state.layerId = static_cast<int32_t>(11);
+    mLifecycleManager.applyTransactions(transactions);
+    UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+    EXPECT_EQ(getSnapshot(11)->frameRate.rate.getIntValue(), 90);
+    EXPECT_EQ(getSnapshot(11)->frameRate.type, scheduler::LayerInfo::FrameRateCompatibility::Exact);
+    EXPECT_EQ(getSnapshot(111)->frameRate.rate.getIntValue(), 90);
+    EXPECT_EQ(getSnapshot(111)->frameRate.type,
+              scheduler::LayerInfo::FrameRateCompatibility::Exact);
+    EXPECT_EQ(getSnapshot(1)->frameRate.rate.getIntValue(), 0);
+    EXPECT_EQ(getSnapshot(1)->frameRate.type, scheduler::LayerInfo::FrameRateCompatibility::NoVote);
+}
+
 } // namespace android::surfaceflinger::frontend