• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     auto clipRect = activeSurfaceRect_.IsEmpty() ? surfaceRect_ : activeSurfaceRect_;
143     int left = std::max(std::max(currentFrameDirtyRegion_.left_, 0), clipRect.left_);
144     int top = std::max(std::max(currentFrameDirtyRegion_.top_, 0), clipRect.top_);
145     int width = std::min(currentFrameDirtyRegion_.GetRight(), clipRect.GetRight()) - left;
146     int height = std::min(currentFrameDirtyRegion_.GetBottom(), clipRect.GetBottom()) - top;
147     // If new region is invalid, currentFrameDirtyRegion_ would be reset as [0, 0, 0, 0]
148     currentFrameDirtyRegion_ = ((width <= 0) || (height <= 0)) ? RectI() : RectI(left, top, width, height);
149 }
150 
GetCurrentFrameDirtyRegion()151 const RectI& RSDirtyRegionManager::GetCurrentFrameDirtyRegion()
152 {
153     return currentFrameDirtyRegion_;
154 }
155 
GetDirtyRegion() const156 const RectI& RSDirtyRegionManager::GetDirtyRegion() const
157 {
158     return dirtyRegion_;
159 }
160 
SetCurrentFrameDirtyRect(const RectI & dirtyRect)161 void RSDirtyRegionManager::SetCurrentFrameDirtyRect(const RectI& dirtyRect)
162 {
163     currentFrameDirtyRegion_ = dirtyRect;
164 }
165 
OnSync(std::shared_ptr<RSDirtyRegionManager> targetManager)166 void RSDirtyRegionManager::OnSync(std::shared_ptr<RSDirtyRegionManager> targetManager)
167 {
168     if (!targetManager) {
169         return;
170     }
171     targetManager->lastActiveSurfaceRect_ = lastActiveSurfaceRect_;
172     targetManager->activeSurfaceRect_ = activeSurfaceRect_;
173     targetManager->surfaceRect_ = surfaceRect_;
174     targetManager->dirtyRegion_ = dirtyRegion_;
175     targetManager->hwcDirtyRegion_ = hwcDirtyRegion_;
176     targetManager->currentFrameDirtyRegion_ = currentFrameDirtyRegion_;
177     targetManager->debugRect_ = debugRect_;
178     if (RSSystemProperties::GetDirtyRegionDebugType() != DirtyRegionDebugType::DISABLED) {
179         targetManager->dirtySurfaceNodeInfo_ = dirtySurfaceNodeInfo_;
180         targetManager->dirtyCanvasNodeInfo_ = dirtyCanvasNodeInfo_;
181     }
182     // To avoid the impact of the remaining surface dirty on global dirty when nodes are skipped the next frame.
183     Clear();
184 }
185 
GetDirtyRegionFlipWithinSurface() const186 RectI RSDirtyRegionManager::GetDirtyRegionFlipWithinSurface() const
187 {
188     RectI glRect;
189     if (isDirtyRegionAlignedEnable_) {
190         glRect = GetPixelAlignedRect(dirtyRegion_);
191     } else {
192         glRect = dirtyRegion_;
193     }
194 
195     if (!RSSystemProperties::IsUseVulkan()) {
196         // left-top to left-bottom corner(in current surface)
197         glRect.top_ = surfaceRect_.height_ - glRect.top_ - glRect.height_;
198     }
199     return glRect;
200 }
201 
GetRectFlipWithinSurface(const RectI & rect) const202 RectI RSDirtyRegionManager::GetRectFlipWithinSurface(const RectI& rect) const
203 {
204     RectI glRect = rect;
205     if (!RSSystemProperties::IsUseVulkan()) {
206         // left-top to left-bottom corner(in current surface)
207         glRect.top_ = surfaceRect_.height_ - rect.top_ - rect.height_;
208     }
209     return glRect;
210 }
211 
GetLatestDirtyRegion() const212 const RectI& RSDirtyRegionManager::GetLatestDirtyRegion() const
213 {
214     if (historyHead_ < 0) {
215         return dirtyRegion_;
216     }
217     return dirtyHistory_[historyHead_];
218 }
219 
GetPixelAlignedRect(const RectI & rect,int32_t alignedBits)220 RectI RSDirtyRegionManager::GetPixelAlignedRect(const RectI& rect, int32_t alignedBits)
221 {
222     RectI newRect = rect;
223     if (alignedBits > 1) {
224         int32_t left = (rect.left_ / alignedBits) * alignedBits;
225         int32_t top = (rect.top_ / alignedBits) * alignedBits;
226         int32_t width = ((rect.GetRight() + alignedBits - 1) / alignedBits) * alignedBits - left;
227         int32_t height = ((rect.GetBottom() + alignedBits - 1) / alignedBits) * alignedBits - top;
228         newRect = RectI(left, top, width, height);
229     }
230     return newRect;
231 }
232 
Clear()233 void RSDirtyRegionManager::Clear()
234 {
235     dirtyRegion_.Clear();
236     currentFrameDirtyRegion_.Clear();
237     hwcDirtyRegion_.Clear();
238     visitedDirtyRegions_.clear();
239     mergedDirtyRegions_.clear();
240     cacheableFilterRects_.clear();
241     dirtyCanvasNodeInfo_.clear();
242     dirtyCanvasNodeInfo_.resize(DirtyRegionType::TYPE_AMOUNT);
243     dirtySurfaceNodeInfo_.clear();
244     dirtySurfaceNodeInfo_.resize(DirtyRegionType::TYPE_AMOUNT);
245     isDfxTarget_ = false;
246     isFilterCacheRectValid_ = true;
247 }
248 
IsCurrentFrameDirty() const249 bool RSDirtyRegionManager::IsCurrentFrameDirty() const
250 {
251     return !currentFrameDirtyRegion_.IsEmpty() && currentFrameDirtyRegion_ != debugRect_;
252 }
253 
IsDirty() const254 bool RSDirtyRegionManager::IsDirty() const
255 {
256     return !dirtyRegion_.IsEmpty();
257 }
258 
UpdateDirty(bool enableAligned)259 void RSDirtyRegionManager::UpdateDirty(bool enableAligned)
260 {
261     if (enableAligned) {
262         UpdateDirtyByAligned();
263     }
264     // if last frame doesn't align and current frame need align, we should align history ditry regions.
265     if (!isDirtyRegionAlignedEnable_ && enableAligned) {
266         AlignHistory();
267     }
268     isDirtyRegionAlignedEnable_ = enableAligned;
269     PushHistory(currentFrameDirtyRegion_);
270     dirtyRegion_ = MergeHistory(bufferAge_, currentFrameDirtyRegion_);
271 }
272 
UpdateDirtyByAligned(int32_t alignedBits)273 void RSDirtyRegionManager::UpdateDirtyByAligned(int32_t alignedBits)
274 {
275     currentFrameDirtyRegion_ = GetPixelAlignedRect(currentFrameDirtyRegion_, alignedBits);
276 }
277 
UpdateDirtyRegionInfoForDfx(NodeId id,RSRenderNodeType nodeType,DirtyRegionType dirtyType,const RectI & rect)278 void RSDirtyRegionManager::UpdateDirtyRegionInfoForDfx(NodeId id, RSRenderNodeType nodeType,
279     DirtyRegionType dirtyType, const RectI& rect)
280 {
281     if ((dirtyType >= dirtyCanvasNodeInfo_.size()) || (dirtyType >= DirtyRegionType::TYPE_AMOUNT) ||
282         (dirtyType < 0) || (rect.IsEmpty())) {
283         return;
284     }
285     if (nodeType == RSRenderNodeType::CANVAS_NODE) {
286         dirtyCanvasNodeInfo_[dirtyType].emplace(std::make_pair(id, rect));
287     } else if (nodeType == RSRenderNodeType::SURFACE_NODE) {
288         dirtySurfaceNodeInfo_[dirtyType].emplace(std::make_pair(id, rect));
289     }
290 }
291 
GetDirtyRegionInfo(std::map<NodeId,RectI> & target,RSRenderNodeType nodeType,DirtyRegionType dirtyType) const292 void RSDirtyRegionManager::GetDirtyRegionInfo(std::map<NodeId, RectI>& target,
293     RSRenderNodeType nodeType, DirtyRegionType dirtyType) const
294 {
295     target.clear();
296     if ((dirtyType >= dirtyCanvasNodeInfo_.size()) || (dirtyType >= DirtyRegionType::TYPE_AMOUNT) ||
297         (dirtyType < 0)) {
298         return;
299     }
300     if (nodeType == RSRenderNodeType::CANVAS_NODE) {
301         target = dirtyCanvasNodeInfo_[dirtyType];
302     } else if (nodeType == RSRenderNodeType::SURFACE_NODE) {
303         target = dirtySurfaceNodeInfo_[dirtyType];
304     }
305 }
306 
HasOffset()307 bool RSDirtyRegionManager::HasOffset()
308 {
309     return hasOffset_;
310 }
SetOffset(int offsetX,int offsetY)311 void RSDirtyRegionManager::SetOffset(int offsetX, int offsetY)
312 {
313     offsetX_ = offsetX;
314     offsetY_ = offsetY;
315 }
GetOffsetedDirtyRegion() const316 RectI RSDirtyRegionManager::GetOffsetedDirtyRegion() const
317 {
318     return GetDirtyRegion().Offset(offsetX_, offsetY_);
319 }
320 
SetBufferAge(const int age)321 bool RSDirtyRegionManager::SetBufferAge(const int age)
322 {
323     if (age < 0) {
324         bufferAge_ = 0; // reset invalid age
325         return false;
326     }
327     bufferAge_ = static_cast<unsigned int>(age);
328     return true;
329 }
330 
MergeSurfaceRect()331 void RSDirtyRegionManager::MergeSurfaceRect()
332 {
333     return MergeDirtyRect(activeSurfaceRect_.IsEmpty() ? surfaceRect_ : activeSurfaceRect_);
334 }
335 
ResetDirtyAsSurfaceSize()336 void RSDirtyRegionManager::ResetDirtyAsSurfaceSize()
337 {
338     const auto& rect = activeSurfaceRect_.IsEmpty() ? surfaceRect_ : activeSurfaceRect_;
339     dirtyRegion_ = rect;
340     currentFrameDirtyRegion_ = rect;
341 }
342 
UpdateDebugRegionTypeEnable(DirtyRegionDebugType dirtyDebugType)343 void RSDirtyRegionManager::UpdateDebugRegionTypeEnable(DirtyRegionDebugType dirtyDebugType)
344 {
345     debugRegionEnabled_.assign(DebugRegionType::TYPE_MAX, false);
346     switch (dirtyDebugType) {
347         case DirtyRegionDebugType::CURRENT_SUB:
348             debugRegionEnabled_[DebugRegionType::CURRENT_SUB] = true;
349             break;
350         case DirtyRegionDebugType::CURRENT_WHOLE:
351             debugRegionEnabled_[DebugRegionType::CURRENT_WHOLE] = true;
352             break;
353         case DirtyRegionDebugType::MULTI_HISTORY:
354             debugRegionEnabled_[DebugRegionType::MULTI_HISTORY] = true;
355             break;
356         case DirtyRegionDebugType::CURRENT_SUB_AND_WHOLE:
357             debugRegionEnabled_[DebugRegionType::CURRENT_SUB] = true;
358             debugRegionEnabled_[DebugRegionType::CURRENT_WHOLE] = true;
359             break;
360         case DirtyRegionDebugType::CURRENT_WHOLE_AND_MULTI_HISTORY:
361             debugRegionEnabled_[DebugRegionType::CURRENT_WHOLE] = true;
362             debugRegionEnabled_[DebugRegionType::MULTI_HISTORY] = true;
363             break;
364         case DirtyRegionDebugType::EGL_DAMAGE:
365             debugRegionEnabled_[DebugRegionType::EGL_DAMAGE] = true;
366             break;
367         case DirtyRegionDebugType::DISABLED:
368         default:
369             break;
370     }
371 }
372 
MergeHistory(unsigned int age,RectI rect) const373 RectI RSDirtyRegionManager::MergeHistory(unsigned int age, RectI rect) const
374 {
375     if (age == 0 || age > historySize_) {
376         rect = rect.JoinRect(surfaceRect_);
377         age = historySize_;
378     }
379     // GetHistory(historySize_) is equal to dirtyHistory_[historyHead_] (latest his rect)
380     // therefore, this loop merges rect with age frames' dirtyRect
381     // Attention: should not set i >= 0 for unsigned int!!!!!
382     for (unsigned int i = historySize_; i > historySize_ - age; --i) {
383         auto subRect = GetHistory((i - 1));
384         if (subRect.IsEmpty()) {
385             continue;
386         }
387         if (rect.IsEmpty()) {
388             rect = subRect;
389             continue;
390         }
391         // only join valid his dirty region
392         rect = rect.JoinRect(subRect);
393     }
394     return rect;
395 }
396 
PushHistory(RectI rect)397 void RSDirtyRegionManager::PushHistory(RectI rect)
398 {
399     int next = (historyHead_ + 1) % HISTORY_QUEUE_MAX_SIZE;
400     dirtyHistory_[next] = rect;
401     if (historySize_ < HISTORY_QUEUE_MAX_SIZE) {
402         ++historySize_;
403     }
404     historyHead_ = next;
405 }
406 
GetHistory(unsigned int i) const407 RectI RSDirtyRegionManager::GetHistory(unsigned int i) const
408 {
409     if (i >= HISTORY_QUEUE_MAX_SIZE) {
410         i %= HISTORY_QUEUE_MAX_SIZE;
411     }
412     if (historySize_ > 0) {
413         i = (i + historyHead_) % historySize_;
414     }
415     return dirtyHistory_[i];
416 }
417 
AlignHistory()418 void RSDirtyRegionManager::AlignHistory()
419 {
420     for (uint8_t i = 0; i < dirtyHistory_.size(); i++) {
421         dirtyHistory_[i] = GetPixelAlignedRect(dirtyHistory_[i]);
422     }
423 }
424 
425 } // namespace Rosen
426 } // namespace OHOS
427