blob: 0f55615d5051ac10c9d26d337fad89a9eb8586ec [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
197 float max = 0;
198 const RefreshRate* bestRefreshRate = nullptr;
199 for (const auto [refreshRate, score] : scores) {
200 ALOGV("%s scores %.2f", refreshRate->name.c_str(), score);
201
Ady Abrahamdec1a412020-01-24 10:23:50 -0800202 ATRACE_INT(refreshRate->name.c_str(), round<int>(score * 100));
Ady Abraham8a82ba62020-01-17 12:43:17 -0800203
204 if (score > max) {
205 max = score;
206 bestRefreshRate = refreshRate;
207 }
208 }
209
210 return bestRefreshRate == nullptr ? *mCurrentRefreshRate : *bestRefreshRate;
211}
212
Ady Abraham2139f732019-11-13 18:56:40 -0800213const AllRefreshRatesMapType& RefreshRateConfigs::getAllRefreshRates() const {
214 return mRefreshRates;
215}
216
217const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicy() const {
218 std::lock_guard lock(mLock);
Ana Krulec10e02052020-02-04 17:16:10 +0000219 if (!mRefreshRateSwitching) {
220 return *mCurrentRefreshRate;
221 } else {
222 return *mAvailableRefreshRates.front();
223 }
Ady Abraham2139f732019-11-13 18:56:40 -0800224}
225
226const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicy() const {
227 std::lock_guard lock(mLock);
Ana Krulec10e02052020-02-04 17:16:10 +0000228 if (!mRefreshRateSwitching) {
229 return *mCurrentRefreshRate;
230 } else {
Ady Abraham2139f732019-11-13 18:56:40 -0800231 return *mAvailableRefreshRates.back();
Ana Krulec10e02052020-02-04 17:16:10 +0000232 }
Ady Abraham2139f732019-11-13 18:56:40 -0800233}
234
235const RefreshRate& RefreshRateConfigs::getCurrentRefreshRate() const {
236 std::lock_guard lock(mLock);
237 return *mCurrentRefreshRate;
238}
239
240void RefreshRateConfigs::setCurrentConfigId(HwcConfigIndexType configId) {
241 std::lock_guard lock(mLock);
242 mCurrentRefreshRate = &mRefreshRates.at(configId);
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800243}
244
Ana Krulec10e02052020-02-04 17:16:10 +0000245RefreshRateConfigs::RefreshRateConfigs(bool refreshRateSwitching,
246 const std::vector<InputConfig>& configs,
247 HwcConfigIndexType currentHwcConfig)
248 : mRefreshRateSwitching(refreshRateSwitching) {
Ady Abraham2139f732019-11-13 18:56:40 -0800249 init(configs, currentHwcConfig);
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800250}
251
252RefreshRateConfigs::RefreshRateConfigs(
Ana Krulec10e02052020-02-04 17:16:10 +0000253 bool refreshRateSwitching,
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800254 const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
Ana Krulec10e02052020-02-04 17:16:10 +0000255 HwcConfigIndexType currentConfigId)
256 : mRefreshRateSwitching(refreshRateSwitching) {
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800257 std::vector<InputConfig> inputConfigs;
Ady Abrahamdec1a412020-01-24 10:23:50 -0800258 for (size_t configId = 0; configId < configs.size(); ++configId) {
259 auto configGroup = HwcConfigGroupType(configs[configId]->getConfigGroup());
260 inputConfigs.push_back({HwcConfigIndexType(static_cast<int>(configId)), configGroup,
261 configs[configId]->getVsyncPeriod()});
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800262 }
Ady Abraham2139f732019-11-13 18:56:40 -0800263 init(inputConfigs, currentConfigId);
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800264}
265
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100266status_t RefreshRateConfigs::setPolicy(HwcConfigIndexType defaultConfigId, float minRefreshRate,
267 float maxRefreshRate, bool* outPolicyChanged) {
Ady Abraham2139f732019-11-13 18:56:40 -0800268 std::lock_guard lock(mLock);
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100269 bool policyChanged = defaultConfigId != mDefaultConfig ||
270 minRefreshRate != mMinRefreshRateFps || maxRefreshRate != mMaxRefreshRateFps;
271 if (outPolicyChanged) {
272 *outPolicyChanged = policyChanged;
273 }
274 if (!policyChanged) {
275 return NO_ERROR;
276 }
277 // defaultConfigId must be a valid config ID, and within the given refresh rate range.
278 if (mRefreshRates.count(defaultConfigId) == 0) {
279 return BAD_VALUE;
280 }
281 const RefreshRate& refreshRate = mRefreshRates.at(defaultConfigId);
Ana Krulec72f0d6e2020-01-06 15:24:47 -0800282 if (!refreshRate.inPolicy(minRefreshRate, maxRefreshRate)) {
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100283 return BAD_VALUE;
284 }
285 mDefaultConfig = defaultConfigId;
Ady Abraham2139f732019-11-13 18:56:40 -0800286 mMinRefreshRateFps = minRefreshRate;
287 mMaxRefreshRateFps = maxRefreshRate;
288 constructAvailableRefreshRates();
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100289 return NO_ERROR;
290}
291
292void RefreshRateConfigs::getPolicy(HwcConfigIndexType* defaultConfigId, float* minRefreshRate,
293 float* maxRefreshRate) const {
294 std::lock_guard lock(mLock);
295 *defaultConfigId = mDefaultConfig;
296 *minRefreshRate = mMinRefreshRateFps;
297 *maxRefreshRate = mMaxRefreshRateFps;
298}
299
300bool RefreshRateConfigs::isConfigAllowed(HwcConfigIndexType config) const {
301 std::lock_guard lock(mLock);
302 for (const RefreshRate* refreshRate : mAvailableRefreshRates) {
303 if (refreshRate->configId == config) {
304 return true;
305 }
306 }
307 return false;
Ady Abraham2139f732019-11-13 18:56:40 -0800308}
309
310void RefreshRateConfigs::getSortedRefreshRateList(
311 const std::function<bool(const RefreshRate&)>& shouldAddRefreshRate,
312 std::vector<const RefreshRate*>* outRefreshRates) {
313 outRefreshRates->clear();
314 outRefreshRates->reserve(mRefreshRates.size());
315 for (const auto& [type, refreshRate] : mRefreshRates) {
316 if (shouldAddRefreshRate(refreshRate)) {
317 ALOGV("getSortedRefreshRateList: config %d added to list policy",
318 refreshRate.configId.value());
319 outRefreshRates->push_back(&refreshRate);
320 }
321 }
322
323 std::sort(outRefreshRates->begin(), outRefreshRates->end(),
324 [](const auto refreshRate1, const auto refreshRate2) {
325 return refreshRate1->vsyncPeriod > refreshRate2->vsyncPeriod;
326 });
327}
328
329void RefreshRateConfigs::constructAvailableRefreshRates() {
330 // Filter configs based on current policy and sort based on vsync period
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100331 HwcConfigGroupType group = mRefreshRates.at(mDefaultConfig).configGroup;
Ady Abraham8a82ba62020-01-17 12:43:17 -0800332 ALOGV("constructAvailableRefreshRates: default %d group %d min %.2f max %.2f",
333 mDefaultConfig.value(), group.value(), mMinRefreshRateFps, mMaxRefreshRateFps);
Ady Abraham2139f732019-11-13 18:56:40 -0800334 getSortedRefreshRateList(
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100335 [&](const RefreshRate& refreshRate) REQUIRES(mLock) {
Ana Krulec72f0d6e2020-01-06 15:24:47 -0800336 return refreshRate.configGroup == group &&
337 refreshRate.inPolicy(mMinRefreshRateFps, mMaxRefreshRateFps);
Ady Abraham2139f732019-11-13 18:56:40 -0800338 },
339 &mAvailableRefreshRates);
Ady Abraham8a82ba62020-01-17 12:43:17 -0800340
341 std::string availableRefreshRates;
342 for (const auto& refreshRate : mAvailableRefreshRates) {
343 base::StringAppendF(&availableRefreshRates, "%s ", refreshRate->name.c_str());
344 }
345
346 ALOGV("Available refresh rates: %s", availableRefreshRates.c_str());
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100347 LOG_ALWAYS_FATAL_IF(mAvailableRefreshRates.empty(),
348 "No compatible display configs for default=%d min=%.0f max=%.0f",
349 mDefaultConfig.value(), mMinRefreshRateFps, mMaxRefreshRateFps);
Ady Abraham2139f732019-11-13 18:56:40 -0800350}
351
352// NO_THREAD_SAFETY_ANALYSIS since this is called from the constructor
353void RefreshRateConfigs::init(const std::vector<InputConfig>& configs,
354 HwcConfigIndexType currentHwcConfig) NO_THREAD_SAFETY_ANALYSIS {
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800355 LOG_ALWAYS_FATAL_IF(configs.empty());
Ady Abraham2139f732019-11-13 18:56:40 -0800356 LOG_ALWAYS_FATAL_IF(currentHwcConfig.value() >= configs.size());
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800357
Ady Abraham2139f732019-11-13 18:56:40 -0800358 auto buildRefreshRate = [&](InputConfig config) -> RefreshRate {
359 const float fps = 1e9f / config.vsyncPeriod;
360 return RefreshRate(config.configId, config.vsyncPeriod, config.configGroup,
361 base::StringPrintf("%2.ffps", fps), fps);
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800362 };
363
Ady Abraham2139f732019-11-13 18:56:40 -0800364 for (const auto& config : configs) {
365 mRefreshRates.emplace(config.configId, buildRefreshRate(config));
366 if (config.configId == currentHwcConfig) {
367 mCurrentRefreshRate = &mRefreshRates.at(config.configId);
Ady Abraham2139f732019-11-13 18:56:40 -0800368 }
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800369 }
370
Ady Abraham2139f732019-11-13 18:56:40 -0800371 std::vector<const RefreshRate*> sortedConfigs;
372 getSortedRefreshRateList([](const RefreshRate&) { return true; }, &sortedConfigs);
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100373 mDefaultConfig = currentHwcConfig;
Ady Abraham2139f732019-11-13 18:56:40 -0800374 mMinSupportedRefreshRate = sortedConfigs.front();
375 mMaxSupportedRefreshRate = sortedConfigs.back();
376 constructAvailableRefreshRates();
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800377}
378
Ady Abraham2139f732019-11-13 18:56:40 -0800379} // namespace android::scheduler