blob: f83a859de75a11487c0bb91de9e8fdd542f7f42c [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:
44 enum Variant {
45 Attached,
46 Detached,
47 Relative,
48 Mirror,
49 };
50 // Represents a unique path to a node.
51 struct TraversalPath {
52 uint32_t id;
53 LayerHierarchy::Variant variant;
54 // Mirrored layers can have a different geometry than their parents so we need to track
55 // the mirror roots in the traversal.
56 ftl::SmallVector<uint32_t, 5> mirrorRootIds;
57 // Relative layers can be visited twice, once by their parent and then once again by
58 // their relative parent. We keep track of the roots here to detect any loops in the
59 // hierarchy. If a relative root already exists in the list while building the
60 // TraversalPath, it means that somewhere in the hierarchy two layers are relatively
61 // parented to each other.
62 ftl::SmallVector<uint32_t, 5> relativeRootIds;
63 // First duplicate relative root id found. If this is a valid layer id that means we are
64 // in a loop.
65 uint32_t invalidRelativeRootId = UNASSIGNED_LAYER_ID;
66 bool hasRelZLoop() const { return invalidRelativeRootId != UNASSIGNED_LAYER_ID; }
67 bool isRelative() { return !relativeRootIds.empty(); }
68
69 bool operator==(const TraversalPath& other) const {
70 return id == other.id && mirrorRootIds == other.mirrorRootIds;
71 }
72 std::string toString() const;
73
74 static TraversalPath ROOT_TRAVERSAL_ID;
75 };
76
77 // Helper class to add nodes to an existing traversal id and removes the
78 // node when it goes out of scope.
79 class ScopedAddToTraversalPath {
80 public:
81 ScopedAddToTraversalPath(TraversalPath& traversalPath, uint32_t layerId,
82 LayerHierarchy::Variant variantArg);
83 ~ScopedAddToTraversalPath();
84
85 private:
86 TraversalPath& mTraversalPath;
87 uint32_t mParentId;
88 LayerHierarchy::Variant mParentVariant;
89 };
90 LayerHierarchy(RequestedLayerState* layer);
91
92 // Visitor function that provides the hierarchy node and a traversal id which uniquely
93 // identifies how was visited. The hierarchy contains a pointer to the RequestedLayerState.
94 // Return false to stop traversing down the hierarchy.
95 typedef std::function<bool(const LayerHierarchy& hierarchy,
96 const LayerHierarchy::TraversalPath& traversalPath)>
97 Visitor;
98
99 // Traverse the hierarchy and visit all child variants.
100 void traverse(const Visitor& visitor) const {
101 traverse(visitor, TraversalPath::ROOT_TRAVERSAL_ID);
102 }
103
104 // Traverse the hierarchy in z-order, skipping children that have relative parents.
105 void traverseInZOrder(const Visitor& visitor) const {
106 traverseInZOrder(visitor, TraversalPath::ROOT_TRAVERSAL_ID);
107 }
108
109 const RequestedLayerState* getLayer() const;
110 std::string getDebugString(const char* prefix = "") const;
111 std::string getDebugStringShort() const;
112 // Traverse the hierarchy and return true if loops are found. The outInvalidRelativeRoot
113 // will contain the first relative root that was visited twice in a traversal.
114 bool hasRelZLoop(uint32_t& outInvalidRelativeRoot) const;
115 std::vector<std::pair<LayerHierarchy*, Variant>> mChildren;
116
117private:
118 friend LayerHierarchyBuilder;
119 LayerHierarchy(const LayerHierarchy& hierarchy, bool childrenOnly);
120 void addChild(LayerHierarchy*, LayerHierarchy::Variant);
121 void removeChild(LayerHierarchy*);
122 void sortChildrenByZOrder();
123 void updateChild(LayerHierarchy*, LayerHierarchy::Variant);
124 void traverseInZOrder(const Visitor& visitor, LayerHierarchy::TraversalPath& parent) const;
125 void traverse(const Visitor& visitor, LayerHierarchy::TraversalPath& parent) const;
126
127 const RequestedLayerState* mLayer;
128 LayerHierarchy* mParent = nullptr;
129 LayerHierarchy* mRelativeParent = nullptr;
130};
131
132// Given a list of RequestedLayerState, this class will build a root hierarchy and an
133// offscreen hierarchy. The builder also has an update method which can update an existing
134// hierarchy from a list of RequestedLayerState and associated change flags.
135class LayerHierarchyBuilder {
136public:
137 LayerHierarchyBuilder(const std::vector<std::unique_ptr<RequestedLayerState>>&);
138 void update(const std::vector<std::unique_ptr<RequestedLayerState>>& layers,
139 const std::vector<std::unique_ptr<RequestedLayerState>>& destroyedLayers);
140 LayerHierarchy getPartialHierarchy(uint32_t, bool childrenOnly) const;
141 const LayerHierarchy& getHierarchy() const;
142 const LayerHierarchy& getOffscreenHierarchy() const;
143 std::string getDebugString(uint32_t layerId, uint32_t depth = 0) const;
144
145private:
146 void onLayerAdded(RequestedLayerState* layer);
147 void attachToParent(LayerHierarchy*);
148 void detachFromParent(LayerHierarchy*);
149 void attachToRelativeParent(LayerHierarchy*);
150 void detachFromRelativeParent(LayerHierarchy*);
151 void attachHierarchyToRelativeParent(LayerHierarchy*);
152 void detachHierarchyFromRelativeParent(LayerHierarchy*);
153
154 void onLayerDestroyed(RequestedLayerState* layer);
155 void updateMirrorLayer(RequestedLayerState* layer);
156 LayerHierarchy* getHierarchyFromId(uint32_t layerId, bool crashOnFailure = true);
157 std::unordered_map<uint32_t, LayerHierarchy*> mLayerIdToHierarchy;
158 std::vector<std::unique_ptr<LayerHierarchy>> mHierarchies;
159 LayerHierarchy mRoot{nullptr};
160 LayerHierarchy mOffscreenRoot{nullptr};
161};
162
163} // namespace android::surfaceflinger::frontend