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