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