1 /* 2 * Copyright (C) 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 <ostream> 21 #include <string> 22 23 #include <android-base/stringprintf.h> 24 #include <utils/Timers.h> 25 26 namespace android { 27 28 // Value which represents "frames per second". This class is a wrapper around 29 // float, providing some useful utilities, such as comparisons with tolerance 30 // and converting between period duration and frequency. 31 class Fps { 32 public: fromPeriodNsecs(nsecs_t period)33 static constexpr Fps fromPeriodNsecs(nsecs_t period) { return Fps(1e9f / period, period); } 34 35 Fps() = default; Fps(float fps)36 explicit constexpr Fps(float fps) 37 : fps(fps), period(fps == 0.0f ? 0 : static_cast<nsecs_t>(1e9f / fps)) {} 38 getValue()39 constexpr float getValue() const { return fps; } 40 getPeriodNsecs()41 constexpr nsecs_t getPeriodNsecs() const { return period; } 42 equalsWithMargin(const Fps & other)43 bool equalsWithMargin(const Fps& other) const { return std::abs(fps - other.fps) < kMargin; } 44 45 // DO NOT use for std::sort. Instead use comparesLess(). lessThanWithMargin(const Fps & other)46 bool lessThanWithMargin(const Fps& other) const { return fps + kMargin < other.fps; } 47 greaterThanWithMargin(const Fps & other)48 bool greaterThanWithMargin(const Fps& other) const { return fps > other.fps + kMargin; } 49 lessThanOrEqualWithMargin(const Fps & other)50 bool lessThanOrEqualWithMargin(const Fps& other) const { return !greaterThanWithMargin(other); } 51 greaterThanOrEqualWithMargin(const Fps & other)52 bool greaterThanOrEqualWithMargin(const Fps& other) const { return !lessThanWithMargin(other); } 53 isValid()54 bool isValid() const { return fps > 0.0f; } 55 getIntValue()56 int getIntValue() const { return static_cast<int>(std::round(fps)); } 57 58 // Use this comparator for sorting. Using a comparator with margins can 59 // cause std::sort to crash. comparesLess(const Fps & left,const Fps & right)60 inline static bool comparesLess(const Fps& left, const Fps& right) { 61 return left.fps < right.fps; 62 } 63 64 // Compares two FPS with margin. 65 // Transitivity is not guaranteed, i.e. a==b and b==c doesn't imply a==c. 66 // DO NOT use with hash maps. Instead use EqualsInBuckets. 67 struct EqualsWithMargin { operatorEqualsWithMargin68 bool operator()(const Fps& left, const Fps& right) const { 69 return left.equalsWithMargin(right); 70 } 71 }; 72 73 // Equals comparator which can be used with hash maps. 74 // It's guaranteed that if two elements are equal, then their hashes are equal. 75 struct EqualsInBuckets { operatorEqualsInBuckets76 bool operator()(const Fps& left, const Fps& right) const { 77 return left.getBucket() == right.getBucket(); 78 } 79 }; 80 to_string(const Fps & fps)81 inline friend std::string to_string(const Fps& fps) { 82 return base::StringPrintf("%.2ffps", fps.fps); 83 } 84 85 inline friend std::ostream& operator<<(std::ostream& os, const Fps& fps) { 86 return os << to_string(fps); 87 } 88 89 private: 90 friend std::hash<android::Fps>; 91 Fps(float fps,nsecs_t period)92 constexpr Fps(float fps, nsecs_t period) : fps(fps), period(period) {} 93 getBucket()94 float getBucket() const { return std::round(fps / kMargin); } 95 96 static constexpr float kMargin = 0.001f; 97 float fps = 0; 98 nsecs_t period = 0; 99 }; 100 101 static_assert(std::is_trivially_copyable_v<Fps>); 102 103 } // namespace android 104 105 namespace std { 106 template <> 107 struct hash<android::Fps> { 108 std::size_t operator()(const android::Fps& fps) const { 109 return std::hash<float>()(fps.getBucket()); 110 } 111 }; 112 } // namespace std