• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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