• 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 "pipeline/rs_recording_canvas.h"
23 #include "pipeline/rs_render_node.h"
24 #include "pipeline/rs_surface_render_node.h"
25 #include "platform/common/rs_log.h"
26 #include "property/rs_filter_cache_manager.h"
27 #include "render/rs_drawing_filter.h"
28 #include "render/rs_linear_gradient_blur_shader_filter.h"
29 
30 namespace OHOS::Rosen {
31 constexpr int AIBAR_CACHE_UPDATE_INTERVAL = 5;
32 constexpr int ROTATION_CACHE_UPDATE_INTERVAL = 1;
33 namespace DrawableV2 {
34 constexpr int TRACE_LEVEL_TWO = 2;
OnSync()35 void RSPropertyDrawable::OnSync()
36 {
37     if (!needSync_) {
38         return;
39     }
40     std::swap(drawCmdList_, stagingDrawCmdList_);
41     propertyDescription_ = stagingPropertyDescription_;
42     stagingPropertyDescription_.clear();
43     needSync_ = false;
44 }
45 
OnPurge()46 void RSPropertyDrawable::OnPurge()
47 {
48     if (drawCmdList_) {
49         drawCmdList_->Purge();
50     }
51 }
52 
CreateDrawFunc() const53 Drawing::RecordingCanvas::DrawFunc RSPropertyDrawable::CreateDrawFunc() const
54 {
55     auto ptr = std::static_pointer_cast<const RSPropertyDrawable>(shared_from_this());
56     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
57         ptr->drawCmdList_->Playback(*canvas);
58         if (!ptr->propertyDescription_.empty()) {
59             RS_OPTIONAL_TRACE_NAME_FMT_LEVEL(TRACE_LEVEL_TWO, "RSPropertyDrawable:: %s, bounds:%s",
60                 ptr->propertyDescription_.c_str(), rect->ToString().c_str());
61         }
62     };
63 }
64 
65 // ============================================================================
66 // Updater
RSPropertyDrawCmdListUpdater(int width,int height,RSPropertyDrawable * target)67 RSPropertyDrawCmdListUpdater::RSPropertyDrawCmdListUpdater(int width, int height, RSPropertyDrawable* target)
68     : target_(target)
69 {
70     // PLANNING: use RSRenderNode to determine the correct recording canvas size
71     recordingCanvas_ = ExtendRecordingCanvas::Obtain(10, 10, false); // width 10, height 10
72 }
73 
~RSPropertyDrawCmdListUpdater()74 RSPropertyDrawCmdListUpdater::~RSPropertyDrawCmdListUpdater()
75 {
76     if (recordingCanvas_ && target_) {
77         target_->stagingDrawCmdList_ = recordingCanvas_->GetDrawCmdList();
78         target_->needSync_ = true;
79         ExtendRecordingCanvas::Recycle(recordingCanvas_);
80         recordingCanvas_.reset();
81         target_ = nullptr;
82     } else {
83         ROSEN_LOGE("Update failed, recording canvas is null!");
84     }
85 }
86 
GetRecordingCanvas() const87 const std::unique_ptr<ExtendRecordingCanvas>& RSPropertyDrawCmdListUpdater::GetRecordingCanvas() const
88 {
89     return recordingCanvas_;
90 }
91 
92 // ============================================================================
OnGenerate(const RSRenderNode & node)93 RSDrawable::Ptr RSFrameOffsetDrawable::OnGenerate(const RSRenderNode& node)
94 {
95     if (auto ret = std::make_shared<RSFrameOffsetDrawable>(); ret->OnUpdate(node)) {
96         return std::move(ret);
97     }
98     return nullptr;
99 };
100 
OnUpdate(const RSRenderNode & node)101 bool RSFrameOffsetDrawable::OnUpdate(const RSRenderNode& node)
102 {
103     const RSProperties& properties = node.GetRenderProperties();
104     auto frameOffsetX = properties.GetFrameOffsetX();
105     auto frameOffsetY = properties.GetFrameOffsetY();
106     if (frameOffsetX == 0 && frameOffsetY == 0) {
107         return false;
108     }
109 
110     // regenerate stagingDrawCmdList_
111     RSPropertyDrawCmdListUpdater updater(0, 0, this);
112     updater.GetRecordingCanvas()->Translate(frameOffsetX, frameOffsetY);
113     return true;
114 }
115 
116 // ============================================================================
OnGenerate(const RSRenderNode & node)117 RSDrawable::Ptr RSClipToBoundsDrawable::OnGenerate(const RSRenderNode& node)
118 {
119     auto ret = std::make_shared<RSClipToBoundsDrawable>();
120     ret->OnUpdate(node);
121     ret->OnSync();
122     return std::move(ret);
123 };
124 
OnUpdate(const RSRenderNode & node)125 bool RSClipToBoundsDrawable::OnUpdate(const RSRenderNode& node)
126 {
127     const RSProperties& properties = node.GetRenderProperties();
128     RSPropertyDrawCmdListUpdater updater(0, 0, this);
129     auto& canvas = *updater.GetRecordingCanvas();
130     if (properties.GetClipBounds() != nullptr) {
131         canvas.ClipPath(properties.GetClipBounds()->GetDrawingPath(), Drawing::ClipOp::INTERSECT, true);
132     } else if (properties.GetClipToRRect()) {
133         canvas.ClipRoundRect(
134             RSPropertyDrawableUtils::RRect2DrawingRRect(properties.GetClipRRect()), Drawing::ClipOp::INTERSECT, true);
135     } else if (!properties.GetCornerRadius().IsZero()) {
136         canvas.ClipRoundRect(
137             RSPropertyDrawableUtils::RRect2DrawingRRect(properties.GetRRect()), Drawing::ClipOp::INTERSECT, true);
138     } else {
139         // Enable anti-aliasing only on surface nodes to resolve the issue of jagged edges on card compoments
140         // during dragging.
141         bool aa = node.IsInstanceOf<RSSurfaceRenderNode>();
142         canvas.ClipRect(
143             RSPropertyDrawableUtils::Rect2DrawingRect(properties.GetBoundsRect()), Drawing::ClipOp::INTERSECT, aa);
144     }
145     return true;
146 }
147 
OnGenerate(const RSRenderNode & node)148 RSDrawable::Ptr RSClipToFrameDrawable::OnGenerate(const RSRenderNode& node)
149 {
150     if (auto ret = std::make_shared<RSClipToFrameDrawable>(); ret->OnUpdate(node)) {
151         return std::move(ret);
152     }
153     return nullptr;
154 }
155 
OnUpdate(const RSRenderNode & node)156 bool RSClipToFrameDrawable::OnUpdate(const RSRenderNode& node)
157 {
158     const RSProperties& properties = node.GetRenderProperties();
159     if (!properties.GetClipToFrame()) {
160         return false;
161     }
162 
163     RSPropertyDrawCmdListUpdater updater(0, 0, this);
164     updater.GetRecordingCanvas()->ClipRect(
165         RSPropertyDrawableUtils::Rect2DrawingRect(properties.GetFrameRect()), Drawing::ClipOp::INTERSECT, false);
166     return true;
167 }
168 
RSFilterDrawable()169 RSFilterDrawable::RSFilterDrawable()
170 {
171     if (RSProperties::FilterCacheEnabled) {
172         cacheManager_ = std::make_unique<RSFilterCacheManager>();
173     }
174 }
175 
OnSync()176 void RSFilterDrawable::OnSync()
177 {
178     if (needSync_) {
179         filter_ = std::move(stagingFilter_);
180         needSync_ = false;
181     }
182 
183     renderFilterHashChanged_ = stagingFilterHashChanged_;
184     renderForceClearCacheForLastFrame_ = stagingForceClearCacheForLastFrame_;
185     renderIsEffectNode_ = stagingIsEffectNode_;
186     renderIsSkipFrame_ = stagingIsSkipFrame_;
187     renderNodeId_ = stagingNodeId_;
188     renderClearType_ = stagingClearType_;
189     renderIntersectWithDRM_ = stagingIntersectWithDRM_;
190     renderIsDarkColorMode_ = stagingIsDarkColorMode_;
191 
192     ClearFilterCache();
193 
194     stagingFilterHashChanged_ = false;
195     stagingFilterRegionChanged_ = false;
196     stagingFilterInteractWithDirty_ = false;
197     stagingRotationChanged_ = false;
198     stagingForceClearCache_ = false;
199     stagingForceUseCache_ = false;
200     stagingIsOccluded_ = false;
201     stagingForceClearCacheForLastFrame_ = false;
202     stagingIntersectWithDRM_ = false;
203     stagingIsDarkColorMode_ = false;
204 
205     stagingClearType_ = FilterCacheType::BOTH;
206     stagingIsLargeArea_ = false;
207     isFilterCacheValid_ = false;
208     stagingIsEffectNode_ = false;
209     stagingIsSkipFrame_ = false;
210     needSync_ = false;
211 }
212 
CreateDrawFunc() const213 Drawing::RecordingCanvas::DrawFunc RSFilterDrawable::CreateDrawFunc() const
214 {
215     auto ptr = std::static_pointer_cast<const RSFilterDrawable>(shared_from_this());
216     return [ptr](Drawing::Canvas* canvas, const Drawing::Rect* rect) {
217         if (canvas && ptr && ptr->renderIntersectWithDRM_) {
218             RS_TRACE_NAME_FMT("RSFilterDrawable::CreateDrawFunc IntersectWithDRM node[%lld] isDarkColorMode[%d]",
219                 ptr->renderNodeId_, ptr->renderIsDarkColorMode_);
220             RSPropertyDrawableUtils::DrawFilterWithDRM(canvas, ptr->renderIsDarkColorMode_);
221             return;
222         }
223         if (canvas && ptr && ptr->filter_) {
224             RS_TRACE_NAME_FMT("RSFilterDrawable::CreateDrawFunc node[%llu] ", ptr->renderNodeId_);
225             if (ptr->filter_->GetFilterType() == RSFilter::LINEAR_GRADIENT_BLUR && rect != nullptr) {
226                 auto filter = std::static_pointer_cast<RSDrawingFilter>(ptr->filter_);
227                 std::shared_ptr<RSShaderFilter> rsShaderFilter =
228                     filter->GetShaderFilterWithType(RSShaderFilter::LINEAR_GRADIENT_BLUR);
229                 if (rsShaderFilter != nullptr) {
230                     auto tmpFilter = std::static_pointer_cast<RSLinearGradientBlurShaderFilter>(rsShaderFilter);
231                     tmpFilter->SetGeometry(*canvas, rect->GetWidth(), rect->GetHeight());
232                 }
233             }
234             RSPropertyDrawableUtils::DrawFilter(canvas, ptr->filter_,
235                 ptr->cacheManager_, ptr->IsForeground(), ptr->renderClearFilteredCacheAfterDrawing_);
236         }
237     };
238 }
239 
GetFilterCachedRegion() const240 const RectI RSFilterDrawable::GetFilterCachedRegion() const
241 {
242     return cacheManager_ == nullptr ? RectI() : cacheManager_->GetCachedImageRegion();
243 }
244 
MarkFilterRegionChanged()245 void RSFilterDrawable::MarkFilterRegionChanged()
246 {
247     stagingFilterRegionChanged_ = true;
248 }
249 
MarkFilterRegionInteractWithDirty()250 void RSFilterDrawable::MarkFilterRegionInteractWithDirty()
251 {
252     stagingFilterInteractWithDirty_ = true;
253 }
254 
MarkFilterRegionIsLargeArea()255 void RSFilterDrawable::MarkFilterRegionIsLargeArea()
256 {
257     stagingIsLargeArea_ = true;
258 }
259 
MarkFilterForceUseCache(bool forceUseCache)260 void RSFilterDrawable::MarkFilterForceUseCache(bool forceUseCache)
261 {
262     stagingForceUseCache_ = forceUseCache;
263 }
264 
MarkFilterForceClearCache()265 void RSFilterDrawable::MarkFilterForceClearCache()
266 {
267     stagingForceClearCache_ = true;
268 }
269 
MarkRotationChanged()270 void RSFilterDrawable::MarkRotationChanged()
271 {
272     stagingRotationChanged_ = true;
273 }
274 
MarkNodeIsOccluded(bool isOccluded)275 void RSFilterDrawable::MarkNodeIsOccluded(bool isOccluded)
276 {
277     stagingIsOccluded_ = isOccluded;
278 }
279 
MarkForceClearCacheWithLastFrame()280 void RSFilterDrawable::MarkForceClearCacheWithLastFrame()
281 {
282     stagingForceClearCacheForLastFrame_ = true;
283 }
284 
MarkNeedClearFilterCache()285 void RSFilterDrawable::MarkNeedClearFilterCache()
286 {
287     if (cacheManager_ == nullptr) {
288         return;
289     }
290 
291     RS_TRACE_NAME_FMT("RSFilterDrawable::MarkNeedClearFilterCache nodeId[%llu], forceUseCache_:%d,"
292         "forceClearCache_:%d, hashChanged:%d, regionChanged_:%d, belowDirty_:%d,"
293         "lastCacheType:%d, cacheUpdateInterval_:%d, canSkip:%d, isLargeArea:%d, filterType_:%d, pendingPurge_:%d,"
294         "forceClearCacheWithLastFrame:%d, rotationChanged:%d",
295         stagingNodeId_, stagingForceUseCache_, stagingForceClearCache_, stagingFilterHashChanged_,
296         stagingFilterRegionChanged_, stagingFilterInteractWithDirty_,
297         lastCacheType_, cacheUpdateInterval_, canSkipFrame_, stagingIsLargeArea_,
298         filterType_, pendingPurge_, stagingForceClearCacheForLastFrame_, stagingRotationChanged_);
299 
300     // if do not request NextVsync, close skip
301     if (stagingForceClearCacheForLastFrame_) {
302         cacheUpdateInterval_ = 0;
303     }
304 
305     stagingIsSkipFrame_ = stagingIsLargeArea_ && canSkipFrame_ && !stagingFilterRegionChanged_;
306 
307     // no valid cache
308     if (lastCacheType_ == FilterCacheType::NONE) {
309         UpdateFlags(FilterCacheType::NONE, false);
310         return;
311     }
312     // No need to invalidate cache if background image is not null or freezed
313     if (stagingForceUseCache_) {
314         UpdateFlags(FilterCacheType::NONE, true);
315         return;
316     }
317 
318     // clear both two type cache: 1. force clear 2. filter region changed 3.skip-frame finished
319     // 4. background changed and effectNode rotated will enable skip-frame, the last frame need to update.
320     if (stagingForceClearCache_ || (stagingFilterRegionChanged_ && !stagingRotationChanged_) || NeedPendingPurge() ||
321         ((stagingFilterInteractWithDirty_ || stagingRotationChanged_) && cacheUpdateInterval_ <= 0)) {
322         UpdateFlags(FilterCacheType::BOTH, false);
323         return;
324     }
325 
326     // clear snapshot cache last frame and clear filtered cache current frame
327     if (lastCacheType_ == FilterCacheType::FILTERED_SNAPSHOT && stagingFilterHashChanged_) {
328         UpdateFlags(FilterCacheType::FILTERED_SNAPSHOT, false);
329         return;
330     }
331 
332     // when blur filter changes, we need to clear filtered cache if it valid.
333     UpdateFlags(stagingFilterHashChanged_ ?
334         FilterCacheType::FILTERED_SNAPSHOT : FilterCacheType::NONE, true);
335 }
336 
337 //should be called in rs main thread
MarkBlurIntersectWithDRM(bool intersectWithDRM,bool isDark)338 void RSFilterDrawable::MarkBlurIntersectWithDRM(bool intersectWithDRM, bool isDark)
339 {
340     stagingIntersectWithDRM_ = intersectWithDRM;
341     stagingIsDarkColorMode_ = isDark;
342 }
343 
IsFilterCacheValid() const344 bool RSFilterDrawable::IsFilterCacheValid() const
345 {
346     return isFilterCacheValid_;
347 }
348 
IsSkippingFrame() const349 bool RSFilterDrawable::IsSkippingFrame() const
350 {
351     return (stagingFilterInteractWithDirty_ || stagingRotationChanged_) && cacheUpdateInterval_ > 0;
352 }
353 
IsForceClearFilterCache() const354 bool RSFilterDrawable::IsForceClearFilterCache() const
355 {
356     return stagingForceClearCache_;
357 }
358 
IsForceUseFilterCache() const359 bool RSFilterDrawable::IsForceUseFilterCache() const
360 {
361     return stagingForceUseCache_;
362 }
363 
NeedPendingPurge() const364 bool RSFilterDrawable::NeedPendingPurge() const
365 {
366     return !stagingFilterInteractWithDirty_ && pendingPurge_;
367 }
368 
MarkEffectNode()369 void RSFilterDrawable::MarkEffectNode()
370 {
371     stagingIsEffectNode_  = true;
372 }
373 
RecordFilterInfos(const std::shared_ptr<RSFilter> & rsFilter)374 void RSFilterDrawable::RecordFilterInfos(const std::shared_ptr<RSFilter>& rsFilter)
375 {
376     auto filter = std::static_pointer_cast<RSDrawingFilter>(rsFilter);
377     if (filter == nullptr) {
378         return;
379     }
380     stagingFilterHashChanged_ = stagingCachedFilterHash_ != filter->Hash();
381     if (stagingFilterHashChanged_) {
382         stagingCachedFilterHash_ = filter->Hash();
383     }
384     filterType_ = filter->GetFilterType();
385     canSkipFrame_ = filter->CanSkipFrame();
386 }
387 
ClearFilterCache()388 void RSFilterDrawable::ClearFilterCache()
389 {
390     if (!RSProperties::FilterCacheEnabled || cacheManager_ == nullptr || filter_ == nullptr) {
391         ROSEN_LOGD("Clear filter cache failed or no need to clear cache, filterCacheEnabled:%{public}d,"
392             "cacheManager:%{public}d, filter:%{public}d", RSProperties::FilterCacheEnabled,
393             cacheManager_ != nullptr, filter_ == nullptr);
394         return;
395     }
396     // 1. clear memory when region changed and is not the first time occured.
397     bool needClearMemoryForGpu = stagingFilterRegionChanged_ && cacheManager_->GetCachedType() != FilterCacheType::NONE;
398     if (filterType_ == RSFilter::AIBAR && stagingIsOccluded_) {
399         cacheManager_->InvalidateFilterCache(FilterCacheType::BOTH);
400     } else {
401         cacheManager_->InvalidateFilterCache(renderClearType_);
402     }
403     // 2. clear memory when region changed without skip frame.
404     needClearMemoryForGpu = needClearMemoryForGpu && cacheManager_->GetCachedType() == FilterCacheType::NONE;
405     if (needClearMemoryForGpu) {
406         cacheManager_->SetFilterInvalid(true);
407     }
408 
409     // whether to clear blur images. true: clear blur image, false: clear snapshot
410     bool isSaveSnapshot = renderFilterHashChanged_ || cacheManager_->GetCachedType() == FilterCacheType::NONE;
411     bool isAIbarWithLastFrame = filterType_ == RSFilter::AIBAR && renderForceClearCacheForLastFrame_; // last vsync
412 
413     if ((filterType_ != RSFilter::AIBAR || isAIbarWithLastFrame) && isSaveSnapshot) {
414         renderClearFilteredCacheAfterDrawing_ = true;      // hold snapshot
415     } else {
416         renderClearFilteredCacheAfterDrawing_ = false;     // hold blur image
417     }
418     if (renderIsEffectNode_ || renderIsSkipFrame_) { renderClearFilteredCacheAfterDrawing_ = renderFilterHashChanged_; }
419     lastCacheType_ = stagingIsOccluded_ ? cacheManager_->GetCachedType() : (renderClearFilteredCacheAfterDrawing_ ?
420         FilterCacheType::SNAPSHOT : FilterCacheType::FILTERED_SNAPSHOT);
421     RS_TRACE_NAME_FMT("RSFilterDrawable::ClearFilterCache nodeId[%llu], clearType:%d,"
422         " isOccluded_:%d, lastCacheType:%d needClearMemoryForGpu:%d ClearFilteredCacheAfterDrawing:%d",
423         renderNodeId_, renderClearType_, stagingIsOccluded_, lastCacheType_, needClearMemoryForGpu,
424         renderClearFilteredCacheAfterDrawing_);
425 }
426 
427 // called after OnSync()
IsFilterCacheValidForOcclusion()428 bool RSFilterDrawable::IsFilterCacheValidForOcclusion()
429 {
430     auto cacheType = cacheManager_->GetCachedType();
431     RS_OPTIONAL_TRACE_NAME_FMT("RSFilterDrawable::IsFilterCacheValidForOcclusion cacheType:%d renderClearType_:%d",
432         cacheType, renderClearType_);
433 
434     return cacheType != FilterCacheType::NONE;
435 }
436 
UpdateFlags(FilterCacheType type,bool cacheValid)437 void RSFilterDrawable::UpdateFlags(FilterCacheType type, bool cacheValid)
438 {
439     stagingClearType_ = type;
440     isFilterCacheValid_ = cacheValid;
441     if (!cacheValid) {
442         cacheUpdateInterval_ = stagingRotationChanged_ ? ROTATION_CACHE_UPDATE_INTERVAL :
443             (filterType_ == RSFilter::AIBAR ? AIBAR_CACHE_UPDATE_INTERVAL :
444             (stagingIsLargeArea_ && canSkipFrame_ ? RSSystemProperties::GetFilterCacheUpdateInterval() : 0));
445         pendingPurge_ = false;
446         return;
447     }
448     if (stagingIsAIBarInteractWithHWC_) {
449         if (cacheUpdateInterval_ > 0) {
450             cacheUpdateInterval_--;
451             pendingPurge_ = true;
452         }
453     } else {
454         if ((stagingFilterInteractWithDirty_ || stagingRotationChanged_) && cacheUpdateInterval_ > 0) {
455             cacheUpdateInterval_--;
456             pendingPurge_ = true;
457         }
458     }
459     stagingIsAIBarInteractWithHWC_ = false;
460 }
461 
IsAIBarCacheValid()462 bool RSFilterDrawable::IsAIBarCacheValid()
463 {
464     if (filterType_ != RSFilter::AIBAR) {
465         return false;
466     }
467     stagingIsAIBarInteractWithHWC_ = true;
468     RS_OPTIONAL_TRACE_NAME_FMT("IsAIBarCacheValid cacheUpdateInterval_:%d forceClearCacheForLastFrame_:%d",
469         cacheUpdateInterval_, stagingForceClearCacheForLastFrame_);
470     if (cacheUpdateInterval_ == 0 || stagingForceClearCacheForLastFrame_) {
471         return false;
472     } else {
473         MarkFilterForceUseCache(true);
474         return true;
475     }
476 }
477 } // namespace DrawableV2
478 } // namespace OHOS::Rosen
479