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_property_drawable.h"
17
18 #include "rs_trace.h"
19
20 #include "common/rs_optional_trace.h"
21 #include "drawable/rs_property_drawable_utils.h"
22 #include "gfx/performance/rs_perfmonitor_reporter.h"
23 #include "pipeline/rs_recording_canvas.h"
24 #include "pipeline/rs_render_node.h"
25 #include "pipeline/rs_surface_render_node.h"
26 #include "platform/common/rs_log.h"
27 #include "render/rs_filter_cache_manager.h"
28 #include "render/rs_drawing_filter.h"
29 #include "render/rs_linear_gradient_blur_shader_filter.h"
30
31 namespace OHOS::Rosen {
32 namespace DrawableV2 {
33 constexpr int TRACE_LEVEL_TWO = 2;
OnSync()34 void RSPropertyDrawable::OnSync()
35 {
36 if (!needSync_) {
37 return;
38 }
39 std::swap(drawCmdList_, stagingDrawCmdList_);
40 propertyDescription_ = stagingPropertyDescription_;
41 stagingPropertyDescription_.clear();
42 needSync_ = false;
43 }
44
OnPurge()45 void RSPropertyDrawable::OnPurge()
46 {
47 if (drawCmdList_) {
48 drawCmdList_->Purge();
49 }
50 }
51
CreateDrawFunc() const52 Drawing::RecordingCanvas::DrawFunc RSPropertyDrawable::CreateDrawFunc() const
53 {
54 auto ptr = std::static_pointer_cast<const RSPropertyDrawable>(shared_from_this());
55 return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
56 ptr->drawCmdList_->Playback(*canvas);
57 if (!ptr->propertyDescription_.empty()) {
58 RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO, "RSPropertyDrawable:: %s, bounds:%s",
59 ptr->propertyDescription_.c_str(), rect->ToString().c_str());
60 }
61 };
62 }
63
64 // ============================================================================
65 // Updater
RSPropertyDrawCmdListUpdater(int width,int height,RSPropertyDrawable * target)66 RSPropertyDrawCmdListUpdater::RSPropertyDrawCmdListUpdater(int width, int height, RSPropertyDrawable* target)
67 : target_(target)
68 {
69 // PLANNING: use RSRenderNode to determine the correct recording canvas size
70 recordingCanvas_ = ExtendRecordingCanvas::Obtain(10, 10, false); // width 10, height 10
71 }
72
~RSPropertyDrawCmdListUpdater()73 RSPropertyDrawCmdListUpdater::~RSPropertyDrawCmdListUpdater()
74 {
75 if (recordingCanvas_ && target_) {
76 target_->stagingDrawCmdList_ = recordingCanvas_->GetDrawCmdList();
77 target_->needSync_ = true;
78 ExtendRecordingCanvas::Recycle(recordingCanvas_);
79 recordingCanvas_.reset();
80 target_ = nullptr;
81 } else {
82 ROSEN_LOGE("Update failed, recording canvas is null!");
83 }
84 }
85
GetRecordingCanvas() const86 const std::unique_ptr<ExtendRecordingCanvas>& RSPropertyDrawCmdListUpdater::GetRecordingCanvas() const
87 {
88 return recordingCanvas_;
89 }
90
91 // ============================================================================
OnGenerate(const RSRenderNode & node)92 RSDrawable::Ptr RSFrameOffsetDrawable::OnGenerate(const RSRenderNode& node)
93 {
94 if (auto ret = std::make_shared<RSFrameOffsetDrawable>(); ret->OnUpdate(node)) {
95 return std::move(ret);
96 }
97 return nullptr;
98 };
99
OnUpdate(const RSRenderNode & node)100 bool RSFrameOffsetDrawable::OnUpdate(const RSRenderNode& node)
101 {
102 const RSProperties& properties = node.GetRenderProperties();
103 auto frameOffsetX = properties.GetFrameOffsetX();
104 auto frameOffsetY = properties.GetFrameOffsetY();
105 if (frameOffsetX == 0 && frameOffsetY == 0) {
106 return false;
107 }
108
109 // regenerate stagingDrawCmdList_
110 RSPropertyDrawCmdListUpdater updater(0, 0, this);
111 updater.GetRecordingCanvas()->Translate(frameOffsetX, frameOffsetY);
112 return true;
113 }
114
115 // ============================================================================
OnGenerate(const RSRenderNode & node)116 RSDrawable::Ptr RSClipToBoundsDrawable::OnGenerate(const RSRenderNode& node)
117 {
118 auto ret = std::make_shared<RSClipToBoundsDrawable>();
119 ret->OnUpdate(node);
120 ret->OnSync();
121 return std::move(ret);
122 };
123
OnUpdate(const RSRenderNode & node)124 bool RSClipToBoundsDrawable::OnUpdate(const RSRenderNode& node)
125 {
126 const RSProperties& properties = node.GetRenderProperties();
127 RSPropertyDrawCmdListUpdater updater(0, 0, this);
128 auto& canvas = *updater.GetRecordingCanvas();
129 if (properties.GetClipBounds() != nullptr) {
130 canvas.ClipPath(properties.GetClipBounds()->GetDrawingPath(), Drawing::ClipOp::INTERSECT, true);
131 } else if (properties.GetClipToRRect()) {
132 canvas.ClipRoundRect(
133 RSPropertyDrawableUtils::RRect2DrawingRRect(properties.GetClipRRect()), Drawing::ClipOp::INTERSECT, true);
134 } else if (!properties.GetCornerRadius().IsZero()) {
135 canvas.ClipRoundRect(
136 RSPropertyDrawableUtils::RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, true);
137 } else if (node.GetType() == RSRenderNodeType::SURFACE_NODE && RSSystemProperties::GetCacheEnabledForRotation() &&
138 node.ReinterpretCastTo<RSSurfaceRenderNode>()->IsAppWindow()) {
139 Drawing::Rect rect = RSPropertyDrawableUtils::Rect2DrawingRect(properties.GetBoundsRect());
140 Drawing::RectI iRect(rect.GetLeft(), rect.GetTop(), rect.GetRight(), rect.GetBottom());
141 canvas.ClipIRect(iRect, Drawing::ClipOp::INTERSECT);
142 } else {
143 canvas.ClipRect(
144 RSPropertyDrawableUtils::Rect2DrawingRect(properties.GetBoundsRect()), Drawing::ClipOp::INTERSECT, false);
145 }
146 return true;
147 }
148
OnGenerate(const RSRenderNode & node)149 RSDrawable::Ptr RSClipToFrameDrawable::OnGenerate(const RSRenderNode& node)
150 {
151 if (auto ret = std::make_shared<RSClipToFrameDrawable>(); ret->OnUpdate(node)) {
152 return std::move(ret);
153 }
154 return nullptr;
155 }
156
OnUpdate(const RSRenderNode & node)157 bool RSClipToFrameDrawable::OnUpdate(const RSRenderNode& node)
158 {
159 const RSProperties& properties = node.GetRenderProperties();
160 if (!properties.GetClipToFrame()) {
161 return false;
162 }
163
164 RSPropertyDrawCmdListUpdater updater(0, 0, this);
165 updater.GetRecordingCanvas()->ClipRect(
166 RSPropertyDrawableUtils::Rect2DrawingRect(properties.GetFrameRect()), Drawing::ClipOp::INTERSECT, false);
167 return true;
168 }
169
RSFilterDrawable()170 RSFilterDrawable::RSFilterDrawable()
171 {
172 if (RSProperties::filterCacheEnabled_) {
173 stagingCacheManager_ = std::make_unique<RSFilterCacheManager>();
174 cacheManager_ = std::make_unique<RSFilterCacheManager>();
175 }
176 }
177
OnSync()178 void RSFilterDrawable::OnSync()
179 {
180 if (needSync_) {
181 filter_ = std::move(stagingFilter_);
182 needSync_ = false;
183 }
184 renderNodeId_ = stagingNodeId_;
185 renderNodeName_ = stagingNodeName_;
186 renderIntersectWithDRM_ = stagingIntersectWithDRM_;
187 renderIsDarkColorMode_ = stagingIsDarkColorMode_;
188
189 stagingIntersectWithDRM_ = false;
190 stagingIsDarkColorMode_ = false;
191
192 needSync_ = false;
193
194 if (!RSProperties::filterCacheEnabled_ || stagingCacheManager_ == nullptr ||
195 cacheManager_ == nullptr || filter_ == nullptr) {
196 ROSEN_LOGD("Clear filter cache failed or no need to clear cache, filterCacheEnabled:%{public}d,"
197 "cacheManager:%{public}d, filter:%{public}d", RSProperties::filterCacheEnabled_,
198 stagingCacheManager_ != nullptr, filter_ == nullptr);
199 return;
200 }
201 stagingCacheManager_->SwapDataAndInitStagingFlags(cacheManager_);
202 }
203
WouldDrawLargeAreaBlur()204 bool RSFilterDrawable::WouldDrawLargeAreaBlur()
205 {
206 RS_TRACE_NAME_FMT("wouldDrawLargeAreaBlur stagingNodeId[%llu]", stagingNodeId_);
207 if (stagingCacheManager_ == nullptr) {
208 return false;
209 }
210 return stagingCacheManager_->WouldDrawLargeAreaBlur();
211 }
212
WouldDrawLargeAreaBlurPrecisely()213 bool RSFilterDrawable::WouldDrawLargeAreaBlurPrecisely()
214 {
215 RS_TRACE_NAME_FMT("wouldDrawLargeAreaBlurPrecisely stagingNodeId[%llu]", stagingNodeId_);
216 if (stagingCacheManager_ == nullptr) {
217 return false;
218 }
219 return stagingCacheManager_->WouldDrawLargeAreaBlurPrecisely();
220 }
221
CreateDrawFunc() const222 Drawing::RecordingCanvas::DrawFunc RSFilterDrawable::CreateDrawFunc() const
223 {
224 auto ptr = std::static_pointer_cast<const RSFilterDrawable>(shared_from_this());
225 return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
226 if (ptr->needDrawBehindWindow_) {
227 auto paintFilterCanvas = static_cast<RSPaintFilterCanvas*>(canvas);
228 if (!paintFilterCanvas || !canvas->GetSurface()) {
229 RS_LOGE("RSFilterDrawable::CreateDrawFunc DrawBehindWindow canvas:[%{public}d], surface:[%{public}d]",
230 paintFilterCanvas != nullptr, canvas->GetSurface() != nullptr);
231 return;
232 }
233 RS_TRACE_NAME_FMT("RSFilterDrawable::CreateDrawFunc DrawBehindWindow node[%llu], windowFreezeCapture[%d]",
234 ptr->renderNodeId_, paintFilterCanvas->GetIsWindowFreezeCapture());
235 if (paintFilterCanvas->GetIsWindowFreezeCapture()) {
236 RS_LOGD("RSFilterDrawable::CreateDrawFunc DrawBehindWindow capture freeze surface, "
237 "no need to drawBehindWindow");
238 return;
239 }
240 Drawing::AutoCanvasRestore acr(*canvas, true);
241 paintFilterCanvas->ClipRect(*rect);
242 Drawing::Rect absRect(0.0, 0.0, 0.0, 0.0);
243 Drawing::Rect relativeBounds(ptr->drawBehindWindowRegion_.GetLeft(), ptr->drawBehindWindowRegion_.GetTop(),
244 ptr->drawBehindWindowRegion_.GetRight(), ptr->drawBehindWindowRegion_.GetBottom());
245 canvas->GetTotalMatrix().MapRect(absRect, relativeBounds);
246 Drawing::RectI bounds(std::ceil(absRect.GetLeft()), std::ceil(absRect.GetTop()),
247 std::ceil(absRect.GetRight()), std::ceil(absRect.GetBottom()));
248 auto deviceRect = Drawing::RectI(0, 0, canvas->GetSurface()->Width(), canvas->GetSurface()->Height());
249 bounds.Intersect(deviceRect);
250 RSPropertyDrawableUtils::DrawBackgroundEffect(paintFilterCanvas, ptr->filter_, ptr->cacheManager_,
251 bounds, true);
252 return;
253 }
254 if (canvas && ptr && ptr->renderIntersectWithDRM_) {
255 RS_TRACE_NAME_FMT("RSFilterDrawable::CreateDrawFunc IntersectWithDRM node[%lld] isDarkColorMode[%d]",
256 ptr->renderNodeId_, ptr->renderIsDarkColorMode_);
257 RSPropertyDrawableUtils::DrawFilterWithDRM(canvas, ptr->renderIsDarkColorMode_);
258 return;
259 }
260 if (canvas && ptr && ptr->filter_) {
261 RS_TRACE_NAME_FMT("RSFilterDrawable::CreateDrawFunc node[%llu] ", ptr->renderNodeId_);
262 if (ptr->filter_->GetFilterType() == RSFilter::LINEAR_GRADIENT_BLUR && rect != nullptr) {
263 auto filter = std::static_pointer_cast<RSDrawingFilter>(ptr->filter_);
264 std::shared_ptr<RSShaderFilter> rsShaderFilter =
265 filter->GetShaderFilterWithType(RSShaderFilter::LINEAR_GRADIENT_BLUR);
266 if (rsShaderFilter != nullptr) {
267 auto tmpFilter = std::static_pointer_cast<RSLinearGradientBlurShaderFilter>(rsShaderFilter);
268 tmpFilter->SetGeometry(*canvas, rect->GetWidth(), rect->GetHeight());
269 }
270 }
271 int64_t startBlurTime = Drawing::PerfmonitorReporter::GetCurrentTime();
272 RSPropertyDrawableUtils::DrawFilter(canvas, ptr->filter_,
273 ptr->cacheManager_, ptr->IsForeground());
274 int64_t blurDuration = Drawing::PerfmonitorReporter::GetCurrentTime() - startBlurTime;
275 auto filterType = ptr->filter_->GetFilterType();
276 RSPerfMonitorReporter::GetInstance().RecordBlurNode(ptr->renderNodeName_, blurDuration,
277 RSPropertyDrawableUtils::IsBlurFilterType(filterType));
278 if (rect != nullptr) {
279 RSPerfMonitorReporter::GetInstance().RecordBlurPerfEvent(ptr->renderNodeId_, ptr->renderNodeName_,
280 static_cast<uint16_t>(filterType), RSPropertyDrawableUtils::GetBlurFilterRadius(ptr->filter_),
281 rect->GetWidth(), rect->GetHeight(), blurDuration,
282 RSPropertyDrawableUtils::IsBlurFilterType(filterType));
283 }
284 }
285 };
286 }
287
GetFilterCachedRegion() const288 const RectI RSFilterDrawable::GetFilterCachedRegion() const
289 {
290 return cacheManager_ == nullptr ? RectI() : cacheManager_->GetCachedImageRegion();
291 }
292
MarkFilterRegionChanged()293 void RSFilterDrawable::MarkFilterRegionChanged()
294 {
295 if (stagingCacheManager_ == nullptr) {
296 return;
297 }
298 RSPerfMonitorReporter::GetInstance().RecordBlurCacheReason(this->renderNodeName_,
299 BLUR_CLEAR_CACHE_REASON::BLUR_REGION_CHANGED,
300 RSPropertyDrawableUtils::IsBlurFilterType(stagingCacheManager_->GetFilterType()));
301
302 stagingCacheManager_->MarkFilterRegionChanged();
303 }
304
MarkFilterRegionInteractWithDirty()305 void RSFilterDrawable::MarkFilterRegionInteractWithDirty()
306 {
307 if (stagingCacheManager_ == nullptr) {
308 return;
309 }
310 RSPerfMonitorReporter::GetInstance().RecordBlurCacheReason(this->renderNodeName_,
311 BLUR_CLEAR_CACHE_REASON::BLUR_CONTENT_CHANGED,
312 RSPropertyDrawableUtils::IsBlurFilterType(stagingCacheManager_->GetFilterType()));
313
314 stagingCacheManager_->MarkFilterRegionInteractWithDirty();
315 }
316
MarkFilterRegionIsLargeArea()317 void RSFilterDrawable::MarkFilterRegionIsLargeArea()
318 {
319 if (stagingCacheManager_ == nullptr) {
320 return;
321 }
322 RSPerfMonitorReporter::GetInstance().RecordBlurCacheReason(this->renderNodeName_,
323 BLUR_CLEAR_CACHE_REASON::DIRTY_OVER_SIZE,
324 RSPropertyDrawableUtils::IsBlurFilterType(stagingCacheManager_->GetFilterType()));
325
326 stagingCacheManager_->MarkFilterRegionIsLargeArea();
327 }
328
MarkFilterForceUseCache(bool forceUseCache)329 void RSFilterDrawable::MarkFilterForceUseCache(bool forceUseCache)
330 {
331 if (stagingCacheManager_ != nullptr) {
332 stagingCacheManager_->MarkFilterForceUseCache(forceUseCache);
333 }
334 }
335
MarkFilterForceClearCache()336 void RSFilterDrawable::MarkFilterForceClearCache()
337 {
338 if (stagingCacheManager_ == nullptr) {
339 return;
340 }
341 RSPerfMonitorReporter::GetInstance().RecordBlurCacheReason(this->renderNodeName_,
342 BLUR_CLEAR_CACHE_REASON::FORCE_CLEAR_CACHE,
343 RSPropertyDrawableUtils::IsBlurFilterType(stagingCacheManager_->GetFilterType()));
344 stagingCacheManager_->MarkFilterForceClearCache();
345 }
346
MarkRotationChanged()347 void RSFilterDrawable::MarkRotationChanged()
348 {
349 if (stagingCacheManager_ == nullptr) {
350 return;
351 }
352 RSPerfMonitorReporter::GetInstance().RecordBlurCacheReason(this->renderNodeName_,
353 BLUR_CLEAR_CACHE_REASON::ROTATION_CHANGED,
354 RSPropertyDrawableUtils::IsBlurFilterType(stagingCacheManager_->GetFilterType()));
355
356 stagingCacheManager_->MarkRotationChanged();
357 }
358
MarkNodeIsOccluded(bool isOccluded)359 void RSFilterDrawable::MarkNodeIsOccluded(bool isOccluded)
360 {
361 if (stagingCacheManager_ == nullptr) {
362 return;
363 }
364 RSPerfMonitorReporter::GetInstance().RecordBlurCacheReason(this->renderNodeName_,
365 BLUR_CLEAR_CACHE_REASON::NODE_IS_OCCLUDED,
366 RSPropertyDrawableUtils::IsBlurFilterType(stagingCacheManager_->GetFilterType()));
367
368 stagingCacheManager_->MarkNodeIsOccluded(isOccluded);
369 }
370
MarkForceClearCacheWithLastFrame()371 void RSFilterDrawable::MarkForceClearCacheWithLastFrame()
372 {
373 if (stagingCacheManager_ == nullptr) {
374 return;
375 }
376 RSPerfMonitorReporter::GetInstance().RecordBlurCacheReason(this->renderNodeName_,
377 BLUR_CLEAR_CACHE_REASON::SKIP_FRAME_NO_VSYNC,
378 RSPropertyDrawableUtils::IsBlurFilterType(stagingCacheManager_->GetFilterType()));
379
380 stagingCacheManager_->MarkForceClearCacheWithLastFrame();
381 }
382
MarkNeedClearFilterCache()383 void RSFilterDrawable::MarkNeedClearFilterCache()
384 {
385 if (stagingCacheManager_ == nullptr) {
386 return;
387 }
388 RS_TRACE_NAME_FMT("RSFilterDrawable::MarkNeedClearFilterCache nodeId[%llu]", stagingNodeId_);
389 stagingCacheManager_->MarkNeedClearFilterCache();
390 ROSEN_LOGD("RSFilterDrawable::MarkNeedClearFilterCache nodeId[%{public}lld]",
391 static_cast<long long>(stagingNodeId_));
392 }
393
394 //should be called in rs main thread
MarkBlurIntersectWithDRM(bool intersectWithDRM,bool isDark)395 void RSFilterDrawable::MarkBlurIntersectWithDRM(bool intersectWithDRM, bool isDark)
396 {
397 stagingIntersectWithDRM_ = intersectWithDRM;
398 stagingIsDarkColorMode_ = isDark;
399 }
400
IsFilterCacheValid() const401 bool RSFilterDrawable::IsFilterCacheValid() const
402 {
403 if (stagingCacheManager_ == nullptr) {
404 return false;
405 }
406 return stagingCacheManager_->IsFilterCacheValid();
407 }
408
IsSkippingFrame() const409 bool RSFilterDrawable::IsSkippingFrame() const
410 {
411 if (stagingCacheManager_ == nullptr) {
412 return false;
413 }
414 return stagingCacheManager_->IsSkippingFrame();
415 }
416
IsForceClearFilterCache() const417 bool RSFilterDrawable::IsForceClearFilterCache() const
418 {
419 if (stagingCacheManager_ == nullptr) {
420 return false;
421 }
422 return stagingCacheManager_->IsForceClearFilterCache();
423 }
424
IsForceUseFilterCache() const425 bool RSFilterDrawable::IsForceUseFilterCache() const
426 {
427 if (stagingCacheManager_ == nullptr) {
428 return false;
429 }
430 return stagingCacheManager_->IsForceUseFilterCache();
431 }
432
NeedPendingPurge() const433 bool RSFilterDrawable::NeedPendingPurge() const
434 {
435 if (stagingCacheManager_ == nullptr) {
436 return false;
437 }
438 return stagingCacheManager_->NeedPendingPurge();
439 }
440
MarkEffectNode()441 void RSFilterDrawable::MarkEffectNode()
442 {
443 if (stagingCacheManager_ != nullptr) {
444 stagingCacheManager_->MarkEffectNode();
445 }
446 }
447
RecordFilterInfos(const std::shared_ptr<RSFilter> & rsFilter)448 void RSFilterDrawable::RecordFilterInfos(const std::shared_ptr<RSFilter>& rsFilter)
449 {
450 if (stagingCacheManager_ != nullptr) {
451 stagingCacheManager_->RecordFilterInfos(rsFilter);
452 }
453 }
454
455 // called after OnSync()
IsFilterCacheValidForOcclusion()456 bool RSFilterDrawable::IsFilterCacheValidForOcclusion()
457 {
458 if (cacheManager_ == nullptr) {
459 ROSEN_LOGD("RSFilterDrawable::IsFilterCacheValidForOcclusion cacheManager not available");
460 return false;
461 }
462 return cacheManager_->IsFilterCacheValidForOcclusion();
463 }
464
IsAIBarFilter() const465 bool RSFilterDrawable::IsAIBarFilter() const
466 {
467 if (stagingCacheManager_ == nullptr) {
468 return false;
469 }
470 return stagingCacheManager_->GetFilterType() == RSFilter::AIBAR;
471 }
472
IsAIBarCacheValid()473 bool RSFilterDrawable::IsAIBarCacheValid()
474 {
475 if (stagingCacheManager_ == nullptr) {
476 return false;
477 }
478 return stagingCacheManager_->IsAIBarCacheValid();
479 }
480
SetDrawBehindWindowRegion(RectI region)481 void RSFilterDrawable::SetDrawBehindWindowRegion(RectI region)
482 {
483 stagingDrawBehindWindowRegion_ = region;
484 }
485 } // namespace DrawableV2
486 } // namespace OHOS::Rosen
487