Add Fps class
Add a class to wrap a fps value. This is useful because across
the code we
- convert between vsyncPeriod and fps
- compare with tolerance (this ensures we use consistent tolerance)
- consistent toString method
Bug: 159590486
Test: presubmit
Change-Id: Iebb77a33a2f822056642aa61bd6fac6514aa656d
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 83fa20e..4b7251b 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -29,10 +29,10 @@
namespace android::scheduler {
namespace {
std::string formatLayerInfo(const RefreshRateConfigs::LayerRequirement& layer, float weight) {
- return base::StringPrintf("%s (type=%s, weight=%.2f seamlessness=%s) %.2fHz",
- layer.name.c_str(),
+ return base::StringPrintf("%s (type=%s, weight=%.2f seamlessness=%s) %s", layer.name.c_str(),
RefreshRateConfigs::layerVoteTypeString(layer.vote).c_str(), weight,
- toString(layer.seamlessness).c_str(), layer.desiredRefreshRate);
+ toString(layer.seamlessness).c_str(),
+ to_string(layer.desiredRefreshRate).c_str());
}
} // namespace
@@ -41,7 +41,7 @@
std::string RefreshRate::toString() const {
return base::StringPrintf("{id=%d, hwcId=%d, fps=%.2f, width=%d, height=%d group=%d}",
- getConfigId().value(), hwcConfig->getId(), getFps(),
+ getConfigId().value(), hwcConfig->getId(), getFps().getValue(),
hwcConfig->getWidth(), hwcConfig->getHeight(), getConfigGroup());
}
@@ -64,9 +64,9 @@
std::string RefreshRateConfigs::Policy::toString() const {
return base::StringPrintf("default config ID: %d, allowGroupSwitching = %d"
- ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]",
- defaultConfig.value(), allowGroupSwitching, primaryRange.min,
- primaryRange.max, appRequestRange.min, appRequestRange.max);
+ ", primary range: %s, app request range: %s",
+ defaultConfig.value(), allowGroupSwitching,
+ primaryRange.toString().c_str(), appRequestRange.toString().c_str());
}
std::pair<nsecs_t, nsecs_t> RefreshRateConfigs::getDisplayFrames(nsecs_t layerPeriod,
@@ -144,7 +144,8 @@
// move out the of range if layers explicitly request a different refresh
// rate.
const Policy* policy = getCurrentPolicyLocked();
- const bool primaryRangeIsSingleRate = policy->primaryRange.min == policy->primaryRange.max;
+ const bool primaryRangeIsSingleRate =
+ policy->primaryRange.min.equalsWithMargin(policy->primaryRange.max);
if (!globalSignals.touch && globalSignals.idle &&
!(primaryRangeIsSingleRate && hasExplicitVoteLayers)) {
@@ -229,17 +230,18 @@
// If the layer wants Max, give higher score to the higher refresh rate
if (layer.vote == LayerVoteType::Max) {
- const auto ratio = scores[i].first->fps / scores.back().first->fps;
+ const auto ratio =
+ scores[i].first->fps.getValue() / scores.back().first->fps.getValue();
// use ratio^2 to get a lower score the more we get further from peak
const auto layerScore = ratio * ratio;
ALOGV("%s gives %s score of %.2f", formatLayerInfo(layer, weight).c_str(),
- scores[i].first->name.c_str(), layerScore);
+ scores[i].first->getName().c_str(), layerScore);
scores[i].second += weight * layerScore;
continue;
}
const auto displayPeriod = scores[i].first->hwcConfig->getVsyncPeriod();
- const auto layerPeriod = round<nsecs_t>(1e9f / layer.desiredRefreshRate);
+ const auto layerPeriod = layer.desiredRefreshRate.getPeriodNsecs();
if (layer.vote == LayerVoteType::ExplicitDefault) {
const auto layerScore = [&]() {
// Find the actual rate the layer will render, assuming
@@ -256,7 +258,7 @@
}();
ALOGV("%s gives %s score of %.2f", formatLayerInfo(layer, weight).c_str(),
- scores[i].first->name.c_str(), layerScore);
+ scores[i].first->getName().c_str(), layerScore);
scores[i].second += weight * layerScore;
continue;
}
@@ -297,7 +299,7 @@
constexpr float kSeamedSwitchPenalty = 0.95f;
const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty;
ALOGV("%s gives %s score of %.2f", formatLayerInfo(layer, weight).c_str(),
- scores[i].first->name.c_str(), layerScore);
+ scores[i].first->getName().c_str(), layerScore);
scores[i].second += weight * layerScore * seamlessness;
continue;
}
@@ -331,7 +333,7 @@
const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked();
if (globalSignals.touch && explicitDefaultVoteLayers == 0 &&
- bestRefreshRate->fps < touchRefreshRate.fps) {
+ bestRefreshRate->fps.lessThanWithMargin(touchRefreshRate.fps)) {
setTouchConsidered();
ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str());
return touchRefreshRate;
@@ -347,9 +349,9 @@
float max = begin->second;
for (auto i = begin; i != end; ++i) {
const auto [refreshRate, score] = *i;
- ALOGV("%s scores %.2f", refreshRate->name.c_str(), score);
+ ALOGV("%s scores %.2f", refreshRate->getName().c_str(), score);
- ATRACE_INT(refreshRate->name.c_str(), round<int>(score * 100));
+ ATRACE_INT(refreshRate->getName().c_str(), round<int>(score * 100));
if (score > max * (1 + EPSILON)) {
max = score;
@@ -433,10 +435,10 @@
for (auto configId = HwcConfigIndexType(0); configId.value() < configs.size(); configId++) {
const auto& config = configs.at(static_cast<size_t>(configId.value()));
- const float fps = 1e9f / config->getVsyncPeriod();
mRefreshRates.emplace(configId,
std::make_unique<RefreshRate>(configId, config,
- base::StringPrintf("%.2ffps", fps), fps,
+ Fps::fromPeriodNsecs(
+ config->getVsyncPeriod()),
RefreshRate::ConstructorTag(0)));
if (configId == currentConfigId) {
mCurrentRefreshRate = mRefreshRates.at(configId).get();
@@ -463,8 +465,8 @@
ALOGE("Default config is not in the primary range.");
return false;
}
- return policy.appRequestRange.min <= policy.primaryRange.min &&
- policy.appRequestRange.max >= policy.primaryRange.max;
+ return policy.appRequestRange.min.lessThanOrEqualWithMargin(policy.primaryRange.min) &&
+ policy.appRequestRange.max.greaterThanOrEqualWithMargin(policy.primaryRange.max);
}
status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) {
@@ -550,12 +552,9 @@
// Filter configs based on current policy and sort based on vsync period
const Policy* policy = getCurrentPolicyLocked();
const auto& defaultConfig = mRefreshRates.at(policy->defaultConfig)->hwcConfig;
- ALOGV("constructAvailableRefreshRates: default %d group %d primaryRange=[%.2f %.2f]"
- " appRequestRange=[%.2f %.2f]",
- policy->defaultConfig.value(), defaultConfig->getConfigGroup(), policy->primaryRange.min,
- policy->primaryRange.max, policy->appRequestRange.min, policy->appRequestRange.max);
+ ALOGV("constructAvailableRefreshRates: %s ", policy->toString().c_str());
- auto filterRefreshRates = [&](float min, float max, const char* listName,
+ auto filterRefreshRates = [&](Fps min, Fps max, const char* listName,
std::vector<const RefreshRate*>* outRefreshRates) {
getSortedRefreshRateList(
[&](const RefreshRate& refreshRate) REQUIRES(mLock) {
@@ -572,12 +571,12 @@
outRefreshRates);
LOG_ALWAYS_FATAL_IF(outRefreshRates->empty(),
- "No matching configs for %s range: min=%.0f max=%.0f", listName, min,
- max);
+ "No matching configs for %s range: min=%s max=%s", listName,
+ to_string(min).c_str(), to_string(max).c_str());
auto stringifyRefreshRates = [&]() -> std::string {
std::string str;
for (auto refreshRate : *outRefreshRates) {
- base::StringAppendF(&str, "%s ", refreshRate->name.c_str());
+ base::StringAppendF(&str, "%s ", refreshRate->getName().c_str());
}
return str;
};
@@ -590,39 +589,39 @@
&mAppRequestRefreshRates);
}
-std::vector<float> RefreshRateConfigs::constructKnownFrameRates(
+std::vector<Fps> RefreshRateConfigs::constructKnownFrameRates(
const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
- std::vector<float> knownFrameRates = {24.0f, 30.0f, 45.0f, 60.0f, 72.0f};
+ std::vector<Fps> knownFrameRates = {Fps(24.0f), Fps(30.0f), Fps(45.0f), Fps(60.0f), Fps(72.0f)};
knownFrameRates.reserve(knownFrameRates.size() + configs.size());
// Add all supported refresh rates to the set
for (const auto& config : configs) {
- const auto refreshRate = 1e9f / config->getVsyncPeriod();
+ const auto refreshRate = Fps::fromPeriodNsecs(config->getVsyncPeriod());
knownFrameRates.emplace_back(refreshRate);
}
// Sort and remove duplicates
- const auto frameRatesEqual = [](float a, float b) { return std::abs(a - b) <= 0.01f; };
- std::sort(knownFrameRates.begin(), knownFrameRates.end());
+ std::sort(knownFrameRates.begin(), knownFrameRates.end(), Fps::comparesLess);
knownFrameRates.erase(std::unique(knownFrameRates.begin(), knownFrameRates.end(),
- frameRatesEqual),
+ Fps::EqualsWithMargin()),
knownFrameRates.end());
return knownFrameRates;
}
-float RefreshRateConfigs::findClosestKnownFrameRate(float frameRate) const {
- if (frameRate <= *mKnownFrameRates.begin()) {
+Fps RefreshRateConfigs::findClosestKnownFrameRate(Fps frameRate) const {
+ if (frameRate.lessThanOrEqualWithMargin(*mKnownFrameRates.begin())) {
return *mKnownFrameRates.begin();
}
- if (frameRate >= *std::prev(mKnownFrameRates.end())) {
+ if (frameRate.greaterThanOrEqualWithMargin(*std::prev(mKnownFrameRates.end()))) {
return *std::prev(mKnownFrameRates.end());
}
- auto lowerBound = std::lower_bound(mKnownFrameRates.begin(), mKnownFrameRates.end(), frameRate);
+ auto lowerBound = std::lower_bound(mKnownFrameRates.begin(), mKnownFrameRates.end(), frameRate,
+ Fps::comparesLess);
- const auto distance1 = std::abs(frameRate - *lowerBound);
- const auto distance2 = std::abs(frameRate - *std::prev(lowerBound));
+ const auto distance1 = std::abs((frameRate.getValue() - lowerBound->getValue()));
+ const auto distance2 = std::abs((frameRate.getValue() - std::prev(lowerBound)->getValue()));
return distance1 < distance2 ? *lowerBound : *std::prev(lowerBound);
}
@@ -657,7 +656,7 @@
std::lock_guard lock(mLock);
if (frameRateOverride.frameRateHz != 0) {
- mPreferredRefreshRateForUid[frameRateOverride.uid] = frameRateOverride.frameRateHz;
+ mPreferredRefreshRateForUid[frameRateOverride.uid] = Fps(frameRateOverride.frameRateHz);
} else {
mPreferredRefreshRateForUid.erase(frameRateOverride.uid);
}
@@ -675,7 +674,7 @@
// in DisplayManagerService.getDisplayInfoForFrameRateOverride
constexpr float kThreshold = 0.1f;
const auto refreshRateHz = iter->second;
- const auto numPeriods = mCurrentRefreshRate->getFps() / refreshRateHz;
+ const auto numPeriods = mCurrentRefreshRate->getFps().getValue() / refreshRateHz.getValue();
const auto numPeriodsRounded = std::round(numPeriods);
if (std::abs(numPeriods - numPeriodsRounded) > kThreshold) {
return 1;
@@ -690,7 +689,7 @@
overrides.reserve(mPreferredRefreshRateForUid.size());
for (const auto [uid, frameRate] : mPreferredRefreshRateForUid) {
- overrides.emplace_back(FrameRateOverride{uid, frameRate});
+ overrides.emplace_back(FrameRateOverride{uid, frameRate.getValue()});
}
return overrides;