1 /*
2  * Copyright (c) 2021-2022 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 
16 #include "pipeline/rs_dirty_region_manager.h"
17 
18 #include <string>
19 
20 #include "rs_trace.h"
21 
22 #include "platform/common/rs_log.h"
23 namespace OHOS {
24 namespace Rosen {
RSDirtyRegionManager()25 RSDirtyRegionManager::RSDirtyRegionManager()
26 {
27     dirtyHistory_.resize(HISTORY_QUEUE_MAX_SIZE);
28     debugRegionEnabled_.resize(DebugRegionType::TYPE_MAX);
29     dirtyCanvasNodeInfo_.resize(DirtyRegionType::TYPE_AMOUNT);
30     dirtySurfaceNodeInfo_.resize(DirtyRegionType::TYPE_AMOUNT);
31 }
32 
RSDirtyRegionManager(bool isDisplayDirtyManager)33 RSDirtyRegionManager::RSDirtyRegionManager(bool isDisplayDirtyManager)
34 {
35     dirtyHistory_.resize(HISTORY_QUEUE_MAX_SIZE);
36     debugRegionEnabled_.resize(DebugRegionType::TYPE_MAX);
37     dirtyCanvasNodeInfo_.resize(DirtyRegionType::TYPE_AMOUNT);
38     dirtySurfaceNodeInfo_.resize(DirtyRegionType::TYPE_AMOUNT);
39     isDisplayDirtyManager_ = isDisplayDirtyManager;
40 }
41 
MergeDirtyRect(const RectI & rect,bool isDebugRect)42 void RSDirtyRegionManager::MergeDirtyRect(const RectI& rect, bool isDebugRect)
43 {
44     if (rect.IsEmpty()) {
45         return;
46     }
47     if (currentFrameDirtyRegion_.IsEmpty()) {
48         currentFrameDirtyRegion_ = rect;
49     } else {
50         currentFrameDirtyRegion_ = currentFrameDirtyRegion_.JoinRect(rect);
51     }
52     if (isDisplayDirtyManager_) {
53         mergedDirtyRegions_.emplace_back(rect);
54     }
55     if (isDebugRect) {
56         debugRect_ = rect;
57     }
58 }
59 
MergeHwcDirtyRect(const RectI & rect)60 void RSDirtyRegionManager::MergeHwcDirtyRect(const RectI& rect)
61 {
62     if (rect.IsEmpty()) {
63         return;
64     }
65     if (hwcDirtyRegion_.IsEmpty()) {
66         hwcDirtyRegion_ = rect;
67     } else {
68         hwcDirtyRegion_ = hwcDirtyRegion_.JoinRect(rect);
69     }
70 }
71 
MergeDirtyRectIfIntersect(const RectI & rect)72 bool RSDirtyRegionManager::MergeDirtyRectIfIntersect(const RectI& rect)
73 {
74     if (!currentFrameDirtyRegion_.Intersect(rect)) {
75         return false;
76     }
77     currentFrameDirtyRegion_ = currentFrameDirtyRegion_.JoinRect(rect);
78     if (isDisplayDirtyManager_) {
79         mergedDirtyRegions_.emplace_back(rect);
80     }
81     return true;
82 }
83 
MergeDirtyRectAfterMergeHistory(const RectI & rect)84 void RSDirtyRegionManager::MergeDirtyRectAfterMergeHistory(const RectI& rect)
85 {
86     if (rect.IsEmpty()) {
87         return;
88     }
89     if (dirtyRegion_.IsEmpty()) {
90         dirtyRegion_ = rect;
91     } else {
92         dirtyRegion_ = dirtyRegion_.JoinRect(rect);
93     }
94 }
95 
UpdateVisitedDirtyRects(const std::vector<RectI> & rects)96 void RSDirtyRegionManager::UpdateVisitedDirtyRects(const std::vector<RectI>& rects)
97 {
98     if (rects.empty()) {
99         visitedDirtyRegions_.clear();
100         return;
101     }
102     visitedDirtyRegions_ = rects;
103 }
104 
GetIntersectedVisitedDirtyRect(const RectI & absRect) const105 RectI RSDirtyRegionManager::GetIntersectedVisitedDirtyRect(const RectI& absRect) const
106 {
107     RectI belowDirty = currentFrameDirtyRegion_;
108     for (const auto& subDirty : visitedDirtyRegions_) {
109         if (absRect.IsInsideOf(belowDirty)) {
110             return belowDirty;
111         }
112         belowDirty = belowDirty.JoinRect(subDirty.IntersectRect(absRect));
113     }
114     return belowDirty;
115 }
116 
UpdateCacheableFilterRect(const RectI & rect)117 void RSDirtyRegionManager::UpdateCacheableFilterRect(const RectI& rect)
118 {
119     if (rect.IsEmpty()) {
120         return;
121     }
122     cacheableFilterRects_.emplace_back(rect);
123 }
124 
IfCacheableFilterRectFullyCover(const RectI & targetRect)125 bool RSDirtyRegionManager::IfCacheableFilterRectFullyCover(const RectI& targetRect)
126 {
127     for (auto rect : cacheableFilterRects_) {
128         if (targetRect.IsInsideOf(rect)) {
129             return true;
130         }
131     }
132     return false;
133 }
134 
IntersectDirtyRect(const RectI & rect)135 void RSDirtyRegionManager::IntersectDirtyRect(const RectI& rect)
136 {
137     currentFrameDirtyRegion_ = currentFrameDirtyRegion_.IntersectRect(rect);
138 }
139 
ClipDirtyRectWithinSurface()140 void RSDirtyRegionManager::ClipDirtyRectWithinSurface()
141 {
142     int left = std::max(std::max(currentFrameDirtyRegion_.left_, 0), surfaceRect_.left_);
143     int top = std::max(std::max(currentFrameDirtyRegion_.top_, 0), surfaceRect_.top_);
144     int width = std::min(currentFrameDirtyRegion_.GetRight(), surfaceRect_.GetRight()) - left;
145     int height = std::min(currentFrameDirtyRegion_.GetBottom(), surfaceRect_.GetBottom()) - top;
146     // If new region is invalid, currentFrameDirtyRegion_ would be reset as [0, 0, 0, 0]
147     currentFrameDirtyRegion_ = ((width <= 0) || (height <= 0)) ? RectI() : RectI(left, top, width, height);
148 }
149 
GetCurrentFrameDirtyRegion()150 const RectI& RSDirtyRegionManager::GetCurrentFrameDirtyRegion()
151 {
152     return currentFrameDirtyRegion_;
153 }
154 
GetDirtyRegion() const155 const RectI& RSDirtyRegionManager::GetDirtyRegion() const
156 {
157     return dirtyRegion_;
158 }
159 
SetCurrentFrameDirtyRect(const RectI & dirtyRect)160 void RSDirtyRegionManager::SetCurrentFrameDirtyRect(const RectI& dirtyRect)
161 {
162     currentFrameDirtyRegion_ = dirtyRect;
163 }
164 
OnSync(std::shared_ptr<RSDirtyRegionManager> targetManager)165 void RSDirtyRegionManager::OnSync(std::shared_ptr<RSDirtyRegionManager> targetManager)
166 {
167     if (!targetManager) {
168         return;
169     }
170     targetManager->surfaceRect_ = surfaceRect_;
171     targetManager->dirtyRegion_ = dirtyRegion_;
172     targetManager->hwcDirtyRegion_ = hwcDirtyRegion_;
173     targetManager->currentFrameDirtyRegion_ = currentFrameDirtyRegion_;
174     targetManager->debugRect_ = debugRect_;
175     if (RSSystemProperties::GetDirtyRegionDebugType() != DirtyRegionDebugType::DISABLED) {
176         targetManager->dirtySurfaceNodeInfo_ = dirtySurfaceNodeInfo_;
177         targetManager->dirtyCanvasNodeInfo_ = dirtyCanvasNodeInfo_;
178     }
179     // To avoid the impact of the remaining surface dirty on global dirty when nodes are skipped the next frame.
180     Clear();
181 }
182 
GetDirtyRegionFlipWithinSurface() const183 RectI RSDirtyRegionManager::GetDirtyRegionFlipWithinSurface() const
184 {
185     RectI glRect;
186     if (isDirtyRegionAlignedEnable_) {
187         glRect = GetPixelAlignedRect(dirtyRegion_);
188     } else {
189         glRect = dirtyRegion_;
190     }
191 
192     if (!RSSystemProperties::IsUseVulkan()) {
193         // left-top to left-bottom corner(in current surface)
194         glRect.top_ = surfaceRect_.height_ - glRect.top_ - glRect.height_;
195     }
196     return glRect;
197 }
198 
GetRectFlipWithinSurface(const RectI & rect) const199 RectI RSDirtyRegionManager::GetRectFlipWithinSurface(const RectI& rect) const
200 {
201     RectI glRect = rect;
202     if (!RSSystemProperties::IsUseVulkan()) {
203         // left-top to left-bottom corner(in current surface)
204         glRect.top_ = surfaceRect_.height_ - rect.top_ - rect.height_;
205     }
206     return glRect;
207 }
208 
GetLatestDirtyRegion() const209 const RectI& RSDirtyRegionManager::GetLatestDirtyRegion() const
210 {
211     if (historyHead_ < 0) {
212         return dirtyRegion_;
213     }
214     return dirtyHistory_[historyHead_];
215 }
216 
GetPixelAlignedRect(const RectI & rect,int32_t alignedBits)217 RectI RSDirtyRegionManager::GetPixelAlignedRect(const RectI& rect, int32_t alignedBits)
218 {
219     RectI newRect = rect;
220     if (alignedBits > 1) {
221         int32_t left = (rect.left_ / alignedBits) * alignedBits;
222         int32_t top = (rect.top_ / alignedBits) * alignedBits;
223         int32_t width = ((rect.GetRight() + alignedBits - 1) / alignedBits) * alignedBits - left;
224         int32_t height = ((rect.GetBottom() + alignedBits - 1) / alignedBits) * alignedBits - top;
225         newRect = RectI(left, top, width, height);
226     }
227     return newRect;
228 }
229 
Clear()230 void RSDirtyRegionManager::Clear()
231 {
232     dirtyRegion_.Clear();
233     currentFrameDirtyRegion_.Clear();
234     hwcDirtyRegion_.Clear();
235     visitedDirtyRegions_.clear();
236     mergedDirtyRegions_.clear();
237     cacheableFilterRects_.clear();
238     dirtyCanvasNodeInfo_.clear();
239     dirtyCanvasNodeInfo_.resize(DirtyRegionType::TYPE_AMOUNT);
240     dirtySurfaceNodeInfo_.clear();
241     dirtySurfaceNodeInfo_.resize(DirtyRegionType::TYPE_AMOUNT);
242     isDfxTarget_ = false;
243     isFilterCacheRectValid_ = true;
244 }
245 
IsCurrentFrameDirty() const246 bool RSDirtyRegionManager::IsCurrentFrameDirty() const
247 {
248     return !currentFrameDirtyRegion_.IsEmpty() && currentFrameDirtyRegion_ != debugRect_;
249 }
250 
IsDirty() const251 bool RSDirtyRegionManager::IsDirty() const
252 {
253     return !dirtyRegion_.IsEmpty();
254 }
255 
UpdateDirty(bool enableAligned)256 void RSDirtyRegionManager::UpdateDirty(bool enableAligned)
257 {
258     if (enableAligned) {
259         UpdateDirtyByAligned();
260     }
261     // if last frame doesn't align and current frame need align, we should align history ditry regions.
262     if (!isDirtyRegionAlignedEnable_ && enableAligned) {
263         AlignHistory();
264     }
265     isDirtyRegionAlignedEnable_ = enableAligned;
266     PushHistory(currentFrameDirtyRegion_);
267     dirtyRegion_ = MergeHistory(bufferAge_, currentFrameDirtyRegion_);
268 }
269 
UpdateDirtyByAligned(int32_t alignedBits)270 void RSDirtyRegionManager::UpdateDirtyByAligned(int32_t alignedBits)
271 {
272     currentFrameDirtyRegion_ = GetPixelAlignedRect(currentFrameDirtyRegion_, alignedBits);
273 }
274 
UpdateDirtyRegionInfoForDfx(NodeId id,RSRenderNodeType nodeType,DirtyRegionType dirtyType,const RectI & rect)275 void RSDirtyRegionManager::UpdateDirtyRegionInfoForDfx(NodeId id, RSRenderNodeType nodeType,
276     DirtyRegionType dirtyType, const RectI& rect)
277 {
278     if ((dirtyType >= dirtyCanvasNodeInfo_.size()) || (dirtyType >= DirtyRegionType::TYPE_AMOUNT) ||
279         (dirtyType < 0) || (rect.IsEmpty())) {
280         return;
281     }
282     if (nodeType == RSRenderNodeType::CANVAS_NODE) {
283         dirtyCanvasNodeInfo_[dirtyType].emplace(std::make_pair(id, rect));
284     } else if (nodeType == RSRenderNodeType::SURFACE_NODE) {
285         dirtySurfaceNodeInfo_[dirtyType].emplace(std::make_pair(id, rect));
286     }
287 }
288 
GetDirtyRegionInfo(std::map<NodeId,RectI> & target,RSRenderNodeType nodeType,DirtyRegionType dirtyType) const289 void RSDirtyRegionManager::GetDirtyRegionInfo(std::map<NodeId, RectI>& target,
290     RSRenderNodeType nodeType, DirtyRegionType dirtyType) const
291 {
292     target.clear();
293     if ((dirtyType >= dirtyCanvasNodeInfo_.size()) || (dirtyType >= DirtyRegionType::TYPE_AMOUNT) ||
294         (dirtyType < 0)) {
295         return;
296     }
297     if (nodeType == RSRenderNodeType::CANVAS_NODE) {
298         target = dirtyCanvasNodeInfo_[dirtyType];
299     } else if (nodeType == RSRenderNodeType::SURFACE_NODE) {
300         target = dirtySurfaceNodeInfo_[dirtyType];
301     }
302 }
303 
HasOffset()304 bool RSDirtyRegionManager::HasOffset()
305 {
306     return hasOffset_;
307 }
SetOffset(int offsetX,int offsetY)308 void RSDirtyRegionManager::SetOffset(int offsetX, int offsetY)
309 {
310     offsetX_ = offsetX;
311     offsetY_ = offsetY;
312 }
GetOffsetedDirtyRegion() const313 RectI RSDirtyRegionManager::GetOffsetedDirtyRegion() const
314 {
315     return GetDirtyRegion().Offset(offsetX_, offsetY_);
316 }
317 
SetBufferAge(const int age)318 bool RSDirtyRegionManager::SetBufferAge(const int age)
319 {
320     if (age < 0) {
321         bufferAge_ = 0; // reset invalid age
322         return false;
323     }
324     bufferAge_ = static_cast<unsigned int>(age);
325     return true;
326 }
327 
SetSurfaceSize(const int32_t width,const int32_t height)328 bool RSDirtyRegionManager::SetSurfaceSize(const int32_t width, const int32_t height)
329 {
330     if (width < 0 || height < 0) {
331         return false;
332     }
333     surfaceRect_ = RectI(0, 0, width, height);
334     return true;
335 }
336 
MergeSurfaceRect()337 void RSDirtyRegionManager::MergeSurfaceRect()
338 {
339     return MergeDirtyRect(GetSurfaceRect());
340 }
341 
ResetDirtyAsSurfaceSize()342 void RSDirtyRegionManager::ResetDirtyAsSurfaceSize()
343 {
344     dirtyRegion_ = surfaceRect_;
345     currentFrameDirtyRegion_ = surfaceRect_;
346 }
347 
UpdateDebugRegionTypeEnable(DirtyRegionDebugType dirtyDebugType)348 void RSDirtyRegionManager::UpdateDebugRegionTypeEnable(DirtyRegionDebugType dirtyDebugType)
349 {
350     debugRegionEnabled_.assign(DebugRegionType::TYPE_MAX, false);
351     switch (dirtyDebugType) {
352         case DirtyRegionDebugType::CURRENT_SUB:
353             debugRegionEnabled_[DebugRegionType::CURRENT_SUB] = true;
354             break;
355         case DirtyRegionDebugType::CURRENT_WHOLE:
356             debugRegionEnabled_[DebugRegionType::CURRENT_WHOLE] = true;
357             break;
358         case DirtyRegionDebugType::MULTI_HISTORY:
359             debugRegionEnabled_[DebugRegionType::MULTI_HISTORY] = true;
360             break;
361         case DirtyRegionDebugType::CURRENT_SUB_AND_WHOLE:
362             debugRegionEnabled_[DebugRegionType::CURRENT_SUB] = true;
363             debugRegionEnabled_[DebugRegionType::CURRENT_WHOLE] = true;
364             break;
365         case DirtyRegionDebugType::CURRENT_WHOLE_AND_MULTI_HISTORY:
366             debugRegionEnabled_[DebugRegionType::CURRENT_WHOLE] = true;
367             debugRegionEnabled_[DebugRegionType::MULTI_HISTORY] = true;
368             break;
369         case DirtyRegionDebugType::EGL_DAMAGE:
370             debugRegionEnabled_[DebugRegionType::EGL_DAMAGE] = true;
371             break;
372         case DirtyRegionDebugType::DISABLED:
373         default:
374             break;
375     }
376 }
377 
MergeHistory(unsigned int age,RectI rect) const378 RectI RSDirtyRegionManager::MergeHistory(unsigned int age, RectI rect) const
379 {
380     if (age == 0 || age > historySize_) {
381         return surfaceRect_;
382     }
383     // GetHistory(historySize_) is equal to dirtyHistory_[historyHead_] (latest his rect)
384     // therefore, this loop merges rect with age frames' dirtyRect
385     // Attention: should not set i >= 0 for unsigned int!!!!!
386     for (unsigned int i = historySize_; i > historySize_ - age; --i) {
387         auto subRect = GetHistory((i - 1));
388         if (subRect.IsEmpty()) {
389             continue;
390         }
391         if (rect.IsEmpty()) {
392             rect = subRect;
393             continue;
394         }
395         // only join valid his dirty region
396         rect = rect.JoinRect(subRect);
397     }
398     return rect;
399 }
400 
PushHistory(RectI rect)401 void RSDirtyRegionManager::PushHistory(RectI rect)
402 {
403     int next = (historyHead_ + 1) % HISTORY_QUEUE_MAX_SIZE;
404     dirtyHistory_[next] = rect;
405     if (historySize_ < HISTORY_QUEUE_MAX_SIZE) {
406         ++historySize_;
407     }
408     historyHead_ = next;
409 }
410 
GetHistory(unsigned int i) const411 RectI RSDirtyRegionManager::GetHistory(unsigned int i) const
412 {
413     if (i >= HISTORY_QUEUE_MAX_SIZE) {
414         i %= HISTORY_QUEUE_MAX_SIZE;
415     }
416     if (historySize_ > 0) {
417         i = (i + historyHead_) % historySize_;
418     }
419     return dirtyHistory_[i];
420 }
421 
AlignHistory()422 void RSDirtyRegionManager::AlignHistory()
423 {
424     for (uint8_t i = 0; i < dirtyHistory_.size(); i++) {
425         dirtyHistory_[i] = GetPixelAlignedRect(dirtyHistory_[i]);
426     }
427 }
428 
429 } // namespace Rosen
430 } // namespace OHOS
431