blob: 639b3e5ed8e396bd57dfc73a2685a300e0f2c2f9 [file] [log] [blame]
Marin Shalamanove8a663d2020-11-24 17:48:00 +01001/*
Dominik Laskowski6eab42d2021-09-13 14:34:13 -07002 * Copyright 2020 The Android Open Source Project
Marin Shalamanove8a663d2020-11-24 17:48:00 +01003 *
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 <ostream>
21#include <string>
Dominik Laskowski6eab42d2021-09-13 14:34:13 -070022#include <type_traits>
Marin Shalamanove8a663d2020-11-24 17:48:00 +010023
24#include <android-base/stringprintf.h>
25#include <utils/Timers.h>
26
27namespace android {
28
Dominik Laskowski6eab42d2021-09-13 14:34:13 -070029// Frames per second, stored as floating-point frequency. Provides conversion from/to period in
30// nanoseconds, and relational operators with precision threshold.
31//
32// const Fps fps = 60_Hz;
33//
34// using namespace fps_approx_ops;
35// assert(fps == Fps::fromPeriodNsecs(16'666'667));
36//
Marin Shalamanove8a663d2020-11-24 17:48:00 +010037class Fps {
38public:
Dominik Laskowski6eab42d2021-09-13 14:34:13 -070039 constexpr Fps() = default;
Marin Shalamanove8a663d2020-11-24 17:48:00 +010040
Dominik Laskowski6eab42d2021-09-13 14:34:13 -070041 static constexpr Fps fromValue(float frequency) {
42 return frequency > 0.f ? Fps(frequency, static_cast<nsecs_t>(1e9f / frequency)) : Fps();
Marin Shalamanove8a663d2020-11-24 17:48:00 +010043 }
44
Dominik Laskowski6eab42d2021-09-13 14:34:13 -070045 static constexpr Fps fromPeriodNsecs(nsecs_t period) {
46 return period > 0 ? Fps(1e9f / period, period) : Fps();
Marin Shalamanove8a663d2020-11-24 17:48:00 +010047 }
48
Dominik Laskowski6eab42d2021-09-13 14:34:13 -070049 constexpr bool isValid() const { return mFrequency > 0.f; }
50
51 constexpr float getValue() const { return mFrequency; }
52 int getIntValue() const { return static_cast<int>(std::round(mFrequency)); }
53
54 constexpr nsecs_t getPeriodNsecs() const { return mPeriod; }
Marin Shalamanove8a663d2020-11-24 17:48:00 +010055
56private:
Dominik Laskowski6eab42d2021-09-13 14:34:13 -070057 constexpr Fps(float frequency, nsecs_t period) : mFrequency(frequency), mPeriod(period) {}
Marin Shalamanove8a663d2020-11-24 17:48:00 +010058
Dominik Laskowski6eab42d2021-09-13 14:34:13 -070059 float mFrequency = 0.f;
60 nsecs_t mPeriod = 0;
Marin Shalamanove8a663d2020-11-24 17:48:00 +010061};
62
63static_assert(std::is_trivially_copyable_v<Fps>);
64
Dominik Laskowski6eab42d2021-09-13 14:34:13 -070065constexpr Fps operator""_Hz(unsigned long long frequency) {
66 return Fps::fromValue(static_cast<float>(frequency));
67}
Marin Shalamanove8a663d2020-11-24 17:48:00 +010068
Dominik Laskowski6eab42d2021-09-13 14:34:13 -070069constexpr Fps operator""_Hz(long double frequency) {
70 return Fps::fromValue(static_cast<float>(frequency));
71}
72
73inline bool isStrictlyLess(Fps lhs, Fps rhs) {
74 return lhs.getValue() < rhs.getValue();
75}
76
77// Does not satisfy equivalence relation.
78inline bool isApproxEqual(Fps lhs, Fps rhs) {
79 // TODO(b/185536303): Replace with ULP distance.
80 return std::abs(lhs.getValue() - rhs.getValue()) < 0.001f;
81}
82
83// Does not satisfy strict weak order.
84inline bool isApproxLess(Fps lhs, Fps rhs) {
85 return isStrictlyLess(lhs, rhs) && !isApproxEqual(lhs, rhs);
86}
87
88namespace fps_approx_ops {
89
90inline bool operator==(Fps lhs, Fps rhs) {
91 return isApproxEqual(lhs, rhs);
92}
93
94inline bool operator<(Fps lhs, Fps rhs) {
95 return isApproxLess(lhs, rhs);
96}
97
98inline bool operator!=(Fps lhs, Fps rhs) {
99 return !isApproxEqual(lhs, rhs);
100}
101
102inline bool operator>(Fps lhs, Fps rhs) {
103 return isApproxLess(rhs, lhs);
104}
105
106inline bool operator<=(Fps lhs, Fps rhs) {
107 return !isApproxLess(rhs, lhs);
108}
109
110inline bool operator>=(Fps lhs, Fps rhs) {
111 return !isApproxLess(lhs, rhs);
112}
113
114} // namespace fps_approx_ops
115
116struct FpsApproxEqual {
117 bool operator()(Fps lhs, Fps rhs) const { return isApproxEqual(lhs, rhs); }
Marin Shalamanove8a663d2020-11-24 17:48:00 +0100118};
Dominik Laskowski6eab42d2021-09-13 14:34:13 -0700119
120inline std::string to_string(Fps fps) {
121 return base::StringPrintf("%.2f Hz", fps.getValue());
122}
123
124inline std::ostream& operator<<(std::ostream& stream, Fps fps) {
125 return stream << to_string(fps);
126}
127
128} // namespace android