blob: 1e4838727bd7be3272d75aa2262b0988c177f997 [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"
20#include "RequestedLayerState.h"
21#include "ftl/small_vector.h"
22
23namespace android::surfaceflinger::frontend {
24class LayerHierarchyBuilder;
25
26// LayerHierarchy allows us to navigate the layer hierarchy in z-order, or depth first traversal.
27// The hierarchy is created from a set of RequestedLayerStates. The hierarchy itself does not
28// contain additional states. Instead, it is a representation of RequestedLayerStates as a graph.
29//
30// Each node in the hierarchy can be visited by multiple parents (making this a graph). While
31// traversing the hierarchy, a new concept called Variant can be used to understand the
32// relationship of the layer to its parent. The following variants are possible:
33// Attached - child of the parent
34// Detached - child of the parent but currently relative parented to another layer
35// Relative - relative child of the parent
36// Mirror - mirrored from another layer
37//
38// By representing the hierarchy as a graph, we can represent mirrored layer hierarchies without
39// cloning the layer requested state. The mirrored hierarchy and its corresponding
40// RequestedLayerStates are kept in sync because the mirrored hierarchy does not clone any
41// states.
42class LayerHierarchy {
43public:
Vishnu Naircfb2d252023-01-19 04:44:02 +000044 enum Variant : uint32_t {
Vishnu Naira02943f2023-06-03 13:44:46 -070045 Attached, // child of the parent
46 Detached, // child of the parent but currently relative parented to another layer
47 Relative, // relative child of the parent
48 Mirror, // mirrored from another layer
Vishnu Naircfb2d252023-01-19 04:44:02 +000049 ftl_first = Attached,
50 ftl_last = Mirror,
Vishnu Nair04f89692022-11-16 23:21:05 +000051 };
52 // Represents a unique path to a node.
Vishnu Nair80a5a702023-02-11 01:21:51 +000053 // The layer hierarchy is represented as a graph. Each node can be visited by multiple parents.
54 // This allows us to represent mirroring in an efficient way. See the example below:
55 // root
56 // ├─ A {Traversal path id = 1}
57 // ├─ B {Traversal path id = 2}
58 // │ ├─ C {Traversal path id = 3}
59 // │ ├─ D {Traversal path id = 4}
60 // │ └─ E {Traversal path id = 5}
61 // ├─ F (Mirrors B) {Traversal path id = 6}
62 // └─ G (Mirrors F) {Traversal path id = 7}
63 //
64 // C, D and E can be traversed via B or via F then B or via G then F then B.
65 // Depending on how the node is reached, its properties such as geometry or visibility might be
66 // different. And we can uniquely identify the node by keeping track of the nodes leading up to
67 // it. But to be more efficient we only need to track the nodes id and the top mirror root path.
68 // So C for example, would have the following unique traversal paths:
69 // - {Traversal path id = 3}
70 // - {Traversal path id = 3, mirrorRootId = 6}
71 // - {Traversal path id = 3, mirrorRootId = 7}
72
Vishnu Nair04f89692022-11-16 23:21:05 +000073 struct TraversalPath {
74 uint32_t id;
75 LayerHierarchy::Variant variant;
76 // Mirrored layers can have a different geometry than their parents so we need to track
77 // the mirror roots in the traversal.
Vishnu Nair80a5a702023-02-11 01:21:51 +000078 uint32_t mirrorRootId = UNASSIGNED_LAYER_ID;
Vishnu Nair04f89692022-11-16 23:21:05 +000079 // Relative layers can be visited twice, once by their parent and then once again by
80 // their relative parent. We keep track of the roots here to detect any loops in the
81 // hierarchy. If a relative root already exists in the list while building the
82 // TraversalPath, it means that somewhere in the hierarchy two layers are relatively
83 // parented to each other.
84 ftl::SmallVector<uint32_t, 5> relativeRootIds;
85 // First duplicate relative root id found. If this is a valid layer id that means we are
86 // in a loop.
87 uint32_t invalidRelativeRootId = UNASSIGNED_LAYER_ID;
Vishnu Nair8fc721b2022-12-22 20:06:32 +000088 // See isAttached()
89 bool detached = false;
Vishnu Nair04f89692022-11-16 23:21:05 +000090 bool hasRelZLoop() const { return invalidRelativeRootId != UNASSIGNED_LAYER_ID; }
Vishnu Nair8fc721b2022-12-22 20:06:32 +000091 // Returns true if this node is reached via one or more relative parents.
92 bool isRelative() const { return !relativeRootIds.empty(); }
93 // Returns true if the node or its parents are not Detached.
94 bool isAttached() const { return !detached; }
95 // Returns true if the node is a clone.
Vishnu Nair80a5a702023-02-11 01:21:51 +000096 bool isClone() const { return mirrorRootId != UNASSIGNED_LAYER_ID; }
97 TraversalPath getMirrorRoot() const;
Vishnu Nair04f89692022-11-16 23:21:05 +000098
99 bool operator==(const TraversalPath& other) const {
Vishnu Nair80a5a702023-02-11 01:21:51 +0000100 return id == other.id && mirrorRootId == other.mirrorRootId;
Vishnu Nair04f89692022-11-16 23:21:05 +0000101 }
102 std::string toString() const;
103
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000104 static const TraversalPath ROOT;
Vishnu Nair04f89692022-11-16 23:21:05 +0000105 };
106
Vishnu Naird0183602023-03-16 18:52:15 +0000107 struct TraversalPathHash {
108 std::size_t operator()(const LayerHierarchy::TraversalPath& key) const {
109 uint32_t hashCode = key.id * 31;
110 if (key.mirrorRootId != UNASSIGNED_LAYER_ID) {
111 hashCode += key.mirrorRootId * 31;
112 }
113 return std::hash<size_t>{}(hashCode);
114 }
115 };
116
Vishnu Nair04f89692022-11-16 23:21:05 +0000117 // Helper class to add nodes to an existing traversal id and removes the
118 // node when it goes out of scope.
119 class ScopedAddToTraversalPath {
120 public:
121 ScopedAddToTraversalPath(TraversalPath& traversalPath, uint32_t layerId,
122 LayerHierarchy::Variant variantArg);
123 ~ScopedAddToTraversalPath();
124
125 private:
126 TraversalPath& mTraversalPath;
Vishnu Nair80a5a702023-02-11 01:21:51 +0000127 TraversalPath mParentPath;
Vishnu Nair04f89692022-11-16 23:21:05 +0000128 };
129 LayerHierarchy(RequestedLayerState* layer);
130
131 // Visitor function that provides the hierarchy node and a traversal id which uniquely
132 // identifies how was visited. The hierarchy contains a pointer to the RequestedLayerState.
133 // Return false to stop traversing down the hierarchy.
134 typedef std::function<bool(const LayerHierarchy& hierarchy,
135 const LayerHierarchy::TraversalPath& traversalPath)>
136 Visitor;
137
138 // Traverse the hierarchy and visit all child variants.
139 void traverse(const Visitor& visitor) const {
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000140 TraversalPath root = TraversalPath::ROOT;
Vishnu Naird47bcee2023-02-24 18:08:51 +0000141 if (mLayer) {
142 root.id = mLayer->id;
143 }
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000144 traverse(visitor, root);
Vishnu Nair04f89692022-11-16 23:21:05 +0000145 }
146
147 // Traverse the hierarchy in z-order, skipping children that have relative parents.
148 void traverseInZOrder(const Visitor& visitor) const {
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000149 TraversalPath root = TraversalPath::ROOT;
Vishnu Naird47bcee2023-02-24 18:08:51 +0000150 if (mLayer) {
151 root.id = mLayer->id;
152 }
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000153 traverseInZOrder(visitor, root);
Vishnu Nair04f89692022-11-16 23:21:05 +0000154 }
155
156 const RequestedLayerState* getLayer() const;
Vishnu Nairea6ff812023-02-27 17:41:39 +0000157 const LayerHierarchy* getRelativeParent() const;
158 const LayerHierarchy* getParent() const;
Vishnu Nair3cc15a42023-06-30 06:20:22 +0000159 friend std::ostream& operator<<(std::ostream& os, const LayerHierarchy& obj) {
160 std::string prefix = " ";
161 obj.dump(os, prefix, LayerHierarchy::Variant::Attached, /*isLastChild=*/false);
162 return os;
163 }
164
Vishnu Nair04f89692022-11-16 23:21:05 +0000165 std::string getDebugStringShort() const;
166 // Traverse the hierarchy and return true if loops are found. The outInvalidRelativeRoot
167 // will contain the first relative root that was visited twice in a traversal.
168 bool hasRelZLoop(uint32_t& outInvalidRelativeRoot) const;
169 std::vector<std::pair<LayerHierarchy*, Variant>> mChildren;
170
171private:
172 friend LayerHierarchyBuilder;
173 LayerHierarchy(const LayerHierarchy& hierarchy, bool childrenOnly);
174 void addChild(LayerHierarchy*, LayerHierarchy::Variant);
175 void removeChild(LayerHierarchy*);
176 void sortChildrenByZOrder();
177 void updateChild(LayerHierarchy*, LayerHierarchy::Variant);
178 void traverseInZOrder(const Visitor& visitor, LayerHierarchy::TraversalPath& parent) const;
179 void traverse(const Visitor& visitor, LayerHierarchy::TraversalPath& parent) const;
Vishnu Nair3cc15a42023-06-30 06:20:22 +0000180 void dump(std::ostream& out, const std::string& prefix, LayerHierarchy::Variant variant,
181 bool isLastChild) const;
Vishnu Nair04f89692022-11-16 23:21:05 +0000182
183 const RequestedLayerState* mLayer;
184 LayerHierarchy* mParent = nullptr;
185 LayerHierarchy* mRelativeParent = nullptr;
186};
187
188// Given a list of RequestedLayerState, this class will build a root hierarchy and an
189// offscreen hierarchy. The builder also has an update method which can update an existing
190// hierarchy from a list of RequestedLayerState and associated change flags.
191class LayerHierarchyBuilder {
192public:
193 LayerHierarchyBuilder(const std::vector<std::unique_ptr<RequestedLayerState>>&);
194 void update(const std::vector<std::unique_ptr<RequestedLayerState>>& layers,
195 const std::vector<std::unique_ptr<RequestedLayerState>>& destroyedLayers);
196 LayerHierarchy getPartialHierarchy(uint32_t, bool childrenOnly) const;
197 const LayerHierarchy& getHierarchy() const;
198 const LayerHierarchy& getOffscreenHierarchy() const;
199 std::string getDebugString(uint32_t layerId, uint32_t depth = 0) const;
200
201private:
202 void onLayerAdded(RequestedLayerState* layer);
203 void attachToParent(LayerHierarchy*);
204 void detachFromParent(LayerHierarchy*);
205 void attachToRelativeParent(LayerHierarchy*);
206 void detachFromRelativeParent(LayerHierarchy*);
207 void attachHierarchyToRelativeParent(LayerHierarchy*);
208 void detachHierarchyFromRelativeParent(LayerHierarchy*);
209
210 void onLayerDestroyed(RequestedLayerState* layer);
211 void updateMirrorLayer(RequestedLayerState* layer);
212 LayerHierarchy* getHierarchyFromId(uint32_t layerId, bool crashOnFailure = true);
213 std::unordered_map<uint32_t, LayerHierarchy*> mLayerIdToHierarchy;
214 std::vector<std::unique_ptr<LayerHierarchy>> mHierarchies;
215 LayerHierarchy mRoot{nullptr};
216 LayerHierarchy mOffscreenRoot{nullptr};
217};
218
219} // namespace android::surfaceflinger::frontend