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