1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
|
/*
* 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
#include "FrontEnd/LayerCreationArgs.h"
#include "FrontEnd/LayerLifecycleManager.h"
#include "RequestedLayerState.h"
#include "ftl/small_vector.h"
namespace android::surfaceflinger::frontend {
class LayerHierarchyBuilder;
// LayerHierarchy allows us to navigate the layer hierarchy in z-order, or depth first traversal.
// The hierarchy is created from a set of RequestedLayerStates. The hierarchy itself does not
// contain additional states. Instead, it is a representation of RequestedLayerStates as a graph.
//
// Each node in the hierarchy can be visited by multiple parents (making this a graph). While
// traversing the hierarchy, a new concept called Variant can be used to understand the
// relationship of the layer to its parent. The following variants are possible:
// Attached - child of the parent
// Detached - child of the parent but currently relative parented to another layer
// Relative - relative child of the parent
// Mirror - mirrored from another layer
// Detached_Mirror - mirrored from another layer, ignoring local transform
//
// By representing the hierarchy as a graph, we can represent mirrored layer hierarchies without
// cloning the layer requested state. The mirrored hierarchy and its corresponding
// RequestedLayerStates are kept in sync because the mirrored hierarchy does not clone any
// states.
class LayerHierarchy {
public:
enum Variant : uint32_t {
Attached, // child of the parent
Detached, // child of the parent but currently relative parented to another layer
Relative, // relative child of the parent
Mirror, // mirrored from another layer
Detached_Mirror, // mirrored from another layer, ignoring local transform
ftl_first = Attached,
ftl_last = Detached_Mirror,
};
static inline bool isMirror(Variant variant) {
return ((variant == Mirror) || (variant == Detached_Mirror));
}
// Represents a unique path to a node.
// The layer hierarchy is represented as a graph. Each node can be visited by multiple parents.
// This allows us to represent mirroring in an efficient way. See the example below:
// root
// ├─ A {Traversal path id = 1}
// ├─ B {Traversal path id = 2}
// │ ├─ C {Traversal path id = 3}
// │ ├─ D {Traversal path id = 4}
// │ └─ E (Mirrors C) {Traversal path id = 5}
// └─ F (Mirrors B) {Traversal path id = 6}
//
// 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, 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.
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
// TraversalPath, it means that somewhere in the hierarchy two layers are relatively
// parented to each other.
ftl::SmallVector<uint32_t, 5> relativeRootIds;
// First duplicate relative root id found. If this is a valid layer id that means we are
// in a loop.
uint32_t invalidRelativeRootId = UNASSIGNED_LAYER_ID;
// See isAttached()
bool detached = false;
bool hasRelZLoop() const { return invalidRelativeRootId != UNASSIGNED_LAYER_ID; }
// Returns true if this node is reached via one or more relative parents.
bool isRelative() const { return !relativeRootIds.empty(); }
// 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 !mirrorRootIds.empty(); }
TraversalPath getClonedFrom() const { return {.id = id, .variant = variant}; }
TraversalPath makeChild(uint32_t layerId, LayerHierarchy::Variant variant) const;
bool operator==(const TraversalPath& other) const {
return id == other.id && mirrorRootIds == other.mirrorRootIds;
}
std::string toString() const;
static const TraversalPath ROOT;
};
struct TraversalPathHash {
std::size_t operator()(const LayerHierarchy::TraversalPath& key) const {
uint32_t hashCode = key.id * 31;
for (uint32_t mirrorRootId : key.mirrorRootIds) {
hashCode += mirrorRootId * 31;
}
return std::hash<size_t>{}(hashCode);
}
};
LayerHierarchy(RequestedLayerState* layer);
// Visitor function that provides the hierarchy node and a traversal id which uniquely
// identifies how was visited. The hierarchy contains a pointer to the RequestedLayerState.
// Return false to stop traversing down the hierarchy.
typedef std::function<bool(const LayerHierarchy& hierarchy,
const LayerHierarchy::TraversalPath& traversalPath)>
Visitor;
// Traverse the hierarchy and visit all child variants.
void traverse(const Visitor& visitor) const {
TraversalPath root = TraversalPath::ROOT;
if (mLayer) {
root.id = mLayer->id;
}
traverse(visitor, root, /*depth=*/0);
}
// Traverse the hierarchy in z-order, skipping children that have relative parents.
void traverseInZOrder(const Visitor& visitor) const {
TraversalPath root = TraversalPath::ROOT;
if (mLayer) {
root.id = mLayer->id;
}
traverseInZOrder(visitor, root);
}
const RequestedLayerState* getLayer() const;
const LayerHierarchy* getRelativeParent() const;
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,
/*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
// will contain the first relative root that was visited twice in a traversal.
bool hasRelZLoop(uint32_t& outInvalidRelativeRoot) const;
std::vector<std::pair<LayerHierarchy*, Variant>> mChildren;
private:
friend LayerHierarchyBuilder;
LayerHierarchy(const LayerHierarchy& hierarchy, bool childrenOnly);
void addChild(LayerHierarchy*, LayerHierarchy::Variant);
void removeChild(LayerHierarchy*);
void sortChildrenByZOrder();
void updateChild(LayerHierarchy*, LayerHierarchy::Variant);
void traverseInZOrder(const Visitor& visitor,
const LayerHierarchy::TraversalPath& parent) const;
void traverse(const Visitor& visitor, const LayerHierarchy::TraversalPath& parent,
uint32_t depth = 0) const;
void dump(std::ostream& out, const std::string& prefix, LayerHierarchy::Variant variant,
bool isLastChild, bool includeMirroredHierarchy) const;
const RequestedLayerState* mLayer;
LayerHierarchy* mParent = nullptr;
LayerHierarchy* mRelativeParent = nullptr;
};
// Given a list of RequestedLayerState, this class will build a root hierarchy and an
// offscreen hierarchy. The builder also has an update method which can update an existing
// hierarchy from a list of RequestedLayerState and associated change flags.
class LayerHierarchyBuilder {
public:
LayerHierarchyBuilder() = default;
void update(LayerLifecycleManager& layerLifecycleManager);
LayerHierarchy getPartialHierarchy(uint32_t, bool childrenOnly) const;
const LayerHierarchy& getHierarchy() const;
const LayerHierarchy& getOffscreenHierarchy() const;
std::string getDebugString(uint32_t layerId, uint32_t depth = 0) const;
void dumpLayerSample(const LayerHierarchy& layerHierarchy) const;
private:
void logSampledChildren(const LayerHierarchy& hierarchy) const;
void onLayerAdded(RequestedLayerState* layer);
void attachToParent(LayerHierarchy*);
void detachFromParent(LayerHierarchy*);
void attachToRelativeParent(LayerHierarchy*);
void detachFromRelativeParent(LayerHierarchy*);
std::vector<LayerHierarchy*> getDescendants(LayerHierarchy*);
void attachHierarchyToRelativeParent(LayerHierarchy*);
void detachHierarchyFromRelativeParent(LayerHierarchy*);
void init(const std::vector<std::unique_ptr<RequestedLayerState>>&);
void doUpdate(const std::vector<std::unique_ptr<RequestedLayerState>>& layers,
const std::vector<std::unique_ptr<RequestedLayerState>>& destroyedLayers);
void onLayerDestroyed(RequestedLayerState* layer);
void updateMirrorLayer(RequestedLayerState* layer);
LayerHierarchy* getHierarchyFromId(uint32_t layerId, bool crashOnFailure = true);
std::unordered_map<uint32_t, LayerHierarchy*> mLayerIdToHierarchy;
std::vector<std::unique_ptr<LayerHierarchy>> mHierarchies;
LayerHierarchy mRoot{nullptr};
LayerHierarchy mOffscreenRoot{nullptr};
bool mInitialized = false;
};
} // namespace android::surfaceflinger::frontend
|