blob: d1de737a8984e81ed307db34dd1221e32910e2f1 [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 Abraham71c437d2020-01-31 15:56:57 -080040 if (layer.vote == LayerVoteType::ExplicitDefault ||
41 layer.vote == LayerVoteType::ExplicitExactOrMultiple) {
Ady Abrahamdec1a412020-01-24 10:23:50 -080042 if (desiredRefreshRateRound > explicitContentFramerate) {
43 explicitContentFramerate = desiredRefreshRateRound;
Ady Abraham8a82ba62020-01-17 12:43:17 -080044 }
45 } else {
Ady Abrahamdec1a412020-01-24 10:23:50 -080046 if (desiredRefreshRateRound > contentFramerate) {
47 contentFramerate = desiredRefreshRateRound;
Ady Abraham8a82ba62020-01-17 12:43:17 -080048 }
49 }
50 }
51
Ady Abrahamdec1a412020-01-24 10:23:50 -080052 if (explicitContentFramerate != 0) {
Ady Abraham8a82ba62020-01-17 12:43:17 -080053 contentFramerate = explicitContentFramerate;
Ady Abrahamdec1a412020-01-24 10:23:50 -080054 } else if (contentFramerate == 0) {
55 contentFramerate = round<int>(mMaxSupportedRefreshRate->fps);
Ady Abraham8a82ba62020-01-17 12:43:17 -080056 }
Ady Abraham8a82ba62020-01-17 12:43:17 -080057 ATRACE_INT("ContentFPS", contentFramerate);
58
Ady Abraham2139f732019-11-13 18:56:40 -080059 // Find the appropriate refresh rate with minimal error
60 auto iter = min_element(mAvailableRefreshRates.cbegin(), mAvailableRefreshRates.cend(),
61 [contentFramerate](const auto& lhs, const auto& rhs) -> bool {
62 return std::abs(lhs->fps - contentFramerate) <
63 std::abs(rhs->fps - contentFramerate);
64 });
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -080065
Ady Abraham2139f732019-11-13 18:56:40 -080066 // Some content aligns better on higher refresh rate. For example for 45fps we should choose
67 // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't
68 // align well with both
69 const RefreshRate* bestSoFar = *iter;
70 constexpr float MARGIN = 0.05f;
71 float ratio = (*iter)->fps / contentFramerate;
72 if (std::abs(std::round(ratio) - ratio) > MARGIN) {
73 while (iter != mAvailableRefreshRates.cend()) {
74 ratio = (*iter)->fps / contentFramerate;
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -080075
Ady Abraham2139f732019-11-13 18:56:40 -080076 if (std::abs(std::round(ratio) - ratio) <= MARGIN) {
77 bestSoFar = *iter;
78 break;
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -080079 }
Ady Abraham2139f732019-11-13 18:56:40 -080080 ++iter;
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -080081 }
82 }
83
Ady Abraham2139f732019-11-13 18:56:40 -080084 return *bestSoFar;
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -080085}
86
Ady Abraham8a82ba62020-01-17 12:43:17 -080087const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2(
88 const std::vector<LayerRequirement>& layers) const {
89 constexpr nsecs_t MARGIN = std::chrono::nanoseconds(800us).count();
90 ATRACE_CALL();
91 ALOGV("getRefreshRateForContent %zu layers", layers.size());
92
93 std::lock_guard lock(mLock);
94
95 int noVoteLayers = 0;
96 int minVoteLayers = 0;
97 int maxVoteLayers = 0;
Ady Abraham71c437d2020-01-31 15:56:57 -080098 int explicitDefaultVoteLayers = 0;
99 int explicitExactOrMultipleVoteLayers = 0;
Ady Abraham8a82ba62020-01-17 12:43:17 -0800100 for (const auto& layer : layers) {
101 if (layer.vote == LayerVoteType::NoVote)
102 noVoteLayers++;
103 else if (layer.vote == LayerVoteType::Min)
104 minVoteLayers++;
105 else if (layer.vote == LayerVoteType::Max)
106 maxVoteLayers++;
Ady Abraham71c437d2020-01-31 15:56:57 -0800107 else if (layer.vote == LayerVoteType::ExplicitDefault)
108 explicitDefaultVoteLayers++;
109 else if (layer.vote == LayerVoteType::ExplicitExactOrMultiple)
110 explicitExactOrMultipleVoteLayers++;
Ady Abraham8a82ba62020-01-17 12:43:17 -0800111 }
112
113 // Only if all layers want Min we should return Min
114 if (noVoteLayers + minVoteLayers == layers.size()) {
115 return *mAvailableRefreshRates.front();
116 }
117
118 // If we have some Max layers and no Explicit we should return Max
Ady Abraham71c437d2020-01-31 15:56:57 -0800119 if (maxVoteLayers > 0 && explicitDefaultVoteLayers + explicitExactOrMultipleVoteLayers == 0) {
Ady Abraham8a82ba62020-01-17 12:43:17 -0800120 return *mAvailableRefreshRates.back();
121 }
122
123 // Find the best refresh rate based on score
124 std::vector<std::pair<const RefreshRate*, float>> scores;
125 scores.reserve(mAvailableRefreshRates.size());
126
127 for (const auto refreshRate : mAvailableRefreshRates) {
128 scores.emplace_back(refreshRate, 0.0f);
129 }
130
131 for (const auto& layer : layers) {
Ady Abrahamf6b77072020-01-30 14:22:54 -0800132 ALOGV("Calculating score for %s (type: %d)", layer.name.c_str(), layer.vote);
Ady Abraham8a82ba62020-01-17 12:43:17 -0800133 if (layer.vote == LayerVoteType::NoVote || layer.vote == LayerVoteType::Min ||
134 layer.vote == LayerVoteType::Max) {
135 continue;
136 }
137
Ady Abraham71c437d2020-01-31 15:56:57 -0800138 // Adjust the weight in case we have explicit layers. The priority is:
139 // - ExplicitExactOrMultiple
140 // - ExplicitDefault
141 // - Heuristic
142 auto weight = layer.weight;
143 if (explicitExactOrMultipleVoteLayers + explicitDefaultVoteLayers > 0) {
144 if (layer.vote == LayerVoteType::Heuristic) {
145 weight /= 2.f;
146 }
147 }
148
149 if (explicitExactOrMultipleVoteLayers > 0) {
150 if (layer.vote == LayerVoteType::Heuristic ||
151 layer.vote == LayerVoteType::ExplicitDefault) {
152 weight /= 2.f;
153 }
Ady Abraham8a82ba62020-01-17 12:43:17 -0800154 }
155
156 for (auto& [refreshRate, overallScore] : scores) {
157 const auto displayPeriod = refreshRate->vsyncPeriod;
Ady Abrahamdec1a412020-01-24 10:23:50 -0800158 const auto layerPeriod = round<nsecs_t>(1e9f / layer.desiredRefreshRate);
Ady Abraham8a82ba62020-01-17 12:43:17 -0800159
160 // Calculate how many display vsyncs we need to present a single frame for this layer
161 auto [displayFramesQuot, displayFramesRem] = std::div(layerPeriod, displayPeriod);
162 if (displayFramesRem <= MARGIN ||
163 std::abs(displayFramesRem - displayPeriod) <= MARGIN) {
164 displayFramesQuot++;
165 displayFramesRem = 0;
166 }
167
168 float layerScore;
Ady Abrahamf6b77072020-01-30 14:22:54 -0800169 static constexpr size_t MAX_FRAMES_TO_FIT = 10; // Stop calculating when score < 0.1
Ady Abraham8a82ba62020-01-17 12:43:17 -0800170 if (displayFramesRem == 0) {
171 // Layer desired refresh rate matches the display rate.
Ady Abraham71c437d2020-01-31 15:56:57 -0800172 layerScore = weight * 1.0f;
Ady Abraham8a82ba62020-01-17 12:43:17 -0800173 } else if (displayFramesQuot == 0) {
174 // Layer desired refresh rate is higher the display rate.
Ady Abraham71c437d2020-01-31 15:56:57 -0800175 layerScore = weight *
Ady Abrahamf6b77072020-01-30 14:22:54 -0800176 (static_cast<float>(layerPeriod) / static_cast<float>(displayPeriod)) *
177 (1.0f / (MAX_FRAMES_TO_FIT + 1));
Ady Abraham8a82ba62020-01-17 12:43:17 -0800178 } else {
179 // Layer desired refresh rate is lower the display rate. Check how well it fits the
180 // cadence
181 auto diff = std::abs(displayFramesRem - (displayPeriod - displayFramesRem));
182 int iter = 2;
Ady Abrahamf6b77072020-01-30 14:22:54 -0800183 while (diff > MARGIN && iter < MAX_FRAMES_TO_FIT) {
Ady Abraham8a82ba62020-01-17 12:43:17 -0800184 diff = diff - (displayPeriod - diff);
185 iter++;
186 }
187
Ady Abraham71c437d2020-01-31 15:56:57 -0800188 layerScore = weight * (1.0f / iter);
Ady Abraham8a82ba62020-01-17 12:43:17 -0800189 }
190
Ady Abraham71c437d2020-01-31 15:56:57 -0800191 ALOGV("%s (weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(), weight,
192 1e9f / layerPeriod, refreshRate->name.c_str(), layerScore);
Ady Abraham8a82ba62020-01-17 12:43:17 -0800193 overallScore += layerScore;
194 }
195 }
196
Ady Abraham34702102020-02-10 14:12:05 -0800197 // Now that we scored all the refresh rates we need to pick the one that got the highest score.
198 // In case of a tie we will pick the higher refresh rate if any of the layers wanted Max,
199 // or the lower otherwise.
200 const RefreshRate* bestRefreshRate = maxVoteLayers > 0
201 ? getBestRefreshRate(scores.rbegin(), scores.rend())
202 : getBestRefreshRate(scores.begin(), scores.end());
203
204 return bestRefreshRate == nullptr ? *mCurrentRefreshRate : *bestRefreshRate;
205}
206
207template <typename Iter>
208const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) const {
Ady Abraham8a82ba62020-01-17 12:43:17 -0800209 const RefreshRate* bestRefreshRate = nullptr;
Ady Abraham34702102020-02-10 14:12:05 -0800210 float max = 0;
211 for (auto i = begin; i != end; ++i) {
212 const auto [refreshRate, score] = *i;
Ady Abraham8a82ba62020-01-17 12:43:17 -0800213 ALOGV("%s scores %.2f", refreshRate->name.c_str(), score);
214
Ady Abrahamdec1a412020-01-24 10:23:50 -0800215 ATRACE_INT(refreshRate->name.c_str(), round<int>(score * 100));
Ady Abraham8a82ba62020-01-17 12:43:17 -0800216
217 if (score > max) {
218 max = score;
219 bestRefreshRate = refreshRate;
220 }
221 }
222
Ady Abraham34702102020-02-10 14:12:05 -0800223 return bestRefreshRate;
Ady Abraham8a82ba62020-01-17 12:43:17 -0800224}
225
Ady Abraham2139f732019-11-13 18:56:40 -0800226const AllRefreshRatesMapType& RefreshRateConfigs::getAllRefreshRates() const {
227 return mRefreshRates;
228}
229
230const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicy() const {
231 std::lock_guard lock(mLock);
Ana Krulec3f6a2062020-01-23 15:48:01 -0800232 return *mAvailableRefreshRates.front();
Ady Abraham2139f732019-11-13 18:56:40 -0800233}
234
235const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicy() const {
236 std::lock_guard lock(mLock);
Ady Abraham2139f732019-11-13 18:56:40 -0800237 return *mAvailableRefreshRates.back();
Ady Abraham2139f732019-11-13 18:56:40 -0800238}
239
240const RefreshRate& RefreshRateConfigs::getCurrentRefreshRate() const {
241 std::lock_guard lock(mLock);
242 return *mCurrentRefreshRate;
243}
244
Ana Krulec5d477912020-02-07 12:02:38 -0800245const RefreshRate& RefreshRateConfigs::getCurrentRefreshRateByPolicy() const {
246 std::lock_guard lock(mLock);
247 if (std::find(mAvailableRefreshRates.begin(), mAvailableRefreshRates.end(),
248 mCurrentRefreshRate) != mAvailableRefreshRates.end()) {
249 return *mCurrentRefreshRate;
250 }
251 return mRefreshRates.at(mDefaultConfig);
252}
253
Ady Abraham2139f732019-11-13 18:56:40 -0800254void RefreshRateConfigs::setCurrentConfigId(HwcConfigIndexType configId) {
255 std::lock_guard lock(mLock);
256 mCurrentRefreshRate = &mRefreshRates.at(configId);
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800257}
258
Ana Krulec3f6a2062020-01-23 15:48:01 -0800259RefreshRateConfigs::RefreshRateConfigs(const std::vector<InputConfig>& configs,
260 HwcConfigIndexType currentHwcConfig) {
Ady Abraham2139f732019-11-13 18:56:40 -0800261 init(configs, currentHwcConfig);
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800262}
263
264RefreshRateConfigs::RefreshRateConfigs(
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800265 const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
Ana Krulec3f6a2062020-01-23 15:48:01 -0800266 HwcConfigIndexType currentConfigId) {
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800267 std::vector<InputConfig> inputConfigs;
Ady Abrahamdec1a412020-01-24 10:23:50 -0800268 for (size_t configId = 0; configId < configs.size(); ++configId) {
269 auto configGroup = HwcConfigGroupType(configs[configId]->getConfigGroup());
270 inputConfigs.push_back({HwcConfigIndexType(static_cast<int>(configId)), configGroup,
271 configs[configId]->getVsyncPeriod()});
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800272 }
Ady Abraham2139f732019-11-13 18:56:40 -0800273 init(inputConfigs, currentConfigId);
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800274}
275
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100276status_t RefreshRateConfigs::setPolicy(HwcConfigIndexType defaultConfigId, float minRefreshRate,
277 float maxRefreshRate, bool* outPolicyChanged) {
Ady Abraham2139f732019-11-13 18:56:40 -0800278 std::lock_guard lock(mLock);
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100279 bool policyChanged = defaultConfigId != mDefaultConfig ||
280 minRefreshRate != mMinRefreshRateFps || maxRefreshRate != mMaxRefreshRateFps;
281 if (outPolicyChanged) {
282 *outPolicyChanged = policyChanged;
283 }
284 if (!policyChanged) {
285 return NO_ERROR;
286 }
287 // defaultConfigId must be a valid config ID, and within the given refresh rate range.
288 if (mRefreshRates.count(defaultConfigId) == 0) {
289 return BAD_VALUE;
290 }
291 const RefreshRate& refreshRate = mRefreshRates.at(defaultConfigId);
Ana Krulec72f0d6e2020-01-06 15:24:47 -0800292 if (!refreshRate.inPolicy(minRefreshRate, maxRefreshRate)) {
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100293 return BAD_VALUE;
294 }
295 mDefaultConfig = defaultConfigId;
Ady Abraham2139f732019-11-13 18:56:40 -0800296 mMinRefreshRateFps = minRefreshRate;
297 mMaxRefreshRateFps = maxRefreshRate;
298 constructAvailableRefreshRates();
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100299 return NO_ERROR;
300}
301
302void RefreshRateConfigs::getPolicy(HwcConfigIndexType* defaultConfigId, float* minRefreshRate,
303 float* maxRefreshRate) const {
304 std::lock_guard lock(mLock);
305 *defaultConfigId = mDefaultConfig;
306 *minRefreshRate = mMinRefreshRateFps;
307 *maxRefreshRate = mMaxRefreshRateFps;
308}
309
310bool RefreshRateConfigs::isConfigAllowed(HwcConfigIndexType config) const {
311 std::lock_guard lock(mLock);
312 for (const RefreshRate* refreshRate : mAvailableRefreshRates) {
313 if (refreshRate->configId == config) {
314 return true;
315 }
316 }
317 return false;
Ady Abraham2139f732019-11-13 18:56:40 -0800318}
319
320void RefreshRateConfigs::getSortedRefreshRateList(
321 const std::function<bool(const RefreshRate&)>& shouldAddRefreshRate,
322 std::vector<const RefreshRate*>* outRefreshRates) {
323 outRefreshRates->clear();
324 outRefreshRates->reserve(mRefreshRates.size());
325 for (const auto& [type, refreshRate] : mRefreshRates) {
326 if (shouldAddRefreshRate(refreshRate)) {
327 ALOGV("getSortedRefreshRateList: config %d added to list policy",
328 refreshRate.configId.value());
329 outRefreshRates->push_back(&refreshRate);
330 }
331 }
332
333 std::sort(outRefreshRates->begin(), outRefreshRates->end(),
334 [](const auto refreshRate1, const auto refreshRate2) {
335 return refreshRate1->vsyncPeriod > refreshRate2->vsyncPeriod;
336 });
337}
338
339void RefreshRateConfigs::constructAvailableRefreshRates() {
340 // Filter configs based on current policy and sort based on vsync period
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100341 HwcConfigGroupType group = mRefreshRates.at(mDefaultConfig).configGroup;
Ady Abraham8a82ba62020-01-17 12:43:17 -0800342 ALOGV("constructAvailableRefreshRates: default %d group %d min %.2f max %.2f",
343 mDefaultConfig.value(), group.value(), mMinRefreshRateFps, mMaxRefreshRateFps);
Ady Abraham2139f732019-11-13 18:56:40 -0800344 getSortedRefreshRateList(
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100345 [&](const RefreshRate& refreshRate) REQUIRES(mLock) {
Ana Krulec72f0d6e2020-01-06 15:24:47 -0800346 return refreshRate.configGroup == group &&
347 refreshRate.inPolicy(mMinRefreshRateFps, mMaxRefreshRateFps);
Ady Abraham2139f732019-11-13 18:56:40 -0800348 },
349 &mAvailableRefreshRates);
Ady Abraham8a82ba62020-01-17 12:43:17 -0800350
351 std::string availableRefreshRates;
352 for (const auto& refreshRate : mAvailableRefreshRates) {
353 base::StringAppendF(&availableRefreshRates, "%s ", refreshRate->name.c_str());
354 }
355
356 ALOGV("Available refresh rates: %s", availableRefreshRates.c_str());
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100357 LOG_ALWAYS_FATAL_IF(mAvailableRefreshRates.empty(),
358 "No compatible display configs for default=%d min=%.0f max=%.0f",
359 mDefaultConfig.value(), mMinRefreshRateFps, mMaxRefreshRateFps);
Ady Abraham2139f732019-11-13 18:56:40 -0800360}
361
362// NO_THREAD_SAFETY_ANALYSIS since this is called from the constructor
363void RefreshRateConfigs::init(const std::vector<InputConfig>& configs,
364 HwcConfigIndexType currentHwcConfig) NO_THREAD_SAFETY_ANALYSIS {
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800365 LOG_ALWAYS_FATAL_IF(configs.empty());
Ady Abraham2139f732019-11-13 18:56:40 -0800366 LOG_ALWAYS_FATAL_IF(currentHwcConfig.value() >= configs.size());
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800367
Ady Abraham2139f732019-11-13 18:56:40 -0800368 auto buildRefreshRate = [&](InputConfig config) -> RefreshRate {
369 const float fps = 1e9f / config.vsyncPeriod;
370 return RefreshRate(config.configId, config.vsyncPeriod, config.configGroup,
371 base::StringPrintf("%2.ffps", fps), fps);
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800372 };
373
Ady Abraham2139f732019-11-13 18:56:40 -0800374 for (const auto& config : configs) {
375 mRefreshRates.emplace(config.configId, buildRefreshRate(config));
376 if (config.configId == currentHwcConfig) {
377 mCurrentRefreshRate = &mRefreshRates.at(config.configId);
Ady Abraham2139f732019-11-13 18:56:40 -0800378 }
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800379 }
380
Ady Abraham2139f732019-11-13 18:56:40 -0800381 std::vector<const RefreshRate*> sortedConfigs;
382 getSortedRefreshRateList([](const RefreshRate&) { return true; }, &sortedConfigs);
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100383 mDefaultConfig = currentHwcConfig;
Ady Abraham2139f732019-11-13 18:56:40 -0800384 mMinSupportedRefreshRate = sortedConfigs.front();
385 mMaxSupportedRefreshRate = sortedConfigs.back();
386 constructAvailableRefreshRates();
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800387}
388
Ady Abraham2139f732019-11-13 18:56:40 -0800389} // namespace android::scheduler