blob: 8202515bec9d9e3a5b29be7ccafd52ded2548967 [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 Krulec3f6a2062020-01-23 15:48:01 -0800219 return *mAvailableRefreshRates.front();
Ady Abraham2139f732019-11-13 18:56:40 -0800220}
221
222const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicy() const {
223 std::lock_guard lock(mLock);
Ady Abraham2139f732019-11-13 18:56:40 -0800224 return *mAvailableRefreshRates.back();
Ady Abraham2139f732019-11-13 18:56:40 -0800225}
226
227const RefreshRate& RefreshRateConfigs::getCurrentRefreshRate() const {
228 std::lock_guard lock(mLock);
229 return *mCurrentRefreshRate;
230}
231
Ana Krulec5d477912020-02-07 12:02:38 -0800232const RefreshRate& RefreshRateConfigs::getCurrentRefreshRateByPolicy() const {
233 std::lock_guard lock(mLock);
234 if (std::find(mAvailableRefreshRates.begin(), mAvailableRefreshRates.end(),
235 mCurrentRefreshRate) != mAvailableRefreshRates.end()) {
236 return *mCurrentRefreshRate;
237 }
238 return mRefreshRates.at(mDefaultConfig);
239}
240
Ady Abraham2139f732019-11-13 18:56:40 -0800241void RefreshRateConfigs::setCurrentConfigId(HwcConfigIndexType configId) {
242 std::lock_guard lock(mLock);
243 mCurrentRefreshRate = &mRefreshRates.at(configId);
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800244}
245
Ana Krulec3f6a2062020-01-23 15:48:01 -0800246RefreshRateConfigs::RefreshRateConfigs(const std::vector<InputConfig>& configs,
247 HwcConfigIndexType currentHwcConfig) {
Ady Abraham2139f732019-11-13 18:56:40 -0800248 init(configs, currentHwcConfig);
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800249}
250
251RefreshRateConfigs::RefreshRateConfigs(
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800252 const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
Ana Krulec3f6a2062020-01-23 15:48:01 -0800253 HwcConfigIndexType currentConfigId) {
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800254 std::vector<InputConfig> inputConfigs;
Ady Abrahamdec1a412020-01-24 10:23:50 -0800255 for (size_t configId = 0; configId < configs.size(); ++configId) {
256 auto configGroup = HwcConfigGroupType(configs[configId]->getConfigGroup());
257 inputConfigs.push_back({HwcConfigIndexType(static_cast<int>(configId)), configGroup,
258 configs[configId]->getVsyncPeriod()});
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800259 }
Ady Abraham2139f732019-11-13 18:56:40 -0800260 init(inputConfigs, currentConfigId);
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800261}
262
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100263status_t RefreshRateConfigs::setPolicy(HwcConfigIndexType defaultConfigId, float minRefreshRate,
264 float maxRefreshRate, bool* outPolicyChanged) {
Ady Abraham2139f732019-11-13 18:56:40 -0800265 std::lock_guard lock(mLock);
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100266 bool policyChanged = defaultConfigId != mDefaultConfig ||
267 minRefreshRate != mMinRefreshRateFps || maxRefreshRate != mMaxRefreshRateFps;
268 if (outPolicyChanged) {
269 *outPolicyChanged = policyChanged;
270 }
271 if (!policyChanged) {
272 return NO_ERROR;
273 }
274 // defaultConfigId must be a valid config ID, and within the given refresh rate range.
275 if (mRefreshRates.count(defaultConfigId) == 0) {
276 return BAD_VALUE;
277 }
278 const RefreshRate& refreshRate = mRefreshRates.at(defaultConfigId);
Ana Krulec72f0d6e2020-01-06 15:24:47 -0800279 if (!refreshRate.inPolicy(minRefreshRate, maxRefreshRate)) {
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100280 return BAD_VALUE;
281 }
282 mDefaultConfig = defaultConfigId;
Ady Abraham2139f732019-11-13 18:56:40 -0800283 mMinRefreshRateFps = minRefreshRate;
284 mMaxRefreshRateFps = maxRefreshRate;
285 constructAvailableRefreshRates();
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100286 return NO_ERROR;
287}
288
289void RefreshRateConfigs::getPolicy(HwcConfigIndexType* defaultConfigId, float* minRefreshRate,
290 float* maxRefreshRate) const {
291 std::lock_guard lock(mLock);
292 *defaultConfigId = mDefaultConfig;
293 *minRefreshRate = mMinRefreshRateFps;
294 *maxRefreshRate = mMaxRefreshRateFps;
295}
296
297bool RefreshRateConfigs::isConfigAllowed(HwcConfigIndexType config) const {
298 std::lock_guard lock(mLock);
299 for (const RefreshRate* refreshRate : mAvailableRefreshRates) {
300 if (refreshRate->configId == config) {
301 return true;
302 }
303 }
304 return false;
Ady Abraham2139f732019-11-13 18:56:40 -0800305}
306
307void RefreshRateConfigs::getSortedRefreshRateList(
308 const std::function<bool(const RefreshRate&)>& shouldAddRefreshRate,
309 std::vector<const RefreshRate*>* outRefreshRates) {
310 outRefreshRates->clear();
311 outRefreshRates->reserve(mRefreshRates.size());
312 for (const auto& [type, refreshRate] : mRefreshRates) {
313 if (shouldAddRefreshRate(refreshRate)) {
314 ALOGV("getSortedRefreshRateList: config %d added to list policy",
315 refreshRate.configId.value());
316 outRefreshRates->push_back(&refreshRate);
317 }
318 }
319
320 std::sort(outRefreshRates->begin(), outRefreshRates->end(),
321 [](const auto refreshRate1, const auto refreshRate2) {
322 return refreshRate1->vsyncPeriod > refreshRate2->vsyncPeriod;
323 });
324}
325
326void RefreshRateConfigs::constructAvailableRefreshRates() {
327 // Filter configs based on current policy and sort based on vsync period
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100328 HwcConfigGroupType group = mRefreshRates.at(mDefaultConfig).configGroup;
Ady Abraham8a82ba62020-01-17 12:43:17 -0800329 ALOGV("constructAvailableRefreshRates: default %d group %d min %.2f max %.2f",
330 mDefaultConfig.value(), group.value(), mMinRefreshRateFps, mMaxRefreshRateFps);
Ady Abraham2139f732019-11-13 18:56:40 -0800331 getSortedRefreshRateList(
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100332 [&](const RefreshRate& refreshRate) REQUIRES(mLock) {
Ana Krulec72f0d6e2020-01-06 15:24:47 -0800333 return refreshRate.configGroup == group &&
334 refreshRate.inPolicy(mMinRefreshRateFps, mMaxRefreshRateFps);
Ady Abraham2139f732019-11-13 18:56:40 -0800335 },
336 &mAvailableRefreshRates);
Ady Abraham8a82ba62020-01-17 12:43:17 -0800337
338 std::string availableRefreshRates;
339 for (const auto& refreshRate : mAvailableRefreshRates) {
340 base::StringAppendF(&availableRefreshRates, "%s ", refreshRate->name.c_str());
341 }
342
343 ALOGV("Available refresh rates: %s", availableRefreshRates.c_str());
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100344 LOG_ALWAYS_FATAL_IF(mAvailableRefreshRates.empty(),
345 "No compatible display configs for default=%d min=%.0f max=%.0f",
346 mDefaultConfig.value(), mMinRefreshRateFps, mMaxRefreshRateFps);
Ady Abraham2139f732019-11-13 18:56:40 -0800347}
348
349// NO_THREAD_SAFETY_ANALYSIS since this is called from the constructor
350void RefreshRateConfigs::init(const std::vector<InputConfig>& configs,
351 HwcConfigIndexType currentHwcConfig) NO_THREAD_SAFETY_ANALYSIS {
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800352 LOG_ALWAYS_FATAL_IF(configs.empty());
Ady Abraham2139f732019-11-13 18:56:40 -0800353 LOG_ALWAYS_FATAL_IF(currentHwcConfig.value() >= configs.size());
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800354
Ady Abraham2139f732019-11-13 18:56:40 -0800355 auto buildRefreshRate = [&](InputConfig config) -> RefreshRate {
356 const float fps = 1e9f / config.vsyncPeriod;
357 return RefreshRate(config.configId, config.vsyncPeriod, config.configGroup,
358 base::StringPrintf("%2.ffps", fps), fps);
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800359 };
360
Ady Abraham2139f732019-11-13 18:56:40 -0800361 for (const auto& config : configs) {
362 mRefreshRates.emplace(config.configId, buildRefreshRate(config));
363 if (config.configId == currentHwcConfig) {
364 mCurrentRefreshRate = &mRefreshRates.at(config.configId);
Ady Abraham2139f732019-11-13 18:56:40 -0800365 }
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800366 }
367
Ady Abraham2139f732019-11-13 18:56:40 -0800368 std::vector<const RefreshRate*> sortedConfigs;
369 getSortedRefreshRateList([](const RefreshRate&) { return true; }, &sortedConfigs);
Ana Kruleced3a8cc2019-11-14 00:55:07 +0100370 mDefaultConfig = currentHwcConfig;
Ady Abraham2139f732019-11-13 18:56:40 -0800371 mMinSupportedRefreshRate = sortedConfigs.front();
372 mMaxSupportedRefreshRate = sortedConfigs.back();
373 constructAvailableRefreshRates();
Ady Abrahamb4b1e0a2019-11-20 18:25:35 -0800374}
375
Ady Abraham2139f732019-11-13 18:56:40 -0800376} // namespace android::scheduler