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 "animation/rs_animation_rate_decider.h"
17 
18 #include <cmath>
19 #include <string>
20 
21 #include "common/rs_optional_trace.h"
22 #include "modifier/rs_render_property.h"
23 #include "platform/common/rs_log.h"
24 
25 namespace OHOS {
26 namespace Rosen {
27 constexpr int32_t DEFAULT_PREFERRED_FPS = 120;
28 
SetScaleReferenceSize(float width,float height)29 void RSAnimationRateDecider::SetScaleReferenceSize(float width, float height)
30 {
31     scaleWidth_ = width;
32     scaleHeight_ = height;
33 }
34 
Reset()35 void RSAnimationRateDecider::Reset()
36 {
37     frameRateRange_.Reset();
38     decisionElements_.clear();
39 }
40 
AddDecisionElement(PropertyId id,const PropertyValue & velocity,FrameRateRange range)41 void RSAnimationRateDecider::AddDecisionElement(PropertyId id, const PropertyValue& velocity, FrameRateRange range)
42 {
43     if (!isEnabled_) {
44         return;
45     }
46     if (!velocity && !range.IsValid()) {
47         return;
48     }
49     PropertyValue data = nullptr;
50     if (velocity != nullptr) {
51         data = velocity->Clone();
52     }
53     if (decisionElements_.find(id) != decisionElements_.end()) {
54         auto& element = decisionElements_[id];
55         if (data != nullptr) {
56             element.first = element.first ? element.first + data : data;
57         }
58         element.second.Merge(range);
59     } else {
60         decisionElements_.emplace(id, std::make_pair(data, range));
61     }
62 }
63 
MakeDecision(const FrameRateGetFunc & func)64 void RSAnimationRateDecider::MakeDecision(const FrameRateGetFunc& func)
65 {
66     if (!isEnabled_) {
67         frameRateRange_.Set(0, RANGE_MAX_REFRESHRATE, DEFAULT_PREFERRED_FPS);
68         return;
69     }
70     for (const auto& [id, element] : decisionElements_) {
71         FrameRateRange propertyRange;
72         RS_OPTIONAL_TRACE_BEGIN("MakeDecision property id: [" + std::to_string(id) + "]");
73         if (element.first != nullptr && func != nullptr) {
74             int32_t preferred = CalculatePreferredRate(element.first, func);
75             if (preferred > 0) {
76                 propertyRange = {0, RANGE_MAX_REFRESHRATE, preferred};
77             }
78         }
79         FrameRateRange finalRange;
80         if (propertyRange.IsValid()) {
81             finalRange = propertyRange;
82             if (element.second.IsValid() && element.second.preferred_ < propertyRange.preferred_) {
83                 finalRange = element.second;
84             }
85         } else {
86             finalRange = element.second;
87         }
88         frameRateRange_.Merge(finalRange);
89         RS_OPTIONAL_TRACE_END();
90     }
91 }
92 
GetFrameRateRange() const93 const FrameRateRange& RSAnimationRateDecider::GetFrameRateRange() const
94 {
95     return frameRateRange_;
96 }
97 
CalculatePreferredRate(const PropertyValue & property,const FrameRateGetFunc & func)98 int32_t RSAnimationRateDecider::CalculatePreferredRate(const PropertyValue& property, const FrameRateGetFunc& func)
99 {
100     switch (property->GetPropertyType()) {
101         case RSRenderPropertyType::PROPERTY_VECTOR4F:
102             return ProcessVector4f(property, func);
103         case RSRenderPropertyType::PROPERTY_VECTOR2F:
104             return ProcessVector2f(property, func);
105         case RSRenderPropertyType::PROPERTY_FLOAT:
106             return ProcessFloat(property, func);
107         default:
108             return 0;
109     }
110 }
111 
ProcessVector4f(const PropertyValue & property,const FrameRateGetFunc & func)112 int32_t RSAnimationRateDecider::ProcessVector4f(const PropertyValue& property, const FrameRateGetFunc& func)
113 {
114     auto animatableProperty = std::static_pointer_cast<RSRenderAnimatableProperty<Vector4f>>(property);
115     auto propertyUnit = property->GetPropertyUnit();
116     if (!animatableProperty || propertyUnit != RSPropertyUnit::PIXEL_POSITION) {
117         return 0;
118     }
119     auto data = animatableProperty->Get();
120     // Vector4f data include data[0], data[1], data[2], data[3]
121     int32_t positionRate = func(propertyUnit, sqrt(data[0] * data[0] + data[1] * data[1]));
122     int32_t sizeRate = func(RSPropertyUnit::PIXEL_SIZE, sqrt(data[2] * data[2] + data[3] * data[3]));
123     return std::max(positionRate, sizeRate);
124 }
125 
ProcessVector2f(const PropertyValue & property,const FrameRateGetFunc & func)126 int32_t RSAnimationRateDecider::ProcessVector2f(const PropertyValue& property, const FrameRateGetFunc& func)
127 {
128     float velocity = 0.0f;
129     if (property->GetPropertyUnit() == RSPropertyUnit::RATIO_SCALE) {
130         auto animatableProperty = std::static_pointer_cast<RSRenderAnimatableProperty<Vector2f>>(property);
131         if (animatableProperty != nullptr) {
132             auto data = animatableProperty->Get();
133             // Vector2f data include data[0], data[1]
134             float velocityX = data[0] * scaleWidth_;
135             float velocityY = data[1] * scaleHeight_;
136             velocity = sqrt(velocityX * velocityX + velocityY * velocityY);
137         }
138     } else {
139         velocity = property->ToFloat();
140     }
141     return func(property->GetPropertyUnit(), velocity);
142 }
143 
ProcessFloat(const PropertyValue & property,const FrameRateGetFunc & func)144 int32_t RSAnimationRateDecider::ProcessFloat(const PropertyValue& property, const FrameRateGetFunc& func)
145 {
146     auto propertyUnit = property->GetPropertyUnit();
147     float propertyValue = property->ToFloat();
148     if (propertyUnit == RSPropertyUnit::ANGLE_ROTATION) {
149         // get the longest from height and width, record as H.
150         float height = ROSEN_GE(scaleHeight_, scaleWidth_) ? scaleHeight_ : scaleWidth_;
151         // V = W * R = W * (H / 2) = w * (2 * pi) * (H / 2) / 360 = w * pi * H / 360
152         // let w = propertyValue => w *= H * FLOAT_PI / 360
153         // 360 means 360 angle, relative to 2 * pi radian.
154         propertyValue *= height * FLOAT_PI / 360;
155         ROSEN_LOGD("%{public}s, ANGLE_ROTATION scene, propertyValue: %{public}f", __func__, propertyValue);
156     }
157     return func(propertyUnit, propertyValue);
158 }
159 } // namespace Rosen
160 } // namespace OHOS
161