1 /*
2  * Copyright (c) 2024 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 #ifdef DDGR_ENABLE_FEATURE_OPINC_DFX
18 #include "string_utils.h"
19 #endif
20 #include "common/rs_optional_trace.h"
21 #include "params/rs_render_params.h"
22 namespace OHOS::Rosen::DrawableV2 {
23 
24 namespace {
25 constexpr int32_t BITMAP_CACHE_SIZE_MIN = 50;
26 constexpr int32_t REALDRAW_WIDTH_EX = 200;
27 constexpr int32_t OPINC_ROOT_TOTAL_MAX = 1;
28 constexpr int32_t OPINC_CACHE_HEIGHT_THRESHOLD = 2720;
29 constexpr int32_t OPINC_CACHE_WIDTH_MAX = 1460;
30 constexpr int32_t OPINC_CACHE_SIZE_MAX = 1314000;
31 }
32 
ShouldPaint() const33 bool RSRenderNodeDrawable::ShouldPaint() const
34 {
35     return LIKELY(renderParams_ != nullptr) && renderParams_->GetShouldPaint();
36 }
37 
IsOpincRenderCacheEnable()38 bool RSRenderNodeDrawable::IsOpincRenderCacheEnable()
39 {
40     return RSSystemProperties::GetDdgrOpincType() == OHOS::Rosen::DdgrOpincType::OPINC_AUTOCACHE;
41 }
42 
IsOpincRealDrawCacheEnable()43 bool RSRenderNodeDrawable::IsOpincRealDrawCacheEnable()
44 {
45     return RSSystemProperties::IsOpincRealDrawCacheEnable();
46 }
47 
IsAutoCacheDebugEnable()48 bool RSRenderNodeDrawable::IsAutoCacheDebugEnable()
49 {
50     return RSSystemProperties::GetAutoCacheDebugEnabled() && RSSystemProperties::IsDdgrOpincEnable();
51 }
52 
OpincCalculateBefore(Drawing::Canvas & canvas,const RSRenderParams & params,bool & isOpincDropNodeExt)53 void RSRenderNodeDrawable::OpincCalculateBefore(Drawing::Canvas& canvas,
54     const RSRenderParams& params, bool& isOpincDropNodeExt)
55 {
56     isOpincDropNodeExtTemp_ = isOpincDropNodeExt;
57     isOpincCaculateStart_ = false;
58     if (IsOpincRealDrawCacheEnable() && IsOpListDrawAreaEnable()) {
59         isOpincCaculateStart_ = canvas.OpCalculateBefore(params.GetMatrix());
60         isOpincDropNodeExt = false;
61     }
62 }
63 
OpincCalculateAfter(Drawing::Canvas & canvas,bool & isOpincDropNodeExt)64 void RSRenderNodeDrawable::OpincCalculateAfter(Drawing::Canvas& canvas, bool& isOpincDropNodeExt)
65 {
66     if (isOpincCaculateStart_) {
67         isOpincCaculateStart_ = false;
68         auto localBound =
69             Drawing::Rect(0.f, 0.f, (float)(OPINC_CACHE_WIDTH_MAX), (float)OPINC_CACHE_HEIGHT_THRESHOLD);
70         auto drawAreaTemp = canvas.OpCalculateAfter(localBound);
71         isDrawAreaEnable_ = DrawAreaEnableState::DRAW_AREA_DISABLE;
72         opCanCache_ = false;
73         if (drawAreaTemp) {
74             opCanCache_ = drawAreaTemp->GetOpInfo().canReUseCache;
75         }
76         if (opCanCache_) {
77             opListDrawAreas_ = std::move(*drawAreaTemp);
78             isDrawAreaEnable_ = DrawAreaEnableState::DRAW_AREA_ENABLE;
79         }
80     }
81     isOpincDropNodeExt = isOpincDropNodeExtTemp_;
82 }
83 
PreDrawableCacheState(RSRenderParams & params,bool & isOpincDropNodeExt)84 bool RSRenderNodeDrawable::PreDrawableCacheState(RSRenderParams& params, bool& isOpincDropNodeExt)
85 {
86     if (params.OpincGetCacheChangeState()) {
87         RS_OPTIONAL_TRACE_NAME_FMT("OpincGetCacheChangeState Changed %llx", GetId());
88         DrawableCacheStateReset(params);
89     }
90     return isOpincDropNodeExt && (!IsOpincRootNode());
91 }
92 
OpincCanvasUnionTranslate(RSPaintFilterCanvas & canvas)93 void RSRenderNodeDrawable::OpincCanvasUnionTranslate(RSPaintFilterCanvas& canvas)
94 {
95     if (!IsComputeDrawAreaSucc()) {
96         return;
97     }
98     auto& unionRect = GetOpListUnionArea();
99     canvas.Translate(-unionRect.GetLeft(), -unionRect.GetTop());
100 }
101 
ResumeOpincCanvasTranslate(RSPaintFilterCanvas & canvas)102 void RSRenderNodeDrawable::ResumeOpincCanvasTranslate(RSPaintFilterCanvas& canvas)
103 {
104     if (!IsComputeDrawAreaSucc()) {
105         return;
106     }
107     auto& unionRect = GetOpListUnionArea();
108     canvas.Translate(unionRect.GetLeft(), unionRect.GetTop());
109 }
110 
DrawableCacheStateReset(RSRenderParams & params)111 void RSRenderNodeDrawable::DrawableCacheStateReset(RSRenderParams& params)
112 {
113     isDrawAreaEnable_ = DrawAreaEnableState::DRAW_AREA_INIT;
114     rootNodeStragyType_ = NodeStrategyType::CACHE_NONE;
115     temNodeStragyType_ = NodeStrategyType::CACHE_NONE;
116     recordState_ = NodeRecordState::RECORD_NONE;
117     opListDrawAreas_.ResetOpInfo();
118     isOpincRootNode_ = false;
119     opCanCache_ = false;
120     isOpincMarkCached_ = false;
121 }
122 
IsOpListDrawAreaEnable()123 bool RSRenderNodeDrawable::IsOpListDrawAreaEnable()
124 {
125     return (rootNodeStragyType_ == NodeStrategyType::OPINC_AUTOCACHE) &&
126         (recordState_ == NodeRecordState::RECORD_CALCULATE);
127 }
128 
IsTranslate(Drawing::Matrix & mat)129 bool RSRenderNodeDrawable::IsTranslate(Drawing::Matrix& mat)
130 {
131     return (mat.Get(Drawing::Matrix::SCALE_X) == 1.0f) && (mat.Get(Drawing::Matrix::SCALE_Y) == 1.0f) &&
132         (mat.Get(Drawing::Matrix::SKEW_X) == 0.0f) && (mat.Get(Drawing::Matrix::SKEW_Y) == 0.0f);
133 }
134 
NodeCacheStateDisable()135 void RSRenderNodeDrawable::NodeCacheStateDisable()
136 {
137     recordState_ = NodeRecordState::RECORD_DISABLE;
138     rootNodeStragyType_ = NodeStrategyType::CACHE_DISABLE;
139     temNodeStragyType_ = NodeStrategyType::CACHE_DISABLE;
140     isDrawAreaEnable_ = DrawAreaEnableState::DRAW_AREA_DISABLE;
141     if (opCanCache_) {
142         opCanCache_ = false;
143         opListDrawAreas_.ResetOpInfo();
144     }
145 }
146 
BeforeDrawCacheProcessChildNode(NodeStrategyType & cacheStragy,RSRenderParams & params)147 bool RSRenderNodeDrawable::BeforeDrawCacheProcessChildNode(NodeStrategyType& cacheStragy,
148     RSRenderParams& params)
149 {
150 #ifdef DDGR_ENABLE_FEATURE_OPINC_DFX
151     RS_TRACE_NAME_FMT("BeforeDrawCacheProcessChildNode cs:%d rs:%d csBak:%d",
152         cacheStragy, recordState_, temNodeStragyType_);
153 #endif
154     // find root node
155     if (cacheStragy != NodeStrategyType::CACHE_NONE || !params.OpincGetRootFlag()) {
156         if (recordState_ == NodeRecordState::RECORD_CACHED &&
157             rootNodeStragyType_ == NodeStrategyType::OPINC_AUTOCACHE) {
158             DrawableCacheStateReset(params);
159         }
160         if (rootNodeStragyType_ == NodeStrategyType::CACHE_DISABLE) {
161             NodeCacheStateDisable();
162         }
163         return false;
164     }
165     return true;
166 }
167 
BeforeDrawCacheFindRootNode(Drawing::Canvas & canvas,const RSRenderParams & params,bool & isOpincDropNodeExt)168 void RSRenderNodeDrawable::BeforeDrawCacheFindRootNode(Drawing::Canvas& canvas,
169     const RSRenderParams& params, bool& isOpincDropNodeExt)
170 {
171     if (IsOpincRealDrawCacheEnable() && !params.OpincGetRootFlag()) {
172         return;
173     }
174     auto size = params.GetCacheSize();
175     if (size.x_ > OPINC_CACHE_WIDTH_MAX || size.y_ > OPINC_CACHE_HEIGHT_THRESHOLD) {
176         RS_TRACE_NAME_FMT("opinc oversize: width:%d, height:%d", size.x_, size.y_);
177         return;
178     }
179     auto isOffscreen = (canvas.GetCacheType() == RSPaintFilterCanvas::CacheType::OFFSCREEN);
180     if (!isOffscreen &&
181         size.y_ > BITMAP_CACHE_SIZE_MIN && size.x_ > BITMAP_CACHE_SIZE_MIN &&
182         size.x_ * size.y_ < OPINC_CACHE_SIZE_MAX) {
183         recordState_ = NodeRecordState::RECORD_CALCULATE;
184         rootNodeStragyType_ = NodeStrategyType::OPINC_AUTOCACHE;
185     }
186 #ifdef DDGR_ENABLE_FEATURE_OPINC_DFX
187     RS_TRACE_NAME_FMT("BeforeDrawCacheFindRootNode rootS:%d xy:%d", rootNodeStragyType_,
188         (size.y_ > BITMAP_CACHE_SIZE_MIN && size.x_ > BITMAP_CACHE_SIZE_MIN));
189 #endif
190 }
191 
BeforeDrawCache(NodeStrategyType & cacheStragy,Drawing::Canvas & canvas,RSRenderParams & params,bool & isOpincDropNodeExt)192 void RSRenderNodeDrawable::BeforeDrawCache(NodeStrategyType& cacheStragy,
193     Drawing::Canvas& canvas, RSRenderParams& params, bool& isOpincDropNodeExt)
194 {
195     if (!autoCacheEnable_) {
196         return;
197     }
198     temNodeStragyType_ = cacheStragy;
199     if (!BeforeDrawCacheProcessChildNode(cacheStragy, params)) {
200         OpincCalculateBefore(canvas, params, isOpincDropNodeExt);
201         return;
202     }
203     switch (recordState_) {
204         case NodeRecordState::RECORD_NONE:
205             // find root node
206             BeforeDrawCacheFindRootNode(canvas, params, isOpincDropNodeExt);
207             break;
208         case NodeRecordState::RECORD_CALCULATE:
209             // cal img
210             break;
211         case NodeRecordState::RECORD_CACHING:
212             // recording
213             break;
214         case NodeRecordState::RECORD_CACHED:
215             reuseCount_++;
216             break;
217         default:
218             break;
219     }
220     cacheStragy = rootNodeStragyType_;
221     OpincCalculateBefore(canvas, params, isOpincDropNodeExt);
222 }
223 
IsOpincNodeInScreenRect(RSRenderParams & params)224 bool RSRenderNodeDrawable::IsOpincNodeInScreenRect(RSRenderParams& params)
225 {
226     auto nodeAbsRect = params.GetAbsDrawRect();
227     RS_OPTIONAL_TRACE_NAME_FMT("opincNodeAbsRect{%d %d %d %d}, screenRect{%d %d %d %d}",
228         nodeAbsRect.GetLeft(), nodeAbsRect.GetTop(), nodeAbsRect.GetRight(), nodeAbsRect.GetBottom(),
229         screenRectInfo_.GetLeft(), screenRectInfo_.GetTop(), screenRectInfo_.GetRight(), screenRectInfo_.GetBottom());
230     if (!nodeAbsRect.IsEmpty() && nodeAbsRect.IsInsideOf(screenRectInfo_)) {
231         return true;
232     }
233     return false;
234 }
235 
AfterDrawCache(NodeStrategyType & cacheStragy,Drawing::Canvas & canvas,RSRenderParams & params,bool & isOpincDropNodeExt,int & opincRootTotalCount)236 void RSRenderNodeDrawable::AfterDrawCache(NodeStrategyType& cacheStragy,
237     Drawing::Canvas& canvas, RSRenderParams& params, bool& isOpincDropNodeExt, int& opincRootTotalCount)
238 {
239     if (!autoCacheEnable_) {
240         return;
241     }
242     OpincCalculateAfter(canvas, isOpincDropNodeExt);
243     if (rootNodeStragyType_ == NodeStrategyType::OPINC_AUTOCACHE && recordState_ == NodeRecordState::RECORD_CALCULATE) {
244         bool isOnlyTranslate = false;
245         auto totalMatrix = canvas.GetTotalMatrix();
246         auto rootAlpha = canvas.GetAlpha();
247         if (IsTranslate(totalMatrix) && (rootAlpha == 0.0f || rootAlpha == 1.0f)) {
248             isOnlyTranslate = true;
249         }
250         if (IsOpincRealDrawCacheEnable()) {
251             if (isDrawAreaEnable_ == DrawAreaEnableState::DRAW_AREA_ENABLE && isOnlyTranslate) {
252                 recordState_ = NodeRecordState::RECORD_CACHING;
253             } else if (isDrawAreaEnable_ == DrawAreaEnableState::DRAW_AREA_DISABLE) {
254                 NodeCacheStateDisable();
255             }
256         }
257     } else if (rootNodeStragyType_ == NodeStrategyType::OPINC_AUTOCACHE &&
258         recordState_ == NodeRecordState::RECORD_CACHING) {
259         if ((opincRootTotalCount < OPINC_ROOT_TOTAL_MAX) && (!OpincGetCachedMark()) &&
260             IsOpincNodeInScreenRect(params)) {
261             opincRootTotalCount++;
262             isOpincMarkCached_ = true;
263             recordState_ = NodeRecordState::RECORD_CACHED;
264             reuseCount_ = 0;
265             isOpincRootNode_ = true;
266         }
267     }
268     cacheStragy = temNodeStragyType_;
269 }
270 
DrawAutoCache(RSPaintFilterCanvas & canvas,Drawing::Image & image,const Drawing::SamplingOptions & samplingOption,Drawing::SrcRectConstraint constraint)271 bool RSRenderNodeDrawable::DrawAutoCache(RSPaintFilterCanvas& canvas, Drawing::Image& image,
272     const Drawing::SamplingOptions& samplingOption, Drawing::SrcRectConstraint constraint)
273 {
274     if (!IsComputeDrawAreaSucc() || !opCanCache_) {
275         return false;
276     }
277     auto& unionRect = opListDrawAreas_.GetOpInfo().unionRect;
278     auto& drawRects = opListDrawAreas_.GetOpInfo().drawAreaRects;
279     if (unionRect.IsEmpty() || drawRects.size() == 0) {
280         return false;
281     }
282     for (auto& rect : drawRects) {
283         auto srcRect = rect;
284         srcRect.Offset(-unionRect.GetLeft(), -unionRect.GetTop());
285         canvas.DrawImageRect(image, srcRect, rect, samplingOption, constraint);
286     }
287     RS_OPTIONAL_TRACE_NAME_FMT("opinc_size:%d", drawRects.size());
288     return true;
289 }
290 
DrawAutoCacheDfx(RSPaintFilterCanvas & canvas,std::vector<std::pair<RectI,std::string>> & autoCacheRenderNodeInfos)291 void RSRenderNodeDrawable::DrawAutoCacheDfx(RSPaintFilterCanvas& canvas,
292     std::vector<std::pair<RectI, std::string>>& autoCacheRenderNodeInfos)
293 {
294 #ifdef DDGR_ENABLE_FEATURE_OPINC_DFX
295     if (!IsAutoCacheDebugEnable()) {
296         return;
297     }
298     auto& unionRect = opListDrawAreas_.GetOpInfo().unionRect;
299     auto& drawRects = opListDrawAreas_.GetOpInfo().drawAreaRects;
300     if (unionRect.IsEmpty() || drawRects.size() == 0) {
301         return;
302     }
303     Drawing::Brush brush;
304     brush.SetColor(Drawing::Color(0x807C7CD5));
305     canvas.AttachBrush(brush);
306     canvas.DrawRect(unionRect);
307     canvas.DetachBrush();
308     Drawing::Pen pen;
309     pen.SetColor(Drawing::Color(0x80FF00FF));
310     pen.SetWidth(1);
311     canvas.AttachPen(pen);
312     for (auto& rect : drawRects) {
313         canvas.DrawRect(rect);
314     }
315     canvas.DetachPen();
316 #else
317     if (!IsAutoCacheDebugEnable()) {
318         return;
319     }
320     Drawing::Rect dst;
321     canvas.GetTotalMatrix().MapRect(dst, opListDrawAreas_.GetOpInfo().unionRect);
322     RectI dfxRect(static_cast<int>(dst.GetLeft()), static_cast<int>(dst.GetTop()),
323         static_cast<int>(dst.GetWidth()), static_cast<int>(dst.GetHeight()));
324     auto& info = opListDrawAreas_.GetOpInfo();
325     std::string extra =
326         "Re:" + std::to_string(reuseCount_) +
327         " S:" + (rootNodeStragyType_ == NodeStrategyType::OPINC_AUTOCACHE ? "img" : "op") +
328         " Op" + std::to_string(info.num) +
329         " Pe" + std::to_string(info.percent);
330     autoCacheRenderNodeInfos.push_back({dfxRect, extra});
331 #endif
332 }
333 
334 // opinc dfx
GetNodeDebugInfo()335 std::string RSRenderNodeDrawable::GetNodeDebugInfo()
336 {
337     std::string ret("");
338 #ifdef DDGR_ENABLE_FEATURE_OPINC_DFX
339     const auto& params = GetRenderParams();
340     if (!params) {
341         return ret;
342     }
343     auto& unionRect = opListDrawAreas_.GetOpInfo().unionRect;
344     AppendFormat(ret, "%llx, rootF:%d record:%d rootS:%d opCan:%d isRD:%d, GetOpDropped:%d isOpincDropNodeExt:%d",
345         params->GetId(), params->OpincGetRootFlag(),
346         recordState_, rootNodeStragyType_, opCanCache_, isDrawAreaEnable_, GetOpDropped(), isOpincDropNodeExt_);
347     auto& info = opListDrawAreas_.GetOpInfo();
348     AppendFormat(ret, " opNum%d", info.num, info.percent);
349     auto bounds = params->GetBounds();
350     AppendFormat(ret, ", rr{%.1f %.1f %.1f %.1f}",
351         0.f, 0.f, bounds.GetWidth(), bounds.GetHeight());
352     AppendFormat(ret, ", ur{%.1f %.1f %.1f %.1f}",
353         unionRect.GetLeft(), unionRect.GetTop(), unionRect.GetWidth(), unionRect.GetHeight());
354 #endif
355     return ret;
356 }
357 } // namespace OHOS::Rosen::DrawableV2
358