blob: e4b02871482ce4d7f4c13e72db6fb75f6ed33f49 [file] [log] [blame]
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -08001/*
2 * Copyright 2019 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 */
Ady Abraham2139f732019-11-13 18:56:40 -080016
Ady Abraham8a82ba62020-01-17 12:43:17 -080017// #define LOG_NDEBUG 0
18#define ATRACE_TAG ATRACE_TAG_GRAPHICS
19
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -080020#include "RefreshRateConfigs.h"
Ady Abraham8a82ba62020-01-17 12:43:17 -080021#include <android-base/stringprintf.h>
22#include <utils/Trace.h>
23#include <chrono>
24#include <cmath>
25
26using namespace std::chrono_literals;
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -080027
28namespace android::scheduler {
Ady Abraham2139f732019-11-13 18:56:40 -080029
30using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType;
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -080031using RefreshRate = RefreshRateConfigs::RefreshRate;
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -080032
Ady Abraham8a82ba62020-01-17 12:43:17 -080033const RefreshRate& RefreshRateConfigs::getRefreshRateForContent(
34 const std::vector<LayerRequirement>& layers) const {
Ady Abraham2139f732019-11-13 18:56:40 -080035 std::lock_guard lock(mLock);
Ady Abrahamdec1a412020-01-24 10:23:50 -080036 int contentFramerate = 0;
37 int explicitContentFramerate = 0;
Ady Abraham8a82ba62020-01-17 12:43:17 -080038 for (const auto& layer : layers) {
Ady Abrahamdec1a412020-01-24 10:23:50 -080039 const auto desiredRefreshRateRound = round<int>(layer.desiredRefreshRate);
Ady Abraham8a82ba62020-01-17 12:43:17 -080040 if (layer.vote == LayerVoteType::Explicit) {
Ady Abrahamdec1a412020-01-24 10:23:50 -080041 if (desiredRefreshRateRound > explicitContentFramerate) {
42 explicitContentFramerate = desiredRefreshRateRound;
Ady Abraham8a82ba62020-01-17 12:43:17 -080043 }
44 } else {
Ady Abrahamdec1a412020-01-24 10:23:50 -080045 if (desiredRefreshRateRound > contentFramerate) {
46 contentFramerate = desiredRefreshRateRound;
Ady Abraham8a82ba62020-01-17 12:43:17 -080047 }
48 }
49 }
50
Ady Abrahamdec1a412020-01-24 10:23:50 -080051 if (explicitContentFramerate != 0) {
Ady Abraham8a82ba62020-01-17 12:43:17 -080052 contentFramerate = explicitContentFramerate;
Ady Abrahamdec1a412020-01-24 10:23:50 -080053 } else if (contentFramerate == 0) {
54 contentFramerate = round<int>(mMaxSupportedRefreshRate->fps);
Ady Abraham8a82ba62020-01-17 12:43:17 -080055 }
Ady Abraham8a82ba62020-01-17 12:43:17 -080056 ATRACE_INT("ContentFPS", contentFramerate);
57
Ady Abraham2139f732019-11-13 18:56:40 -080058 // Find the appropriate refresh rate with minimal error
59 auto iter = min_element(mAvailableRefreshRates.cbegin(), mAvailableRefreshRates.cend(),
60 [contentFramerate](const auto& lhs, const auto& rhs) -> bool {
61 return std::abs(lhs->fps - contentFramerate) <
62 std::abs(rhs->fps - contentFramerate);
63 });
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -080064
Ady Abraham2139f732019-11-13 18:56:40 -080065 // Some content aligns better on higher refresh rate. For example for 45fps we should choose
66 // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't
67 // align well with both
68 const RefreshRate* bestSoFar = *iter;
69 constexpr float MARGIN = 0.05f;
70 float ratio = (*iter)->fps / contentFramerate;
71 if (std::abs(std::round(ratio) - ratio) > MARGIN) {
72 while (iter != mAvailableRefreshRates.cend()) {
73 ratio = (*iter)->fps / contentFramerate;
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -080074
Ady Abraham2139f732019-11-13 18:56:40 -080075 if (std::abs(std::round(ratio) - ratio) <= MARGIN) {
76 bestSoFar = *iter;
77 break;
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -080078 }
Ady Abraham2139f732019-11-13 18:56:40 -080079 ++iter;
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -080080 }
81 }
82
Ady Abraham2139f732019-11-13 18:56:40 -080083 return *bestSoFar;
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -080084}
85
Ady Abraham8a82ba62020-01-17 12:43:17 -080086const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2(
87 const std::vector<LayerRequirement>& layers) const {
88 constexpr nsecs_t MARGIN = std::chrono::nanoseconds(800us).count();
89 ATRACE_CALL();
90 ALOGV("getRefreshRateForContent %zu layers", layers.size());
91
92 std::lock_guard lock(mLock);
93
94 int noVoteLayers = 0;
95 int minVoteLayers = 0;
96 int maxVoteLayers = 0;
97 int explicitVoteLayers = 0;
98 for (const auto& layer : layers) {
99 if (layer.vote == LayerVoteType::NoVote)
100 noVoteLayers++;
101 else if (layer.vote == LayerVoteType::Min)
102 minVoteLayers++;
103 else if (layer.vote == LayerVoteType::Max)
104 maxVoteLayers++;
105 else if (layer.vote == LayerVoteType::Explicit)
106 explicitVoteLayers++;
107 }
108
109 // Only if all layers want Min we should return Min
110 if (noVoteLayers + minVoteLayers == layers.size()) {
111 return *mAvailableRefreshRates.front();
112 }
113
114 // If we have some Max layers and no Explicit we should return Max
115 if (maxVoteLayers > 0 && explicitVoteLayers == 0) {
116 return *mAvailableRefreshRates.back();
117 }
118
119 // Find the best refresh rate based on score
120 std::vector<std::pair<const RefreshRate*, float>> scores;
121 scores.reserve(mAvailableRefreshRates.size());
122
123 for (const auto refreshRate : mAvailableRefreshRates) {
124 scores.emplace_back(refreshRate, 0.0f);
125 }
126
127 for (const auto& layer : layers) {
Ady Abrahamf6b77072020-01-30 14:22:54 -0800128 ALOGV("Calculating score for %s (type: %d)", layer.name.c_str(), layer.vote);
Ady Abraham8a82ba62020-01-17 12:43:17 -0800129 if (layer.vote == LayerVoteType::NoVote || layer.vote == LayerVoteType::Min ||
130 layer.vote == LayerVoteType::Max) {
131 continue;
132 }
133
Ady Abrahamf6b77072020-01-30 14:22:54 -0800134 // If we have Explicit layers, ignore the Hueristic ones
Ady Abraham8a82ba62020-01-17 12:43:17 -0800135 if (explicitVoteLayers > 0 && layer.vote == LayerVoteType::Heuristic) {
136 continue;
137 }
138
139 for (auto& [refreshRate, overallScore] : scores) {
140 const auto displayPeriod = refreshRate->vsyncPeriod;
Ady Abrahamdec1a412020-01-24 10:23:50 -0800141 const auto layerPeriod = round<nsecs_t>(1e9f / layer.desiredRefreshRate);
Ady Abraham8a82ba62020-01-17 12:43:17 -0800142
143 // Calculate how many display vsyncs we need to present a single frame for this layer
144 auto [displayFramesQuot, displayFramesRem] = std::div(layerPeriod, displayPeriod);
145 if (displayFramesRem <= MARGIN ||
146 std::abs(displayFramesRem - displayPeriod) <= MARGIN) {
147 displayFramesQuot++;
148 displayFramesRem = 0;
149 }
150
151 float layerScore;
Ady Abrahamf6b77072020-01-30 14:22:54 -0800152 static constexpr size_t MAX_FRAMES_TO_FIT = 10; // Stop calculating when score < 0.1
Ady Abraham8a82ba62020-01-17 12:43:17 -0800153 if (displayFramesRem == 0) {
154 // Layer desired refresh rate matches the display rate.
155 layerScore = layer.weight * 1.0f;
156 } else if (displayFramesQuot == 0) {
157 // Layer desired refresh rate is higher the display rate.
Ady Abrahamf6b77072020-01-30 14:22:54 -0800158 layerScore = layer.weight *
159 (static_cast<float>(layerPeriod) / static_cast<float>(displayPeriod)) *
160 (1.0f / (MAX_FRAMES_TO_FIT + 1));
Ady Abraham8a82ba62020-01-17 12:43:17 -0800161 } else {
162 // Layer desired refresh rate is lower the display rate. Check how well it fits the
163 // cadence
164 auto diff = std::abs(displayFramesRem - (displayPeriod - displayFramesRem));
165 int iter = 2;
Ady Abrahamf6b77072020-01-30 14:22:54 -0800166 while (diff > MARGIN && iter < MAX_FRAMES_TO_FIT) {
Ady Abraham8a82ba62020-01-17 12:43:17 -0800167 diff = diff - (displayPeriod - diff);
168 iter++;
169 }
170
Ady Abrahamf6b77072020-01-30 14:22:54 -0800171 layerScore = layer.weight * (1.0f / iter);
Ady Abraham8a82ba62020-01-17 12:43:17 -0800172 }
173
174 ALOGV("%s (weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(),
175 layer.weight, 1e9f / layerPeriod, refreshRate->name.c_str(), layerScore);
176 overallScore += layerScore;
177 }
178 }
179
180 float max = 0;
181 const RefreshRate* bestRefreshRate = nullptr;
182 for (const auto [refreshRate, score] : scores) {
183 ALOGV("%s scores %.2f", refreshRate->name.c_str(), score);
184
Ady Abrahamdec1a412020-01-24 10:23:50 -0800185 ATRACE_INT(refreshRate->name.c_str(), round<int>(score * 100));
Ady Abraham8a82ba62020-01-17 12:43:17 -0800186
187 if (score > max) {
188 max = score;
189 bestRefreshRate = refreshRate;
190 }
191 }
192
193 return bestRefreshRate == nullptr ? *mCurrentRefreshRate : *bestRefreshRate;
194}
195
Ady Abraham2139f732019-11-13 18:56:40 -0800196const AllRefreshRatesMapType& RefreshRateConfigs::getAllRefreshRates() const {
197 return mRefreshRates;
198}
199
200const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicy() const {
201 std::lock_guard lock(mLock);
202 if (!mRefreshRateSwitching) {
203 return *mCurrentRefreshRate;
204 } else {
205 return *mAvailableRefreshRates.front();
206 }
207}
208
209const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicy() const {
210 std::lock_guard lock(mLock);
211 if (!mRefreshRateSwitching) {
212 return *mCurrentRefreshRate;
213 } else {
214 return *mAvailableRefreshRates.back();
215 }
216}
217
218const RefreshRate& RefreshRateConfigs::getCurrentRefreshRate() const {
219 std::lock_guard lock(mLock);
220 return *mCurrentRefreshRate;
221}
222
223void RefreshRateConfigs::setCurrentConfigId(HwcConfigIndexType configId) {
224 std::lock_guard lock(mLock);
225 mCurrentRefreshRate = &mRefreshRates.at(configId);
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800226}
227
228RefreshRateConfigs::RefreshRateConfigs(bool refreshRateSwitching,
Ady Abraham2139f732019-11-13 18:56:40 -0800229 const std::vector<InputConfig>& configs,
230 HwcConfigIndexType currentHwcConfig)
231 : mRefreshRateSwitching(refreshRateSwitching) {
232 init(configs, currentHwcConfig);
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800233}
234
235RefreshRateConfigs::RefreshRateConfigs(
236 bool refreshRateSwitching,
237 const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
Ady Abraham2139f732019-11-13 18:56:40 -0800238 HwcConfigIndexType currentConfigId)
239 : mRefreshRateSwitching(refreshRateSwitching) {
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800240 std::vector<InputConfig> inputConfigs;
Ady Abrahamdec1a412020-01-24 10:23:50 -0800241 for (size_t configId = 0; configId < configs.size(); ++configId) {
242 auto configGroup = HwcConfigGroupType(configs[configId]->getConfigGroup());
243 inputConfigs.push_back({HwcConfigIndexType(static_cast<int>(configId)), configGroup,
244 configs[configId]->getVsyncPeriod()});
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800245 }
Ady Abraham2139f732019-11-13 18:56:40 -0800246 init(inputConfigs, currentConfigId);
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800247}
248
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100249status_t RefreshRateConfigs::setPolicy(HwcConfigIndexType defaultConfigId, float minRefreshRate,
250 float maxRefreshRate, bool* outPolicyChanged) {
Ady Abraham2139f732019-11-13 18:56:40 -0800251 std::lock_guard lock(mLock);
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100252 bool policyChanged = defaultConfigId != mDefaultConfig ||
253 minRefreshRate != mMinRefreshRateFps || maxRefreshRate != mMaxRefreshRateFps;
254 if (outPolicyChanged) {
255 *outPolicyChanged = policyChanged;
256 }
257 if (!policyChanged) {
258 return NO_ERROR;
259 }
260 // defaultConfigId must be a valid config ID, and within the given refresh rate range.
261 if (mRefreshRates.count(defaultConfigId) == 0) {
262 return BAD_VALUE;
263 }
264 const RefreshRate& refreshRate = mRefreshRates.at(defaultConfigId);
Ana Krulec72f0d6e2020-01-06 15:24:47 -0800265 if (!refreshRate.inPolicy(minRefreshRate, maxRefreshRate)) {
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100266 return BAD_VALUE;
267 }
268 mDefaultConfig = defaultConfigId;
Ady Abraham2139f732019-11-13 18:56:40 -0800269 mMinRefreshRateFps = minRefreshRate;
270 mMaxRefreshRateFps = maxRefreshRate;
271 constructAvailableRefreshRates();
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100272 return NO_ERROR;
273}
274
275void RefreshRateConfigs::getPolicy(HwcConfigIndexType* defaultConfigId, float* minRefreshRate,
276 float* maxRefreshRate) const {
277 std::lock_guard lock(mLock);
278 *defaultConfigId = mDefaultConfig;
279 *minRefreshRate = mMinRefreshRateFps;
280 *maxRefreshRate = mMaxRefreshRateFps;
281}
282
283bool RefreshRateConfigs::isConfigAllowed(HwcConfigIndexType config) const {
284 std::lock_guard lock(mLock);
285 for (const RefreshRate* refreshRate : mAvailableRefreshRates) {
286 if (refreshRate->configId == config) {
287 return true;
288 }
289 }
290 return false;
Ady Abraham2139f732019-11-13 18:56:40 -0800291}
292
293void RefreshRateConfigs::getSortedRefreshRateList(
294 const std::function<bool(const RefreshRate&)>& shouldAddRefreshRate,
295 std::vector<const RefreshRate*>* outRefreshRates) {
296 outRefreshRates->clear();
297 outRefreshRates->reserve(mRefreshRates.size());
298 for (const auto& [type, refreshRate] : mRefreshRates) {
299 if (shouldAddRefreshRate(refreshRate)) {
300 ALOGV("getSortedRefreshRateList: config %d added to list policy",
301 refreshRate.configId.value());
302 outRefreshRates->push_back(&refreshRate);
303 }
304 }
305
306 std::sort(outRefreshRates->begin(), outRefreshRates->end(),
307 [](const auto refreshRate1, const auto refreshRate2) {
308 return refreshRate1->vsyncPeriod > refreshRate2->vsyncPeriod;
309 });
310}
311
312void RefreshRateConfigs::constructAvailableRefreshRates() {
313 // Filter configs based on current policy and sort based on vsync period
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100314 HwcConfigGroupType group = mRefreshRates.at(mDefaultConfig).configGroup;
Ady Abraham8a82ba62020-01-17 12:43:17 -0800315 ALOGV("constructAvailableRefreshRates: default %d group %d min %.2f max %.2f",
316 mDefaultConfig.value(), group.value(), mMinRefreshRateFps, mMaxRefreshRateFps);
Ady Abraham2139f732019-11-13 18:56:40 -0800317 getSortedRefreshRateList(
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100318 [&](const RefreshRate& refreshRate) REQUIRES(mLock) {
Ana Krulec72f0d6e2020-01-06 15:24:47 -0800319 return refreshRate.configGroup == group &&
320 refreshRate.inPolicy(mMinRefreshRateFps, mMaxRefreshRateFps);
Ady Abraham2139f732019-11-13 18:56:40 -0800321 },
322 &mAvailableRefreshRates);
Ady Abraham8a82ba62020-01-17 12:43:17 -0800323
324 std::string availableRefreshRates;
325 for (const auto& refreshRate : mAvailableRefreshRates) {
326 base::StringAppendF(&availableRefreshRates, "%s ", refreshRate->name.c_str());
327 }
328
329 ALOGV("Available refresh rates: %s", availableRefreshRates.c_str());
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100330 LOG_ALWAYS_FATAL_IF(mAvailableRefreshRates.empty(),
331 "No compatible display configs for default=%d min=%.0f max=%.0f",
332 mDefaultConfig.value(), mMinRefreshRateFps, mMaxRefreshRateFps);
Ady Abraham2139f732019-11-13 18:56:40 -0800333}
334
335// NO_THREAD_SAFETY_ANALYSIS since this is called from the constructor
336void RefreshRateConfigs::init(const std::vector<InputConfig>& configs,
337 HwcConfigIndexType currentHwcConfig) NO_THREAD_SAFETY_ANALYSIS {
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800338 LOG_ALWAYS_FATAL_IF(configs.empty());
Ady Abraham2139f732019-11-13 18:56:40 -0800339 LOG_ALWAYS_FATAL_IF(currentHwcConfig.value() >= configs.size());
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800340
Ady Abraham2139f732019-11-13 18:56:40 -0800341 auto buildRefreshRate = [&](InputConfig config) -> RefreshRate {
342 const float fps = 1e9f / config.vsyncPeriod;
343 return RefreshRate(config.configId, config.vsyncPeriod, config.configGroup,
344 base::StringPrintf("%2.ffps", fps), fps);
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800345 };
346
Ady Abraham2139f732019-11-13 18:56:40 -0800347 for (const auto& config : configs) {
348 mRefreshRates.emplace(config.configId, buildRefreshRate(config));
349 if (config.configId == currentHwcConfig) {
350 mCurrentRefreshRate = &mRefreshRates.at(config.configId);
Ady Abraham2139f732019-11-13 18:56:40 -0800351 }
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800352 }
353
Ady Abraham2139f732019-11-13 18:56:40 -0800354 std::vector<const RefreshRate*> sortedConfigs;
355 getSortedRefreshRateList([](const RefreshRate&) { return true; }, &sortedConfigs);
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100356 mDefaultConfig = currentHwcConfig;
Ady Abraham2139f732019-11-13 18:56:40 -0800357 mMinSupportedRefreshRate = sortedConfigs.front();
358 mMaxSupportedRefreshRate = sortedConfigs.back();
359 constructAvailableRefreshRates();
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800360}
361
Ady Abraham2139f732019-11-13 18:56:40 -0800362} // namespace android::scheduler