1 /*
2  * Copyright 2018 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 <cutils/properties.h>
24 #include <utils/Log.h>
25 #include <utils/Timers.h>
26 #include <utils/Trace.h>
27 
28 #include <algorithm>
29 #include <cmath>
30 #include <string>
31 #include <utility>
32 
33 #include "../Layer.h"
34 #include "LayerInfo.h"
35 #include "SchedulerUtils.h"
36 
37 namespace android::scheduler::impl {
38 
39 namespace {
40 
isLayerActive(const Layer & layer,const LayerInfo & info,nsecs_t threshold)41 bool isLayerActive(const Layer& layer, const LayerInfo& info, nsecs_t threshold) {
42     if (layer.getFrameRateForLayerTree().rate > 0) {
43         return layer.isVisible();
44     }
45     return layer.isVisible() && info.getLastUpdatedTime() >= threshold;
46 }
47 
traceEnabled()48 bool traceEnabled() {
49     char value[PROPERTY_VALUE_MAX];
50     property_get("debug.sf.layer_history_trace", value, "0");
51     return atoi(value);
52 }
53 
useFrameRatePriority()54 bool useFrameRatePriority() {
55     char value[PROPERTY_VALUE_MAX];
56     property_get("debug.sf.use_frame_rate_priority", value, "1");
57     return atoi(value);
58 }
59 
trace(const wp<Layer> & weak,int fps)60 void trace(const wp<Layer>& weak, int fps) {
61     const auto layer = weak.promote();
62     if (!layer) return;
63 
64     const auto& name = layer->getName();
65     const auto tag = "LFPS " + name;
66     ATRACE_INT(tag.c_str(), fps);
67     ALOGD("%s: %s @ %d Hz", __FUNCTION__, name.c_str(), fps);
68 }
69 } // namespace
70 
LayerHistory()71 LayerHistory::LayerHistory()
72       : mTraceEnabled(traceEnabled()), mUseFrameRatePriority(useFrameRatePriority()) {}
73 LayerHistory::~LayerHistory() = default;
74 
registerLayer(Layer * layer,float lowRefreshRate,float highRefreshRate,LayerVoteType)75 void LayerHistory::registerLayer(Layer* layer, float lowRefreshRate, float highRefreshRate,
76                                  LayerVoteType /*type*/) {
77     auto info = std::make_unique<LayerInfo>(lowRefreshRate, highRefreshRate);
78     std::lock_guard lock(mLock);
79     mLayerInfos.emplace_back(layer, std::move(info));
80 }
81 
record(Layer * layer,nsecs_t presentTime,nsecs_t now,LayerUpdateType)82 void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now,
83                           LayerUpdateType /*updateType*/) {
84     std::lock_guard lock(mLock);
85 
86     const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(),
87                                  [layer](const auto& pair) { return pair.first == layer; });
88     LOG_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer);
89 
90     const auto& info = it->second;
91     info->setLastPresentTime(presentTime, now);
92 
93     // Activate layer if inactive.
94     if (const auto end = activeLayers().end(); it >= end) {
95         std::iter_swap(it, end);
96         mActiveLayersEnd++;
97     }
98 }
99 
summarize(nsecs_t now)100 LayerHistory::Summary LayerHistory::summarize(nsecs_t now) {
101     ATRACE_CALL();
102     std::lock_guard lock(mLock);
103 
104     partitionLayers(now);
105 
106     LayerHistory::Summary summary;
107     for (const auto& [weakLayer, info] : activeLayers()) {
108         const bool recent = info->isRecentlyActive(now);
109         auto layer = weakLayer.promote();
110         // Only use the layer if the reference still exists.
111         if (layer || CC_UNLIKELY(mTraceEnabled)) {
112             const auto layerFocused =
113                     Layer::isLayerFocusedBasedOnPriority(layer->getFrameRateSelectionPriority());
114             // Check if frame rate was set on layer.
115             const auto frameRate = layer->getFrameRateForLayerTree();
116             if (frameRate.rate > 0.f) {
117                 const auto voteType = [&]() {
118                     switch (frameRate.type) {
119                         case Layer::FrameRateCompatibility::Default:
120                             return LayerVoteType::ExplicitDefault;
121                         case Layer::FrameRateCompatibility::ExactOrMultiple:
122                             return LayerVoteType::ExplicitExactOrMultiple;
123                         case Layer::FrameRateCompatibility::NoVote:
124                             return LayerVoteType::NoVote;
125                     }
126                 }();
127                 summary.push_back({layer->getName(), voteType, frameRate.rate, /* weight */ 1.0f,
128                                    layerFocused});
129             } else if (recent) {
130                 summary.push_back({layer->getName(), LayerVoteType::Heuristic,
131                                    info->getRefreshRate(now),
132                                    /* weight */ 1.0f, layerFocused});
133             }
134 
135             if (CC_UNLIKELY(mTraceEnabled)) {
136                 trace(weakLayer, round<int>(frameRate.rate));
137             }
138         }
139     }
140 
141     return summary;
142 }
143 
partitionLayers(nsecs_t now)144 void LayerHistory::partitionLayers(nsecs_t now) {
145     const nsecs_t threshold = getActiveLayerThreshold(now);
146 
147     // Collect expired and inactive layers after active layers.
148     size_t i = 0;
149     while (i < mActiveLayersEnd) {
150         auto& [weak, info] = mLayerInfos[i];
151         if (const auto layer = weak.promote(); layer && isLayerActive(*layer, *info, threshold)) {
152             i++;
153             continue;
154         }
155 
156         if (CC_UNLIKELY(mTraceEnabled)) {
157             trace(weak, 0);
158         }
159 
160         info->clearHistory();
161         std::swap(mLayerInfos[i], mLayerInfos[--mActiveLayersEnd]);
162     }
163 
164     // Collect expired layers after inactive layers.
165     size_t end = mLayerInfos.size();
166     while (i < end) {
167         if (mLayerInfos[i].first.promote()) {
168             i++;
169         } else {
170             std::swap(mLayerInfos[i], mLayerInfos[--end]);
171         }
172     }
173 
174     mLayerInfos.erase(mLayerInfos.begin() + static_cast<long>(end), mLayerInfos.end());
175 }
176 
clear()177 void LayerHistory::clear() {
178     std::lock_guard lock(mLock);
179 
180     for (const auto& [layer, info] : activeLayers()) {
181         info->clearHistory();
182     }
183 
184     mActiveLayersEnd = 0;
185 }
186 } // namespace android::scheduler::impl
187