1 /*
2 * Copyright 2020 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 */
16
17 #undef LOG_TAG
18 #define LOG_TAG "LayerHistory"
19 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
20
21 #include "LayerHistory.h"
22
23 #include <android-base/stringprintf.h>
24 #include <common/trace.h>
25 #include <cutils/properties.h>
26 #include <utils/Log.h>
27 #include <utils/Timers.h>
28
29 #include <algorithm>
30 #include <cmath>
31 #include <string>
32 #include <utility>
33
34 #include <common/FlagManager.h>
35 #include "../Layer.h"
36 #include "EventThread.h"
37 #include "LayerInfo.h"
38
39 namespace android::scheduler {
40
41 namespace {
42
isLayerActive(const LayerInfo & info,nsecs_t threshold,bool isVrrDevice)43 bool isLayerActive(const LayerInfo& info, nsecs_t threshold, bool isVrrDevice) {
44 if (FlagManager::getInstance().misc1() && !info.isVisible()) {
45 return false;
46 }
47
48 // Layers with an explicit frame rate or frame rate category are kept active,
49 // but ignore NoVote.
50 const auto frameRate = info.getSetFrameRateVote();
51 if (frameRate.isValid() && !frameRate.isNoVote() && frameRate.isVoteValidForMrr(isVrrDevice)) {
52 return true;
53 }
54
55 // Make all front buffered layers active
56 if (FlagManager::getInstance().vrr_config() && info.isFrontBuffered() && info.isVisible()) {
57 return true;
58 }
59
60 return info.isVisible() && info.getLastUpdatedTime() >= threshold;
61 }
62
traceEnabled()63 bool traceEnabled() {
64 return property_get_bool("debug.sf.layer_history_trace", false);
65 }
66
useFrameRatePriority()67 bool useFrameRatePriority() {
68 char value[PROPERTY_VALUE_MAX];
69 property_get("debug.sf.use_frame_rate_priority", value, "1");
70 return atoi(value);
71 }
72
trace(const LayerInfo & info,LayerHistory::LayerVoteType type,int fps)73 void trace(const LayerInfo& info, LayerHistory::LayerVoteType type, int fps) {
74 const auto traceType = [&](LayerHistory::LayerVoteType checkedType, int value) {
75 SFTRACE_INT(info.getTraceTag(checkedType), type == checkedType ? value : 0);
76 };
77
78 traceType(LayerHistory::LayerVoteType::NoVote, 1);
79 traceType(LayerHistory::LayerVoteType::Heuristic, fps);
80 traceType(LayerHistory::LayerVoteType::ExplicitDefault, fps);
81 traceType(LayerHistory::LayerVoteType::ExplicitExactOrMultiple, fps);
82 traceType(LayerHistory::LayerVoteType::ExplicitExact, fps);
83 traceType(LayerHistory::LayerVoteType::Min, 1);
84 traceType(LayerHistory::LayerVoteType::Max, 1);
85 traceType(LayerHistory::LayerVoteType::ExplicitCategory, 1);
86
87 ALOGD("%s: %s @ %d Hz", __FUNCTION__, info.getName().c_str(), fps);
88 }
89
getVoteType(FrameRateCompatibility compatibility,bool contentDetectionEnabled)90 LayerHistory::LayerVoteType getVoteType(FrameRateCompatibility compatibility,
91 bool contentDetectionEnabled) {
92 LayerHistory::LayerVoteType voteType;
93 if (!contentDetectionEnabled || compatibility == FrameRateCompatibility::NoVote) {
94 voteType = LayerHistory::LayerVoteType::NoVote;
95 } else if (compatibility == FrameRateCompatibility::Min) {
96 voteType = LayerHistory::LayerVoteType::Min;
97 } else {
98 voteType = LayerHistory::LayerVoteType::Heuristic;
99 }
100 return voteType;
101 }
102
103 } // namespace
104
LayerHistory()105 LayerHistory::LayerHistory()
106 : mTraceEnabled(traceEnabled()), mUseFrameRatePriority(useFrameRatePriority()) {
107 LayerInfo::setTraceEnabled(mTraceEnabled);
108 }
109
110 LayerHistory::~LayerHistory() = default;
111
registerLayer(Layer * layer,bool contentDetectionEnabled,FrameRateCompatibility frameRateCompatibility)112 void LayerHistory::registerLayer(Layer* layer, bool contentDetectionEnabled,
113 FrameRateCompatibility frameRateCompatibility) {
114 std::lock_guard lock(mLock);
115 LOG_ALWAYS_FATAL_IF(findLayer(layer->getSequence()).first != LayerStatus::NotFound,
116 "%s already registered", layer->getName().c_str());
117 LayerVoteType type = getVoteType(frameRateCompatibility, contentDetectionEnabled);
118 auto info = std::make_unique<LayerInfo>(layer->getName(), layer->getOwnerUid(), type);
119
120 // The layer can be placed on either map, it is assumed that partitionLayers() will be called
121 // to correct them.
122 mInactiveLayerInfos.insert({layer->getSequence(), std::make_pair(layer, std::move(info))});
123 }
124
deregisterLayer(Layer * layer)125 void LayerHistory::deregisterLayer(Layer* layer) {
126 std::lock_guard lock(mLock);
127 if (!mActiveLayerInfos.erase(layer->getSequence())) {
128 if (!mInactiveLayerInfos.erase(layer->getSequence())) {
129 LOG_ALWAYS_FATAL("%s: unknown layer %p", __FUNCTION__, layer);
130 }
131 }
132 }
133
record(int32_t id,const LayerProps & layerProps,nsecs_t presentTime,nsecs_t now,LayerUpdateType updateType)134 void LayerHistory::record(int32_t id, const LayerProps& layerProps, nsecs_t presentTime,
135 nsecs_t now, LayerUpdateType updateType) {
136 std::lock_guard lock(mLock);
137 auto [found, layerPair] = findLayer(id);
138 if (found == LayerStatus::NotFound) {
139 // Offscreen layer
140 ALOGV("%s: %d not registered", __func__, id);
141 return;
142 }
143
144 const auto& info = layerPair->second;
145 info->setLastPresentTime(presentTime, now, updateType, mModeChangePending, layerProps);
146
147 // Activate layer if inactive.
148 if (found == LayerStatus::LayerInInactiveMap) {
149 mActiveLayerInfos.insert(
150 {id, std::make_pair(layerPair->first, std::move(layerPair->second))});
151 mInactiveLayerInfos.erase(id);
152 }
153 }
154
setDefaultFrameRateCompatibility(int32_t id,FrameRateCompatibility frameRateCompatibility,bool contentDetectionEnabled)155 void LayerHistory::setDefaultFrameRateCompatibility(int32_t id,
156 FrameRateCompatibility frameRateCompatibility,
157 bool contentDetectionEnabled) {
158 std::lock_guard lock(mLock);
159
160 auto [found, layerPair] = findLayer(id);
161 if (found == LayerStatus::NotFound) {
162 // Offscreen layer
163 ALOGV("%s: %d not registered", __func__, id);
164 return;
165 }
166
167 const auto& info = layerPair->second;
168 info->setDefaultLayerVote(getVoteType(frameRateCompatibility, contentDetectionEnabled));
169 }
170
setLayerProperties(int32_t id,const LayerProps & properties)171 void LayerHistory::setLayerProperties(int32_t id, const LayerProps& properties) {
172 std::lock_guard lock(mLock);
173
174 auto [found, layerPair] = findLayer(id);
175 if (found == LayerStatus::NotFound) {
176 // Offscreen layer
177 ALOGV("%s: %d not registered", __func__, id);
178 return;
179 }
180
181 const auto& info = layerPair->second;
182 info->setProperties(properties);
183
184 // Activate layer if inactive and visible.
185 if (found == LayerStatus::LayerInInactiveMap && info->isVisible()) {
186 mActiveLayerInfos.insert(
187 {id, std::make_pair(layerPair->first, std::move(layerPair->second))});
188 mInactiveLayerInfos.erase(id);
189 }
190 }
191
summarize(const RefreshRateSelector & selector,nsecs_t now)192 auto LayerHistory::summarize(const RefreshRateSelector& selector, nsecs_t now) -> Summary {
193 SFTRACE_CALL();
194 Summary summary;
195
196 std::lock_guard lock(mLock);
197
198 partitionLayers(now, selector.isVrrDevice());
199
200 for (const auto& [key, value] : mActiveLayerInfos) {
201 auto& info = value.second;
202 const auto frameRateSelectionPriority = info->getFrameRateSelectionPriority();
203 const auto layerFocused = Layer::isLayerFocusedBasedOnPriority(frameRateSelectionPriority);
204 ALOGV("%s has priority: %d %s focused", info->getName().c_str(), frameRateSelectionPriority,
205 layerFocused ? "" : "not");
206
207 SFTRACE_FORMAT("%s", info->getName().c_str());
208 const auto votes = info->getRefreshRateVote(selector, now);
209 for (LayerInfo::LayerVote vote : votes) {
210 if (vote.isNoVote()) {
211 continue;
212 }
213
214 // Compute the layer's position on the screen
215 const Rect bounds = Rect(info->getBounds());
216 const ui::Transform transform = info->getTransform();
217 constexpr bool roundOutwards = true;
218 Rect transformed = transform.transform(bounds, roundOutwards);
219
220 const float layerArea = transformed.getWidth() * transformed.getHeight();
221 float weight = mDisplayArea ? layerArea / mDisplayArea : 0.0f;
222 const std::string categoryString = vote.category == FrameRateCategory::Default
223 ? ""
224 : base::StringPrintf("category=%s", ftl::enum_string(vote.category).c_str());
225 SFTRACE_FORMAT_INSTANT("%s %s %s (%.2f)", ftl::enum_string(vote.type).c_str(),
226 to_string(vote.fps).c_str(), categoryString.c_str(), weight);
227 summary.push_back({info->getName(), info->getOwnerUid(), vote.type, vote.fps,
228 vote.seamlessness, vote.category, vote.categorySmoothSwitchOnly,
229 weight, layerFocused});
230
231 if (CC_UNLIKELY(mTraceEnabled)) {
232 trace(*info, vote.type, vote.fps.getIntValue());
233 }
234 }
235 }
236
237 return summary;
238 }
239
partitionLayers(nsecs_t now,bool isVrrDevice)240 void LayerHistory::partitionLayers(nsecs_t now, bool isVrrDevice) {
241 SFTRACE_CALL();
242 const nsecs_t threshold = getActiveLayerThreshold(now);
243
244 // iterate over inactive map
245 LayerInfos::iterator it = mInactiveLayerInfos.begin();
246 while (it != mInactiveLayerInfos.end()) {
247 auto& [layerUnsafe, info] = it->second;
248 if (isLayerActive(*info, threshold, isVrrDevice)) {
249 // move this to the active map
250
251 mActiveLayerInfos.insert({it->first, std::move(it->second)});
252 it = mInactiveLayerInfos.erase(it);
253 } else {
254 if (CC_UNLIKELY(mTraceEnabled)) {
255 trace(*info, LayerVoteType::NoVote, 0);
256 }
257 info->onLayerInactive(now);
258 it++;
259 }
260 }
261
262 // iterate over active map
263 it = mActiveLayerInfos.begin();
264 while (it != mActiveLayerInfos.end()) {
265 auto& [layerUnsafe, info] = it->second;
266 if (isLayerActive(*info, threshold, isVrrDevice)) {
267 // Set layer vote if set
268 const auto frameRate = info->getSetFrameRateVote();
269
270 const auto voteType = [&]() {
271 switch (frameRate.vote.type) {
272 case Layer::FrameRateCompatibility::Default:
273 return LayerVoteType::ExplicitDefault;
274 case Layer::FrameRateCompatibility::Min:
275 return LayerVoteType::Min;
276 case Layer::FrameRateCompatibility::ExactOrMultiple:
277 return LayerVoteType::ExplicitExactOrMultiple;
278 case Layer::FrameRateCompatibility::NoVote:
279 return LayerVoteType::NoVote;
280 case Layer::FrameRateCompatibility::Exact:
281 return LayerVoteType::ExplicitExact;
282 case Layer::FrameRateCompatibility::Gte:
283 if (frameRate.isNoVote()) {
284 return LayerVoteType::NoVote;
285 }
286 if (isVrrDevice) {
287 return LayerVoteType::ExplicitGte;
288 } else {
289 // For MRR, treat GTE votes as Max because it is used for animations and
290 // scroll. MRR cannot change frame rate without jank, so it should
291 // prefer smoothness.
292 return LayerVoteType::Max;
293 }
294 }
295 }();
296 const bool isValuelessVote = voteType == LayerVoteType::NoVote ||
297 voteType == LayerVoteType::Min || voteType == LayerVoteType::Max;
298
299 if (FlagManager::getInstance().game_default_frame_rate()) {
300 // Determine the layer frame rate considering the following priorities:
301 // 1. Game mode intervention frame rate override
302 // 2. setFrameRate vote
303 // 3. Game default frame rate override
304
305 const auto& [gameModeFrameRateOverride, gameDefaultFrameRateOverride] =
306 getGameFrameRateOverrideLocked(info->getOwnerUid());
307
308 const auto gameFrameRateOverrideVoteType =
309 info->isVisible() ? LayerVoteType::ExplicitDefault : LayerVoteType::NoVote;
310
311 const auto setFrameRateVoteType =
312 info->isVisible() ? voteType : LayerVoteType::NoVote;
313
314 const bool hasSetFrameRateOpinion =
315 frameRate.isValuelessType() || frameRate.vote.rate.isValid();
316 const bool hasCategoryOpinion =
317 frameRate.category != FrameRateCategory::NoPreference &&
318 frameRate.category != FrameRateCategory::Default;
319 const bool hasFrameRateOpinionAboveGameDefault =
320 hasSetFrameRateOpinion || hasCategoryOpinion;
321 const bool hasFrameRateOpinionArr = frameRate.isValid() && !frameRate.isNoVote();
322
323 if (gameModeFrameRateOverride.isValid()) {
324 info->setLayerVote({gameFrameRateOverrideVoteType, gameModeFrameRateOverride});
325 SFTRACE_FORMAT_INSTANT("GameModeFrameRateOverride");
326 if (CC_UNLIKELY(mTraceEnabled)) {
327 trace(*info, gameFrameRateOverrideVoteType,
328 gameModeFrameRateOverride.getIntValue());
329 }
330 } else if (hasFrameRateOpinionAboveGameDefault &&
331 frameRate.isVoteValidForMrr(isVrrDevice)) {
332 info->setLayerVote({setFrameRateVoteType,
333 isValuelessVote ? 0_Hz : frameRate.vote.rate,
334 frameRate.vote.seamlessness, frameRate.category});
335 if (CC_UNLIKELY(mTraceEnabled)) {
336 trace(*info, gameFrameRateOverrideVoteType,
337 frameRate.vote.rate.getIntValue());
338 }
339 } else if (gameDefaultFrameRateOverride.isValid()) {
340 info->setLayerVote(
341 {gameFrameRateOverrideVoteType, gameDefaultFrameRateOverride});
342 SFTRACE_FORMAT_INSTANT("GameDefaultFrameRateOverride");
343 if (CC_UNLIKELY(mTraceEnabled)) {
344 trace(*info, gameFrameRateOverrideVoteType,
345 gameDefaultFrameRateOverride.getIntValue());
346 }
347 } else if (hasFrameRateOpinionArr && frameRate.isVoteValidForMrr(isVrrDevice)) {
348 // This allows NoPreference votes on ARR devices after considering the
349 // gameDefaultFrameRateOverride (above).
350 info->setLayerVote({setFrameRateVoteType,
351 isValuelessVote ? 0_Hz : frameRate.vote.rate,
352 frameRate.vote.seamlessness, frameRate.category});
353 if (CC_UNLIKELY(mTraceEnabled)) {
354 trace(*info, gameFrameRateOverrideVoteType,
355 frameRate.vote.rate.getIntValue());
356 }
357 } else {
358 if (hasFrameRateOpinionArr && !frameRate.isVoteValidForMrr(isVrrDevice)) {
359 SFTRACE_FORMAT_INSTANT("Reset layer to ignore explicit vote on MRR %s: %s "
360 "%s %s",
361 info->getName().c_str(),
362 ftl::enum_string(frameRate.vote.type).c_str(),
363 to_string(frameRate.vote.rate).c_str(),
364 ftl::enum_string(frameRate.category).c_str());
365 }
366 info->resetLayerVote();
367 }
368 } else {
369 if (frameRate.isValid() && frameRate.isVoteValidForMrr(isVrrDevice)) {
370 const auto type = info->isVisible() ? voteType : LayerVoteType::NoVote;
371 info->setLayerVote({type, isValuelessVote ? 0_Hz : frameRate.vote.rate,
372 frameRate.vote.seamlessness, frameRate.category});
373 } else {
374 if (!frameRate.isVoteValidForMrr(isVrrDevice)) {
375 SFTRACE_FORMAT_INSTANT("Reset layer to ignore explicit vote on MRR %s: %s "
376 "%s %s",
377 info->getName().c_str(),
378 ftl::enum_string(frameRate.vote.type).c_str(),
379 to_string(frameRate.vote.rate).c_str(),
380 ftl::enum_string(frameRate.category).c_str());
381 }
382 info->resetLayerVote();
383 }
384 }
385
386 it++;
387 } else {
388 if (CC_UNLIKELY(mTraceEnabled)) {
389 trace(*info, LayerVoteType::NoVote, 0);
390 }
391 info->onLayerInactive(now);
392 // move this to the inactive map
393 mInactiveLayerInfos.insert({it->first, std::move(it->second)});
394 it = mActiveLayerInfos.erase(it);
395 }
396 }
397 }
398
clear()399 void LayerHistory::clear() {
400 std::lock_guard lock(mLock);
401 for (const auto& [key, value] : mActiveLayerInfos) {
402 value.second->clearHistory(systemTime());
403 }
404 }
405
dump() const406 std::string LayerHistory::dump() const {
407 std::lock_guard lock(mLock);
408 return base::StringPrintf("{size=%zu, active=%zu}\n\tGameFrameRateOverrides=\n\t\t%s",
409 mActiveLayerInfos.size() + mInactiveLayerInfos.size(),
410 mActiveLayerInfos.size(), dumpGameFrameRateOverridesLocked().c_str());
411 }
412
dumpGameFrameRateOverridesLocked() const413 std::string LayerHistory::dumpGameFrameRateOverridesLocked() const {
414 std::string overridesString = "(uid, gameModeOverride, gameDefaultOverride)=";
415 for (auto it = mGameFrameRateOverride.begin(); it != mGameFrameRateOverride.end(); ++it) {
416 base::StringAppendF(&overridesString, "{%u, %d %d} ", it->first,
417 it->second.first.getIntValue(), it->second.second.getIntValue());
418 }
419 return overridesString;
420 }
421
getLayerFramerate(nsecs_t now,int32_t id) const422 float LayerHistory::getLayerFramerate(nsecs_t now, int32_t id) const {
423 std::lock_guard lock(mLock);
424 auto [found, layerPair] = findLayer(id);
425 if (found != LayerStatus::NotFound) {
426 return layerPair->second->getFps(now).getValue();
427 }
428 return 0.f;
429 }
430
findLayer(int32_t id)431 auto LayerHistory::findLayer(int32_t id) -> std::pair<LayerStatus, LayerPair*> {
432 // the layer could be in either the active or inactive map, try both
433 auto it = mActiveLayerInfos.find(id);
434 if (it != mActiveLayerInfos.end()) {
435 return {LayerStatus::LayerInActiveMap, &(it->second)};
436 }
437 it = mInactiveLayerInfos.find(id);
438 if (it != mInactiveLayerInfos.end()) {
439 return {LayerStatus::LayerInInactiveMap, &(it->second)};
440 }
441 return {LayerStatus::NotFound, nullptr};
442 }
443
isSmallDirtyArea(uint32_t dirtyArea,float threshold) const444 bool LayerHistory::isSmallDirtyArea(uint32_t dirtyArea, float threshold) const {
445 const float ratio = (float)dirtyArea / mDisplayArea;
446 const bool isSmallDirty = ratio <= threshold;
447 SFTRACE_FORMAT_INSTANT("small dirty=%s, ratio=%.3f", isSmallDirty ? "true" : "false", ratio);
448 return isSmallDirty;
449 }
450
updateGameModeFrameRateOverride(FrameRateOverride frameRateOverride)451 void LayerHistory::updateGameModeFrameRateOverride(FrameRateOverride frameRateOverride) {
452 const uid_t uid = frameRateOverride.uid;
453 std::lock_guard lock(mLock);
454 if (frameRateOverride.frameRateHz != 0.f) {
455 mGameFrameRateOverride[uid].first = Fps::fromValue(frameRateOverride.frameRateHz);
456 } else {
457 if (mGameFrameRateOverride[uid].second.getValue() == 0.f) {
458 mGameFrameRateOverride.erase(uid);
459 } else {
460 mGameFrameRateOverride[uid].first = Fps();
461 }
462 }
463 }
464
updateGameDefaultFrameRateOverride(FrameRateOverride frameRateOverride)465 void LayerHistory::updateGameDefaultFrameRateOverride(FrameRateOverride frameRateOverride) {
466 const uid_t uid = frameRateOverride.uid;
467 std::lock_guard lock(mLock);
468 if (frameRateOverride.frameRateHz != 0.f) {
469 mGameFrameRateOverride[uid].second = Fps::fromValue(frameRateOverride.frameRateHz);
470 } else {
471 if (mGameFrameRateOverride[uid].first.getValue() == 0.f) {
472 mGameFrameRateOverride.erase(uid);
473 } else {
474 mGameFrameRateOverride[uid].second = Fps();
475 }
476 }
477 }
478
getGameFrameRateOverride(uid_t uid) const479 std::pair<Fps, Fps> LayerHistory::getGameFrameRateOverride(uid_t uid) const {
480 if (!FlagManager::getInstance().game_default_frame_rate()) {
481 return std::pair<Fps, Fps>();
482 }
483
484 std::lock_guard lock(mLock);
485
486 return getGameFrameRateOverrideLocked(uid);
487 }
488
getGameFrameRateOverrideLocked(uid_t uid) const489 std::pair<Fps, Fps> LayerHistory::getGameFrameRateOverrideLocked(uid_t uid) const {
490 if (!FlagManager::getInstance().game_default_frame_rate()) {
491 return std::pair<Fps, Fps>();
492 }
493
494 const auto it = mGameFrameRateOverride.find(uid);
495
496 if (it == mGameFrameRateOverride.end()) {
497 return std::pair<Fps, Fps>(Fps(), Fps());
498 }
499
500 return it->second;
501 }
502
503 } // namespace android::scheduler
504