1 /*
2  * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #ifndef RENDER_SERVICE_CLIENT_CORE_PIPELINE_RS_DIRTY_REGION_MANAGER_H
16 #define RENDER_SERVICE_CLIENT_CORE_PIPELINE_RS_DIRTY_REGION_MANAGER_H
17 
18 #include <map>
19 #include <vector>
20 
21 #include "common/rs_macros.h"
22 #include "common/rs_rect.h"
23 #include "platform/common/rs_system_properties.h"
24 
25 namespace OHOS {
26 namespace Rosen {
27 // classify dfx debug options
28 enum DebugRegionType {
29     CURRENT_SUB = 0,
30     CURRENT_WHOLE,
31     MULTI_HISTORY,
32     EGL_DAMAGE,
33     TYPE_MAX
34 };
35 
36 // classify types that cause region dirty
37 enum DirtyRegionType {
38     UPDATE_DIRTY_REGION = 0,
39     OVERLAY_RECT,
40     FILTER_RECT,
41     SHADOW_RECT,
42     PREPARE_CLIP_RECT,
43     REMOVE_CHILD_RECT,
44     RENDER_PROPERTIES_RECT,
45     CANVAS_NODE_SKIP_RECT,
46     OUTLINE_RECT,
47     SUBTREE_SKIP_OUT_OF_PARENT_RECT,
48     TYPE_AMOUNT
49 };
50 
51 class RSB_EXPORT RSDirtyRegionManager final {
52     friend class RSFilterCacheManager;
53 public:
54     static constexpr int32_t ALIGNED_BITS = 32;
55     RSDirtyRegionManager();
56     RSDirtyRegionManager(bool isDisplayDirtyManager);
57     ~RSDirtyRegionManager() = default;
58     // update/expand current frame dirtyregion
59     void MergeDirtyRect(const RectI& rect, bool isDebugRect = false);
60     // update/expand current frame dirtyregion if intersect
61     bool MergeDirtyRectIfIntersect(const RectI& rect);
62     // update/expand dirtyregion after merge history
63     void MergeDirtyRectAfterMergeHistory(const RectI& rect);
64     // clip dirtyregion in current frame
65     void IntersectDirtyRect(const RectI& rect);
66     // Clip currentframe dirtyRegion intersected with surfaceRect
67     void ClipDirtyRectWithinSurface();
68     // clear allinfo except dirtyregion history
69     void Clear();
70     // record hwc region for virtual screen
71     void MergeHwcDirtyRect(const RectI& rect);
72 
73     // update current frame's visited dirtyregion
74     void UpdateVisitedDirtyRects(const std::vector<RectI>& rects);
75     RectI GetIntersectedVisitedDirtyRect(const RectI& absRect) const;
76     void UpdateCacheableFilterRect(const RectI& rect);
77     bool IfCacheableFilterRectFullyCover(const RectI& targetRect);
IsCacheableFilterRectEmpty()78     bool IsCacheableFilterRectEmpty() const
79     {
80         return cacheableFilterRects_.empty();
81     }
82 
InvalidateFilterCacheRect()83     void InvalidateFilterCacheRect()
84     {
85         isFilterCacheRectValid_ = false;
86     }
87 
IsFilterCacheRectValid()88     bool IsFilterCacheRectValid()
89     {
90         return isFilterCacheRectValid_;
91     }
92 
93     // return current frame dirtyregion, can be changed in prepare and process (displaynode) stage
94     const RectI& GetCurrentFrameDirtyRegion();
95     // return merged historical region
96     const RectI& GetDirtyRegion() const;
97     // return mapAbs dirtyRegion
98     const RectI& GetCurrentFrameMpsAbsDirtyRect() const;
99     void SetCurrentFrameDirtyRect(const RectI& dirtyRect);
100     /*  return merged historical region upside down in left-bottom origin coordinate
101         reason: when use OpenGL SetDamageRegion, coordinate system conversion exists.
102     */
103     RectI GetDirtyRegionFlipWithinSurface() const;
104     // return current frame's region from dirtyregion history
105     const RectI& GetLatestDirtyRegion() const;
106     // return merged historical region upside down in left-bottom origin coordinate
107     RectI GetRectFlipWithinSurface(const RectI& rect) const;
108     // get aligned rect as times of alignedBits
109     static RectI GetPixelAlignedRect(const RectI& rect, int32_t alignedBits = ALIGNED_BITS);
110     // return true if current frame dirtyregion is not empty
111     bool IsCurrentFrameDirty() const;
112     // return true if dirtyregion after merge history is not empty
113     bool IsDirty() const;
114     // push currentframe dirtyregion into history, and merge history according to bufferage
115     void UpdateDirty(bool enableAligned = false);
116     // align current frame dirtyregion before merge history
117     void UpdateDirtyByAligned(int32_t alignedBits = ALIGNED_BITS);
118     bool SetBufferAge(const int age);
119     bool SetSurfaceSize(const int32_t width, const int32_t height);
GetSurfaceRect()120     RectI GetSurfaceRect() const
121     {
122         return surfaceRect_;
123     }
124     void MergeSurfaceRect();
125     // Reset current frame dirtyregion to surfacerect to realize full refreshing
126     void ResetDirtyAsSurfaceSize();
127 
128     void UpdateDebugRegionTypeEnable(DirtyRegionDebugType dirtyDebugType);
129 
IsDebugRegionTypeEnable(DebugRegionType var)130     inline bool IsDebugRegionTypeEnable(DebugRegionType var) const
131     {
132         if (var < DebugRegionType::TYPE_MAX) {
133             return debugRegionEnabled_[var];
134         }
135         return false;
136     }
137     // OnSync must be Executed after UpdateDirty API
138     void OnSync(std::shared_ptr<RSDirtyRegionManager> targetManager);
139 
140     // added for dirty region dfx
141     void UpdateDirtyRegionInfoForDfx(NodeId id, RSRenderNodeType nodeType = RSRenderNodeType::CANVAS_NODE,
142         DirtyRegionType dirtyType = DirtyRegionType::UPDATE_DIRTY_REGION, const RectI& rect = RectI());
143     void GetDirtyRegionInfo(std::map<NodeId, RectI>& target,
144         RSRenderNodeType nodeType = RSRenderNodeType::CANVAS_NODE,
145         DirtyRegionType dirtyType = DirtyRegionType::UPDATE_DIRTY_REGION) const;
146 
MarkAsTargetForDfx()147     void MarkAsTargetForDfx()
148     {
149         isDfxTarget_ = true;
150     }
151 
IsTargetForDfx()152     bool IsTargetForDfx() {
153         return isDfxTarget_;
154     }
155 
156     bool HasOffset();
157     void SetOffset(int offsetX, int offsetY);
158     RectI GetOffsetedDirtyRegion() const;
159 
GetMergedDirtyRegions()160     const std::vector<RectI>& GetMergedDirtyRegions() const
161     {
162         return mergedDirtyRegions_;
163     }
164 
MergeDirtyHistoryInVirtual(unsigned int age)165     void MergeDirtyHistoryInVirtual(unsigned int age)
166     {
167         mergedDirtyInVirtualScreen_ = MergeHistory(age, currentFrameDirtyRegion_);
168     }
169 
GetDirtyRegionInVirtual()170     RectI GetDirtyRegionInVirtual() const
171     {
172         return mergedDirtyInVirtualScreen_;
173     }
174 
GetHwcDirtyRegion()175     RectI GetHwcDirtyRegion() const
176     {
177         return hwcDirtyRegion_;
178     }
179 
180 private:
181     RectI MergeHistory(unsigned int age, RectI rect) const;
182     void PushHistory(RectI rect);
183     // get his rect according to index offset
184     RectI GetHistory(unsigned int i) const;
185     void AlignHistory();
186 
187     RectI surfaceRect_;             // dirtyregion clipbounds
188     RectI dirtyRegion_;             // dirtyregion after merge history
189     RectI currentFrameDirtyRegion_; // dirtyRegion in current frame
190     RectI hwcDirtyRegion_;          // hwc dirty region used in virtual screen
191     RectI debugRect_;               // dirtyRegion for showing currentFreshRate debug
192     RectI mergedDirtyInVirtualScreen_;
193     std::vector<RectI> visitedDirtyRegions_ = {};  // visited app's dirtyRegion
194     std::vector<RectI> cacheableFilterRects_ = {};  // node's region if filter cachable
195     std::vector<RectI> mergedDirtyRegions_ = {};
196 
197     // added for dfx
198     std::vector<std::map<NodeId, RectI>> dirtyCanvasNodeInfo_;
199     std::vector<std::map<NodeId, RectI>> dirtySurfaceNodeInfo_;
200     std::vector<bool> debugRegionEnabled_;
201     bool isDfxTarget_ = false;
202     std::vector<RectI> dirtyHistory_;
203     int historyHead_ = -1;
204     unsigned int historySize_ = 0;
205     const unsigned HISTORY_QUEUE_MAX_SIZE = 10;
206     // may add new set function for bufferAge
207     unsigned int bufferAge_ = 0;
208     bool isDirtyRegionAlignedEnable_ = false;
209     bool isFilterCacheRectValid_ = true;
210     bool isDisplayDirtyManager_ = false;
211     std::atomic<bool> isSync_ = false;
212 
213     // Used for coordinate switch, i.e. dirtyRegion = dirtyRegion + offset.
214     // For example when dirtymanager is used in cachesurface when surfacenode's
215     // shadow and surfacenode are cached in a surface, dirty region's coordinate should start
216     // from shadow's left-top rather than that of displaynode.
217     // Normally, this value should be set to:
218     //      offsetX_ =  - surfacePos.x + shadowWidth
219     //      offsetY_ =  - surfacePos.y + shadowHeight
220     bool hasOffset_ = false;
221     int offsetX_ = 0;
222     int offsetY_ = 0;
223 };
224 } // namespace Rosen
225 } // namespace OHOS
226 
227 #endif // RENDER_SERVICE_CLIENT_CORE_PIPELINE_RS_DIRTY_REGION_MANAGER_H
228