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