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