blob: d2af9126b3ca8a8bee26a31c76f9146db418d838 [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);
Ana Krulec8c6f3f62020-01-23 15:48:01 -0800202 return *mAvailableRefreshRates.front();
Ady Abraham2139f732019-11-13 18:56:40 -0800203}
204
205const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicy() const {
206 std::lock_guard lock(mLock);
Ady Abraham2139f732019-11-13 18:56:40 -0800207 return *mAvailableRefreshRates.back();
Ady Abraham2139f732019-11-13 18:56:40 -0800208}
209
210const RefreshRate& RefreshRateConfigs::getCurrentRefreshRate() const {
211 std::lock_guard lock(mLock);
212 return *mCurrentRefreshRate;
213}
214
215void RefreshRateConfigs::setCurrentConfigId(HwcConfigIndexType configId) {
216 std::lock_guard lock(mLock);
217 mCurrentRefreshRate = &mRefreshRates.at(configId);
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800218}
219
Ana Krulec8c6f3f62020-01-23 15:48:01 -0800220RefreshRateConfigs::RefreshRateConfigs(const std::vector<InputConfig>& configs,
221 HwcConfigIndexType currentHwcConfig) {
Ady Abraham2139f732019-11-13 18:56:40 -0800222 init(configs, currentHwcConfig);
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800223}
224
225RefreshRateConfigs::RefreshRateConfigs(
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800226 const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
Ana Krulec8c6f3f62020-01-23 15:48:01 -0800227 HwcConfigIndexType currentConfigId) {
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800228 std::vector<InputConfig> inputConfigs;
Ady Abrahamdec1a412020-01-24 10:23:50 -0800229 for (size_t configId = 0; configId < configs.size(); ++configId) {
230 auto configGroup = HwcConfigGroupType(configs[configId]->getConfigGroup());
231 inputConfigs.push_back({HwcConfigIndexType(static_cast<int>(configId)), configGroup,
232 configs[configId]->getVsyncPeriod()});
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800233 }
Ady Abraham2139f732019-11-13 18:56:40 -0800234 init(inputConfigs, currentConfigId);
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800235}
236
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100237status_t RefreshRateConfigs::setPolicy(HwcConfigIndexType defaultConfigId, float minRefreshRate,
238 float maxRefreshRate, bool* outPolicyChanged) {
Ady Abraham2139f732019-11-13 18:56:40 -0800239 std::lock_guard lock(mLock);
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100240 bool policyChanged = defaultConfigId != mDefaultConfig ||
241 minRefreshRate != mMinRefreshRateFps || maxRefreshRate != mMaxRefreshRateFps;
242 if (outPolicyChanged) {
243 *outPolicyChanged = policyChanged;
244 }
245 if (!policyChanged) {
246 return NO_ERROR;
247 }
248 // defaultConfigId must be a valid config ID, and within the given refresh rate range.
249 if (mRefreshRates.count(defaultConfigId) == 0) {
250 return BAD_VALUE;
251 }
252 const RefreshRate& refreshRate = mRefreshRates.at(defaultConfigId);
Ana Krulec72f0d6e2020-01-06 15:24:47 -0800253 if (!refreshRate.inPolicy(minRefreshRate, maxRefreshRate)) {
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100254 return BAD_VALUE;
255 }
256 mDefaultConfig = defaultConfigId;
Ady Abraham2139f732019-11-13 18:56:40 -0800257 mMinRefreshRateFps = minRefreshRate;
258 mMaxRefreshRateFps = maxRefreshRate;
259 constructAvailableRefreshRates();
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100260 return NO_ERROR;
261}
262
263void RefreshRateConfigs::getPolicy(HwcConfigIndexType* defaultConfigId, float* minRefreshRate,
264 float* maxRefreshRate) const {
265 std::lock_guard lock(mLock);
266 *defaultConfigId = mDefaultConfig;
267 *minRefreshRate = mMinRefreshRateFps;
268 *maxRefreshRate = mMaxRefreshRateFps;
269}
270
271bool RefreshRateConfigs::isConfigAllowed(HwcConfigIndexType config) const {
272 std::lock_guard lock(mLock);
273 for (const RefreshRate* refreshRate : mAvailableRefreshRates) {
274 if (refreshRate->configId == config) {
275 return true;
276 }
277 }
278 return false;
Ady Abraham2139f732019-11-13 18:56:40 -0800279}
280
281void RefreshRateConfigs::getSortedRefreshRateList(
282 const std::function<bool(const RefreshRate&)>& shouldAddRefreshRate,
283 std::vector<const RefreshRate*>* outRefreshRates) {
284 outRefreshRates->clear();
285 outRefreshRates->reserve(mRefreshRates.size());
286 for (const auto& [type, refreshRate] : mRefreshRates) {
287 if (shouldAddRefreshRate(refreshRate)) {
288 ALOGV("getSortedRefreshRateList: config %d added to list policy",
289 refreshRate.configId.value());
290 outRefreshRates->push_back(&refreshRate);
291 }
292 }
293
294 std::sort(outRefreshRates->begin(), outRefreshRates->end(),
295 [](const auto refreshRate1, const auto refreshRate2) {
296 return refreshRate1->vsyncPeriod > refreshRate2->vsyncPeriod;
297 });
298}
299
300void RefreshRateConfigs::constructAvailableRefreshRates() {
301 // Filter configs based on current policy and sort based on vsync period
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100302 HwcConfigGroupType group = mRefreshRates.at(mDefaultConfig).configGroup;
Ady Abraham8a82ba62020-01-17 12:43:17 -0800303 ALOGV("constructAvailableRefreshRates: default %d group %d min %.2f max %.2f",
304 mDefaultConfig.value(), group.value(), mMinRefreshRateFps, mMaxRefreshRateFps);
Ady Abraham2139f732019-11-13 18:56:40 -0800305 getSortedRefreshRateList(
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100306 [&](const RefreshRate& refreshRate) REQUIRES(mLock) {
Ana Krulec72f0d6e2020-01-06 15:24:47 -0800307 return refreshRate.configGroup == group &&
308 refreshRate.inPolicy(mMinRefreshRateFps, mMaxRefreshRateFps);
Ady Abraham2139f732019-11-13 18:56:40 -0800309 },
310 &mAvailableRefreshRates);
Ady Abraham8a82ba62020-01-17 12:43:17 -0800311
312 std::string availableRefreshRates;
313 for (const auto& refreshRate : mAvailableRefreshRates) {
314 base::StringAppendF(&availableRefreshRates, "%s ", refreshRate->name.c_str());
315 }
316
317 ALOGV("Available refresh rates: %s", availableRefreshRates.c_str());
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100318 LOG_ALWAYS_FATAL_IF(mAvailableRefreshRates.empty(),
319 "No compatible display configs for default=%d min=%.0f max=%.0f",
320 mDefaultConfig.value(), mMinRefreshRateFps, mMaxRefreshRateFps);
Ady Abraham2139f732019-11-13 18:56:40 -0800321}
322
323// NO_THREAD_SAFETY_ANALYSIS since this is called from the constructor
324void RefreshRateConfigs::init(const std::vector<InputConfig>& configs,
325 HwcConfigIndexType currentHwcConfig) NO_THREAD_SAFETY_ANALYSIS {
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800326 LOG_ALWAYS_FATAL_IF(configs.empty());
Ady Abraham2139f732019-11-13 18:56:40 -0800327 LOG_ALWAYS_FATAL_IF(currentHwcConfig.value() >= configs.size());
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800328
Ady Abraham2139f732019-11-13 18:56:40 -0800329 auto buildRefreshRate = [&](InputConfig config) -> RefreshRate {
330 const float fps = 1e9f / config.vsyncPeriod;
331 return RefreshRate(config.configId, config.vsyncPeriod, config.configGroup,
332 base::StringPrintf("%2.ffps", fps), fps);
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800333 };
334
Ady Abraham2139f732019-11-13 18:56:40 -0800335 for (const auto& config : configs) {
336 mRefreshRates.emplace(config.configId, buildRefreshRate(config));
337 if (config.configId == currentHwcConfig) {
338 mCurrentRefreshRate = &mRefreshRates.at(config.configId);
Ady Abraham2139f732019-11-13 18:56:40 -0800339 }
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800340 }
341
Ady Abraham2139f732019-11-13 18:56:40 -0800342 std::vector<const RefreshRate*> sortedConfigs;
343 getSortedRefreshRateList([](const RefreshRate&) { return true; }, &sortedConfigs);
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100344 mDefaultConfig = currentHwcConfig;
Ady Abraham2139f732019-11-13 18:56:40 -0800345 mMinSupportedRefreshRate = sortedConfigs.front();
346 mMaxSupportedRefreshRate = sortedConfigs.back();
347 constructAvailableRefreshRates();
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800348}
349
Ady Abraham2139f732019-11-13 18:56:40 -0800350} // namespace android::scheduler