• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <cmath>
20 #include <limits>
21 #include <ostream>
22 #include <string>
23 #include <type_traits>
24 
25 #include <android-base/stringprintf.h>
26 #include <scheduler/Time.h>
27 
28 namespace android {
29 
30 // Frames per second, stored as floating-point frequency. Provides conversion from/to period in
31 // nanoseconds, and relational operators with precision threshold.
32 //
33 //     const Fps fps = 60_Hz;
34 //
35 //     using namespace fps_approx_ops;
36 //     assert(fps == Fps::fromPeriodNsecs(16'666'667));
37 //
38 class Fps {
39 public:
40     constexpr Fps() = default;
41 
fromValue(float frequency)42     static constexpr Fps fromValue(float frequency) {
43         return frequency > 0.f ? Fps(frequency, static_cast<nsecs_t>(1e9f / frequency)) : Fps();
44     }
45 
fromPeriodNsecs(nsecs_t period)46     static constexpr Fps fromPeriodNsecs(nsecs_t period) {
47         return period > 0 ? Fps(1e9f / period, period) : Fps();
48     }
49 
isValid()50     constexpr bool isValid() const { return mFrequency > 0.f; }
51 
getValue()52     constexpr float getValue() const { return mFrequency; }
getIntValue()53     int getIntValue() const { return static_cast<int>(std::round(mFrequency)); }
54 
getPeriod()55     constexpr Period getPeriod() const { return Period::fromNs(mPeriod); }
getPeriodNsecs()56     constexpr nsecs_t getPeriodNsecs() const { return mPeriod; }
57 
58 private:
Fps(float frequency,nsecs_t period)59     constexpr Fps(float frequency, nsecs_t period) : mFrequency(frequency), mPeriod(period) {}
60 
61     float mFrequency = 0.f;
62     nsecs_t mPeriod = 0;
63 };
64 
65 struct FpsRange {
66     Fps min = Fps::fromValue(0.f);
67     Fps max = Fps::fromValue(std::numeric_limits<float>::max());
68 
69     bool includes(Fps) const;
70     bool includes(FpsRange) const;
71 };
72 
73 struct FpsRanges {
74     // The range of refresh rates that refers to the display mode setting.
75     FpsRange physical;
76 
77     // the range of frame rates that refers to the render rate, which is
78     // the rate that frames are swapped.
79     FpsRange render;
80 
81     bool valid() const;
82 };
83 
84 static_assert(std::is_trivially_copyable_v<Fps>);
85 
86 constexpr Fps operator""_Hz(unsigned long long frequency) {
87     return Fps::fromValue(static_cast<float>(frequency));
88 }
89 
90 constexpr Fps operator""_Hz(long double frequency) {
91     return Fps::fromValue(static_cast<float>(frequency));
92 }
93 
isStrictlyLess(Fps lhs,Fps rhs)94 inline bool isStrictlyLess(Fps lhs, Fps rhs) {
95     return lhs.getValue() < rhs.getValue();
96 }
97 
98 // Does not satisfy equivalence relation.
isApproxEqual(Fps lhs,Fps rhs)99 inline bool isApproxEqual(Fps lhs, Fps rhs) {
100     // TODO(b/185536303): Replace with ULP distance.
101     return std::abs(lhs.getValue() - rhs.getValue()) < 0.001f;
102 }
103 
104 // Does not satisfy strict weak order.
isApproxLess(Fps lhs,Fps rhs)105 inline bool isApproxLess(Fps lhs, Fps rhs) {
106     return isStrictlyLess(lhs, rhs) && !isApproxEqual(lhs, rhs);
107 }
108 
109 namespace fps_approx_ops {
110 
111 inline bool operator==(Fps lhs, Fps rhs) {
112     return isApproxEqual(lhs, rhs);
113 }
114 
115 inline bool operator<(Fps lhs, Fps rhs) {
116     return isApproxLess(lhs, rhs);
117 }
118 
119 inline bool operator!=(Fps lhs, Fps rhs) {
120     return !isApproxEqual(lhs, rhs);
121 }
122 
123 inline bool operator>(Fps lhs, Fps rhs) {
124     return isApproxLess(rhs, lhs);
125 }
126 
127 inline bool operator<=(Fps lhs, Fps rhs) {
128     return !isApproxLess(rhs, lhs);
129 }
130 
131 inline bool operator>=(Fps lhs, Fps rhs) {
132     return !isApproxLess(lhs, rhs);
133 }
134 
135 inline bool operator==(FpsRange lhs, FpsRange rhs) {
136     return isApproxEqual(lhs.min, rhs.min) && isApproxEqual(lhs.max, rhs.max);
137 }
138 
139 inline bool operator!=(FpsRange lhs, FpsRange rhs) {
140     return !(lhs == rhs);
141 }
142 
143 inline bool operator==(const FpsRanges& lhs, const FpsRanges& rhs) {
144     return lhs.physical == rhs.physical && lhs.render == rhs.render;
145 }
146 
147 inline bool operator!=(const FpsRanges& lhs, const FpsRanges& rhs) {
148     return !(lhs == rhs);
149 }
150 
151 inline unsigned operator/(Fps lhs, Fps rhs) {
152     return static_cast<unsigned>(std::ceil(lhs.getValue() / rhs.getValue()));
153 }
154 
155 } // namespace fps_approx_ops
156 
157 constexpr Fps operator/(Fps fps, unsigned divisor) {
158     return Fps::fromPeriodNsecs(fps.getPeriodNsecs() * static_cast<nsecs_t>(divisor));
159 }
160 
includes(Fps fps)161 inline bool FpsRange::includes(Fps fps) const {
162     using fps_approx_ops::operator<=;
163     return min <= fps && fps <= max;
164 }
165 
includes(FpsRange range)166 inline bool FpsRange::includes(FpsRange range) const {
167     using namespace fps_approx_ops;
168     return min <= range.min && max >= range.max;
169 }
170 
valid()171 inline bool FpsRanges::valid() const {
172     using fps_approx_ops::operator>=;
173     return physical.max >= render.max;
174 }
175 
176 struct FpsApproxEqual {
operatorFpsApproxEqual177     bool operator()(Fps lhs, Fps rhs) const { return isApproxEqual(lhs, rhs); }
178 };
179 
to_string(Fps fps)180 inline std::string to_string(Fps fps) {
181     return base::StringPrintf("%.2f Hz", fps.getValue());
182 }
183 
184 inline std::ostream& operator<<(std::ostream& stream, Fps fps) {
185     return stream << to_string(fps);
186 }
187 
to_string(FpsRange range)188 inline std::string to_string(FpsRange range) {
189     const auto [min, max] = range;
190     return base::StringPrintf("[%s, %s]", to_string(min).c_str(), to_string(max).c_str());
191 }
192 
to_string(FpsRanges ranges)193 inline std::string to_string(FpsRanges ranges) {
194     const auto& [physical, render] = ranges;
195     return base::StringPrintf("{physical=%s, render=%s}", to_string(physical).c_str(),
196                               to_string(render).c_str());
197 }
198 
199 } // namespace android
200