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