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 <cutils/properties.h>
25 #include <gui/TraceUtils.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 ATRACE_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)112 void LayerHistory::registerLayer(Layer* layer, bool contentDetectionEnabled) {
113 std::lock_guard lock(mLock);
114 LOG_ALWAYS_FATAL_IF(findLayer(layer->getSequence()).first != LayerStatus::NotFound,
115 "%s already registered", layer->getName().c_str());
116 LayerVoteType type =
117 getVoteType(layer->getDefaultFrameRateCompatibility(), 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 ATRACE_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 ATRACE_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 ATRACE_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 ATRACE_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 (isVrrDevice) {
284 return LayerVoteType::ExplicitGte;
285 } else {
286 // For MRR, treat GTE votes as Max because it is used for animations and
287 // scroll. MRR cannot change frame rate without jank, so it should
288 // prefer smoothness.
289 return LayerVoteType::Max;
290 }
291 }
292 }();
293 const bool isValuelessVote = voteType == LayerVoteType::NoVote ||
294 voteType == LayerVoteType::Min || voteType == LayerVoteType::Max;
295
296 if (FlagManager::getInstance().game_default_frame_rate()) {
297 // Determine the layer frame rate considering the following priorities:
298 // 1. Game mode intervention frame rate override
299 // 2. setFrameRate vote
300 // 3. Game default frame rate override
301
302 const auto& [gameModeFrameRateOverride, gameDefaultFrameRateOverride] =
303 getGameFrameRateOverrideLocked(info->getOwnerUid());
304
305 const auto gameFrameRateOverrideVoteType =
306 info->isVisible() ? LayerVoteType::ExplicitDefault : LayerVoteType::NoVote;
307
308 const auto setFrameRateVoteType =
309 info->isVisible() ? voteType : LayerVoteType::NoVote;
310
311 if (gameModeFrameRateOverride.isValid()) {
312 info->setLayerVote({gameFrameRateOverrideVoteType, gameModeFrameRateOverride});
313 ATRACE_FORMAT_INSTANT("GameModeFrameRateOverride");
314 if (CC_UNLIKELY(mTraceEnabled)) {
315 trace(*info, gameFrameRateOverrideVoteType,
316 gameModeFrameRateOverride.getIntValue());
317 }
318 } else if (frameRate.isValid() && frameRate.isVoteValidForMrr(isVrrDevice)) {
319 info->setLayerVote({setFrameRateVoteType,
320 isValuelessVote ? 0_Hz : frameRate.vote.rate,
321 frameRate.vote.seamlessness, frameRate.category});
322 if (CC_UNLIKELY(mTraceEnabled)) {
323 trace(*info, gameFrameRateOverrideVoteType,
324 frameRate.vote.rate.getIntValue());
325 }
326 } else if (gameDefaultFrameRateOverride.isValid()) {
327 info->setLayerVote(
328 {gameFrameRateOverrideVoteType, gameDefaultFrameRateOverride});
329 ATRACE_FORMAT_INSTANT("GameDefaultFrameRateOverride");
330 if (CC_UNLIKELY(mTraceEnabled)) {
331 trace(*info, gameFrameRateOverrideVoteType,
332 gameDefaultFrameRateOverride.getIntValue());
333 }
334 } else {
335 if (frameRate.isValid() && !frameRate.isVoteValidForMrr(isVrrDevice)) {
336 ATRACE_FORMAT_INSTANT("Reset layer to ignore explicit vote on MRR %s: %s "
337 "%s %s",
338 info->getName().c_str(),
339 ftl::enum_string(frameRate.vote.type).c_str(),
340 to_string(frameRate.vote.rate).c_str(),
341 ftl::enum_string(frameRate.category).c_str());
342 }
343 info->resetLayerVote();
344 }
345 } else {
346 if (frameRate.isValid() && frameRate.isVoteValidForMrr(isVrrDevice)) {
347 const auto type = info->isVisible() ? voteType : LayerVoteType::NoVote;
348 info->setLayerVote({type, isValuelessVote ? 0_Hz : frameRate.vote.rate,
349 frameRate.vote.seamlessness, frameRate.category});
350 } else {
351 if (!frameRate.isVoteValidForMrr(isVrrDevice)) {
352 ATRACE_FORMAT_INSTANT("Reset layer to ignore explicit vote on MRR %s: %s "
353 "%s %s",
354 info->getName().c_str(),
355 ftl::enum_string(frameRate.vote.type).c_str(),
356 to_string(frameRate.vote.rate).c_str(),
357 ftl::enum_string(frameRate.category).c_str());
358 }
359 info->resetLayerVote();
360 }
361 }
362
363 it++;
364 } else {
365 if (CC_UNLIKELY(mTraceEnabled)) {
366 trace(*info, LayerVoteType::NoVote, 0);
367 }
368 info->onLayerInactive(now);
369 // move this to the inactive map
370 mInactiveLayerInfos.insert({it->first, std::move(it->second)});
371 it = mActiveLayerInfos.erase(it);
372 }
373 }
374 }
375
clear()376 void LayerHistory::clear() {
377 std::lock_guard lock(mLock);
378 for (const auto& [key, value] : mActiveLayerInfos) {
379 value.second->clearHistory(systemTime());
380 }
381 }
382
dump() const383 std::string LayerHistory::dump() const {
384 std::lock_guard lock(mLock);
385 return base::StringPrintf("{size=%zu, active=%zu}\n\tGameFrameRateOverrides=\n\t\t%s",
386 mActiveLayerInfos.size() + mInactiveLayerInfos.size(),
387 mActiveLayerInfos.size(), dumpGameFrameRateOverridesLocked().c_str());
388 }
389
dumpGameFrameRateOverridesLocked() const390 std::string LayerHistory::dumpGameFrameRateOverridesLocked() const {
391 std::string overridesString = "(uid, gameModeOverride, gameDefaultOverride)=";
392 for (auto it = mGameFrameRateOverride.begin(); it != mGameFrameRateOverride.end(); ++it) {
393 base::StringAppendF(&overridesString, "{%u, %d %d} ", it->first,
394 it->second.first.getIntValue(), it->second.second.getIntValue());
395 }
396 return overridesString;
397 }
398
getLayerFramerate(nsecs_t now,int32_t id) const399 float LayerHistory::getLayerFramerate(nsecs_t now, int32_t id) const {
400 std::lock_guard lock(mLock);
401 auto [found, layerPair] = findLayer(id);
402 if (found != LayerStatus::NotFound) {
403 return layerPair->second->getFps(now).getValue();
404 }
405 return 0.f;
406 }
407
findLayer(int32_t id)408 auto LayerHistory::findLayer(int32_t id) -> std::pair<LayerStatus, LayerPair*> {
409 // the layer could be in either the active or inactive map, try both
410 auto it = mActiveLayerInfos.find(id);
411 if (it != mActiveLayerInfos.end()) {
412 return {LayerStatus::LayerInActiveMap, &(it->second)};
413 }
414 it = mInactiveLayerInfos.find(id);
415 if (it != mInactiveLayerInfos.end()) {
416 return {LayerStatus::LayerInInactiveMap, &(it->second)};
417 }
418 return {LayerStatus::NotFound, nullptr};
419 }
420
isSmallDirtyArea(uint32_t dirtyArea,float threshold) const421 bool LayerHistory::isSmallDirtyArea(uint32_t dirtyArea, float threshold) const {
422 const float ratio = (float)dirtyArea / mDisplayArea;
423 const bool isSmallDirty = ratio <= threshold;
424 ATRACE_FORMAT_INSTANT("small dirty=%s, ratio=%.3f", isSmallDirty ? "true" : "false", ratio);
425 return isSmallDirty;
426 }
427
updateGameModeFrameRateOverride(FrameRateOverride frameRateOverride)428 void LayerHistory::updateGameModeFrameRateOverride(FrameRateOverride frameRateOverride) {
429 const uid_t uid = frameRateOverride.uid;
430 std::lock_guard lock(mLock);
431 if (frameRateOverride.frameRateHz != 0.f) {
432 mGameFrameRateOverride[uid].first = Fps::fromValue(frameRateOverride.frameRateHz);
433 } else {
434 if (mGameFrameRateOverride[uid].second.getValue() == 0.f) {
435 mGameFrameRateOverride.erase(uid);
436 } else {
437 mGameFrameRateOverride[uid].first = Fps();
438 }
439 }
440 }
441
updateGameDefaultFrameRateOverride(FrameRateOverride frameRateOverride)442 void LayerHistory::updateGameDefaultFrameRateOverride(FrameRateOverride frameRateOverride) {
443 const uid_t uid = frameRateOverride.uid;
444 std::lock_guard lock(mLock);
445 if (frameRateOverride.frameRateHz != 0.f) {
446 mGameFrameRateOverride[uid].second = Fps::fromValue(frameRateOverride.frameRateHz);
447 } else {
448 if (mGameFrameRateOverride[uid].first.getValue() == 0.f) {
449 mGameFrameRateOverride.erase(uid);
450 } else {
451 mGameFrameRateOverride[uid].second = Fps();
452 }
453 }
454 }
455
getGameFrameRateOverride(uid_t uid) const456 std::pair<Fps, Fps> LayerHistory::getGameFrameRateOverride(uid_t uid) const {
457 if (!FlagManager::getInstance().game_default_frame_rate()) {
458 return std::pair<Fps, Fps>();
459 }
460
461 std::lock_guard lock(mLock);
462
463 return getGameFrameRateOverrideLocked(uid);
464 }
465
getGameFrameRateOverrideLocked(uid_t uid) const466 std::pair<Fps, Fps> LayerHistory::getGameFrameRateOverrideLocked(uid_t uid) const {
467 if (!FlagManager::getInstance().game_default_frame_rate()) {
468 return std::pair<Fps, Fps>();
469 }
470
471 const auto it = mGameFrameRateOverride.find(uid);
472
473 if (it == mGameFrameRateOverride.end()) {
474 return std::pair<Fps, Fps>(Fps(), Fps());
475 }
476
477 return it->second;
478 }
479
480 } // namespace android::scheduler
481