[sf-newfe] Fix snapshot paths for recursive mirror paths
If we are mirroring a hierarchy that already contains a mirror
then we need to track all the mirror roots inorder to have
a unique path.
Test: presubmit
Test: can screenrecord magnifier
Test: dumpsys SurfaceFlinger --frontend
Bug: 238781169
Change-Id: Id2272981f6f6244f41328428b73184bccf5d1888
diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
index 962dc09..1e5a6fb 100644
--- a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
@@ -145,7 +145,8 @@
}
void LayerHierarchy::dump(std::ostream& out, const std::string& prefix,
- LayerHierarchy::Variant variant, bool isLastChild) const {
+ LayerHierarchy::Variant variant, bool isLastChild,
+ bool includeMirroredHierarchy) const {
if (!mLayer) {
out << " ROOT";
} else {
@@ -153,8 +154,11 @@
if (variant == LayerHierarchy::Variant::Relative) {
out << "(Relative) ";
} else if (variant == LayerHierarchy::Variant::Mirror) {
- out << "(Mirroring) " << *mLayer << "\n" + prefix + " └─ ...";
- return;
+ if (!includeMirroredHierarchy) {
+ out << "(Mirroring) " << *mLayer << "\n" + prefix + " └─ ...";
+ return;
+ }
+ out << "(Mirroring) ";
}
out << *mLayer;
}
@@ -168,7 +172,7 @@
childPrefix += (isLastChild ? " " : "│ ");
}
out << "\n";
- child->dump(out, childPrefix, childVariant, lastChild);
+ child->dump(out, childPrefix, childVariant, lastChild, includeMirroredHierarchy);
}
return;
}
@@ -435,8 +439,11 @@
std::stringstream ss;
ss << "TraversalPath{.id = " << id;
- if (mirrorRootId != UNASSIGNED_LAYER_ID) {
- ss << ", .mirrorRootId=" << mirrorRootId;
+ if (!mirrorRootIds.empty()) {
+ ss << ", .mirrorRootIds=";
+ for (auto rootId : mirrorRootIds) {
+ ss << rootId << ",";
+ }
}
if (!relativeRootIds.empty()) {
@@ -453,13 +460,6 @@
return ss.str();
}
-LayerHierarchy::TraversalPath LayerHierarchy::TraversalPath::getMirrorRoot() const {
- LLOG_ALWAYS_FATAL_WITH_TRACE_IF(!isClone(), "Cannot get mirror root of a non cloned node");
- TraversalPath mirrorRootPath = *this;
- mirrorRootPath.id = mirrorRootId;
- return mirrorRootPath;
-}
-
// Helper class to update a passed in TraversalPath when visiting a child. When the object goes out
// of scope the TraversalPath is reset to its original state.
LayerHierarchy::ScopedAddToTraversalPath::ScopedAddToTraversalPath(TraversalPath& traversalPath,
@@ -471,7 +471,7 @@
traversalPath.id = layerId;
traversalPath.variant = variant;
if (variant == LayerHierarchy::Variant::Mirror) {
- traversalPath.mirrorRootId = mParentPath.id;
+ traversalPath.mirrorRootIds.emplace_back(mParentPath.id);
} else if (variant == LayerHierarchy::Variant::Relative) {
if (std::find(traversalPath.relativeRootIds.begin(), traversalPath.relativeRootIds.end(),
layerId) != traversalPath.relativeRootIds.end()) {
@@ -486,7 +486,7 @@
// Reset the traversal id to its original parent state using the state that was saved in
// the constructor.
if (mTraversalPath.variant == LayerHierarchy::Variant::Mirror) {
- mTraversalPath.mirrorRootId = mParentPath.mirrorRootId;
+ mTraversalPath.mirrorRootIds.pop_back();
} else if (mTraversalPath.variant == LayerHierarchy::Variant::Relative) {
mTraversalPath.relativeRootIds.pop_back();
}
diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.h b/services/surfaceflinger/FrontEnd/LayerHierarchy.h
index 1e48387..ba2e262 100644
--- a/services/surfaceflinger/FrontEnd/LayerHierarchy.h
+++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.h
@@ -57,25 +57,25 @@
// ├─ B {Traversal path id = 2}
// │ ├─ C {Traversal path id = 3}
// │ ├─ D {Traversal path id = 4}
- // │ └─ E {Traversal path id = 5}
- // ├─ F (Mirrors B) {Traversal path id = 6}
- // └─ G (Mirrors F) {Traversal path id = 7}
+ // │ └─ E (Mirrors C) {Traversal path id = 5}
+ // └─ F (Mirrors B) {Traversal path id = 6}
//
- // C, D and E can be traversed via B or via F then B or via G then F then B.
+ // C can be traversed via B or E or F and or via F then E.
// Depending on how the node is reached, its properties such as geometry or visibility might be
// different. And we can uniquely identify the node by keeping track of the nodes leading up to
// it. But to be more efficient we only need to track the nodes id and the top mirror root path.
// So C for example, would have the following unique traversal paths:
// - {Traversal path id = 3}
- // - {Traversal path id = 3, mirrorRootId = 6}
- // - {Traversal path id = 3, mirrorRootId = 7}
+ // - {Traversal path id = 3, mirrorRootIds = 5}
+ // - {Traversal path id = 3, mirrorRootIds = 6}
+ // - {Traversal path id = 3, mirrorRootIds = 6, 5}
struct TraversalPath {
uint32_t id;
LayerHierarchy::Variant variant;
// Mirrored layers can have a different geometry than their parents so we need to track
// the mirror roots in the traversal.
- uint32_t mirrorRootId = UNASSIGNED_LAYER_ID;
+ ftl::SmallVector<uint32_t, 5> mirrorRootIds;
// Relative layers can be visited twice, once by their parent and then once again by
// their relative parent. We keep track of the roots here to detect any loops in the
// hierarchy. If a relative root already exists in the list while building the
@@ -93,11 +93,10 @@
// Returns true if the node or its parents are not Detached.
bool isAttached() const { return !detached; }
// Returns true if the node is a clone.
- bool isClone() const { return mirrorRootId != UNASSIGNED_LAYER_ID; }
- TraversalPath getMirrorRoot() const;
+ bool isClone() const { return !mirrorRootIds.empty(); }
bool operator==(const TraversalPath& other) const {
- return id == other.id && mirrorRootId == other.mirrorRootId;
+ return id == other.id && mirrorRootIds == other.mirrorRootIds;
}
std::string toString() const;
@@ -107,8 +106,8 @@
struct TraversalPathHash {
std::size_t operator()(const LayerHierarchy::TraversalPath& key) const {
uint32_t hashCode = key.id * 31;
- if (key.mirrorRootId != UNASSIGNED_LAYER_ID) {
- hashCode += key.mirrorRootId * 31;
+ for (uint32_t mirrorRootId : key.mirrorRootIds) {
+ hashCode += mirrorRootId * 31;
}
return std::hash<size_t>{}(hashCode);
}
@@ -158,9 +157,17 @@
const LayerHierarchy* getParent() const;
friend std::ostream& operator<<(std::ostream& os, const LayerHierarchy& obj) {
std::string prefix = " ";
- obj.dump(os, prefix, LayerHierarchy::Variant::Attached, /*isLastChild=*/false);
+ obj.dump(os, prefix, LayerHierarchy::Variant::Attached, /*isLastChild=*/false,
+ /*includeMirroredHierarchy*/ false);
return os;
}
+ std::string dump() const {
+ std::string prefix = " ";
+ std::ostringstream os;
+ dump(os, prefix, LayerHierarchy::Variant::Attached, /*isLastChild=*/false,
+ /*includeMirroredHierarchy*/ true);
+ return os.str();
+ }
std::string getDebugStringShort() const;
// Traverse the hierarchy and return true if loops are found. The outInvalidRelativeRoot
@@ -178,7 +185,7 @@
void traverseInZOrder(const Visitor& visitor, LayerHierarchy::TraversalPath& parent) const;
void traverse(const Visitor& visitor, LayerHierarchy::TraversalPath& parent) const;
void dump(std::ostream& out, const std::string& prefix, LayerHierarchy::Variant variant,
- bool isLastChild) const;
+ bool isLastChild, bool includeMirroredHierarchy) const;
const RequestedLayerState* mLayer;
LayerHierarchy* mParent = nullptr;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index 80bedf4..899d2de 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -294,8 +294,11 @@
std::ostream& operator<<(std::ostream& out, const LayerSnapshot& obj) {
out << "Layer [" << obj.path.id;
- if (obj.path.mirrorRootId != UNASSIGNED_LAYER_ID) {
- out << " mirrored from " << obj.path.mirrorRootId;
+ if (!obj.path.mirrorRootIds.empty()) {
+ out << " mirrored from ";
+ for (auto rootId : obj.path.mirrorRootIds) {
+ out << rootId << ",";
+ }
}
out << "] " << obj.name << "\n " << (obj.isVisible ? "visible" : "invisible")
<< " reason=" << obj.getIsVisibleReason();