• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 "rs_uni_dirty_compute_util.h"
17 
18 #include <cstdint>
19 #include <memory>
20 #include <parameter.h>
21 #include <parameters.h>
22 #include <string>
23 
24 #include "common/rs_optional_trace.h"
25 #include "common/rs_rectangles_merger.h"
26 #include "drawable/dfx/rs_dirty_rects_dfx.h"
27 #include "drawable/rs_logical_display_render_node_drawable.h"
28 #include "drawable/rs_screen_render_node_drawable.h"
29 #include "drawable/rs_surface_render_node_drawable.h"
30 #ifdef RS_ENABLE_OVERLAY_DISPLAY
31 #include "feature/overlay_display/rs_overlay_display_manager.h"
32 #endif
33 #include "feature/uifirst/rs_uifirst_manager.h"
34 #include "info_collection/rs_gpu_dirty_region_collection.h"
35 #include "params/rs_screen_render_params.h"
36 #include "params/rs_surface_render_params.h"
37 #include "pipeline/main_thread/rs_main_thread.h"
38 #include "pipeline/render_thread/rs_base_render_util.h"
39 #include "pipeline/rs_effect_render_node.h"
40 #include "pipeline/rs_render_node.h"
41 #include "pipeline/rs_surface_render_node.h"
42 #include "platform/common/rs_log.h"
43 #include "property/rs_properties.h"
44 #include "rs_trace.h"
45 
46 namespace OHOS {
47 namespace Rosen {
GetCurrentFrameVisibleDirty(DrawableV2::RSScreenRenderNodeDrawable & screenNodeDrawable,ScreenInfo & screenInfo,RSScreenRenderParams & params)48 std::vector<RectI> RSUniDirtyComputeUtil::GetCurrentFrameVisibleDirty(
49     DrawableV2::RSScreenRenderNodeDrawable& screenNodeDrawable, ScreenInfo& screenInfo, RSScreenRenderParams& params)
50 {
51     Occlusion::Region damageRegions;
52     auto& curAllSurfaceDrawables = params.GetAllMainAndLeashSurfaceDrawables();
53     // update all child surfacenode history
54     for (auto it = curAllSurfaceDrawables.rbegin(); it != curAllSurfaceDrawables.rend(); ++it) {
55         auto surfaceNodeDrawable = std::static_pointer_cast<DrawableV2::RSSurfaceRenderNodeDrawable>(*it);
56         if (surfaceNodeDrawable == nullptr) {
57             RS_LOGI("GetCurrentFrameVisibleDirty surfaceNodeDrawable is nullptr");
58             continue;
59         }
60         auto surfaceParams = static_cast<RSSurfaceRenderParams*>(surfaceNodeDrawable->GetRenderParams().get());
61         auto surfaceDirtyManager = surfaceNodeDrawable->GetSyncDirtyManager();
62         if (!surfaceParams || !surfaceDirtyManager) {
63             RS_LOGI("RSUniDirtyComputeUtil::GetCurrentFrameVisibleDirty node(%{public}" PRIu64") params or "
64                 "dirty manager is nullptr", surfaceNodeDrawable->GetId());
65             continue;
66         }
67         if (!surfaceParams->IsLeashOrMainWindow() || surfaceParams->GetDstRect().IsEmpty()) {
68             continue;
69         }
70         // for cross-screen surface, only consider the dirty region on the first display (use global dirty for others).
71         if (surfaceParams->IsFirstLevelCrossNode() &&
72             !RSUniRenderThread::Instance().GetRSRenderThreadParams()->IsFirstVisitCrossNodeDisplay()) {
73             continue;
74         }
75         auto visibleRegion = surfaceParams->GetVisibleRegion();
76         auto surfaceCurrentFrameDirtyRegion = surfaceDirtyManager->GetCurrentFrameDirtyRegion();
77         Occlusion::Region currentFrameDirtyRegion { Occlusion::Rect {
78             surfaceCurrentFrameDirtyRegion.left_, surfaceCurrentFrameDirtyRegion.top_,
79             surfaceCurrentFrameDirtyRegion.GetRight(), surfaceCurrentFrameDirtyRegion.GetBottom() } };
80         Occlusion::Region damageRegion = currentFrameDirtyRegion.And(visibleRegion);
81         damageRegions.OrSelf(damageRegion);
82         auto& surfaceFilterCollector = surfaceDirtyManager->GetFilterCollector();
83         damageRegions.OrSelf(surfaceFilterCollector.GetPureCleanFilterDirtyRegion());
84         surfaceFilterCollector.ClearPureCleanFilterDirtyRegion();
85     }
86     auto screenDirtyManager = screenNodeDrawable.GetSyncDirtyManager();
87     if (screenDirtyManager == nullptr) {
88         return {};
89     }
90     auto& screenFilterCollector = screenDirtyManager->GetFilterCollector();
91     damageRegions.OrSelf(screenFilterCollector.GetPureCleanFilterDirtyRegion());
92     screenFilterCollector.ClearPureCleanFilterDirtyRegion();
93     auto rects = RSUniDirtyComputeUtil::ScreenIntersectDirtyRects(damageRegions, screenInfo);
94     RectI rect = screenDirtyManager->GetDirtyRegionFlipWithinSurface();
95     if (!rect.IsEmpty()) {
96         rects.emplace_back(rect);
97     }
98     return rects;
99 }
100 
ScreenIntersectDirtyRects(const Occlusion::Region & region,const ScreenInfo & screenInfo)101 std::vector<RectI> RSUniDirtyComputeUtil::ScreenIntersectDirtyRects(
102     const Occlusion::Region &region, const ScreenInfo& screenInfo)
103 {
104     const std::vector<Occlusion::Rect>& rects = region.GetRegionRects();
105     std::vector<RectI> retRects;
106     for (const Occlusion::Rect& rect : rects) {
107         // origin transformation
108 #ifdef RS_ENABLE_VK
109         if (RSSystemProperties::GetGpuApiType() == GpuApiType::VULKAN ||
110             RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR) {
111             retRects.emplace_back(RectI(rect.left_, rect.top_,
112                 rect.right_ - rect.left_, rect.bottom_ - rect.top_));
113         } else {
114             retRects.emplace_back(RectI(rect.left_, screenInfo.GetRotatedHeight() - rect.bottom_,
115                 rect.right_ - rect.left_, rect.bottom_ - rect.top_));
116         }
117 #else
118         retRects.emplace_back(RectI(rect.left_, screenInfo.GetRotatedHeight() - rect.bottom_,
119             rect.right_ - rect.left_, rect.bottom_ - rect.top_));
120 #endif
121     }
122     RS_LOGD("ScreenIntersectDirtyRects size %{public}d %{public}s", region.GetSize(), region.GetRegionInfo().c_str());
123     return retRects;
124 }
125 
GetFilpDirtyRects(const std::vector<RectI> & srcRects,const ScreenInfo & screenInfo)126 std::vector<RectI> RSUniDirtyComputeUtil::GetFilpDirtyRects(
127     const std::vector<RectI>& srcRects, const ScreenInfo& screenInfo)
128 {
129 #ifdef RS_ENABLE_VK
130     if (RSSystemProperties::GetGpuApiType() == GpuApiType::VULKAN ||
131         RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR) {
132         return srcRects;
133     }
134 #endif
135 
136     return FilpRects(srcRects, screenInfo);
137 }
138 
FilpRects(const std::vector<RectI> & srcRects,const ScreenInfo & screenInfo)139 std::vector<RectI> RSUniDirtyComputeUtil::FilpRects(const std::vector<RectI>& srcRects, const ScreenInfo& screenInfo)
140 {
141     std::vector<RectI> retRects;
142     for (const RectI& rect : srcRects) {
143         retRects.emplace_back(RectI(rect.left_, screenInfo.GetRotatedHeight() - rect.top_ - rect.height_,
144             rect.width_, rect.height_));
145     }
146     return retRects;
147 }
148 
IntersectRect(const GraphicIRect & first,const GraphicIRect & second)149 GraphicIRect RSUniDirtyComputeUtil::IntersectRect(const GraphicIRect& first, const GraphicIRect& second)
150 {
151     int left = std::max(first.x, second.x);
152     int top = std::max(first.y, second.y);
153     int right = std::min(first.x + first.w, second.x + second.w);
154     int bottom = std::min(first.y + first.h, second.y + second.h);
155     int width = right - left;
156     int height = bottom - top;
157 
158     if (width <= 0 || height <= 0) {
159         return GraphicIRect { 0, 0, 0, 0 };
160     } else {
161         return GraphicIRect { left, top, width, height };
162     }
163 }
164 
DealWithFilterDirtyRegion(Occlusion::Region & damageRegion,Occlusion::Region & drawRegion,DrawableV2::RSScreenRenderNodeDrawable & screenNodeDrawable,const std::optional<Drawing::Matrix> & matrix,bool dirtyAlign)165 void RSUniFilterDirtyComputeUtil::DealWithFilterDirtyRegion(Occlusion::Region& damageRegion,
166     Occlusion::Region& drawRegion, DrawableV2::RSScreenRenderNodeDrawable& screenNodeDrawable,
167     const std::optional<Drawing::Matrix>& matrix, bool dirtyAlign)
168 {
169     dirtyAlignEnabled_ = dirtyAlign;
170     if (UNLIKELY(screenNodeDrawable.GetRenderParams() == nullptr)) {
171         return;
172     }
173     auto screenParams = static_cast<RSScreenRenderParams*>(screenNodeDrawable.GetRenderParams().get());
174     // If screen zoomed, filter cache is globally disabled, thus partial render of filter cache should be disabled.
175     RSFilterDirtyCollector::SetValidCachePartialRender(!screenParams->GetZoomed());
176     auto& surfaceDrawables = screenParams->GetAllMainAndLeashSurfaceDrawables();
177     // Iteratively process filters recorded in screen manager and surface manager, until convergence.
178     bool elementChanged = false;
179     do {
180         elementChanged = false;
181         elementChanged |= DealWithFilterDirtyForScreen(damageRegion, drawRegion, screenNodeDrawable, matrix);
182         elementChanged |= DealWithFilterDirtyForSurface(damageRegion, drawRegion, surfaceDrawables, matrix);
183     } while (elementChanged);
184     ResetFilterInfoStatus(screenNodeDrawable, surfaceDrawables);
185 }
186 
DealWithFilterDirtyForScreen(Occlusion::Region & damageRegion,Occlusion::Region & drawRegion,DrawableV2::RSScreenRenderNodeDrawable & screenNodeDrawable,const std::optional<Drawing::Matrix> & matrix)187 bool RSUniFilterDirtyComputeUtil::DealWithFilterDirtyForScreen(Occlusion::Region& damageRegion,
188     Occlusion::Region& drawRegion, DrawableV2::RSScreenRenderNodeDrawable& screenNodeDrawable,
189     const std::optional<Drawing::Matrix>& matrix)
190 {
191     auto screenDirtyManager = screenNodeDrawable.GetSyncDirtyManager();
192     if (UNLIKELY(screenDirtyManager == nullptr)) {
193         return false;
194     }
195     return CheckMergeFilterDirty(damageRegion, drawRegion, *screenDirtyManager, matrix, std::nullopt);
196 }
197 
DealWithFilterDirtyForSurface(Occlusion::Region & damageRegion,Occlusion::Region & drawRegion,std::vector<DrawableV2::RSRenderNodeDrawableAdapter::SharedPtr> & drawables,const std::optional<Drawing::Matrix> & matrix)198 bool RSUniFilterDirtyComputeUtil::DealWithFilterDirtyForSurface(Occlusion::Region& damageRegion,
199     Occlusion::Region& drawRegion, std::vector<DrawableV2::RSRenderNodeDrawableAdapter::SharedPtr>& drawables,
200     const std::optional<Drawing::Matrix>& matrix)
201 {
202     bool elementChanged = false;
203     for (auto it = drawables.begin(); it != drawables.end(); ++it) {
204         auto surfaceNodeDrawable = std::static_pointer_cast<DrawableV2::RSSurfaceRenderNodeDrawable>(*it);
205         if (UNLIKELY(surfaceNodeDrawable == nullptr)) {
206             RS_LOGI("DealWithFilterDirtyForSurface surfaceNodeDrawable is nullptr");
207             continue;
208         }
209         auto surfaceParams = static_cast<RSSurfaceRenderParams*>(surfaceNodeDrawable->GetRenderParams().get());
210         auto surfaceDirtyManager = surfaceNodeDrawable->GetSyncDirtyManager();
211         if (UNLIKELY(surfaceParams == nullptr || surfaceDirtyManager == nullptr)) {
212             RS_LOGI("DealWithFilterDirtyForSurface surface param or dirty manager is nullptr");
213             continue;
214         }
215         bool skipComputeIfOccluded =
216             surfaceParams->GetVisibleRegion().IsEmpty() || surfaceParams->GetOccludedByFilterCache();
217         if (skipComputeIfOccluded) {
218             RS_OPTIONAL_TRACE_FMT("Skip filter dirty processing for %s occluded.", surfaceParams->GetName().c_str());
219             continue;
220         }
221         elementChanged |= CheckMergeFilterDirty(damageRegion, drawRegion, *surfaceDirtyManager,
222             matrix, surfaceParams->GetVisibleRegion());
223     }
224     return elementChanged;
225 }
226 
CheckMergeFilterDirty(Occlusion::Region & damageRegion,Occlusion::Region & drawRegion,RSDirtyRegionManager & dirtyManager,const std::optional<Drawing::Matrix> & matrix,const std::optional<Occlusion::Region> & visibleRegion)227 bool RSUniFilterDirtyComputeUtil::CheckMergeFilterDirty(Occlusion::Region& damageRegion, Occlusion::Region& drawRegion,
228     RSDirtyRegionManager& dirtyManager, const std::optional<Drawing::Matrix>& matrix,
229     const std::optional<Occlusion::Region>& visibleRegion)
230 {
231     auto& collector = dirtyManager.GetFilterCollector();
232     bool filterCachePartialRender =
233         !dirtyManager.IsCurrentFrameDirty() && RSFilterDirtyCollector::GetValidCachePartialRender();
234     auto addDirtyInIntersect = [&] (FilterDirtyRegionInfo& info) {
235         // case - 0. If this filter satisfied certain partial render conditions, skip it.
236         if (filterCachePartialRender && RSFilterDirtyCollector::GetFilterCacheValidForOcclusion(info.id_)) {
237             RS_TRACE_NAME_FMT("Filter [%" PRIu64 "], partial render enabled, skip dirty expanding.", info.id_);
238             return false;
239         }
240         // case - 1. If this filter is already counted in damage region, skip it.
241         if (info.addToDirty_) {
242             return false;
243         }
244         // case - 2. If this filter is not intersected with drawRegion, skip it.
245         Occlusion::Region intersectRegion = matrix.has_value() ?
246             RSObjAbsGeometry::MapRegion(info.intersectRegion_, matrix.value()) : info.intersectRegion_;
247         intersectRegion = visibleRegion.has_value() ?
248             intersectRegion.And(visibleRegion.value()) : intersectRegion;
249         if (drawRegion.And(intersectRegion).IsEmpty()) {
250             return false;
251         }
252         // case - 3. Add this filter into both damage region (for GPU) and draw region (for RS).
253         RS_OPTIONAL_TRACE_NAME_FMT("Filter [%" PRIu64 "], intersected with draw region: %s, add %s to damage.",
254             info.id_, drawRegion.GetRegionInfo().c_str(), info.filterDirty_.GetRegionInfo().c_str());
255         Occlusion::Region dirtyRegion = matrix.has_value() ?
256             RSObjAbsGeometry::MapRegion(info.filterDirty_, matrix.value()) : info.filterDirty_;
257         Occlusion::Region alignedDirtyRegion = matrix.has_value() ?
258             RSObjAbsGeometry::MapRegion(info.alignedFilterDirty_, matrix.value()) : info.alignedFilterDirty_;
259         collector.AddPureCleanFilterDirtyRegion(dirtyRegion);
260         damageRegion.OrSelf(dirtyRegion);
261         drawRegion.OrSelf(dirtyAlignEnabled_ ? alignedDirtyRegion : dirtyRegion);
262         info.addToDirty_ = true;
263         return true;
264     };
265     // return if any filter is added to damage region and draw region.
266     auto& filterList = collector.GetFilterDirtyRegionInfoList(true);
267     return std::find_if(filterList.begin(), filterList.end(), addDirtyInIntersect) != filterList.end();
268 }
269 
ResetFilterInfoStatus(DrawableV2::RSScreenRenderNodeDrawable & screenNodeDrawable,std::vector<DrawableV2::RSRenderNodeDrawableAdapter::SharedPtr> & surfaceDrawables)270 void RSUniFilterDirtyComputeUtil::ResetFilterInfoStatus(DrawableV2::RSScreenRenderNodeDrawable& screenNodeDrawable,
271     std::vector<DrawableV2::RSRenderNodeDrawableAdapter::SharedPtr>& surfaceDrawables)
272 {
273     auto resetFilterStatus = [] (FilterDirtyRegionInfo& filterInfo) { filterInfo.addToDirty_ = false; };
274     if (auto screenDirtyManager = screenNodeDrawable.GetSyncDirtyManager()) {
275         auto& screenFilterList = screenDirtyManager->GetFilterCollector().GetFilterDirtyRegionInfoList(true);
276         std::for_each(screenFilterList.begin(), screenFilterList.end(), resetFilterStatus);
277     }
278     for (auto it = surfaceDrawables.rbegin(); it != surfaceDrawables.rend(); ++it) {
279         auto surfaceNodeDrawable = std::static_pointer_cast<DrawableV2::RSSurfaceRenderNodeDrawable>(*it);
280         if (UNLIKELY(surfaceNodeDrawable == nullptr)) {
281             RS_LOGI("ResetFilterInfoStatus surfaceNodeDrawable is nullptr");
282             continue;
283         }
284         if (auto surfaceDirtyManager = surfaceNodeDrawable->GetSyncDirtyManager()) {
285             auto& surfaceFilterList = surfaceDirtyManager->GetFilterCollector().GetFilterDirtyRegionInfoList(true);
286             std::for_each(surfaceFilterList.begin(), surfaceFilterList.end(), resetFilterStatus);
287         }
288     }
289     RSFilterDirtyCollector::ResetFilterCacheValidForOcclusion();
290 }
291 
GenerateFilterDirtyRegionInfo(RSRenderNode & filterNode,const std::optional<Occlusion::Region> & preDirty,bool isSurface)292 FilterDirtyRegionInfo RSUniFilterDirtyComputeUtil::GenerateFilterDirtyRegionInfo(
293     RSRenderNode& filterNode, const std::optional<Occlusion::Region>& preDirty, bool isSurface)
294 {
295     bool effectNodeExpandDirty =
296         filterNode.IsInstanceOf<RSEffectRenderNode>() && !filterNode.FirstFrameHasEffectChildren();
297     auto filterRegion = effectNodeExpandDirty ?
298         GetVisibleEffectRegion(filterNode) : Occlusion::Region(Occlusion::Rect(filterNode.GetOldDirtyInSurface()));
299     auto dirtyRegion = effectNodeExpandDirty ?
300         filterRegion.Or(Occlusion::Region(Occlusion::Rect(filterNode.GetFilterRect()))) : filterRegion;
301     if (filterNode.NeedDrawBehindWindow()) {
302         filterRegion = Occlusion::Region(Occlusion::Rect(filterNode.GetFilterRect()));
303         dirtyRegion = filterRegion;
304     }
305     // Subtree dirty region doesn't need to be considered for background filter.
306     auto& filterProperties = filterNode.GetRenderProperties();
307     FilterDirtyRegionInfo filterInfo = {
308         .id_ = filterNode.GetId(),
309         .intersectRegion_ = isSurface ? filterRegion : dirtyRegion,
310         .filterDirty_ = isSurface ? filterRegion : dirtyRegion,
311         .alignedFilterDirty_ = dirtyRegion.GetAlignedRegion(MAX_DIRTY_ALIGNMENT_SIZE),
312         .belowDirty_ = preDirty.value_or(Occlusion::Region()),
313         .isBackgroundFilterClean_ =
314             (filterProperties.GetBackgroundFilter() || filterProperties.GetNeedDrawBehindWindow()) &&
315             !filterNode.IsBackgroundInAppOrNodeSelfDirty()
316     };
317     return filterInfo;
318 }
319 
GetVisibleEffectRegion(RSRenderNode & filterNode)320 Occlusion::Region RSUniFilterDirtyComputeUtil::GetVisibleEffectRegion(RSRenderNode& filterNode)
321 {
322     auto context = filterNode.GetContext().lock();
323     Occlusion::Region childEffectRegion;
324     if (!context) {
325         RS_LOGE("GetVisibleEffectRegion filter node%{public}" PRIu64 " context is nullptr", filterNode.GetId());
326         return childEffectRegion;
327     }
328     for (auto& nodeId : filterNode.GetVisibleEffectChild()) {
329         if (auto& subNode = context->GetNodeMap().GetRenderNode<RSRenderNode>(nodeId)) {
330             childEffectRegion = childEffectRegion.OrSelf(Occlusion::Region(subNode->GetOldDirtyInSurface()));
331         }
332     }
333     return childEffectRegion;
334 }
335 
UpdateVirtualExpandScreenAccumulatedParams(RSScreenRenderParams & params,DrawableV2::RSScreenRenderNodeDrawable & screenNodeDrawable)336 void RSUniDirtyComputeUtil::UpdateVirtualExpandScreenAccumulatedParams(
337     RSScreenRenderParams& params, DrawableV2::RSScreenRenderNodeDrawable& screenNodeDrawable)
338 {
339     // All other factors that may prevent skipping virtual expand screen need to be considered
340     // update accumulated dirty region
341     params.SetAccumulatedDirty(params.GetAccumulatedDirty() ||
342         (screenNodeDrawable.GetSyncDirtyManager()->IsCurrentFrameDirty() || params.GetMainAndLeashSurfaceDirty()));
343 
344     // update accumulated hdr status changed
345     params.SetAccumulatedHdrStatusChanged(params.GetAccumulatedHdrStatusChanged() || params.IsHDRStatusChanged());
346 }
347 
CheckVirtualExpandScreenSkip(RSScreenRenderParams & params,DrawableV2::RSScreenRenderNodeDrawable & screenNodeDrawable)348 bool RSUniDirtyComputeUtil::CheckVirtualExpandScreenSkip(
349     RSScreenRenderParams& params, DrawableV2::RSScreenRenderNodeDrawable& screenNodeDrawable)
350 {
351     // Regardless of whether the current frame is skipped, the state needs to be accumulated
352     if (!RSSystemProperties::GetVirtualExpandScreenSkipEnabled()) {
353         return false;
354     }
355 
356     const auto& displayDrawables = params.GetDisplayDrawables();
357     for (const auto& drawable : displayDrawables) {
358         const auto& displayDrawable = static_cast<DrawableV2::RSLogicalDisplayRenderNodeDrawable*>(drawable.get());
359         const auto& displayParams = static_cast<RSLogicalDisplayRenderParams*>(drawable->GetRenderParams().get());
360         if (UNLIKELY(displayDrawable == nullptr || displayParams == nullptr)) {
361             continue;
362         }
363         if (displayDrawable->GetSpecialLayerType(*displayParams) != NO_SPECIAL_LAYER) {
364             RS_TRACE_NAME("CheckVirtualExpandScreenSkip has special layer can not skip");
365             return false;
366         }
367     }
368     RS_TRACE_NAME_FMT("CheckVirtualExpandScreenSkip isAccumulatedDirty: %d, isAccumulatedHdrStatusChanged: %d",
369         params.GetAccumulatedDirty(), params.GetAccumulatedHdrStatusChanged());
370     return !params.GetAccumulatedDirty() && !params.GetAccumulatedHdrStatusChanged();
371 }
372 } // namespace Rosen
373 } // namespace OHOS