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