blob: 47d0041a8bead711e1d797aeac249cc4f297a2e6 [file] [log] [blame]
Vishnu Nair04f89692022-11-16 23:21:05 +00001/*
2 * Copyright 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18
19#include "FrontEnd/LayerCreationArgs.h"
Vishnu Naira0292282023-12-16 14:32:00 -080020#include "FrontEnd/LayerLifecycleManager.h"
Vishnu Nair04f89692022-11-16 23:21:05 +000021#include "RequestedLayerState.h"
22#include "ftl/small_vector.h"
23
24namespace android::surfaceflinger::frontend {
25class LayerHierarchyBuilder;
26
27// LayerHierarchy allows us to navigate the layer hierarchy in z-order, or depth first traversal.
28// The hierarchy is created from a set of RequestedLayerStates. The hierarchy itself does not
29// contain additional states. Instead, it is a representation of RequestedLayerStates as a graph.
30//
31// Each node in the hierarchy can be visited by multiple parents (making this a graph). While
32// traversing the hierarchy, a new concept called Variant can be used to understand the
33// relationship of the layer to its parent. The following variants are possible:
34// Attached - child of the parent
35// Detached - child of the parent but currently relative parented to another layer
36// Relative - relative child of the parent
37// Mirror - mirrored from another layer
Vishnu Nair491827d2024-04-29 23:43:26 +000038// Detached_Mirror - mirrored from another layer, ignoring local transform
Vishnu Nair04f89692022-11-16 23:21:05 +000039//
40// By representing the hierarchy as a graph, we can represent mirrored layer hierarchies without
41// cloning the layer requested state. The mirrored hierarchy and its corresponding
42// RequestedLayerStates are kept in sync because the mirrored hierarchy does not clone any
43// states.
44class LayerHierarchy {
45public:
Vishnu Naircfb2d252023-01-19 04:44:02 +000046 enum Variant : uint32_t {
Vishnu Nair491827d2024-04-29 23:43:26 +000047 Attached, // child of the parent
48 Detached, // child of the parent but currently relative parented to another layer
49 Relative, // relative child of the parent
50 Mirror, // mirrored from another layer
51 Detached_Mirror, // mirrored from another layer, ignoring local transform
Vishnu Naircfb2d252023-01-19 04:44:02 +000052 ftl_first = Attached,
Vishnu Nair491827d2024-04-29 23:43:26 +000053 ftl_last = Detached_Mirror,
Vishnu Nair04f89692022-11-16 23:21:05 +000054 };
Vishnu Nair491827d2024-04-29 23:43:26 +000055 static inline bool isMirror(Variant variant) {
56 return ((variant == Mirror) || (variant == Detached_Mirror));
57 }
58
Vishnu Nair04f89692022-11-16 23:21:05 +000059 // Represents a unique path to a node.
Vishnu Nair80a5a702023-02-11 01:21:51 +000060 // The layer hierarchy is represented as a graph. Each node can be visited by multiple parents.
61 // This allows us to represent mirroring in an efficient way. See the example below:
62 // root
63 // ├─ A {Traversal path id = 1}
64 // ├─ B {Traversal path id = 2}
65 // │ ├─ C {Traversal path id = 3}
66 // │ ├─ D {Traversal path id = 4}
Vishnu Nair6f878312023-09-08 11:05:01 -070067 // │ └─ E (Mirrors C) {Traversal path id = 5}
68 // └─ F (Mirrors B) {Traversal path id = 6}
Vishnu Nair80a5a702023-02-11 01:21:51 +000069 //
Vishnu Nair6f878312023-09-08 11:05:01 -070070 // C can be traversed via B or E or F and or via F then E.
Vishnu Nair80a5a702023-02-11 01:21:51 +000071 // Depending on how the node is reached, its properties such as geometry or visibility might be
72 // different. And we can uniquely identify the node by keeping track of the nodes leading up to
73 // it. But to be more efficient we only need to track the nodes id and the top mirror root path.
74 // So C for example, would have the following unique traversal paths:
75 // - {Traversal path id = 3}
Vishnu Nair6f878312023-09-08 11:05:01 -070076 // - {Traversal path id = 3, mirrorRootIds = 5}
77 // - {Traversal path id = 3, mirrorRootIds = 6}
78 // - {Traversal path id = 3, mirrorRootIds = 6, 5}
Vishnu Nair80a5a702023-02-11 01:21:51 +000079
Vishnu Nair04f89692022-11-16 23:21:05 +000080 struct TraversalPath {
81 uint32_t id;
82 LayerHierarchy::Variant variant;
83 // Mirrored layers can have a different geometry than their parents so we need to track
84 // the mirror roots in the traversal.
Vishnu Nair6f878312023-09-08 11:05:01 -070085 ftl::SmallVector<uint32_t, 5> mirrorRootIds;
Vishnu Nair04f89692022-11-16 23:21:05 +000086 // Relative layers can be visited twice, once by their parent and then once again by
87 // their relative parent. We keep track of the roots here to detect any loops in the
88 // hierarchy. If a relative root already exists in the list while building the
89 // TraversalPath, it means that somewhere in the hierarchy two layers are relatively
90 // parented to each other.
91 ftl::SmallVector<uint32_t, 5> relativeRootIds;
92 // First duplicate relative root id found. If this is a valid layer id that means we are
93 // in a loop.
94 uint32_t invalidRelativeRootId = UNASSIGNED_LAYER_ID;
Vishnu Nair8fc721b2022-12-22 20:06:32 +000095 // See isAttached()
96 bool detached = false;
Vishnu Nair04f89692022-11-16 23:21:05 +000097 bool hasRelZLoop() const { return invalidRelativeRootId != UNASSIGNED_LAYER_ID; }
Vishnu Nair8fc721b2022-12-22 20:06:32 +000098 // Returns true if this node is reached via one or more relative parents.
99 bool isRelative() const { return !relativeRootIds.empty(); }
100 // Returns true if the node or its parents are not Detached.
101 bool isAttached() const { return !detached; }
102 // Returns true if the node is a clone.
Vishnu Nair6f878312023-09-08 11:05:01 -0700103 bool isClone() const { return !mirrorRootIds.empty(); }
Vishnu Nair04f89692022-11-16 23:21:05 +0000104
105 bool operator==(const TraversalPath& other) const {
Vishnu Nair6f878312023-09-08 11:05:01 -0700106 return id == other.id && mirrorRootIds == other.mirrorRootIds;
Vishnu Nair04f89692022-11-16 23:21:05 +0000107 }
108 std::string toString() const;
109
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000110 static const TraversalPath ROOT;
Vishnu Nair04f89692022-11-16 23:21:05 +0000111 };
112
Vishnu Naird0183602023-03-16 18:52:15 +0000113 struct TraversalPathHash {
114 std::size_t operator()(const LayerHierarchy::TraversalPath& key) const {
115 uint32_t hashCode = key.id * 31;
Vishnu Nair6f878312023-09-08 11:05:01 -0700116 for (uint32_t mirrorRootId : key.mirrorRootIds) {
117 hashCode += mirrorRootId * 31;
Vishnu Naird0183602023-03-16 18:52:15 +0000118 }
119 return std::hash<size_t>{}(hashCode);
120 }
121 };
122
Vishnu Nair04f89692022-11-16 23:21:05 +0000123 // Helper class to add nodes to an existing traversal id and removes the
124 // node when it goes out of scope.
125 class ScopedAddToTraversalPath {
126 public:
127 ScopedAddToTraversalPath(TraversalPath& traversalPath, uint32_t layerId,
128 LayerHierarchy::Variant variantArg);
129 ~ScopedAddToTraversalPath();
130
131 private:
132 TraversalPath& mTraversalPath;
Vishnu Nair80a5a702023-02-11 01:21:51 +0000133 TraversalPath mParentPath;
Vishnu Nair04f89692022-11-16 23:21:05 +0000134 };
135 LayerHierarchy(RequestedLayerState* layer);
136
137 // Visitor function that provides the hierarchy node and a traversal id which uniquely
138 // identifies how was visited. The hierarchy contains a pointer to the RequestedLayerState.
139 // Return false to stop traversing down the hierarchy.
140 typedef std::function<bool(const LayerHierarchy& hierarchy,
141 const LayerHierarchy::TraversalPath& traversalPath)>
142 Visitor;
143
144 // Traverse the hierarchy and visit all child variants.
145 void traverse(const Visitor& visitor) const {
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000146 TraversalPath root = TraversalPath::ROOT;
Vishnu Naird47bcee2023-02-24 18:08:51 +0000147 if (mLayer) {
148 root.id = mLayer->id;
149 }
Melody Hsubb2ec6a2024-05-27 22:18:05 +0000150 traverse(visitor, root, /*depth=*/0);
Vishnu Nair04f89692022-11-16 23:21:05 +0000151 }
152
153 // Traverse the hierarchy in z-order, skipping children that have relative parents.
154 void traverseInZOrder(const Visitor& visitor) const {
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000155 TraversalPath root = TraversalPath::ROOT;
Vishnu Naird47bcee2023-02-24 18:08:51 +0000156 if (mLayer) {
157 root.id = mLayer->id;
158 }
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000159 traverseInZOrder(visitor, root);
Vishnu Nair04f89692022-11-16 23:21:05 +0000160 }
161
162 const RequestedLayerState* getLayer() const;
Vishnu Nairea6ff812023-02-27 17:41:39 +0000163 const LayerHierarchy* getRelativeParent() const;
164 const LayerHierarchy* getParent() const;
Vishnu Nair3cc15a42023-06-30 06:20:22 +0000165 friend std::ostream& operator<<(std::ostream& os, const LayerHierarchy& obj) {
166 std::string prefix = " ";
Vishnu Nair6f878312023-09-08 11:05:01 -0700167 obj.dump(os, prefix, LayerHierarchy::Variant::Attached, /*isLastChild=*/false,
168 /*includeMirroredHierarchy*/ false);
Vishnu Nair3cc15a42023-06-30 06:20:22 +0000169 return os;
170 }
Vishnu Nair6f878312023-09-08 11:05:01 -0700171 std::string dump() const {
172 std::string prefix = " ";
173 std::ostringstream os;
174 dump(os, prefix, LayerHierarchy::Variant::Attached, /*isLastChild=*/false,
175 /*includeMirroredHierarchy*/ true);
176 return os.str();
177 }
Vishnu Nair3cc15a42023-06-30 06:20:22 +0000178
Vishnu Nair04f89692022-11-16 23:21:05 +0000179 std::string getDebugStringShort() const;
180 // Traverse the hierarchy and return true if loops are found. The outInvalidRelativeRoot
181 // will contain the first relative root that was visited twice in a traversal.
182 bool hasRelZLoop(uint32_t& outInvalidRelativeRoot) const;
183 std::vector<std::pair<LayerHierarchy*, Variant>> mChildren;
184
185private:
186 friend LayerHierarchyBuilder;
187 LayerHierarchy(const LayerHierarchy& hierarchy, bool childrenOnly);
188 void addChild(LayerHierarchy*, LayerHierarchy::Variant);
189 void removeChild(LayerHierarchy*);
190 void sortChildrenByZOrder();
191 void updateChild(LayerHierarchy*, LayerHierarchy::Variant);
192 void traverseInZOrder(const Visitor& visitor, LayerHierarchy::TraversalPath& parent) const;
Melody Hsubb2ec6a2024-05-27 22:18:05 +0000193 void traverse(const Visitor& visitor, LayerHierarchy::TraversalPath& parent,
194 uint32_t depth = 0) const;
Vishnu Nair3cc15a42023-06-30 06:20:22 +0000195 void dump(std::ostream& out, const std::string& prefix, LayerHierarchy::Variant variant,
Vishnu Nair6f878312023-09-08 11:05:01 -0700196 bool isLastChild, bool includeMirroredHierarchy) const;
Vishnu Nair04f89692022-11-16 23:21:05 +0000197
198 const RequestedLayerState* mLayer;
199 LayerHierarchy* mParent = nullptr;
200 LayerHierarchy* mRelativeParent = nullptr;
201};
202
203// Given a list of RequestedLayerState, this class will build a root hierarchy and an
204// offscreen hierarchy. The builder also has an update method which can update an existing
205// hierarchy from a list of RequestedLayerState and associated change flags.
206class LayerHierarchyBuilder {
207public:
Vishnu Naira0292282023-12-16 14:32:00 -0800208 LayerHierarchyBuilder() = default;
209 void update(LayerLifecycleManager& layerLifecycleManager);
Vishnu Nair04f89692022-11-16 23:21:05 +0000210 LayerHierarchy getPartialHierarchy(uint32_t, bool childrenOnly) const;
211 const LayerHierarchy& getHierarchy() const;
212 const LayerHierarchy& getOffscreenHierarchy() const;
213 std::string getDebugString(uint32_t layerId, uint32_t depth = 0) const;
qinyige10e011d02024-05-23 15:59:08 +0800214 void dumpLayerSample(const LayerHierarchy& layerHierarchy) const;
Vishnu Nair04f89692022-11-16 23:21:05 +0000215
216private:
qinyige10e011d02024-05-23 15:59:08 +0800217 void logSampledChildren(const LayerHierarchy& hierarchy) const;
218
Vishnu Nair04f89692022-11-16 23:21:05 +0000219 void onLayerAdded(RequestedLayerState* layer);
220 void attachToParent(LayerHierarchy*);
221 void detachFromParent(LayerHierarchy*);
222 void attachToRelativeParent(LayerHierarchy*);
223 void detachFromRelativeParent(LayerHierarchy*);
Vishnu Nairf12a6782024-06-03 23:08:15 +0000224 std::vector<LayerHierarchy*> getDescendants(LayerHierarchy*);
Vishnu Nair04f89692022-11-16 23:21:05 +0000225 void attachHierarchyToRelativeParent(LayerHierarchy*);
226 void detachHierarchyFromRelativeParent(LayerHierarchy*);
Vishnu Naira0292282023-12-16 14:32:00 -0800227 void init(const std::vector<std::unique_ptr<RequestedLayerState>>&);
228 void doUpdate(const std::vector<std::unique_ptr<RequestedLayerState>>& layers,
229 const std::vector<std::unique_ptr<RequestedLayerState>>& destroyedLayers);
Vishnu Nair04f89692022-11-16 23:21:05 +0000230 void onLayerDestroyed(RequestedLayerState* layer);
231 void updateMirrorLayer(RequestedLayerState* layer);
232 LayerHierarchy* getHierarchyFromId(uint32_t layerId, bool crashOnFailure = true);
Vishnu Naira0292282023-12-16 14:32:00 -0800233
Vishnu Nair04f89692022-11-16 23:21:05 +0000234 std::unordered_map<uint32_t, LayerHierarchy*> mLayerIdToHierarchy;
235 std::vector<std::unique_ptr<LayerHierarchy>> mHierarchies;
236 LayerHierarchy mRoot{nullptr};
237 LayerHierarchy mOffscreenRoot{nullptr};
Vishnu Naira0292282023-12-16 14:32:00 -0800238 bool mInitialized = false;
Vishnu Nair04f89692022-11-16 23:21:05 +0000239};
240
241} // namespace android::surfaceflinger::frontend