1 /*
2  * Copyright (c) 2022-2023 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 "animation/rs_render_spring_animation.h"
17 
18 #include "animation/rs_animation_trace_utils.h"
19 #include "command/rs_animation_command.h"
20 #include "command/rs_message_processor.h"
21 #include "pipeline/rs_render_node.h"
22 #include "platform/common/rs_log.h"
23 
24 namespace OHOS {
25 namespace Rosen {
26 namespace {
27 constexpr static float SECOND_TO_MILLISECOND = 1e3;
28 constexpr static float MILLISECOND_TO_SECOND = 1e-3;
29 constexpr static float SECOND_TO_NANOSECOND = 1e9;
30 constexpr static float RESPONSE_THRESHOLD = 0.001f;
31 constexpr static float FRACTION_THRESHOLD = 0.001f;
32 constexpr static float FRAME_TIME_INTERVAL = 1.0f / 90.0f;
33 } // namespace
34 
RSRenderSpringAnimation(AnimationId id,const PropertyId & propertyId,const std::shared_ptr<RSRenderPropertyBase> & originValue,const std::shared_ptr<RSRenderPropertyBase> & startValue,const std::shared_ptr<RSRenderPropertyBase> & endValue)35 RSRenderSpringAnimation::RSRenderSpringAnimation(AnimationId id, const PropertyId& propertyId,
36     const std::shared_ptr<RSRenderPropertyBase>& originValue,
37     const std::shared_ptr<RSRenderPropertyBase>& startValue,
38     const std::shared_ptr<RSRenderPropertyBase>& endValue)
39     : RSRenderPropertyAnimation(id, propertyId, originValue), startValue_(startValue), endValue_(endValue)
40 {
41     // spring model is not initialized, so we can't calculate estimated duration
42 }
43 
DumpAnimationType(std::string & out) const44 void RSRenderSpringAnimation::DumpAnimationType(std::string& out) const
45 {
46     out += "Type:RSRenderSpringAnimation";
47 }
48 
SetSpringParameters(float response,float dampingRatio,float blendDuration)49 void RSRenderSpringAnimation::SetSpringParameters(float response, float dampingRatio, float blendDuration)
50 {
51     response_ = response;
52     dampingRatio_ = dampingRatio;
53     blendDuration_ = blendDuration * SECOND_TO_NANOSECOND; // convert to ns
54 }
55 
SetZeroThreshold(float zeroThreshold)56 void RSRenderSpringAnimation::SetZeroThreshold(float zeroThreshold)
57 {
58     constexpr float ZERO = 0.0f;
59     if (zeroThreshold < ZERO) {
60         ROSEN_LOGE("RSRenderSpringAnimation::SetZeroThreshold: invalid threshold value.");
61         needLogicallyFinishCallback_ = false;
62         return;
63     }
64     zeroThreshold_ = zeroThreshold;
65     needLogicallyFinishCallback_ = true;
66 }
67 
68 #ifdef ROSEN_OHOS
Marshalling(Parcel & parcel) const69 bool RSRenderSpringAnimation::Marshalling(Parcel& parcel) const
70 {
71     if (!RSRenderPropertyAnimation::Marshalling(parcel)) {
72         ROSEN_LOGE("RSRenderSpringAnimation::Marshalling, RenderPropertyAnimation failed");
73         return false;
74     }
75     if (!(RSRenderPropertyBase::Marshalling(parcel, startValue_) &&
76             RSRenderPropertyBase::Marshalling(parcel, endValue_))) {
77         ROSEN_LOGE("RSRenderSpringAnimation::Marshalling, MarshallingHelper failed");
78         return false;
79     }
80 
81     if (!(RSMarshallingHelper::Marshalling(parcel, response_) &&
82             RSMarshallingHelper::Marshalling(parcel, dampingRatio_) &&
83             RSMarshallingHelper::Marshalling(parcel, blendDuration_) &&
84             RSMarshallingHelper::Marshalling(parcel, needLogicallyFinishCallback_) &&
85             RSMarshallingHelper::Marshalling(parcel, zeroThreshold_))) {
86         return false;
87     }
88 
89     if (initialVelocity_) {
90         return RSMarshallingHelper::Marshalling(parcel, true) &&
91                RSMarshallingHelper::Marshalling(parcel, initialVelocity_);
92     }
93 
94     return RSMarshallingHelper::Marshalling(parcel, false);
95 }
96 
Unmarshalling(Parcel & parcel)97 RSRenderSpringAnimation* RSRenderSpringAnimation::Unmarshalling(Parcel& parcel)
98 {
99     auto* renderSpringAnimation = new RSRenderSpringAnimation();
100     if (!renderSpringAnimation->ParseParam(parcel)) {
101         ROSEN_LOGE("RSRenderSpringAnimation::Unmarshalling, failed");
102         delete renderSpringAnimation;
103         return nullptr;
104     }
105     return renderSpringAnimation;
106 }
107 
ParseParam(Parcel & parcel)108 bool RSRenderSpringAnimation::ParseParam(Parcel& parcel)
109 {
110     if (!RSRenderPropertyAnimation::ParseParam(parcel)) {
111         ROSEN_LOGE("RSRenderSpringAnimation::ParseParam, ParseParam Fail");
112         return false;
113     }
114 
115     if (!(RSRenderPropertyBase::Unmarshalling(parcel, startValue_) &&
116             RSRenderPropertyBase::Unmarshalling(parcel, endValue_))) {
117         return false;
118     }
119 
120     auto haveInitialVelocity = false;
121     if (!(RSMarshallingHelper::Unmarshalling(parcel, response_) &&
122             RSMarshallingHelper::Unmarshalling(parcel, dampingRatio_) &&
123             RSMarshallingHelper::Unmarshalling(parcel, blendDuration_) &&
124             RSMarshallingHelper::Unmarshalling(parcel, needLogicallyFinishCallback_) &&
125             RSMarshallingHelper::Unmarshalling(parcel, zeroThreshold_) &&
126             RSMarshallingHelper::Unmarshalling(parcel, haveInitialVelocity))) {
127         return false;
128     }
129 
130     if (haveInitialVelocity) {
131         return RSMarshallingHelper::Unmarshalling(parcel, initialVelocity_);
132     }
133     return true;
134 }
135 #endif
136 
OnAnimate(float fraction)137 void RSRenderSpringAnimation::OnAnimate(float fraction)
138 {
139     if (GetPropertyId() == 0) {
140         // calculateAnimationValue_ is embedded modify for stat animate frame drop
141         calculateAnimationValue_ = false;
142         return;
143     }
144     if (springValueEstimator_ == nullptr) {
145         ROSEN_LOGE("RSRenderSpringAnimation::OnAnimate, springValueEstimator is null");
146         return;
147     }
148     if (ROSEN_EQ(fraction, 1.0f, FRACTION_THRESHOLD)) {
149         prevMappedTime_ = GetDuration() * MILLISECOND_TO_SECOND;
150         springValueEstimator_->UpdateAnimationValue(prevMappedTime_, GetAdditive());
151         return;
152     }
153 
154     prevMappedTime_ = GetDuration() * fraction * MILLISECOND_TO_SECOND;
155     springValueEstimator_->UpdateAnimationValue(prevMappedTime_, GetAdditive());
156 
157     if (GetNeedLogicallyFinishCallback() && (animationFraction_.GetRemainingRepeatCount() == 1)) {
158         auto currentValue = springValueEstimator_->GetAnimationProperty();
159         if (currentValue == nullptr) {
160             ROSEN_LOGE("RSRenderSpringAnimation::OnAnimate, failed to get current animation value");
161             return;
162         }
163         auto targetValue = animationFraction_.GetCurrentIsReverseCycle() ? startValue_ : endValue_;
164         if (!currentValue->IsNearEqual(targetValue, zeroThreshold_)) {
165             return;
166         }
167         auto zeroValue = startValue_ - startValue_;
168         auto velocity = springValueEstimator_->GetPropertyVelocity(prevMappedTime_);
169         if ((velocity * FRAME_TIME_INTERVAL)->IsNearEqual(zeroValue, zeroThreshold_)) {
170             CallLogicallyFinishCallback();
171             needLogicallyFinishCallback_ = false;
172         }
173     }
174 }
175 
OnAttach()176 void RSRenderSpringAnimation::OnAttach()
177 {
178     auto target = GetTarget();
179     if (target == nullptr) {
180         ROSEN_LOGE("RSRenderSpringAnimation::OnAttach, target is nullptr");
181         return;
182     }
183     // check if any other spring animation running on this property
184     auto propertyId = GetPropertyId();
185     auto prevAnimation = target->GetAnimationManager().QuerySpringAnimation(propertyId);
186     target->GetAnimationManager().RegisterSpringAnimation(propertyId, GetAnimationId());
187     // stop running the previous animation and inherit velocity from it
188     InheritSpringAnimation(prevAnimation);
189 }
190 
InheritSpringAnimation(const std::shared_ptr<RSRenderAnimation> & prevAnimation)191 void RSRenderSpringAnimation::InheritSpringAnimation(const std::shared_ptr<RSRenderAnimation>& prevAnimation)
192 {
193     // return if no other spring animation(s) running, or the other animation is finished
194     // meanwhile, align run time for both spring animations, prepare for status inheritance
195     if (prevAnimation == nullptr || prevAnimation->Animate(animationFraction_.GetLastFrameTime())) {
196         blendDuration_ = 0;
197         return;
198     }
199 
200     if (springValueEstimator_ == nullptr) {
201         ROSEN_LOGD("RSRenderSpringAnimation::InheritSpringAnimation failed, springValueEstimator is null");
202         return;
203     }
204 
205     // extract spring status from previous spring animation
206     auto prevSpringAnimation = std::static_pointer_cast<RSRenderSpringAnimation>(prevAnimation);
207 
208     // inherit spring status from previous spring animation
209     if (!InheritSpringStatus(prevSpringAnimation.get())) {
210         blendDuration_ = 0;
211         return;
212     }
213     // inherit spring response
214     auto& previousValueEstimator = prevSpringAnimation->springValueEstimator_;
215     if (previousValueEstimator) {
216         springValueEstimator_->SetResponse(previousValueEstimator->GetResponse());
217     } else {
218         ROSEN_LOGD("RSRenderSpringAnimation::InheritSpringAnimation, the springValueEstimator of previous "
219                    "animation is null");
220         blendDuration_ = 0;
221     }
222 
223     if (ROSEN_EQ(springValueEstimator_->GetResponse(), response_, RESPONSE_THRESHOLD)) {
224         // if response is not changed, we can skip blend duration
225         blendDuration_ = 0;
226     } else if (blendDuration_ == 0) {
227         // if blend duration is not set, we can skip blend duration
228         springValueEstimator_->SetResponse(response_);
229     } else if (ROSEN_EQ(response_, prevSpringAnimation->response_, RESPONSE_THRESHOLD)) {
230         // if previous spring is blending to the same final response, we can continue previous blending process
231         blendDuration_ = prevSpringAnimation->blendDuration_;
232     }
233 
234     // set previous spring animation to FINISHED
235     prevSpringAnimation->FinishOnCurrentPosition();
236 }
237 
OnDetach()238 void RSRenderSpringAnimation::OnDetach()
239 {
240     auto target = GetTarget();
241     if (target == nullptr) {
242         ROSEN_LOGD("RSRenderSpringAnimation::OnDetach, target is nullptr");
243         return;
244     }
245     auto propertyId = GetPropertyId();
246     auto id = GetAnimationId();
247     target->GetAnimationManager().UnregisterSpringAnimation(propertyId, id);
248 }
249 
OnInitialize(int64_t time)250 void RSRenderSpringAnimation::OnInitialize(int64_t time)
251 {
252     if (springValueEstimator_ == nullptr) {
253         ROSEN_LOGD("RSRenderSpringAnimation::OnInitialize failed, springValueEstimator is null");
254         RSRenderPropertyAnimation::OnInitialize(time);
255         return;
256     }
257 
258     if (blendDuration_) {
259         auto lastFrameTime = animationFraction_.GetLastFrameTime();
260 
261         // reset animation fraction
262         InheritSpringStatus(this);
263         animationFraction_.ResetFraction();
264         prevMappedTime_ = 0.0f;
265 
266         // blend response by linear interpolation
267         uint64_t blendTime = (time - lastFrameTime) * animationFraction_.GetAnimationScale();
268         if (blendTime < blendDuration_) {
269             auto blendRatio = static_cast<float>(blendTime) / static_cast<float>(blendDuration_);
270             auto response = springValueEstimator_->GetResponse();
271             response += (response_ - response) * blendRatio;
272             springValueEstimator_->SetResponse(response);
273             blendDuration_ -= blendTime;
274         } else {
275             // if blend duration is over, set response to final response
276             springValueEstimator_->SetResponse(response_);
277             blendDuration_ = 0;
278         }
279     }
280 
281     if (startValue_ != nullptr && initialVelocity_ == nullptr) {
282         initialVelocity_ = startValue_ * 0.f;
283     }
284 
285     RSAnimationTraceUtils::GetInstance().addSpringInitialVelocityTrace(
286         GetPropertyId(), GetAnimationId(), initialVelocity_, GetPropertyValue());
287     springValueEstimator_->SetInitialVelocity(initialVelocity_);
288     springValueEstimator_->UpdateSpringParameters();
289 
290     if (blendDuration_) {
291         // blend is still in progress, no need to estimate duration, use 300ms as default
292         SetDuration(300);
293     } else {
294         // blend finished, estimate duration until the spring system reaches rest
295         SetDuration(std::lroundf(springValueEstimator_->UpdateDuration() * SECOND_TO_MILLISECOND));
296         // this will set needInitialize_ to false
297         RSRenderPropertyAnimation::OnInitialize(time);
298     }
299 }
300 
301 std::tuple<std::shared_ptr<RSRenderPropertyBase>, std::shared_ptr<RSRenderPropertyBase>,
302     std::shared_ptr<RSRenderPropertyBase>>
GetSpringStatus() const303 RSRenderSpringAnimation::GetSpringStatus() const
304 {
305     // if animation is never started, return start value and initial velocity
306     // fraction_threshold will change with animationScale.
307     if (ROSEN_EQ(prevMappedTime_, 0.0f, FRACTION_THRESHOLD / animationFraction_.GetAnimationScale())) {
308         return { startValue_, endValue_, initialVelocity_ };
309     }
310 
311     if (springValueEstimator_ == nullptr) {
312         ROSEN_LOGD("RSRenderSpringAnimation::GetSpringStatus failed, springValueEstimator is null");
313         return { startValue_, endValue_, initialVelocity_ };
314     }
315 
316     auto velocity = springValueEstimator_->GetPropertyVelocity(prevMappedTime_);
317 
318     // return current position and velocity
319     return { springValueEstimator_->GetAnimationProperty(), endValue_, velocity };
320 }
321 
InheritSpringStatus(const RSRenderSpringAnimation * from)322 bool RSRenderSpringAnimation::InheritSpringStatus(const RSRenderSpringAnimation* from)
323 {
324     if (from == nullptr) {
325         ROSEN_LOGD("RSRenderSpringAnimation::InheritSpringStatus failed, from is null!");
326         return false;
327     }
328 
329     if (springValueEstimator_ == nullptr) {
330         ROSEN_LOGD("RSRenderSpringAnimation::InheritSpringStatus failed, springValueEstimator is null!");
331         return false;
332     }
333 
334     auto [lastValue, endValue, velocity] = from->GetSpringStatus();
335     if (lastValue == nullptr) {
336         ROSEN_LOGD("RSRenderSpringAnimation::InheritSpringStatus, unexpected lastValue null pointer!");
337         return false;
338     }
339 
340     if (startValue_ && !startValue_->IsEqual(endValue) && !(from == this)) {
341         // means property values may change due to direct setting or other animations
342         ROSEN_LOGD(
343             "RSRenderSpringAnimation::InheritSpringStatus, current animation can't continue with last animation");
344         return false;
345     }
346 
347     // inherit spring status from last spring animation
348     startValue_ = lastValue->Clone();
349     initialVelocity_ = velocity;
350     originValue_ = startValue_->Clone();
351     lastValue_ = startValue_->Clone();
352     springValueEstimator_->UpdateStartValueAndLastValue(startValue_, lastValue_);
353     springValueEstimator_->SetInitialVelocity(velocity);
354     return true;
355 }
356 
GetNeedLogicallyFinishCallback() const357 bool RSRenderSpringAnimation::GetNeedLogicallyFinishCallback() const
358 {
359     return needLogicallyFinishCallback_;
360 }
361 
CallLogicallyFinishCallback() const362 void RSRenderSpringAnimation::CallLogicallyFinishCallback() const
363 {
364     NodeId targetId = GetTargetId();
365     AnimationId animationId = GetAnimationId();
366 
367     std::unique_ptr<RSCommand> command =
368         std::make_unique<RSAnimationCallback>(targetId, animationId, LOGICALLY_FINISHED);
369     RSMessageProcessor::Instance().AddUIMessage(ExtractPid(animationId), std::move(command));
370 }
371 
SetInitialVelocity(const std::shared_ptr<RSRenderPropertyBase> & velocity)372 void RSRenderSpringAnimation::SetInitialVelocity(const std::shared_ptr<RSRenderPropertyBase>& velocity)
373 {
374     if (!velocity) {
375         ROSEN_LOGD("RSRenderSpringAnimation::SetInitialVelocity: velocity is a nullptr.");
376         return;
377     }
378     // if inheritance happens, this velocity will be replace again
379     initialVelocity_ = velocity;
380 }
381 
InitValueEstimator()382 void RSRenderSpringAnimation::InitValueEstimator()
383 {
384     if (property_ == nullptr) {
385         ROSEN_LOGD("RSRenderSpringAnimation::InitValueEstimator failed, the property is null");
386         return;
387     }
388     if (springValueEstimator_ == nullptr) {
389         springValueEstimator_ = property_->CreateRSSpringValueEstimator();
390     }
391     if (springValueEstimator_ == nullptr) {
392         ROSEN_LOGE("RSRenderSpringAnimation::InitValueEstimator, springValueEstimator_ is nullptr.");
393         return;
394     }
395     springValueEstimator_->InitRSSpringValueEstimator(property_, startValue_, endValue_, lastValue_);
396     springValueEstimator_->SetResponse(response_);
397     springValueEstimator_->SetDampingRatio(dampingRatio_);
398 }
399 } // namespace Rosen
400 } // namespace OHOS
401