• 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 namespace OHOS {
19 namespace Rosen {
RSDirtyRegionManager()20 RSDirtyRegionManager::RSDirtyRegionManager()
21 {
22     dirtyHistory_.resize(HISTORY_QUEUE_MAX_SIZE);
23     debugRegionEnabled_.resize(DebugRegionType::TYPE_MAX);
24 }
25 
RSDirtyRegionManager(bool isDisplayDirtyManager)26 RSDirtyRegionManager::RSDirtyRegionManager(bool isDisplayDirtyManager)
27 {
28     dirtyHistory_.resize(HISTORY_QUEUE_MAX_SIZE);
29     debugRegionEnabled_.resize(DebugRegionType::TYPE_MAX);
30     isDisplayDirtyManager_ = isDisplayDirtyManager;
31 }
32 
MergeDirtyRect(const RectI & rect)33 void RSDirtyRegionManager::MergeDirtyRect(const RectI& rect)
34 {
35     if (rect.IsEmpty()) {
36         return;
37     }
38     if (currentFrameDirtyRegion_.IsEmpty()) {
39         currentFrameDirtyRegion_ = rect;
40     } else {
41         currentFrameDirtyRegion_ = currentFrameDirtyRegion_.JoinRect(rect);
42     }
43     if (isDisplayDirtyManager_) {
44         mergedDirtyRegions_.emplace_back(rect);
45     }
46 }
47 
MergeDirtyRectAfterMergeHistory(const RectI & rect)48 void RSDirtyRegionManager::MergeDirtyRectAfterMergeHistory(const RectI& rect)
49 {
50     if (rect.IsEmpty()) {
51         return;
52     }
53     if (dirtyRegion_.IsEmpty()) {
54         dirtyRegion_ = rect;
55     } else {
56         dirtyRegion_ = dirtyRegion_.JoinRect(rect);
57     }
58 }
59 
UpdateVisitedDirtyRects(const std::vector<RectI> & rects)60 void RSDirtyRegionManager::UpdateVisitedDirtyRects(const std::vector<RectI>& rects)
61 {
62     if (rects.empty()) {
63         visitedDirtyRegions_.clear();
64         return;
65     }
66     visitedDirtyRegions_ = rects;
67 }
68 
GetIntersectedVisitedDirtyRect(const RectI & absRect) const69 RectI RSDirtyRegionManager::GetIntersectedVisitedDirtyRect(const RectI& absRect) const
70 {
71     RectI belowDirty = currentFrameDirtyRegion_;
72     for (const auto& subDirty : visitedDirtyRegions_) {
73         if (absRect.IsInsideOf(belowDirty)) {
74             return belowDirty;
75         }
76         belowDirty = belowDirty.JoinRect(subDirty.IntersectRect(absRect));
77     }
78     return belowDirty;
79 }
80 
UpdateCacheableFilterRect(const RectI & rect)81 void RSDirtyRegionManager::UpdateCacheableFilterRect(const RectI& rect)
82 {
83     if (rect.IsEmpty()) {
84         return;
85     }
86     cacheableFilterRects_.emplace_back(rect);
87 }
88 
IfCacheableFilterRectFullyCover(const RectI & targetRect)89 bool RSDirtyRegionManager::IfCacheableFilterRectFullyCover(const RectI& targetRect)
90 {
91     for (auto rect : cacheableFilterRects_) {
92         if (targetRect.IsInsideOf(rect)) {
93             return true;
94         }
95     }
96     return false;
97 }
98 
IntersectDirtyRect(const RectI & rect)99 void RSDirtyRegionManager::IntersectDirtyRect(const RectI& rect)
100 {
101     currentFrameDirtyRegion_ = currentFrameDirtyRegion_.IntersectRect(rect);
102 }
103 
ClipDirtyRectWithinSurface()104 void RSDirtyRegionManager::ClipDirtyRectWithinSurface()
105 {
106     int left = std::max(std::max(currentFrameDirtyRegion_.left_, 0), surfaceRect_.left_);
107     int top = std::max(std::max(currentFrameDirtyRegion_.top_, 0), surfaceRect_.top_);
108     int width = std::min(currentFrameDirtyRegion_.GetRight(), surfaceRect_.GetRight()) - left;
109     int height = std::min(currentFrameDirtyRegion_.GetBottom(), surfaceRect_.GetBottom()) - top;
110     // If new region is invalid, currentFrameDirtyRegion_ would be reset as [0, 0, 0, 0]
111     currentFrameDirtyRegion_ = ((width <= 0) || (height <= 0)) ? RectI() : RectI(left, top, width, height);
112 }
113 
GetCurrentFrameDirtyRegion()114 const RectI& RSDirtyRegionManager::GetCurrentFrameDirtyRegion()
115 {
116     return currentFrameDirtyRegion_;
117 }
118 
GetDirtyRegion() const119 const RectI& RSDirtyRegionManager::GetDirtyRegion() const
120 {
121     return dirtyRegion_;
122 }
123 
GetDirtyRegionFlipWithinSurface() const124 RectI RSDirtyRegionManager::GetDirtyRegionFlipWithinSurface() const
125 {
126     RectI glRect;
127     if (isDirtyRegionAlignedEnable_) {
128         glRect = GetPixelAlignedRect(dirtyRegion_);
129     } else {
130         glRect = dirtyRegion_;
131     }
132 
133     if (RSSystemProperties::GetGpuApiType() != GpuApiType::VULKAN &&
134         RSSystemProperties::GetGpuApiType() != GpuApiType::DDGR) {
135         // left-top to left-bottom corner(in current surface)
136         glRect.top_ = surfaceRect_.height_ - glRect.top_ - glRect.height_;
137     }
138     return glRect;
139 }
140 
GetRectFlipWithinSurface(const RectI & rect) const141 RectI RSDirtyRegionManager::GetRectFlipWithinSurface(const RectI& rect) const
142 {
143     RectI glRect = rect;
144 
145     if (RSSystemProperties::GetGpuApiType() != GpuApiType::VULKAN &&
146         RSSystemProperties::GetGpuApiType() != GpuApiType::DDGR) {
147         // left-top to left-bottom corner(in current surface)
148         glRect.top_ = surfaceRect_.height_ - rect.top_ - rect.height_;
149     }
150     return glRect;
151 }
152 
GetLatestDirtyRegion() const153 const RectI& RSDirtyRegionManager::GetLatestDirtyRegion() const
154 {
155     if (historyHead_ < 0) {
156         return dirtyRegion_;
157     }
158     return dirtyHistory_[historyHead_];
159 }
160 
GetPixelAlignedRect(const RectI & rect,int32_t alignedBits)161 RectI RSDirtyRegionManager::GetPixelAlignedRect(const RectI& rect, int32_t alignedBits)
162 {
163     RectI newRect = rect;
164     if (alignedBits > 1) {
165         int32_t left = (rect.left_ / alignedBits) * alignedBits;
166         int32_t top = (rect.top_ / alignedBits) * alignedBits;
167         int32_t width = ((rect.GetRight() + alignedBits - 1) / alignedBits) * alignedBits - left;
168         int32_t height = ((rect.GetBottom() + alignedBits - 1) / alignedBits) * alignedBits - top;
169         newRect = RectI(left, top, width, height);
170     }
171     return newRect;
172 }
173 
Clear()174 void RSDirtyRegionManager::Clear()
175 {
176     dirtyRegion_.Clear();
177     currentFrameDirtyRegion_.Clear();
178     visitedDirtyRegions_.clear();
179     mergedDirtyRegions_.clear();
180     cacheableFilterRects_.clear();
181     dirtyCanvasNodeInfo_.clear();
182     dirtyCanvasNodeInfo_.resize(DirtyRegionType::TYPE_AMOUNT);
183     dirtySurfaceNodeInfo_.clear();
184     dirtySurfaceNodeInfo_.resize(DirtyRegionType::TYPE_AMOUNT);
185     isDfxTarget_ = false;
186     isFilterCacheRectValid_ = true;
187 }
188 
IsCurrentFrameDirty() const189 bool RSDirtyRegionManager::IsCurrentFrameDirty() const
190 {
191     return !currentFrameDirtyRegion_.IsEmpty();
192 }
193 
IsDirty() const194 bool RSDirtyRegionManager::IsDirty() const
195 {
196     return !dirtyRegion_.IsEmpty();
197 }
198 
UpdateDirty(bool enableAligned)199 void RSDirtyRegionManager::UpdateDirty(bool enableAligned)
200 {
201     if (enableAligned) {
202         UpdateDirtyByAligned();
203     }
204     // if last frame doesn't align and current frame need align, we should align history ditry regions.
205     if (!isDirtyRegionAlignedEnable_ && enableAligned) {
206         AlignHistory();
207     }
208     isDirtyRegionAlignedEnable_ = enableAligned;
209     PushHistory(currentFrameDirtyRegion_);
210     dirtyRegion_ = MergeHistory(bufferAge_, currentFrameDirtyRegion_);
211 }
212 
UpdateDirtyByAligned(int32_t alignedBits)213 void RSDirtyRegionManager::UpdateDirtyByAligned(int32_t alignedBits)
214 {
215     currentFrameDirtyRegion_ = GetPixelAlignedRect(currentFrameDirtyRegion_, alignedBits);
216 }
217 
UpdateDirtyRegionInfoForDfx(NodeId id,RSRenderNodeType nodeType,DirtyRegionType dirtyType,const RectI & rect)218 void RSDirtyRegionManager::UpdateDirtyRegionInfoForDfx(NodeId id, RSRenderNodeType nodeType,
219     DirtyRegionType dirtyType, const RectI& rect)
220 {
221     if (dirtyType >= DirtyRegionType::TYPE_AMOUNT || dirtyType < 0 || rect.IsEmpty()) {
222         return;
223     }
224     if (nodeType == RSRenderNodeType::CANVAS_NODE) {
225         dirtyCanvasNodeInfo_[dirtyType].emplace(std::make_pair(id, rect));
226     } else if (nodeType == RSRenderNodeType::SURFACE_NODE) {
227         dirtySurfaceNodeInfo_[dirtyType].emplace(std::make_pair(id, rect));
228     }
229 }
230 
GetDirtyRegionInfo(std::map<NodeId,RectI> & target,RSRenderNodeType nodeType,DirtyRegionType dirtyType) const231 void RSDirtyRegionManager::GetDirtyRegionInfo(std::map<NodeId, RectI>& target,
232     RSRenderNodeType nodeType, DirtyRegionType dirtyType) const
233 {
234     target.clear();
235     if (dirtyType >= DirtyRegionType::TYPE_AMOUNT || dirtyType < 0) {
236         return;
237     }
238     if (nodeType == RSRenderNodeType::CANVAS_NODE) {
239         target = dirtyCanvasNodeInfo_[dirtyType];
240     } else if (nodeType == RSRenderNodeType::SURFACE_NODE) {
241         target = dirtySurfaceNodeInfo_[dirtyType];
242     }
243 }
244 
HasOffset()245 bool RSDirtyRegionManager::HasOffset()
246 {
247     return hasOffset_;
248 }
SetOffset(int offsetX,int offsetY)249 void RSDirtyRegionManager::SetOffset(int offsetX, int offsetY)
250 {
251     offsetX_ = offsetX;
252     offsetY_ = offsetY;
253 }
GetOffsetedDirtyRegion() const254 RectI RSDirtyRegionManager::GetOffsetedDirtyRegion() const
255 {
256     return GetDirtyRegion().Offset(offsetX_, offsetY_);
257 }
258 
SetBufferAge(const int age)259 bool RSDirtyRegionManager::SetBufferAge(const int age)
260 {
261     if (age < 0) {
262         bufferAge_ = 0; // reset invalid age
263         return false;
264     }
265     bufferAge_ = static_cast<unsigned int>(age);
266     return true;
267 }
268 
SetSurfaceSize(const int32_t width,const int32_t height)269 bool RSDirtyRegionManager::SetSurfaceSize(const int32_t width, const int32_t height)
270 {
271     if (width < 0 || height < 0) {
272         return false;
273     }
274     surfaceRect_ = RectI(0, 0, width, height);
275     return true;
276 }
277 
MergeSurfaceRect()278 void RSDirtyRegionManager::MergeSurfaceRect()
279 {
280     return MergeDirtyRect(GetSurfaceRect());
281 }
282 
ResetDirtyAsSurfaceSize()283 void RSDirtyRegionManager::ResetDirtyAsSurfaceSize()
284 {
285     dirtyRegion_ = surfaceRect_;
286 }
287 
UpdateDebugRegionTypeEnable(DirtyRegionDebugType dirtyDebugType)288 void RSDirtyRegionManager::UpdateDebugRegionTypeEnable(DirtyRegionDebugType dirtyDebugType)
289 {
290     debugRegionEnabled_.assign(DebugRegionType::TYPE_MAX, false);
291     switch (dirtyDebugType) {
292         case DirtyRegionDebugType::CURRENT_SUB:
293             debugRegionEnabled_[DebugRegionType::CURRENT_SUB] = true;
294             break;
295         case DirtyRegionDebugType::CURRENT_WHOLE:
296             debugRegionEnabled_[DebugRegionType::CURRENT_WHOLE] = true;
297             break;
298         case DirtyRegionDebugType::MULTI_HISTORY:
299             debugRegionEnabled_[DebugRegionType::MULTI_HISTORY] = true;
300             break;
301         case DirtyRegionDebugType::CURRENT_SUB_AND_WHOLE:
302             debugRegionEnabled_[DebugRegionType::CURRENT_SUB] = true;
303             debugRegionEnabled_[DebugRegionType::CURRENT_WHOLE] = true;
304             break;
305         case DirtyRegionDebugType::CURRENT_WHOLE_AND_MULTI_HISTORY:
306             debugRegionEnabled_[DebugRegionType::CURRENT_WHOLE] = true;
307             debugRegionEnabled_[DebugRegionType::MULTI_HISTORY] = true;
308             break;
309         case DirtyRegionDebugType::EGL_DAMAGE:
310             debugRegionEnabled_[DebugRegionType::EGL_DAMAGE] = true;
311             break;
312         case DirtyRegionDebugType::DISABLED:
313         default:
314             break;
315     }
316 }
317 
MergeHistory(unsigned int age,RectI rect) const318 RectI RSDirtyRegionManager::MergeHistory(unsigned int age, RectI rect) const
319 {
320     if (age == 0 || age > historySize_) {
321         return surfaceRect_;
322     }
323     // GetHistory(historySize_) is equal to dirtyHistory_[historyHead_] (latest his rect)
324     // therefore, this loop merges rect with age frames' dirtyRect
325     // Attention: should not set i >= 0 for unsigned int!!!!!
326     for (unsigned int i = historySize_; i > historySize_ - age; --i) {
327         auto subRect = GetHistory((i - 1));
328         if (subRect.IsEmpty()) {
329             continue;
330         }
331         if (rect.IsEmpty()) {
332             rect = subRect;
333             continue;
334         }
335         // only join valid his dirty region
336         rect = rect.JoinRect(subRect);
337     }
338     return rect;
339 }
340 
PushHistory(RectI rect)341 void RSDirtyRegionManager::PushHistory(RectI rect)
342 {
343     int next = (historyHead_ + 1) % HISTORY_QUEUE_MAX_SIZE;
344     dirtyHistory_[next] = rect;
345     if (historySize_ < HISTORY_QUEUE_MAX_SIZE) {
346         ++historySize_;
347     }
348     historyHead_ = next;
349 }
350 
GetHistory(unsigned int i) const351 RectI RSDirtyRegionManager::GetHistory(unsigned int i) const
352 {
353     if (i >= HISTORY_QUEUE_MAX_SIZE) {
354         i %= HISTORY_QUEUE_MAX_SIZE;
355     }
356     if (historySize_ > 0) {
357         i = (i + historyHead_) % historySize_;
358     }
359     return dirtyHistory_[i];
360 }
361 
AlignHistory()362 void RSDirtyRegionManager::AlignHistory()
363 {
364     for (uint8_t i = 0; i < dirtyHistory_.size(); i++) {
365         dirtyHistory_[i] = GetPixelAlignedRect(dirtyHistory_[i]);
366     }
367 }
368 
369 } // namespace Rosen
370 } // namespace OHOS
371