• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024-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 "drawable/rs_render_node_drawable.h"
17 
18 #include "common/rs_common_def.h"
19 #include "common/rs_optional_trace.h"
20 #include "display_engine/rs_luminance_control.h"
21 #include "feature/uifirst/rs_uifirst_manager.h"
22 #include "gfx/performance/rs_perfmonitor_reporter.h"
23 #include "include/gpu/vk/GrVulkanTrackerInterface.h"
24 #include "pipeline/render_thread/rs_uni_render_thread.h"
25 #include "pipeline/render_thread/rs_uni_render_util.h"
26 #include "pipeline/rs_paint_filter_canvas.h"
27 #include "pipeline/rs_task_dispatcher.h"
28 #include "platform/common/rs_log.h"
29 #include "rs_trace.h"
30 #include "system/rs_system_parameters.h"
31 #include "string_utils.h"
32 #include "pipeline/main_thread/rs_main_thread.h"
33 #ifdef SUBTREE_PARALLEL_ENABLE
34 #include "rs_parallel_manager.h"
35 #include "rs_parallel_misc.h"
36 #endif
37 
38 namespace OHOS::Rosen::DrawableV2 {
39 #ifdef RS_ENABLE_VK
40 #ifdef USE_M133_SKIA
41 #include "include/gpu/ganesh/vk/GrVkBackendSurface.h"
42 #else
43 #include "include/gpu/GrBackendSurface.h"
44 #endif
45 
46 #include "platform/ohos/backend/native_buffer_utils.h"
47 #include "platform/ohos/backend/rs_vulkan_context.h"
48 #endif
49 RSRenderNodeDrawable::Registrar RSRenderNodeDrawable::instance_;
50 thread_local bool RSRenderNodeDrawable::drawBlurForCache_ = false;
51 thread_local bool RSRenderNodeDrawable::isOpDropped_ = true;
52 thread_local bool RSRenderNodeDrawable::occlusionCullingEnabled_ = false;
53 thread_local bool RSRenderNodeDrawable::isOffScreenWithClipHole_ = false;
54 
55 namespace {
56 constexpr int32_t DRAWING_CACHE_MAX_UPDATE_TIME = 3;
57 constexpr float CACHE_FILL_ALPHA = 0.2f;
58 constexpr float CACHE_UPDATE_FILL_ALPHA = 0.8f;
59 constexpr int TRACE_LEVEL_PRINT_NODEID = 6;
60 }
RSRenderNodeDrawable(std::shared_ptr<const RSRenderNode> && node)61 RSRenderNodeDrawable::RSRenderNodeDrawable(std::shared_ptr<const RSRenderNode>&& node)
62     : RSRenderNodeDrawableAdapter(std::move(node))
63 {
64     auto task = [this] { this->RSRenderNodeDrawable::ClearCachedSurface(); };
65     RegisterClearSurfaceFunc(task);
66 }
67 
~RSRenderNodeDrawable()68 RSRenderNodeDrawable::~RSRenderNodeDrawable()
69 {
70     ClearDrawingCacheDataMap();
71     ClearCachedSurface();
72     ResetClearSurfaceFunc();
73 }
74 
OnGenerate(std::shared_ptr<const RSRenderNode> node)75 RSRenderNodeDrawable::Ptr RSRenderNodeDrawable::OnGenerate(std::shared_ptr<const RSRenderNode> node)
76 {
77     return new RSRenderNodeDrawable(std::move(node));
78 }
79 
Draw(Drawing::Canvas & canvas)80 void RSRenderNodeDrawable::Draw(Drawing::Canvas& canvas)
81 {
82     if (UNLIKELY(RSUniRenderThread::IsInCaptureProcess())) {
83         OnCapture(canvas);
84     } else {
85         OnDraw(canvas);
86     }
87 }
88 
89 /*
90  * This function will be called recursively many times, and the logic should be as concise as possible.
91  */
OnDraw(Drawing::Canvas & canvas)92 void RSRenderNodeDrawable::OnDraw(Drawing::Canvas& canvas)
93 {
94     auto& captureParam = RSUniRenderThread::GetCaptureParam();
95     if (canvas.GetUICapture() && captureParam.captureFinished_) {
96         return;
97     }
98     Drawing::GPUResourceTag::SetCurrentNodeId(GetId());
99     RSRenderNodeDrawable::TotalProcessedNodeCountInc();
100     Drawing::Rect bounds = GetRenderParams() ? GetRenderParams()->GetFrameRect() : Drawing::Rect(0, 0, 0, 0);
101     // Skip nodes that were culled by the control-level occlusion.
102     if (SkipCulledNodeOrEntireSubtree(canvas, bounds)) {
103         return;
104     }
105 
106 #ifdef SUBTREE_PARALLEL_ENABLE
107     if (RSParallelManager::Singleton().OnDrawNodeDrawable(canvas, bounds, this)) {
108         return;
109     }
110 #endif
111     DrawBackground(canvas, bounds);
112 
113     CollectInfoForUnobscuredUEC(canvas);
114 
115     DrawContent(canvas, bounds);
116 
117     bool stopDrawForRangeCapture = (canvas.GetUICapture() &&
118         captureParam.endNodeId_ == GetId() &&
119         captureParam.endNodeId_ != INVALID_NODEID);
120     if (stopDrawForRangeCapture) {
121         captureParam.captureFinished_ = true;
122     }
123     if (!captureParam.isSoloNodeUiCapture_ && !stopDrawForRangeCapture) {
124         DrawChildren(canvas, bounds);
125     }
126 
127     DrawForeground(canvas, bounds);
128 }
129 
SkipCulledNodeOrEntireSubtree(Drawing::Canvas & canvas,Drawing::Rect & bounds)130 bool RSRenderNodeDrawable::SkipCulledNodeOrEntireSubtree(Drawing::Canvas& canvas, Drawing::Rect& bounds)
131 {
132     auto paintFilterCanvas = static_cast<RSPaintFilterCanvas*>(&canvas);
133     auto id = GetId();
134     if (LIKELY(id != INVALID_NODEID) && IsOcclusionCullingEnabled()) {
135         if (paintFilterCanvas->GetCulledEntireSubtree().count(id) > 0) {
136             RS_OPTIONAL_TRACE_NAME_FMT("%s, id: %" PRIu64 " culled entire subtree success", __func__, id);
137             SetDrawSkipType(DrawSkipType::OCCLUSION_SKIP);
138             return true;
139         }
140     }
141     return false;
142 }
143 
144 /*
145  * This function will be called recursively many times, and the logic should be as concise as possible.
146  */
OnCapture(Drawing::Canvas & canvas)147 void RSRenderNodeDrawable::OnCapture(Drawing::Canvas& canvas)
148 {
149     RSRenderNodeDrawable::OnDraw(canvas);
150 }
151 
GenerateCacheIfNeed(Drawing::Canvas & canvas,RSRenderParams & params)152 CM_INLINE void RSRenderNodeDrawable::GenerateCacheIfNeed(
153     Drawing::Canvas& canvas, RSRenderParams& params)
154 {
155     // check if drawing cache enabled
156     if (params.GetDrawingCacheType() != RSDrawingCacheType::DISABLED_CACHE) {
157         RS_OPTIONAL_TRACE_NAME_FMT("RSCanvasRenderNodeDrawable::OnDraw id:%llu cacheType:%d cacheChanged:%d"
158                                    " size:[%.2f, %.2f] ChildHasVisibleFilter:%d ChildHasVisibleEffect:%d"
159                                    " shadowRect:[%.2f, %.2f, %.2f, %.2f] HasFilterOrEffect:%d",
160             params.GetId(), params.GetDrawingCacheType(), params.GetDrawingCacheChanged(), params.GetCacheSize().x_,
161             params.GetCacheSize().y_, params.ChildHasVisibleFilter(), params.ChildHasVisibleEffect(),
162             params.GetShadowRect().GetLeft(), params.GetShadowRect().GetTop(), params.GetShadowRect().GetWidth(),
163             params.GetShadowRect().GetHeight(), HasFilterOrEffect());
164     }
165 
166     RS_LOGI_IF(DEBUG_NODE, "RSRenderNodeDrawable::GenerateCacheCondition drawingCacheType:%{public}d"
167         " RSFreezeFlag:%{public}d OpincGetCachedMark:%{public}d", params.GetDrawingCacheType(),
168         params.GetRSFreezeFlag(), GetOpincDrawCache().OpincGetCachedMark());
169     if (params.GetRSFreezeFlag()) {
170         RS_OPTIONAL_TRACE_NAME_FMT("RSCanvasRenderNodeDrawable::GenerateCacheIfNeed id:%llu"
171                                    " GetRSFreezeFlag:%d hasFilter:%d",
172             params.GetId(), params.GetRSFreezeFlag(), params.ChildHasVisibleFilter());
173     }
174 
175     // check drawing cache type (disabled: clear cache)
176     if ((params.GetDrawingCacheType() == RSDrawingCacheType::DISABLED_CACHE &&
177         !GetOpincDrawCache().OpincGetCachedMark()) && !params.GetRSFreezeFlag()) {
178         ClearCachedSurface();
179         ClearDrawingCacheDataMap();
180         ClearDrawingCacheContiUpdateTimeMap();
181         return;
182     }
183 
184     {
185         std::scoped_lock<std::recursive_mutex> cacheLock(cacheMutex_);
186         if (cachedSurface_ == nullptr) {
187             // Remove node id in update time map to avoid update time exceeds DRAWING_CACHE_MAX_UPDATE_TIME
188             // (If cache disabled for node not on the tree, we clear cache in OnSync func, but we can't clear node
189             // id in drawingCacheUpdateTimeMap_ [drawable will not be visited in RT].
190             // If this node is marked node group by arkui again, we should first clear update time here, otherwise
191             // update time will accumulate.)
192             ClearDrawingCacheDataMap();
193             ClearDrawingCacheContiUpdateTimeMap();
194         }
195     }
196     // generate(first time)/update cache(cache changed) [TARGET -> DISABLED if >= MAX UPDATE TIME]
197     int32_t updateTimes = 0;
198     bool needUpdateCache = CheckIfNeedUpdateCache(params, updateTimes);
199     params.SetNeedUpdateCache(needUpdateCache);
200     int32_t continuousUpdateTimes = 0;
201     {
202         std::lock_guard<std::mutex> lock(drawingCacheContiUpdateTimeMapMutex_);
203         if (drawingCacheContinuousUpdateTimeMap_.count(nodeId_) > 0) {
204             continuousUpdateTimes = drawingCacheContinuousUpdateTimeMap_.at(nodeId_);
205         }
206     }
207     if (needUpdateCache && params.GetDrawingCacheType() == RSDrawingCacheType::TARGETED_CACHE &&
208         continuousUpdateTimes > DRAWING_CACHE_MAX_UPDATE_TIME) {
209         RS_LOGD("RSRenderNodeDrawable::GenerateCacheCondition totalUpdateTimes:%{public}d "
210                 "continuousUpdateTimes:%{public}d needUpdateCache:%{public}d",
211                 updateTimes, continuousUpdateTimes, needUpdateCache);
212         RS_TRACE_NAME_FMT("DisableCache by continuous update time > 3, id:%" PRIu64 "", params.GetId());
213         params.SetDrawingCacheType(RSDrawingCacheType::DISABLED_CACHE);
214         ClearCachedSurface();
215     }
216     // reset drawing cache changed false for render param if drawable is visited this frame
217     // if this drawble is skipped due to occlusion skip of app surface node, this flag should be kept for next frame
218     params.SetDrawingCacheChanged(false, true);
219     bool hasFilter = params.ChildHasVisibleFilter() || params.ChildHasVisibleEffect();
220     if ((params.GetDrawingCacheType() == RSDrawingCacheType::DISABLED_CACHE || (!needUpdateCache && !hasFilter))
221         && !GetOpincDrawCache().OpincGetCachedMark() && !params.GetRSFreezeFlag()) {
222         return;
223     }
224 
225     if (needUpdateCache) {
226         filterInfoVec_.clear();
227     }
228     bool isForegroundFilterCache = params.GetForegroundFilterCache() != nullptr;
229     // in case of no filter
230     if (needUpdateCache && (!hasFilter || isForegroundFilterCache || params.GetRSFreezeFlag())) {
231         RS_TRACE_NAME_FMT("UpdateCacheSurface id:%" PRIu64 ", isForegroundFilter:%d", nodeId_, isForegroundFilterCache);
232         RSRenderNodeDrawableAdapter* root = curDrawingCacheRoot_;
233         curDrawingCacheRoot_ = this;
234         hasSkipCacheLayer_ = false;
235         hasChildInBlackList_ = false;
236         UpdateCacheSurface(canvas, params);
237         curDrawingCacheRoot_ = root;
238         return;
239     }
240 
241     // in case of with filter
242     auto curCanvas = static_cast<RSPaintFilterCanvas*>(&canvas);
243     if (needUpdateCache) {
244         // 1. update cache without filer/shadow/effect & clip hole
245         auto canvasType = curCanvas->GetCacheType();
246         // set canvas type as OFFSCREEN to not draw filter/shadow/filter
247         curCanvas->SetCacheType(RSPaintFilterCanvas::CacheType::OFFSCREEN);
248         bool isOffScreenWithClipHole = isOffScreenWithClipHole_;
249         isOffScreenWithClipHole_ = true;
250         RS_TRACE_NAME_FMT("UpdateCacheSurface with filter id:%" PRIu64 "", nodeId_);
251         RSRenderNodeDrawableAdapter* root = curDrawingCacheRoot_;
252         curDrawingCacheRoot_ = this;
253         hasSkipCacheLayer_ = false;
254         hasChildInBlackList_ = false;
255         UpdateCacheSurface(canvas, params);
256         // if this NodeGroup contains other nodeGroup with filter, we should reset the isOffScreenWithClipHole_
257         isOffScreenWithClipHole_ = isOffScreenWithClipHole;
258         curCanvas->SetCacheType(canvasType);
259         curDrawingCacheRoot_ = root;
260     }
261 }
262 
TraverseSubTreeAndDrawFilterWithClip(Drawing::Canvas & canvas,const RSRenderParams & params)263 void RSRenderNodeDrawable::TraverseSubTreeAndDrawFilterWithClip(Drawing::Canvas& canvas, const RSRenderParams& params)
264 {
265     if (filterInfoVec_.empty()) {
266         return;
267     }
268     RSRenderNodeDrawableAdapter* root = curDrawingCacheRoot_;
269     curDrawingCacheRoot_ = this;
270     filterNodeSize_ = filterInfoVec_.size();
271     Drawing::AutoCanvasRestore arc(canvas, true);
272     bool isOpDropped = isOpDropped_;
273     isOpDropped_ = false;
274     drawBlurForCache_ = true; // may use in uifirst subthread
275     auto drawableCacheType = GetCacheType();
276     SetCacheType(DrawableCacheType::NONE);
277     RS_TRACE_NAME_FMT("DrawBlurForCache id:%" PRIu64 "", nodeId_);
278 
279     DrawBackground(canvas, params.GetBounds());
280     Drawing::Region filterRegion;
281     for (auto& item : filterInfoVec_) {
282         for (auto& rect: item.rectVec_) {
283             Drawing::Region region;
284             region.SetRect(rect);
285             filterRegion.Op(region, Drawing::RegionOp::UNION);
286         }
287     }
288     Drawing::Path filetrPath;
289     filterRegion.GetBoundaryPath(&filetrPath);
290     canvas.ClipPath(filetrPath);
291     DrawContent(canvas, params.GetFrameRect());
292     DrawChildren(canvas, params.GetBounds());
293     curDrawingCacheRoot_->SetLastDrawnFilterNodeId(0);
294 
295     SetCacheType(drawableCacheType);
296     isOpDropped_ = isOpDropped;
297     drawBlurForCache_ = false;
298     curDrawingCacheRoot_ = root;
299 }
300 
DealWithWhiteListNodes(Drawing::Canvas & canvas)301 bool RSRenderNodeDrawable::DealWithWhiteListNodes(Drawing::Canvas& canvas)
302 {
303     auto captureParam = RSUniRenderThread::GetCaptureParam();
304     const auto& whiteList = RSUniRenderThread::Instance().GetWhiteList();
305     if (!captureParam.isMirror_ || whiteList.empty() || captureParam.rootIdInWhiteList_ != INVALID_NODEID) {
306         return false;
307     }
308 
309     const auto& params = GetRenderParams();
310     if (!params) {
311         SetDrawSkipType(DrawSkipType::RENDER_PARAMS_NULL);
312         RS_LOGE("RSSurfaceRenderNodeDrawable::OnCapture params is nullptr");
313         return true;
314     }
315     auto info = params->GetVirtualScreenWhiteListInfo();
316     if (info.find(captureParam.virtualScreenId_) != info.end()) {
317         DrawChildren(canvas, params->GetFrameRect());
318     }
319     return true;
320 }
321 
CheckCacheTypeAndDraw(Drawing::Canvas & canvas,const RSRenderParams & params,bool isInCapture)322 CM_INLINE void RSRenderNodeDrawable::CheckCacheTypeAndDraw(
323     Drawing::Canvas& canvas, const RSRenderParams& params, bool isInCapture)
324 {
325     RS_OPTIONAL_TRACE_BEGIN_LEVEL(TRACE_LEVEL_PRINT_NODEID, "CheckCacheTypeAndDraw nodeId[%llu]", nodeId_);
326     bool hasFilter = params.ChildHasVisibleFilter() || params.ChildHasVisibleEffect();
327     RS_LOGI_IF(DEBUG_NODE,
328         "RSRenderNodeDrawable::CheckCacheTAD hasFilter:%{public}d drawingCacheType:%{public}d",
329         hasFilter, params.GetDrawingCacheType());
330     auto originalCacheType = GetCacheType();
331     // can not draw cache because skipCacheLayer in capture process, such as security layers...
332     if (GetCacheType() != DrawableCacheType::NONE && hasSkipCacheLayer_ && isInCapture) {
333         SetCacheType(DrawableCacheType::NONE);
334     }
335     if (hasFilter && params.GetDrawingCacheType() != RSDrawingCacheType::DISABLED_CACHE &&
336         params.GetForegroundFilterCache() == nullptr && GetCacheType() != DrawableCacheType::NONE) {
337         // traverse children to draw filter/shadow/effect
338         TraverseSubTreeAndDrawFilterWithClip(canvas, params);
339     }
340     // if children don't have any filter or effect, stop traversing
341     if (params.GetForegroundFilterCache() == nullptr && drawBlurForCache_ && curDrawingCacheRoot_ &&
342         curDrawingCacheRoot_->GetFilterNodeSize() == 0) {
343         RS_OPTIONAL_TRACE_NAME_FMT("CheckCacheTypeAndDraw id:%llu child without filter, skip", nodeId_);
344         RS_OPTIONAL_TRACE_END_LEVEL(TRACE_LEVEL_PRINT_NODEID);
345         return;
346     }
347     // in case of generating cache with filter in offscreen, clip hole for filter/shadow but drawing others
348     if (isOffScreenWithClipHole_) {
349         if (HasFilterOrEffect() && params.GetForegroundFilterCache() == nullptr) {
350             // clip hole for filter/shadow
351             DrawBackgroundWithoutFilterAndEffect(canvas, params);
352             DrawContent(canvas, params.GetFrameRect());
353             DrawChildren(canvas, params.GetBounds());
354             DrawForeground(canvas, params.GetBounds());
355             RS_OPTIONAL_TRACE_END_LEVEL(TRACE_LEVEL_PRINT_NODEID);
356             return;
357         }
358         CollectInfoForNodeWithoutFilter(canvas);
359     }
360     RS_LOGI_IF(DEBUG_NODE, "RSRenderNodeDrawable::CheckCacheTAD GetCacheType is %{public}hu", GetCacheType());
361     switch (GetCacheType()) {
362         case DrawableCacheType::NONE: {
363             DrawWithoutNodeGroupCache(canvas, params, originalCacheType);
364             break;
365         }
366         case DrawableCacheType::CONTENT: {
367             DrawWithNodeGroupCache(canvas, params);
368             break;
369         }
370         default:
371             break;
372     }
373     RS_OPTIONAL_TRACE_END_LEVEL(TRACE_LEVEL_PRINT_NODEID);
374 }
375 
DrawWithoutNodeGroupCache(Drawing::Canvas & canvas,const RSRenderParams & params,DrawableCacheType originalCacheType)376 void RSRenderNodeDrawable::DrawWithoutNodeGroupCache(
377     Drawing::Canvas& canvas, const RSRenderParams& params, DrawableCacheType originalCacheType)
378 {
379     if (drawBlurForCache_ && curDrawingCacheRoot_) {
380         auto& filterInfoVec = curDrawingCacheRoot_->GetfilterInfoVec();
381         auto begin = std::find_if(filterInfoVec.begin(), filterInfoVec.end(),
382             [nodeId = GetId()](const auto& item) -> bool { return item.nodeId_ == nodeId; });
383         if (begin == filterInfoVec.end()) {
384             CheckRegionAndDrawWithoutFilter(filterInfoVec, canvas, params);
385         } else {
386             CheckRegionAndDrawWithFilter(begin, filterInfoVec, canvas, params);
387         }
388     } else {
389         RSRenderNodeDrawable::OnDraw(canvas);
390     }
391     SetCacheType(originalCacheType);
392 }
393 
DrawWithNodeGroupCache(Drawing::Canvas & canvas,const RSRenderParams & params)394 void RSRenderNodeDrawable::DrawWithNodeGroupCache(Drawing::Canvas& canvas, const RSRenderParams& params)
395 {
396 #ifdef RS_ENABLE_PREFETCH
397             __builtin_prefetch(&cachedImage_, 0, 1);
398 #endif
399     RS_OPTIONAL_TRACE_NAME_FMT("DrawCachedImage id:%llu", nodeId_);
400     RS_LOGD("RSRenderNodeDrawable::CheckCacheTAD drawingCacheIncludeProperty is %{public}d",
401         params.GetDrawingCacheIncludeProperty());
402     if (hasSkipCacheLayer_ && curDrawingCacheRoot_) {
403         curDrawingCacheRoot_->SetSkipCacheLayer(true);
404     }
405     const auto& uniParam = RSUniRenderThread::Instance().GetRSRenderThreadParams();
406     if (uniParam && uniParam->IsMirrorScreen() && hasChildInBlackList_) {
407         RS_OPTIONAL_TRACE_NAME_FMT(
408             "RSRenderNodeDrawable::DrawWithNodeGroupCache skip DrawCachedImage on mirror screen if node is in "
409             "wireless screen mirroring blacklist");
410         RSRenderNodeDrawable::OnDraw(canvas);
411         return;
412     }
413 
414     auto curCanvas = static_cast<RSPaintFilterCanvas*>(&canvas);
415     if (!curCanvas) {
416         RS_LOGD("RSRenderNodeDrawable::DrawWithNodeGroupCache curCanvas is null");
417         return;
418     }
419     if (LIKELY(!params.GetDrawingCacheIncludeProperty())) {
420         DrawBackground(canvas, params.GetBounds());
421         DrawCachedImage(*curCanvas, params.GetCacheSize());
422         DrawForeground(canvas, params.GetBounds());
423     } else if (params.GetForegroundFilterCache() != nullptr) {
424         DrawBeforeCacheWithForegroundFilter(canvas, params.GetBounds());
425         DrawCachedImage(*curCanvas, params.GetCacheSize(), params.GetForegroundFilterCache());
426         DrawAfterCacheWithForegroundFilter(canvas, params.GetBounds());
427     } else {
428         DrawBeforeCacheWithProperty(canvas, params.GetBounds());
429         DrawCachedImage(*curCanvas, params.GetCacheSize());
430         DrawAfterCacheWithProperty(canvas, params.GetBounds());
431     }
432     ClearDrawingCacheContiUpdateTimeMap();
433     UpdateCacheInfoForDfx(canvas, params.GetBounds(), params.GetId());
434 }
435 
CheckRegionAndDrawWithoutFilter(const std::vector<FilterNodeInfo> & filterInfoVec,Drawing::Canvas & canvas,const RSRenderParams & params)436 void RSRenderNodeDrawable::CheckRegionAndDrawWithoutFilter(
437     const std::vector<FilterNodeInfo>& filterInfoVec, Drawing::Canvas& canvas, const RSRenderParams& params)
438 {
439     if (!curDrawingCacheRoot_) {
440         return;
441     }
442     auto& withoutFilterMatrixMap = curDrawingCacheRoot_->GetWithoutFilterMatrixMap();
443     if (withoutFilterMatrixMap.find(GetId()) == withoutFilterMatrixMap.end()) {
444         RS_LOGE("RSRenderNodeDrawable::CheckRegionAndDrawWithoutFilter can not find matrix of cached node in "
445                 "withoutFilterMatrixMap, id:%{public}" PRIu64 "", GetId());
446         return;
447     }
448     auto matrix = withoutFilterMatrixMap.at(GetId());
449     Drawing::Rect dst;
450     matrix.MapRect(dst, params.GetBounds());
451     Drawing::RectI dstRect(static_cast<int>(dst.GetLeft()), static_cast<int>(dst.GetTop()),
452         static_cast<int>(dst.GetLeft() + dst.GetWidth()), static_cast<int>(dst.GetTop() + dst.GetHeight()));
453     auto filterBegin = std::find_if(filterInfoVec.begin(), filterInfoVec.end(),
454         [nodeId = curDrawingCacheRoot_->GetLastDrawnFilterNodeId()](
455             const auto& item) -> bool { return item.nodeId_ == nodeId; });
456     if (filterBegin == filterInfoVec.end()) {
457         filterBegin = filterInfoVec.begin();
458     } else {
459         filterBegin++; // check isIntersect with undrawn filters
460     }
461     if (IsIntersectedWithFilter(filterBegin, filterInfoVec, dstRect)) {
462         RSRenderNodeDrawable::OnDraw(canvas);
463     } else if (params.ChildHasVisibleEffect() || params.ChildHasVisibleFilter()) {
464         DrawChildren(canvas, params.GetBounds());
465     }
466 }
467 
CheckRegionAndDrawWithFilter(std::vector<FilterNodeInfo>::const_iterator & begin,const std::vector<FilterNodeInfo> & filterInfoVec,Drawing::Canvas & canvas,const RSRenderParams & params)468 void RSRenderNodeDrawable::CheckRegionAndDrawWithFilter(std::vector<FilterNodeInfo>::const_iterator& begin,
469     const std::vector<FilterNodeInfo>& filterInfoVec, Drawing::Canvas& canvas, const RSRenderParams& params)
470 {
471     if (!curDrawingCacheRoot_ || begin == filterInfoVec.end()) {
472         return;
473     }
474     curDrawingCacheRoot_->SetLastDrawnFilterNodeId(GetId());
475     CheckShadowRectAndDrawBackground(canvas, params);
476     curDrawingCacheRoot_->ReduceFilterNodeSize();
477     Drawing::Rect dst;
478     auto matrix = begin->matrix_;
479     matrix.MapRect(dst, params.GetBounds());
480     Drawing::RectI dstRect(static_cast<int>(dst.GetLeft()), static_cast<int>(dst.GetTop()),
481         static_cast<int>(dst.GetLeft() + dst.GetWidth()), static_cast<int>(dst.GetTop() + dst.GetHeight()));
482     begin++; // check isIntersect with undrawn filters
483     if (IsIntersectedWithFilter(begin, filterInfoVec, dstRect)) {
484         DrawContent(canvas, params.GetFrameRect());
485         DrawChildren(canvas, params.GetBounds());
486         // DrawChildren may reduce filterNodeSize, if still have filter in other subtree of
487         // curDrawingCacheRoot_, we should draw foreground here
488         if (curDrawingCacheRoot_->GetFilterNodeSize() > 0) {
489             auto filterBegin = std::find_if(filterInfoVec.begin(), filterInfoVec.end(),
490                 [nodeId = curDrawingCacheRoot_->GetLastDrawnFilterNodeId()](
491                     const auto& item) -> bool { return item.nodeId_ == nodeId; });
492             if (filterBegin != filterInfoVec.end()) {
493                 filterBegin++; // check isIntersect with undrawn filters
494             }
495             if (IsIntersectedWithFilter(filterBegin, filterInfoVec, dstRect)) {
496                 DrawForeground(canvas, params.GetBounds());
497             }
498         }
499     }
500 }
501 
IsIntersectedWithFilter(std::vector<FilterNodeInfo>::const_iterator & begin,const std::vector<FilterNodeInfo> & filterInfoVec,Drawing::RectI & dstRect)502 bool RSRenderNodeDrawable::IsIntersectedWithFilter(std::vector<FilterNodeInfo>::const_iterator& begin,
503     const std::vector<FilterNodeInfo>& filterInfoVec, Drawing::RectI& dstRect)
504 {
505     bool isIntersected = false;
506     for (auto iter = begin; iter != filterInfoVec.end() && !isIntersected; ++iter) {
507         for (auto rect : iter->rectVec_) {
508             if (rect.Intersect(dstRect)) {
509                 isIntersected = true;
510                 break;
511             }
512         }
513     }
514     return isIntersected;
515 }
516 
ClearDrawingCacheDataMap()517 void RSRenderNodeDrawable::ClearDrawingCacheDataMap()
518 {
519     {
520         std::lock_guard<std::mutex> lock(drawingCacheMapMutex_);
521         drawingCacheUpdateTimeMap_.erase(nodeId_);
522     }
523     // clear Rendergroup dfx data map
524     RSPerfMonitorReporter::GetInstance().ClearRendergroupDataMap(nodeId_);
525 }
526 
ClearDrawingCacheContiUpdateTimeMap()527 void RSRenderNodeDrawable::ClearDrawingCacheContiUpdateTimeMap()
528 {
529     std::lock_guard<std::mutex> lock(drawingCacheContiUpdateTimeMapMutex_);
530     drawingCacheContinuousUpdateTimeMap_.erase(nodeId_);
531 }
532 
UpdateCacheInfoForDfx(Drawing::Canvas & canvas,const Drawing::Rect & rect,NodeId id)533 void RSRenderNodeDrawable::UpdateCacheInfoForDfx(Drawing::Canvas& canvas, const Drawing::Rect& rect, NodeId id)
534 {
535     if (!isDrawingCacheDfxEnabled_) {
536         return;
537     }
538     Drawing::Rect dst;
539     canvas.GetTotalMatrix().MapRect(dst, rect);
540     RectI dfxRect(static_cast<int>(dst.GetLeft()), static_cast<int>(dst.GetTop()), static_cast<int>(dst.GetWidth()),
541         static_cast<int>(dst.GetHeight()));
542     int32_t updateTimes = 0;
543     {
544         std::lock_guard<std::mutex> lock(drawingCacheMapMutex_);
545         if (drawingCacheUpdateTimeMap_.count(nodeId_) > 0) {
546             updateTimes = drawingCacheUpdateTimeMap_.at(nodeId_);
547         }
548     }
549     {
550         std::lock_guard<std::mutex> lock(drawingCacheInfoMutex_);
551         drawingCacheInfos_[id] = std::make_pair(dfxRect, updateTimes);
552     }
553 }
554 
InitDfxForCacheInfo()555 void RSRenderNodeDrawable::InitDfxForCacheInfo()
556 {
557     isDrawingCacheEnabled_ = RSSystemParameters::GetDrawingCacheEnabled();
558     auto& uniParam = RSUniRenderThread::Instance().GetRSRenderThreadParams();
559     if (LIKELY(uniParam)) {
560         isDrawingCacheDfxEnabled_ = uniParam->IsDrawingCacheDfxEnabled();
561     }
562     if (isDrawingCacheDfxEnabled_) {
563         std::lock_guard<std::mutex> lock(drawingCacheInfoMutex_);
564         drawingCacheInfos_.clear();
565         cacheUpdatedNodeMap_.clear();
566     }
567 
568 #ifdef DDGR_ENABLE_FEATURE_OPINC
569     autoCacheDrawingEnable_ = RSSystemProperties::GetAutoCacheDebugEnabled() && RSOpincDrawCache::IsAutoCacheEnable();
570     autoCacheRenderNodeInfos_.clear();
571     ClearOpincState();
572 #endif
573 }
574 
DrawDfxForCacheInfo(RSPaintFilterCanvas & canvas,const std::unique_ptr<RSRenderParams> & params)575 void RSRenderNodeDrawable::DrawDfxForCacheInfo(
576     RSPaintFilterCanvas& canvas, const std::unique_ptr<RSRenderParams>& params)
577 {
578     if (isDrawingCacheEnabled_ && isDrawingCacheDfxEnabled_) {
579         std::lock_guard<std::mutex> lock(drawingCacheInfoMutex_);
580         for (const auto& [id, cacheInfo] : drawingCacheInfos_) {
581             std::string extraInfo = ", updateTimes:" + std::to_string(cacheInfo.second);
582             bool cacheUpdated = cacheUpdatedNodeMap_.count(id) > 0;
583             auto color = cacheUpdated ? Drawing::Color::COLOR_RED : Drawing::Color::COLOR_BLUE;
584             float alpha = cacheUpdated ? CACHE_UPDATE_FILL_ALPHA : CACHE_FILL_ALPHA;
585             RSUniRenderUtil::DrawRectForDfx(canvas, cacheInfo.first, color, alpha, extraInfo);
586         }
587     }
588 
589     if (autoCacheDrawingEnable_ && !isDrawingCacheDfxEnabled_) {
590         for (const auto& info : autoCacheRenderNodeInfos_) {
591             RSUniRenderUtil::DrawRectForDfx(
592                 canvas, info.first, Drawing::Color::COLOR_BLUE, 0.2f, info.second); // alpha 0.2 by default
593         }
594     }
595 }
596 
SetCacheType(DrawableCacheType cacheType)597 void RSRenderNodeDrawable::SetCacheType(DrawableCacheType cacheType)
598 {
599     cacheType_ = cacheType;
600 }
601 
GetCacheType() const602 DrawableCacheType RSRenderNodeDrawable::GetCacheType() const
603 {
604     return cacheType_;
605 }
606 
GetCachedSurface(pid_t threadId) const607 std::shared_ptr<Drawing::Surface> RSRenderNodeDrawable::GetCachedSurface(pid_t threadId) const
608 {
609     std::scoped_lock<std::recursive_mutex> lock(cacheMutex_);
610     return threadId == cacheThreadId_ ? cachedSurface_ : nullptr;
611 }
612 
InitCachedSurface(Drawing::GPUContext * gpuContext,const Vector2f & cacheSize,pid_t threadId,bool isNeedFP16,GraphicColorGamut colorGamut)613 void RSRenderNodeDrawable::InitCachedSurface(Drawing::GPUContext* gpuContext, const Vector2f& cacheSize,
614     pid_t threadId, bool isNeedFP16, GraphicColorGamut colorGamut)
615 {
616     std::scoped_lock<std::recursive_mutex> lock(cacheMutex_);
617 #if (defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)) && (defined RS_ENABLE_EGLIMAGE)
618     if (gpuContext == nullptr) {
619         return;
620     }
621     ClearCachedSurface();
622     cacheThreadId_ = threadId;
623     int32_t width = 0;
624     int32_t height = 0;
625     if (GetOpincDrawCache().IsComputeDrawAreaSucc()) {
626         auto& unionRect = GetOpincDrawCache().GetOpListUnionArea();
627         width = static_cast<int32_t>(unionRect.GetWidth());
628         height = static_cast<int32_t>(unionRect.GetHeight());
629     } else {
630         width = static_cast<int32_t>(cacheSize.x_);
631         height = static_cast<int32_t>(cacheSize.y_);
632     }
633 
634 #ifdef RS_ENABLE_GL
635     if (OHOS::Rosen::RSSystemProperties::GetGpuApiType() != OHOS::Rosen::GpuApiType::VULKAN &&
636         OHOS::Rosen::RSSystemProperties::GetGpuApiType() != OHOS::Rosen::GpuApiType::DDGR) {
637         Drawing::ImageInfo info = Drawing::ImageInfo::MakeN32Premul(width, height);
638         cachedSurface_ = Drawing::Surface::MakeRenderTarget(gpuContext, true, info);
639     }
640 #endif
641 #ifdef RS_ENABLE_VK
642     if (OHOS::Rosen::RSSystemProperties::GetGpuApiType() == OHOS::Rosen::GpuApiType::VULKAN ||
643         OHOS::Rosen::RSSystemProperties::GetGpuApiType() == OHOS::Rosen::GpuApiType::DDGR) {
644         auto colorType = Drawing::ColorType::COLORTYPE_RGBA_8888;
645         VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
646         // When colorType is FP16, buffer's colorspace must be sRGB
647         // In other cases, the colorspace follows screen colorspace
648         auto colorSpace = RSBaseRenderEngine::ConvertColorGamutToDrawingColorSpace(colorGamut);
649         if (isNeedFP16) {
650             colorType = Drawing::ColorType::COLORTYPE_RGBA_F16;
651             format = VK_FORMAT_R16G16B16A16_SFLOAT;
652             colorSpace = Drawing::ColorSpace::CreateSRGB();
653         }
654         cachedBackendTexture_ = NativeBufferUtils::MakeBackendTexture(width, height, ExtractPid(nodeId_), format);
655         auto vkTextureInfo = cachedBackendTexture_.GetTextureInfo().GetVKTextureInfo();
656         if (!cachedBackendTexture_.IsValid() || !vkTextureInfo) {
657             return;
658         }
659         vulkanCleanupHelper_ = new NativeBufferUtils::VulkanCleanupHelper(RsVulkanContext::GetSingleton(),
660             vkTextureInfo->vkImage, vkTextureInfo->vkAlloc.memory, vkTextureInfo->vkAlloc.statName);
661         REAL_ALLOC_CONFIG_SET_STATUS(true);
662         cachedSurface_ = Drawing::Surface::MakeFromBackendTexture(gpuContext, cachedBackendTexture_.GetTextureInfo(),
663             Drawing::TextureOrigin::BOTTOM_LEFT, 1, colorType, colorSpace,
664             NativeBufferUtils::DeleteVkImage, vulkanCleanupHelper_);
665         REAL_ALLOC_CONFIG_SET_STATUS(false);
666     }
667 #endif
668 #else
669     cachedSurface_ =
670         Drawing::Surface::MakeRasterN32Premul(static_cast<int32_t>(cacheSize.x_), static_cast<int32_t>(cacheSize.y_));
671 #endif
672 }
673 
NeedInitCachedSurface(const Vector2f & newSize)674 bool RSRenderNodeDrawable::NeedInitCachedSurface(const Vector2f& newSize)
675 {
676     auto width = static_cast<int32_t>(newSize.x_);
677     auto height = static_cast<int32_t>(newSize.y_);
678     if (GetOpincDrawCache().IsComputeDrawAreaSucc()) {
679         auto& unionRect = GetOpincDrawCache().GetOpListUnionArea();
680         width = static_cast<int32_t>(unionRect.GetWidth());
681         height = static_cast<int32_t>(unionRect.GetHeight());
682     }
683     std::scoped_lock<std::recursive_mutex> lock(cacheMutex_);
684     if (cachedSurface_ == nullptr) {
685         return true;
686     }
687     auto cacheCanvas = cachedSurface_->GetCanvas();
688     if (cacheCanvas == nullptr) {
689         return true;
690     }
691     return cacheCanvas->GetWidth() != width || cacheCanvas->GetHeight() != height;
692 }
693 
694 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
695 struct SharedTextureContext {
SharedTextureContextOHOS::Rosen::DrawableV2::SharedTextureContext696     SharedTextureContext(std::shared_ptr<Drawing::Image> sharedImage)
697         : sharedImage_(std::move(sharedImage)) {}
698 
699 private:
700     std::shared_ptr<Drawing::Image> sharedImage_;
701 };
702 
DeleteSharedTextureContext(void * context)703 static void DeleteSharedTextureContext(void* context)
704 {
705     SharedTextureContext* cleanupHelper = static_cast<SharedTextureContext*>(context);
706     if (cleanupHelper != nullptr) {
707         delete cleanupHelper;
708     }
709 }
710 #endif
711 
GetCachedImage(RSPaintFilterCanvas & canvas)712 std::shared_ptr<Drawing::Image> RSRenderNodeDrawable::GetCachedImage(RSPaintFilterCanvas& canvas)
713 {
714     std::scoped_lock<std::recursive_mutex> lock(cacheMutex_);
715     if (!cachedSurface_ || !cachedImage_) {
716         RS_LOGE("RSRenderNodeDrawable::GetCachedImage invalid cachedSurface_");
717         return nullptr;
718     }
719 
720     // do not use threadId to judge image grcontext change
721     if (cachedImage_->IsValid(canvas.GetGPUContext().get())) {
722         return cachedImage_;
723     }
724 #ifdef RS_ENABLE_GL
725     if (OHOS::Rosen::RSSystemProperties::GetGpuApiType() != OHOS::Rosen::GpuApiType::VULKAN &&
726         OHOS::Rosen::RSSystemProperties::GetGpuApiType() != OHOS::Rosen::GpuApiType::DDGR) {
727         if (canvas.GetGPUContext() == nullptr) {
728             return nullptr;
729         }
730         Drawing::TextureOrigin origin = Drawing::TextureOrigin::BOTTOM_LEFT;
731         Drawing::BitmapFormat info = Drawing::BitmapFormat{cachedImage_->GetColorType(), cachedImage_->GetAlphaType()};
732         SharedTextureContext* sharedContext = new SharedTextureContext(cachedImage_); // will move image
733         cachedImage_ = std::make_shared<Drawing::Image>();
734         bool ret = cachedImage_->BuildFromTexture(*canvas.GetGPUContext(), cachedBackendTexture_.GetTextureInfo(),
735             origin, info, nullptr, DeleteSharedTextureContext, sharedContext);
736         if (!ret) {
737             RS_LOGE("RSRenderNodeDrawable::GetCachedImage image BuildFromTexture failed");
738             return nullptr;
739         }
740     }
741 #endif
742 
743 #ifdef RS_ENABLE_VK
744     if (OHOS::Rosen::RSSystemProperties::GetGpuApiType() == OHOS::Rosen::GpuApiType::VULKAN ||
745         OHOS::Rosen::RSSystemProperties::GetGpuApiType() == OHOS::Rosen::GpuApiType::DDGR) {
746         if (vulkanCleanupHelper_ == nullptr || canvas.GetGPUContext() == nullptr) {
747             return nullptr;
748         }
749         Drawing::TextureOrigin origin = Drawing::TextureOrigin::BOTTOM_LEFT;
750         Drawing::BitmapFormat info = Drawing::BitmapFormat{cachedImage_->GetColorType(), cachedImage_->GetAlphaType()};
751         // Ensure the image's color space matches the target surface's color profile.
752         auto colorSpace = cachedSurface_->GetImageInfo().GetColorSpace();
753         cachedImage_ = std::make_shared<Drawing::Image>();
754         bool ret = cachedImage_->BuildFromTexture(*canvas.GetGPUContext(), cachedBackendTexture_.GetTextureInfo(),
755             origin, info, colorSpace, NativeBufferUtils::DeleteVkImage, vulkanCleanupHelper_->Ref());
756         if (!ret) {
757             RS_LOGE("RSRenderNodeDrawable::GetCachedImage image BuildFromTexture failed");
758             return nullptr;
759         }
760     }
761 #endif
762     return cachedImage_;
763 }
764 
SetCacheImageByCapture(std::shared_ptr<Drawing::Image> image)765 void RSRenderNodeDrawable::SetCacheImageByCapture(std::shared_ptr<Drawing::Image> image)
766 {
767     std::lock_guard<std::mutex> lock(freezeByCaptureMutex_);
768     cachedImageByCapture_ = image;
769 }
770 
GetCacheImageByCapture() const771 std::shared_ptr<Drawing::Image> RSRenderNodeDrawable::GetCacheImageByCapture() const
772 {
773     std::lock_guard<std::mutex> lock(freezeByCaptureMutex_);
774     return cachedImageByCapture_;
775 }
776 
DrawCachedImage(RSPaintFilterCanvas & canvas,const Vector2f & boundSize,const std::shared_ptr<RSFilter> & rsFilter)777 void RSRenderNodeDrawable::DrawCachedImage(RSPaintFilterCanvas& canvas, const Vector2f& boundSize,
778     const std::shared_ptr<RSFilter>& rsFilter)
779 {
780     auto cacheImage = GetCachedImage(canvas);
781     std::lock_guard<std::mutex> lock(freezeByCaptureMutex_);
782     if (cachedImageByCapture_) {
783         // node has freezed, and to draw surfaceCapture image
784         cacheImage = cachedImageByCapture_;
785     }
786     if (cacheImage == nullptr) {
787         RS_LOGE("RSRenderNodeDrawable::DrawCachedImage image null");
788         return;
789     }
790     if (RSSystemProperties::GetRecordingEnabled()) {
791         if (cacheImage->IsTextureBacked()) {
792             RS_LOGI("RSRenderNodeDrawable::DrawCachedImage convert cacheImage from texture to raster image");
793             cacheImage = cacheImage->MakeRasterImage();
794         }
795     }
796     if (cacheImage == nullptr || cacheImage->GetWidth() == 0 || cacheImage->GetHeight() == 0) {
797         RS_LOGE("RSRenderNodeDrawable::DrawCachedImage invalid cacheimage");
798         return;
799     }
800     float scaleX = boundSize.x_ / static_cast<float>(cacheImage->GetWidth());
801     float scaleY = boundSize.y_ / static_cast<float>(cacheImage->GetHeight());
802     if (GetOpincDrawCache().IsComputeDrawAreaSucc()) {
803         auto& unionRect = GetOpincDrawCache().GetOpListUnionArea();
804         scaleX = unionRect.GetWidth() / static_cast<float>(cacheImage->GetWidth());
805         scaleY = unionRect.GetHeight() / static_cast<float>(cacheImage->GetHeight());
806     }
807 
808     Drawing::AutoCanvasRestore arc(canvas, true);
809     canvas.Scale(scaleX, scaleY);
810     Drawing::Brush brush;
811     canvas.AttachBrush(brush);
812     auto samplingOptions = Drawing::SamplingOptions(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::NONE);
813     if (GetOpincDrawCache().IsComputeDrawAreaSucc() && GetOpincDrawCache().DrawAutoCache(canvas, *cacheImage,
814         samplingOptions, Drawing::SrcRectConstraint::STRICT_SRC_RECT_CONSTRAINT)) {
815         canvas.DetachBrush();
816         GetOpincDrawCache().DrawAutoCacheDfx(canvas, autoCacheRenderNodeInfos_);
817         return;
818     }
819     if (rsFilter != nullptr) {
820         RS_OPTIONAL_TRACE_FMT("RSRenderNodeDrawable::DrawCachedImage image width: %d, height: %d, %s, nodeID = %llu",
821             cacheImage->GetWidth(), cacheImage->GetHeight(), rsFilter->GetDescription().c_str(), nodeId_);
822         auto foregroundFilter = std::static_pointer_cast<RSDrawingFilterOriginal>(rsFilter);
823         foregroundFilter->DrawImageRect(canvas, cacheImage, Drawing::Rect(0, 0, cacheImage->GetWidth(),
824         cacheImage->GetHeight()), Drawing::Rect(0, 0, cacheImage->GetWidth(), cacheImage->GetHeight()));
825      } else {
826          canvas.DrawImage(*cacheImage, 0.0, 0.0, samplingOptions);
827      }
828     canvas.DetachBrush();
829 }
830 
ClearCachedSurface()831 void RSRenderNodeDrawable::ClearCachedSurface()
832 {
833     SetCacheType(DrawableCacheType::NONE);
834     std::scoped_lock<std::recursive_mutex> lock(cacheMutex_);
835     if (cachedSurface_ == nullptr) {
836         return;
837     }
838     RS_OPTIONAL_TRACE_NAME_FMT("ClearCachedSurface id:%llu", GetId());
839 
840     auto clearTask = [surface = cachedSurface_]() mutable { surface = nullptr; };
841     cachedSurface_ = nullptr;
842     cachedImage_ = nullptr;
843     RSTaskDispatcher::GetInstance().PostTask(cacheThreadId_.load(), clearTask);
844 
845 #ifdef RS_ENABLE_VK
846     if (OHOS::Rosen::RSSystemProperties::GetGpuApiType() == OHOS::Rosen::GpuApiType::VULKAN ||
847         OHOS::Rosen::RSSystemProperties::GetGpuApiType() == OHOS::Rosen::GpuApiType::DDGR) {
848         vulkanCleanupHelper_ = nullptr;
849     }
850 #endif
851 }
852 
CheckIfNeedUpdateCache(RSRenderParams & params,int32_t & updateTimes)853 bool RSRenderNodeDrawable::CheckIfNeedUpdateCache(RSRenderParams& params, int32_t& updateTimes)
854 {
855     {
856         std::lock_guard<std::mutex> lock(drawingCacheMapMutex_);
857         if (drawingCacheUpdateTimeMap_.count(nodeId_) > 0) {
858             updateTimes = drawingCacheUpdateTimeMap_.at(nodeId_);
859         }
860     }
861 
862     RS_OPTIONAL_TRACE_NAME_FMT("CheckUpdateCache id:%llu updateTimes:%d type:%d cacheChanged:%d size:[%.2f, %.2f]",
863         nodeId_, updateTimes, params.GetDrawingCacheType(), params.GetDrawingCacheChanged(),
864         params.GetCacheSize().x_, params.GetCacheSize().y_);
865 
866     // node freeze
867     if (params.GetRSFreezeFlag()) {
868         return updateTimes == 0;
869     }
870 
871     if ((params.GetDrawingCacheType() == RSDrawingCacheType::TARGETED_CACHE && params.NeedFilter() &&
872         params.GetDrawingCacheIncludeProperty()) || ROSEN_LE(params.GetCacheSize().x_, 0.f) ||
873         ROSEN_LE(params.GetCacheSize().y_, 0.f)) {
874         params.SetDrawingCacheType(RSDrawingCacheType::DISABLED_CACHE);
875         ClearCachedSurface();
876         return false;
877     }
878 
879     if (NeedInitCachedSurface(params.GetCacheSize())) {
880         ClearCachedSurface();
881         return true;
882     }
883 
884     if (updateTimes == 0 || params.GetDrawingCacheChanged()) {
885         return true;
886     }
887     return false;
888 }
889 
UpdateCacheSurface(Drawing::Canvas & canvas,const RSRenderParams & params)890 void RSRenderNodeDrawable::UpdateCacheSurface(Drawing::Canvas& canvas, const RSRenderParams& params)
891 {
892     auto startTime = RSPerfMonitorReporter::GetInstance().StartRendergroupMonitor();
893     auto curCanvas = static_cast<RSPaintFilterCanvas*>(&canvas);
894     pid_t threadId = gettid();
895 #ifdef SUBTREE_PARALLEL_ENABLE
896     // Adapt to the subtree feature to ensure the correct thread ID(TID) is set.
897     RSParallelMisc::AdaptSubTreeThreadId(canvas, threadId);
898 #endif
899 
900     bool isHdrOn = false;
901     bool isScRGBEnable = RSSystemParameters::IsNeedScRGBForP3(curCanvas->GetTargetColorGamut()) &&
902         RSUifirstManager::Instance().GetUiFirstSwitch();
903     bool isNeedFP16 = isHdrOn || isScRGBEnable;
904     auto cacheSurface = GetCachedSurface(threadId);
905     if (cacheSurface == nullptr) {
906         RS_TRACE_NAME_FMT("InitCachedSurface size:[%.2f, %.2f]", params.GetCacheSize().x_, params.GetCacheSize().y_);
907         InitCachedSurface(curCanvas->GetGPUContext().get(), params.GetCacheSize(), threadId, isNeedFP16,
908             curCanvas->GetTargetColorGamut());
909         cacheSurface = GetCachedSurface(threadId);
910         if (cacheSurface == nullptr) {
911             return;
912         }
913     }
914 
915     auto cacheCanvas = std::make_shared<RSPaintFilterCanvas>(cacheSurface.get());
916     if (!cacheCanvas) {
917         return;
918     }
919 
920     // copy current canvas properties into cacheCanvas
921     const auto& renderEngine = RSUniRenderThread::Instance().GetRenderEngine();
922     if (renderEngine) {
923         cacheCanvas->SetHighContrast(renderEngine->IsHighContrastEnabled());
924     }
925     cacheCanvas->CopyConfigurationToOffscreenCanvas(*curCanvas);
926     cacheCanvas->CopyHDRConfiguration(*curCanvas);
927     // Using filter cache in multi-thread environment may cause GPU memory leak or invalid textures
928     // [PLANNNING] disable it in sub-thread.
929 
930     // When drawing CacheSurface, all child node should be drawn.
931     // So set isOpDropped_ = false here.
932     bool isOpDropped = isOpDropped_;
933     isOpDropped_ = false;
934     Drawing::AutoCanvasRestore arc(*cacheCanvas, true);
935     cacheCanvas->Clear(Drawing::Color::COLOR_TRANSPARENT);
936 
937     GetOpincDrawCache().OpincCanvasUnionTranslate(*cacheCanvas);
938     if (params.GetRSFreezeFlag()) {
939         cacheCanvas->SetDisableFilterCache(true);
940     }
941     // draw content + children
942     auto bounds = params.GetBounds();
943     ApplyForegroundColorIfNeed(*cacheCanvas, bounds);
944     if (LIKELY(!params.GetDrawingCacheIncludeProperty())) {
945         DrawContent(*cacheCanvas, params.GetFrameRect());
946         DrawChildren(*cacheCanvas, bounds);
947     } else if (params.GetForegroundFilterCache() != nullptr) {
948         DrawCacheWithForegroundFilter(*cacheCanvas, bounds);
949     } else {
950         DrawCacheWithProperty(*cacheCanvas, bounds);
951     }
952     GetOpincDrawCache().ResumeOpincCanvasTranslate(*cacheCanvas);
953 
954     isOpDropped_ = isOpDropped;
955 
956     // get image & backend
957     {
958         std::scoped_lock<std::recursive_mutex> lock(cacheMutex_);
959         cachedImage_ = cacheSurface->GetImageSnapshot();
960         if (cachedImage_) {
961             SetCacheType(DrawableCacheType::CONTENT);
962         }
963     }
964 
965 #if RS_ENABLE_GL
966     // vk backend has been created when surface init.
967     if (OHOS::Rosen::RSSystemProperties::GetGpuApiType() != OHOS::Rosen::GpuApiType::VULKAN &&
968         OHOS::Rosen::RSSystemProperties::GetGpuApiType() != OHOS::Rosen::GpuApiType::DDGR) {
969         cachedBackendTexture_ = cacheSurface->GetBackendTexture();
970     }
971 #endif
972     // update cache updateTimes
973     int32_t updateTimes = 0;
974     {
975         std::lock_guard<std::mutex> lock(drawingCacheMapMutex_);
976         drawingCacheUpdateTimeMap_[nodeId_]++;
977         updateTimes = drawingCacheUpdateTimeMap_[nodeId_];
978     }
979     {
980         std::lock_guard<std::mutex> lock(drawingCacheContiUpdateTimeMapMutex_);
981         drawingCacheContinuousUpdateTimeMap_[nodeId_]++;
982     }
983     {
984         std::lock_guard<std::mutex> lock(drawingCacheInfoMutex_);
985         cacheUpdatedNodeMap_.emplace(params.GetId(), true);
986     }
987     auto ctx = RSUniRenderThread::Instance().GetRSRenderThreadParams()->GetContext();
988     RSPerfMonitorReporter::GetInstance().EndRendergroupMonitor(startTime, nodeId_, ctx, updateTimes);
989 }
990 
GetTotalProcessedNodeCount()991 int RSRenderNodeDrawable::GetTotalProcessedNodeCount()
992 {
993     return totalProcessedNodeCount_;
994 }
995 
TotalProcessedNodeCountInc()996 void RSRenderNodeDrawable::TotalProcessedNodeCountInc()
997 {
998     ++totalProcessedNodeCount_;
999 }
1000 
ClearTotalProcessedNodeCount()1001 void RSRenderNodeDrawable::ClearTotalProcessedNodeCount()
1002 {
1003     totalProcessedNodeCount_ = 0;
1004 }
1005 
GetProcessedNodeCount()1006 int RSRenderNodeDrawable::GetProcessedNodeCount()
1007 {
1008     return processedNodeCount_;
1009 }
1010 
ProcessedNodeCountInc()1011 void RSRenderNodeDrawable::ProcessedNodeCountInc()
1012 {
1013     ++processedNodeCount_;
1014 }
1015 
ClearProcessedNodeCount()1016 void RSRenderNodeDrawable::ClearProcessedNodeCount()
1017 {
1018     processedNodeCount_ = 0;
1019 }
1020 
GetSnapshotProcessedNodeCount()1021 int RSRenderNodeDrawable::GetSnapshotProcessedNodeCount()
1022 {
1023     return snapshotProcessedNodeCount_;
1024 }
1025 
SnapshotProcessedNodeCountInc()1026 void RSRenderNodeDrawable::SnapshotProcessedNodeCountInc()
1027 {
1028     if (RSUniRenderThread::GetCaptureParam().isSingleSurface_) {
1029         ++snapshotProcessedNodeCount_;
1030     }
1031 }
1032 
ClearSnapshotProcessedNodeCount()1033 void RSRenderNodeDrawable::ClearSnapshotProcessedNodeCount()
1034 {
1035     snapshotProcessedNodeCount_ = 0;
1036 }
1037 
ShouldPaint() const1038 bool RSRenderNodeDrawable::ShouldPaint() const
1039 {
1040     return LIKELY(renderParams_ != nullptr) && renderParams_->GetShouldPaint();
1041 }
1042 
1043 // opinc dfx
GetNodeDebugInfo()1044 std::string RSRenderNodeDrawable::GetNodeDebugInfo()
1045 {
1046     std::string ret("");
1047     const auto& params = GetRenderParams();
1048     if (!params) {
1049         return ret;
1050     }
1051     auto& unionRect = opincDrawCache_.GetOpListUnionArea();
1052     AppendFormat(ret, "%" PRIu64 ", rootF:%d record:%d rootS:%d opCan:%d isRD:%d, GetOpDropped:%d,"
1053         " isOpincDropNodeExt:%d", params->GetId(), params->OpincGetRootFlag(),
1054         opincDrawCache_.GetRecordState(), opincDrawCache_.GetRootNodeStrategyType(), opincDrawCache_.IsOpCanCache(),
1055         opincDrawCache_.GetDrawAreaEnableState(), GetOpDropped(), isOpincDropNodeExt_);
1056     auto& info = opincDrawCache_.GetOpListHandle().GetOpInfo();
1057     AppendFormat(ret, " opNum:%d opPercent:%d", info.num, info.percent);
1058     auto bounds = params->GetBounds();
1059     AppendFormat(ret, ", rr{%.1f %.1f %.1f %.1f}",
1060         0.f, 0.f, bounds.GetWidth(), bounds.GetHeight());
1061     AppendFormat(ret, ", ur{%.1f %.1f %.1f %.1f}",
1062         unionRect.GetLeft(), unionRect.GetTop(), unionRect.GetWidth(), unionRect.GetHeight());
1063     return ret;
1064 }
1065 
ClearOpincState()1066 void RSRenderNodeDrawable::ClearOpincState()
1067 {
1068     // Init opincRootTotalCount_ when the new thread init
1069     opincRootTotalCount_ = 0;
1070     isOpincDropNodeExt_ = true;
1071 }
1072 
1073 } // namespace OHOS::Rosen::DrawableV2
1074