blob: 896c2a55acc026ce5fca47302c9a788e6f6720f1 [file] [log] [blame]
Ana Krulec757f63a2019-01-25 10:46:18 -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 */
16
Ady Abrahamb0dbdaa2020-01-06 16:19:42 -080017// TODO(b/129481165): remove the #pragma below and fix conversion issues
18#pragma clang diagnostic push
19#pragma clang diagnostic ignored "-Wconversion"
20
Ana Krulec757f63a2019-01-25 10:46:18 -080021#include "PhaseOffsets.h"
22
23#include <cutils/properties.h>
24
Dominik Laskowskieddeda12019-07-19 11:54:13 -070025#include <optional>
26
Ana Krulec757f63a2019-01-25 10:46:18 -080027#include "SurfaceFlingerProperties.h"
28
Dominik Laskowskieddeda12019-07-19 11:54:13 -070029namespace {
Ana Krulec757f63a2019-01-25 10:46:18 -080030
Dominik Laskowskif83570c2019-08-26 12:04:07 -070031std::optional<nsecs_t> getProperty(const char* name) {
Dominik Laskowskieddeda12019-07-19 11:54:13 -070032 char value[PROPERTY_VALUE_MAX];
33 property_get(name, value, "-1");
34 if (const int i = atoi(value); i != -1) return i;
35 return std::nullopt;
36}
Ana Krulec757f63a2019-01-25 10:46:18 -080037
Ady Abraham090d42c2020-01-08 12:08:11 -080038bool fpsEqualsWithMargin(float fpsA, float fpsB) {
39 static constexpr float MARGIN = 0.01f;
40 return std::abs(fpsA - fpsB) <= MARGIN;
41}
42
Dominik Laskowskieddeda12019-07-19 11:54:13 -070043} // namespace
44
45namespace android::scheduler {
46
Ady Abraham9e16a482019-12-03 17:19:41 -080047PhaseConfiguration::~PhaseConfiguration() = default;
Ana Krulec757f63a2019-01-25 10:46:18 -080048
49namespace impl {
Dominik Laskowskieddeda12019-07-19 11:54:13 -070050
Ady Abraham9e16a482019-12-03 17:19:41 -080051PhaseOffsets::PhaseOffsets(const scheduler::RefreshRateConfigs& refreshRateConfigs)
52 : // Below defines the threshold when an offset is considered to be negative, i.e. targeting
53 // for the N+2 vsync instead of N+1. This means that:
54 // For offset < threshold, SF wake up (vsync_duration - offset) before HW vsync.
55 // For offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW vsync.
56 mThresholdForNextVsync(getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns")
57 .value_or(std::numeric_limits<nsecs_t>::max())),
58 mOffsets(initializeOffsets(refreshRateConfigs)),
59 mRefreshRateFps(refreshRateConfigs.getCurrentRefreshRate().fps) {}
Ana Krulec757f63a2019-01-25 10:46:18 -080060
61void PhaseOffsets::dump(std::string& result) const {
Ady Abraham9e16a482019-12-03 17:19:41 -080062 const auto [early, earlyGl, late] = getCurrentOffsets();
Dominik Laskowski98041832019-08-01 18:35:59 -070063 using base::StringAppendF;
64 StringAppendF(&result,
65 " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64 " ns\n"
66 " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64 " ns\n"
67 " GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n"
68 "next VSYNC threshold: %9" PRId64 " ns\n",
Ady Abraham9e16a482019-12-03 17:19:41 -080069 late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf,
70 mThresholdForNextVsync);
Ana Krulec757f63a2019-01-25 10:46:18 -080071}
72
Ady Abraham090d42c2020-01-08 12:08:11 -080073std::unordered_map<float, PhaseOffsets::Offsets> PhaseOffsets::initializeOffsets(
Ady Abraham9e16a482019-12-03 17:19:41 -080074 const scheduler::RefreshRateConfigs& refreshRateConfigs) const {
Ady Abraham090d42c2020-01-08 12:08:11 -080075 std::unordered_map<float, Offsets> offsets;
Ady Abraham9e16a482019-12-03 17:19:41 -080076
77 for (const auto& [ignored, refreshRate] : refreshRateConfigs.getAllRefreshRates()) {
Ady Abraham9e16a482019-12-03 17:19:41 -080078 if (refreshRate.fps > 65.0f) {
Ady Abraham090d42c2020-01-08 12:08:11 -080079 offsets.emplace(refreshRate.fps, getHighFpsOffsets(refreshRate.vsyncPeriod));
Ady Abraham9e16a482019-12-03 17:19:41 -080080 } else {
Ady Abraham090d42c2020-01-08 12:08:11 -080081 offsets.emplace(refreshRate.fps, getDefaultOffsets(refreshRate.vsyncPeriod));
Ady Abraham9e16a482019-12-03 17:19:41 -080082 }
83 }
84 return offsets;
85}
86
87PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t vsyncDuration) const {
Dominik Laskowskieddeda12019-07-19 11:54:13 -070088 const int64_t vsyncPhaseOffsetNs = sysprop::vsync_event_phase_offset_ns(1000000);
89 const int64_t sfVsyncPhaseOffsetNs = sysprop::vsync_sf_event_phase_offset_ns(1000000);
90
91 const auto earlySfOffsetNs = getProperty("debug.sf.early_phase_offset_ns");
92 const auto earlyGlSfOffsetNs = getProperty("debug.sf.early_gl_phase_offset_ns");
93 const auto earlyAppOffsetNs = getProperty("debug.sf.early_app_phase_offset_ns");
94 const auto earlyGlAppOffsetNs = getProperty("debug.sf.early_gl_app_phase_offset_ns");
95
Ady Abraham9e16a482019-12-03 17:19:41 -080096 return {
97 {
98 earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs) < mThresholdForNextVsync
99 ? earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs)
100 : earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs) - vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700101
Ady Abraham9e16a482019-12-03 17:19:41 -0800102 earlyAppOffsetNs.value_or(vsyncPhaseOffsetNs),
103 },
104 {
105 earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs) < mThresholdForNextVsync
106 ? earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs)
107 : earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs) - vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700108
Ady Abraham9e16a482019-12-03 17:19:41 -0800109 earlyGlAppOffsetNs.value_or(vsyncPhaseOffsetNs),
110 },
111 {
112 sfVsyncPhaseOffsetNs < mThresholdForNextVsync
113 ? sfVsyncPhaseOffsetNs
114 : sfVsyncPhaseOffsetNs - vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700115
Ady Abraham9e16a482019-12-03 17:19:41 -0800116 vsyncPhaseOffsetNs,
117 },
118 };
Ana Krulec757f63a2019-01-25 10:46:18 -0800119}
120
Ady Abraham9e16a482019-12-03 17:19:41 -0800121PhaseOffsets::Offsets PhaseOffsets::getHighFpsOffsets(nsecs_t vsyncDuration) const {
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700122 const int highFpsLateAppOffsetNs =
123 getProperty("debug.sf.high_fps_late_app_phase_offset_ns").value_or(2000000);
124 const int highFpsLateSfOffsetNs =
125 getProperty("debug.sf.high_fps_late_sf_phase_offset_ns").value_or(1000000);
126
127 const auto highFpsEarlySfOffsetNs = getProperty("debug.sf.high_fps_early_phase_offset_ns");
128 const auto highFpsEarlyGlSfOffsetNs = getProperty("debug.sf.high_fps_early_gl_phase_offset_ns");
129 const auto highFpsEarlyAppOffsetNs = getProperty("debug.sf.high_fps_early_app_phase_offset_ns");
130 const auto highFpsEarlyGlAppOffsetNs =
131 getProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns");
132
Ady Abraham9e16a482019-12-03 17:19:41 -0800133 return {
134 {
135 highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs) < mThresholdForNextVsync
136 ? highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs)
137 : highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs) -
138 vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700139
Ady Abraham9e16a482019-12-03 17:19:41 -0800140 highFpsEarlyAppOffsetNs.value_or(highFpsLateAppOffsetNs),
141 },
142 {
143 highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs) <
144 mThresholdForNextVsync
145 ? highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs)
146 : highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs) -
147 vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700148
Ady Abraham9e16a482019-12-03 17:19:41 -0800149 highFpsEarlyGlAppOffsetNs.value_or(highFpsLateAppOffsetNs),
150 },
151 {
152 highFpsLateSfOffsetNs < mThresholdForNextVsync
153 ? highFpsLateSfOffsetNs
154 : highFpsLateSfOffsetNs - vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700155
Ady Abraham9e16a482019-12-03 17:19:41 -0800156 highFpsLateAppOffsetNs,
157 },
158 };
159}
160
Ady Abraham090d42c2020-01-08 12:08:11 -0800161PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate(float fps) const {
162 const auto iter = std::find_if(mOffsets.begin(), mOffsets.end(),
163 [&fps](const std::pair<float, Offsets>& candidateFps) {
164 return fpsEqualsWithMargin(fps, candidateFps.first);
165 });
166 LOG_ALWAYS_FATAL_IF(iter == mOffsets.end());
167 return iter->second;
168}
169
Ady Abraham9e16a482019-12-03 17:19:41 -0800170static void validateSysprops() {
171 const auto validatePropertyBool = [](const char* prop) {
172 LOG_ALWAYS_FATAL_IF(!property_get_bool(prop, false), "%s is false", prop);
173 };
174
175 validatePropertyBool("debug.sf.use_phase_offsets_as_durations");
176
177 LOG_ALWAYS_FATAL_IF(sysprop::vsync_event_phase_offset_ns(-1) != -1,
178 "ro.surface_flinger.vsync_event_phase_offset_ns is set but expecting "
179 "duration");
180
181 LOG_ALWAYS_FATAL_IF(sysprop::vsync_sf_event_phase_offset_ns(-1) != -1,
182 "ro.surface_flinger.vsync_sf_event_phase_offset_ns is set but expecting "
183 "duration");
184
185 const auto validateProperty = [](const char* prop) {
186 LOG_ALWAYS_FATAL_IF(getProperty(prop).has_value(),
187 "%s is set to %" PRId64 " but expecting duration", prop,
188 getProperty(prop).value_or(-1));
189 };
190
191 validateProperty("debug.sf.early_phase_offset_ns");
192 validateProperty("debug.sf.early_gl_phase_offset_ns");
193 validateProperty("debug.sf.early_app_phase_offset_ns");
194 validateProperty("debug.sf.early_gl_app_phase_offset_ns");
195 validateProperty("debug.sf.high_fps_late_app_phase_offset_ns");
196 validateProperty("debug.sf.high_fps_late_sf_phase_offset_ns");
197 validateProperty("debug.sf.high_fps_early_phase_offset_ns");
198 validateProperty("debug.sf.high_fps_early_gl_phase_offset_ns");
199 validateProperty("debug.sf.high_fps_early_app_phase_offset_ns");
200 validateProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns");
201}
202
203static nsecs_t sfDurationToOffset(nsecs_t sfDuration, nsecs_t vsyncDuration) {
204 return sfDuration == -1 ? 1'000'000 : vsyncDuration - sfDuration % vsyncDuration;
205}
206
207static nsecs_t appDurationToOffset(nsecs_t appDuration, nsecs_t sfDuration, nsecs_t vsyncDuration) {
208 return sfDuration == -1 ? 1'000'000
209 : vsyncDuration - (appDuration + sfDuration) % vsyncDuration;
210}
211
Ady Abrahamdfa37362020-01-21 18:02:39 -0800212PhaseDurations::Offsets PhaseDurations::constructOffsets(nsecs_t vsyncDuration) const {
213 return Offsets{
214 {
215 mSfEarlyDuration < vsyncDuration
216 ? sfDurationToOffset(mSfEarlyDuration, vsyncDuration)
217 : sfDurationToOffset(mSfEarlyDuration, vsyncDuration) - vsyncDuration,
218
219 appDurationToOffset(mAppEarlyDuration, mSfEarlyDuration, vsyncDuration),
220 },
221 {
222 mSfEarlyGlDuration < vsyncDuration
223 ? sfDurationToOffset(mSfEarlyGlDuration, vsyncDuration)
224 : sfDurationToOffset(mSfEarlyGlDuration, vsyncDuration) - vsyncDuration,
225
226 appDurationToOffset(mAppEarlyGlDuration, mSfEarlyGlDuration, vsyncDuration),
227 },
228 {
229 mSfDuration < vsyncDuration
230 ? sfDurationToOffset(mSfDuration, vsyncDuration)
231 : sfDurationToOffset(mSfDuration, vsyncDuration) - vsyncDuration,
232
233 appDurationToOffset(mAppDuration, mSfDuration, vsyncDuration),
234 },
235 };
236}
237
Ady Abraham9e16a482019-12-03 17:19:41 -0800238static std::vector<float> getRefreshRatesFromConfigs(
239 const android::scheduler::RefreshRateConfigs& refreshRateConfigs) {
240 const auto& allRefreshRates = refreshRateConfigs.getAllRefreshRates();
241 std::vector<float> refreshRates;
242 refreshRates.reserve(allRefreshRates.size());
243
244 for (const auto& [ignored, refreshRate] : allRefreshRates) {
245 refreshRates.emplace_back(refreshRate.fps);
246 }
247
248 return refreshRates;
249}
250
251std::unordered_map<float, PhaseDurations::Offsets> PhaseDurations::initializeOffsets(
252 const std::vector<float>& refreshRates) const {
Ady Abraham090d42c2020-01-08 12:08:11 -0800253 std::unordered_map<float, Offsets> offsets;
Ady Abraham9e16a482019-12-03 17:19:41 -0800254
255 for (const auto fps : refreshRates) {
Ady Abrahamdfa37362020-01-21 18:02:39 -0800256 offsets.emplace(fps, constructOffsets(static_cast<nsecs_t>(1e9f / fps)));
Ady Abraham9e16a482019-12-03 17:19:41 -0800257 }
258 return offsets;
259}
260
261PhaseDurations::PhaseDurations(const scheduler::RefreshRateConfigs& refreshRateConfigs)
262 : PhaseDurations(getRefreshRatesFromConfigs(refreshRateConfigs),
263 refreshRateConfigs.getCurrentRefreshRate().fps,
264 getProperty("debug.sf.late.sf.duration").value_or(-1),
265 getProperty("debug.sf.late.app.duration").value_or(-1),
266 getProperty("debug.sf.early.sf.duration").value_or(mSfDuration),
267 getProperty("debug.sf.early.app.duration").value_or(mAppDuration),
268 getProperty("debug.sf.earlyGl.sf.duration").value_or(mSfDuration),
269 getProperty("debug.sf.earlyGl.app.duration").value_or(mAppDuration)) {
270 validateSysprops();
271}
272
273PhaseDurations::PhaseDurations(const std::vector<float>& refreshRates, float currentFps,
274 nsecs_t sfDuration, nsecs_t appDuration, nsecs_t sfEarlyDuration,
275 nsecs_t appEarlyDuration, nsecs_t sfEarlyGlDuration,
276 nsecs_t appEarlyGlDuration)
277 : mSfDuration(sfDuration),
278 mAppDuration(appDuration),
279 mSfEarlyDuration(sfEarlyDuration),
280 mAppEarlyDuration(appEarlyDuration),
281 mSfEarlyGlDuration(sfEarlyGlDuration),
282 mAppEarlyGlDuration(appEarlyGlDuration),
283 mOffsets(initializeOffsets(refreshRates)),
284 mRefreshRateFps(currentFps) {}
285
286PhaseOffsets::Offsets PhaseDurations::getOffsetsForRefreshRate(float fps) const {
Ady Abraham090d42c2020-01-08 12:08:11 -0800287 const auto iter = std::find_if(mOffsets.begin(), mOffsets.end(), [=](const auto& candidateFps) {
288 return fpsEqualsWithMargin(fps, candidateFps.first);
289 });
Ady Abrahamdfa37362020-01-21 18:02:39 -0800290
291 if (iter != mOffsets.end()) {
292 return iter->second;
293 }
294
295 // Unknown refresh rate. This might happen if we get a hotplug event for the default display.
296 // This happens only during tests and not during regular device operation.
297 // In this case just construct the offset.
298 ALOGW("Can't find offset for %.2f fps", fps);
299 return constructOffsets(static_cast<nsecs_t>(1e9f / fps));
Ady Abraham9e16a482019-12-03 17:19:41 -0800300}
301
302void PhaseDurations::dump(std::string& result) const {
303 const auto [early, earlyGl, late] = getCurrentOffsets();
304 using base::StringAppendF;
305 StringAppendF(&result,
306 " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64
307 " ns\n"
308 " app duration: %9" PRId64 " ns\t SF duration: %9" PRId64
309 " ns\n"
310 " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64
311 " ns\n"
312 " early app duration: %9" PRId64 " ns\t early SF duration: %9" PRId64
313 " ns\n"
314 " GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64
315 " ns\n"
316 " GL early app duration: %9" PRId64 " ns\tGL early SF duration: %9" PRId64
317 " ns\n",
318 late.app,
319
320 late.sf,
321
322 mAppDuration, mSfDuration,
323
324 early.app, early.sf,
325
326 mAppEarlyDuration, mSfEarlyDuration,
327
328 earlyGl.app,
329
330 earlyGl.sf,
331
332 mAppEarlyGlDuration, mSfEarlyGlDuration);
Ana Krulec757f63a2019-01-25 10:46:18 -0800333}
334
335} // namespace impl
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700336} // namespace android::scheduler
Ady Abrahamb0dbdaa2020-01-06 16:19:42 -0800337
338// TODO(b/129481165): remove the #pragma below and fix conversion issues
339#pragma clang diagnostic pop // ignored "-Wconversion"