blob: 7941cda6eff5d2d9317349a4a506f15daa6cd1df [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
17#include "PhaseOffsets.h"
18
19#include <cutils/properties.h>
20
Dominik Laskowskieddeda12019-07-19 11:54:13 -070021#include <optional>
22
Ana Krulec757f63a2019-01-25 10:46:18 -080023#include "SurfaceFlingerProperties.h"
24
Dominik Laskowskieddeda12019-07-19 11:54:13 -070025namespace {
Ana Krulec757f63a2019-01-25 10:46:18 -080026
Dominik Laskowskif83570c2019-08-26 12:04:07 -070027std::optional<nsecs_t> getProperty(const char* name) {
Dominik Laskowskieddeda12019-07-19 11:54:13 -070028 char value[PROPERTY_VALUE_MAX];
29 property_get(name, value, "-1");
30 if (const int i = atoi(value); i != -1) return i;
31 return std::nullopt;
32}
Ana Krulec757f63a2019-01-25 10:46:18 -080033
Ady Abraham090d42c2020-01-08 12:08:11 -080034bool fpsEqualsWithMargin(float fpsA, float fpsB) {
35 static constexpr float MARGIN = 0.01f;
36 return std::abs(fpsA - fpsB) <= MARGIN;
37}
38
Dominik Laskowskieddeda12019-07-19 11:54:13 -070039} // namespace
40
41namespace android::scheduler {
42
Ady Abraham9e16a482019-12-03 17:19:41 -080043PhaseConfiguration::~PhaseConfiguration() = default;
Ana Krulec757f63a2019-01-25 10:46:18 -080044
45namespace impl {
Dominik Laskowskieddeda12019-07-19 11:54:13 -070046
Ady Abraham9e16a482019-12-03 17:19:41 -080047PhaseOffsets::PhaseOffsets(const scheduler::RefreshRateConfigs& refreshRateConfigs)
48 : // Below defines the threshold when an offset is considered to be negative, i.e. targeting
49 // for the N+2 vsync instead of N+1. This means that:
50 // For offset < threshold, SF wake up (vsync_duration - offset) before HW vsync.
51 // For offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW vsync.
52 mThresholdForNextVsync(getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns")
53 .value_or(std::numeric_limits<nsecs_t>::max())),
54 mOffsets(initializeOffsets(refreshRateConfigs)),
55 mRefreshRateFps(refreshRateConfigs.getCurrentRefreshRate().fps) {}
Ana Krulec757f63a2019-01-25 10:46:18 -080056
57void PhaseOffsets::dump(std::string& result) const {
Ady Abraham9e16a482019-12-03 17:19:41 -080058 const auto [early, earlyGl, late] = getCurrentOffsets();
Dominik Laskowski98041832019-08-01 18:35:59 -070059 using base::StringAppendF;
60 StringAppendF(&result,
61 " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64 " ns\n"
62 " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64 " ns\n"
63 " GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n"
64 "next VSYNC threshold: %9" PRId64 " ns\n",
Ady Abraham9e16a482019-12-03 17:19:41 -080065 late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf,
66 mThresholdForNextVsync);
Ana Krulec757f63a2019-01-25 10:46:18 -080067}
68
Ady Abraham090d42c2020-01-08 12:08:11 -080069std::unordered_map<float, PhaseOffsets::Offsets> PhaseOffsets::initializeOffsets(
Ady Abraham9e16a482019-12-03 17:19:41 -080070 const scheduler::RefreshRateConfigs& refreshRateConfigs) const {
Ady Abraham090d42c2020-01-08 12:08:11 -080071 std::unordered_map<float, Offsets> offsets;
Ady Abraham9e16a482019-12-03 17:19:41 -080072
73 for (const auto& [ignored, refreshRate] : refreshRateConfigs.getAllRefreshRates()) {
Sushil Chauhanbdb9e6d2020-03-19 16:15:46 -070074 const float fps = refreshRate->fps;
75 offsets.emplace(fps, getPhaseOffsets(fps, refreshRate->vsyncPeriod));
Ady Abraham9e16a482019-12-03 17:19:41 -080076 }
77 return offsets;
78}
79
Sushil Chauhanbdb9e6d2020-03-19 16:15:46 -070080PhaseOffsets::Offsets PhaseOffsets::getPhaseOffsets(float fps, nsecs_t vsyncPeriod) const {
81 if (fps > 65.0f) {
82 return getHighFpsOffsets(vsyncPeriod);
83 } else {
84 return getDefaultOffsets(vsyncPeriod);
85 }
86}
87
Ady Abraham9e16a482019-12-03 17:19:41 -080088PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t vsyncDuration) const {
Dominik Laskowskieddeda12019-07-19 11:54:13 -070089 const int64_t vsyncPhaseOffsetNs = sysprop::vsync_event_phase_offset_ns(1000000);
90 const int64_t sfVsyncPhaseOffsetNs = sysprop::vsync_sf_event_phase_offset_ns(1000000);
91
92 const auto earlySfOffsetNs = getProperty("debug.sf.early_phase_offset_ns");
93 const auto earlyGlSfOffsetNs = getProperty("debug.sf.early_gl_phase_offset_ns");
94 const auto earlyAppOffsetNs = getProperty("debug.sf.early_app_phase_offset_ns");
95 const auto earlyGlAppOffsetNs = getProperty("debug.sf.early_gl_app_phase_offset_ns");
96
Ady Abraham9e16a482019-12-03 17:19:41 -080097 return {
98 {
99 earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs) < mThresholdForNextVsync
100 ? earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs)
101 : earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs) - vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700102
Ady Abraham9e16a482019-12-03 17:19:41 -0800103 earlyAppOffsetNs.value_or(vsyncPhaseOffsetNs),
104 },
105 {
106 earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs) < mThresholdForNextVsync
107 ? earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs)
108 : earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs) - vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700109
Ady Abraham9e16a482019-12-03 17:19:41 -0800110 earlyGlAppOffsetNs.value_or(vsyncPhaseOffsetNs),
111 },
112 {
113 sfVsyncPhaseOffsetNs < mThresholdForNextVsync
114 ? sfVsyncPhaseOffsetNs
115 : sfVsyncPhaseOffsetNs - vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700116
Ady Abraham9e16a482019-12-03 17:19:41 -0800117 vsyncPhaseOffsetNs,
118 },
119 };
Ana Krulec757f63a2019-01-25 10:46:18 -0800120}
121
Ady Abraham9e16a482019-12-03 17:19:41 -0800122PhaseOffsets::Offsets PhaseOffsets::getHighFpsOffsets(nsecs_t vsyncDuration) const {
Ady Abrahamdec1a412020-01-24 10:23:50 -0800123 const auto highFpsLateAppOffsetNs =
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700124 getProperty("debug.sf.high_fps_late_app_phase_offset_ns").value_or(2000000);
Ady Abrahamdec1a412020-01-24 10:23:50 -0800125 const auto highFpsLateSfOffsetNs =
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700126 getProperty("debug.sf.high_fps_late_sf_phase_offset_ns").value_or(1000000);
127
128 const auto highFpsEarlySfOffsetNs = getProperty("debug.sf.high_fps_early_phase_offset_ns");
129 const auto highFpsEarlyGlSfOffsetNs = getProperty("debug.sf.high_fps_early_gl_phase_offset_ns");
130 const auto highFpsEarlyAppOffsetNs = getProperty("debug.sf.high_fps_early_app_phase_offset_ns");
131 const auto highFpsEarlyGlAppOffsetNs =
132 getProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns");
133
Ady Abraham9e16a482019-12-03 17:19:41 -0800134 return {
135 {
136 highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs) < mThresholdForNextVsync
137 ? highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs)
138 : highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs) -
139 vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700140
Ady Abraham9e16a482019-12-03 17:19:41 -0800141 highFpsEarlyAppOffsetNs.value_or(highFpsLateAppOffsetNs),
142 },
143 {
144 highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs) <
145 mThresholdForNextVsync
146 ? highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs)
147 : highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs) -
148 vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700149
Ady Abraham9e16a482019-12-03 17:19:41 -0800150 highFpsEarlyGlAppOffsetNs.value_or(highFpsLateAppOffsetNs),
151 },
152 {
153 highFpsLateSfOffsetNs < mThresholdForNextVsync
154 ? highFpsLateSfOffsetNs
155 : highFpsLateSfOffsetNs - vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700156
Ady Abraham9e16a482019-12-03 17:19:41 -0800157 highFpsLateAppOffsetNs,
158 },
159 };
160}
161
Ady Abraham090d42c2020-01-08 12:08:11 -0800162PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate(float fps) const {
163 const auto iter = std::find_if(mOffsets.begin(), mOffsets.end(),
164 [&fps](const std::pair<float, Offsets>& candidateFps) {
165 return fpsEqualsWithMargin(fps, candidateFps.first);
166 });
Sushil Chauhanbdb9e6d2020-03-19 16:15:46 -0700167
168 if (iter != mOffsets.end()) {
169 return iter->second;
170 }
171
172 // Unknown refresh rate. This might happen if we get a hotplug event for an external display.
173 // In this case just construct the offset.
174 ALOGW("Can't find offset for %.2f fps", fps);
175 return getPhaseOffsets(fps, static_cast<nsecs_t>(1e9f / fps));
Ady Abraham090d42c2020-01-08 12:08:11 -0800176}
177
Ady Abraham9e16a482019-12-03 17:19:41 -0800178static void validateSysprops() {
179 const auto validatePropertyBool = [](const char* prop) {
180 LOG_ALWAYS_FATAL_IF(!property_get_bool(prop, false), "%s is false", prop);
181 };
182
183 validatePropertyBool("debug.sf.use_phase_offsets_as_durations");
184
185 LOG_ALWAYS_FATAL_IF(sysprop::vsync_event_phase_offset_ns(-1) != -1,
186 "ro.surface_flinger.vsync_event_phase_offset_ns is set but expecting "
187 "duration");
188
189 LOG_ALWAYS_FATAL_IF(sysprop::vsync_sf_event_phase_offset_ns(-1) != -1,
190 "ro.surface_flinger.vsync_sf_event_phase_offset_ns is set but expecting "
191 "duration");
192
193 const auto validateProperty = [](const char* prop) {
194 LOG_ALWAYS_FATAL_IF(getProperty(prop).has_value(),
195 "%s is set to %" PRId64 " but expecting duration", prop,
196 getProperty(prop).value_or(-1));
197 };
198
199 validateProperty("debug.sf.early_phase_offset_ns");
200 validateProperty("debug.sf.early_gl_phase_offset_ns");
201 validateProperty("debug.sf.early_app_phase_offset_ns");
202 validateProperty("debug.sf.early_gl_app_phase_offset_ns");
203 validateProperty("debug.sf.high_fps_late_app_phase_offset_ns");
204 validateProperty("debug.sf.high_fps_late_sf_phase_offset_ns");
205 validateProperty("debug.sf.high_fps_early_phase_offset_ns");
206 validateProperty("debug.sf.high_fps_early_gl_phase_offset_ns");
207 validateProperty("debug.sf.high_fps_early_app_phase_offset_ns");
208 validateProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns");
209}
210
211static nsecs_t sfDurationToOffset(nsecs_t sfDuration, nsecs_t vsyncDuration) {
212 return sfDuration == -1 ? 1'000'000 : vsyncDuration - sfDuration % vsyncDuration;
213}
214
215static nsecs_t appDurationToOffset(nsecs_t appDuration, nsecs_t sfDuration, nsecs_t vsyncDuration) {
216 return sfDuration == -1 ? 1'000'000
217 : vsyncDuration - (appDuration + sfDuration) % vsyncDuration;
218}
219
Ady Abrahamdfa37362020-01-21 18:02:39 -0800220PhaseDurations::Offsets PhaseDurations::constructOffsets(nsecs_t vsyncDuration) const {
221 return Offsets{
222 {
223 mSfEarlyDuration < vsyncDuration
224 ? sfDurationToOffset(mSfEarlyDuration, vsyncDuration)
225 : sfDurationToOffset(mSfEarlyDuration, vsyncDuration) - vsyncDuration,
226
227 appDurationToOffset(mAppEarlyDuration, mSfEarlyDuration, vsyncDuration),
228 },
229 {
230 mSfEarlyGlDuration < vsyncDuration
231 ? sfDurationToOffset(mSfEarlyGlDuration, vsyncDuration)
232 : sfDurationToOffset(mSfEarlyGlDuration, vsyncDuration) - vsyncDuration,
233
234 appDurationToOffset(mAppEarlyGlDuration, mSfEarlyGlDuration, vsyncDuration),
235 },
236 {
237 mSfDuration < vsyncDuration
238 ? sfDurationToOffset(mSfDuration, vsyncDuration)
239 : sfDurationToOffset(mSfDuration, vsyncDuration) - vsyncDuration,
240
241 appDurationToOffset(mAppDuration, mSfDuration, vsyncDuration),
242 },
243 };
244}
245
Ady Abraham9e16a482019-12-03 17:19:41 -0800246static std::vector<float> getRefreshRatesFromConfigs(
247 const android::scheduler::RefreshRateConfigs& refreshRateConfigs) {
248 const auto& allRefreshRates = refreshRateConfigs.getAllRefreshRates();
249 std::vector<float> refreshRates;
250 refreshRates.reserve(allRefreshRates.size());
251
252 for (const auto& [ignored, refreshRate] : allRefreshRates) {
Ady Abraham2e1dd892020-03-05 13:48:36 -0800253 refreshRates.emplace_back(refreshRate->fps);
Ady Abraham9e16a482019-12-03 17:19:41 -0800254 }
255
256 return refreshRates;
257}
258
259std::unordered_map<float, PhaseDurations::Offsets> PhaseDurations::initializeOffsets(
260 const std::vector<float>& refreshRates) const {
Ady Abraham090d42c2020-01-08 12:08:11 -0800261 std::unordered_map<float, Offsets> offsets;
Ady Abraham9e16a482019-12-03 17:19:41 -0800262
263 for (const auto fps : refreshRates) {
Ady Abrahamdfa37362020-01-21 18:02:39 -0800264 offsets.emplace(fps, constructOffsets(static_cast<nsecs_t>(1e9f / fps)));
Ady Abraham9e16a482019-12-03 17:19:41 -0800265 }
266 return offsets;
267}
268
269PhaseDurations::PhaseDurations(const scheduler::RefreshRateConfigs& refreshRateConfigs)
270 : PhaseDurations(getRefreshRatesFromConfigs(refreshRateConfigs),
271 refreshRateConfigs.getCurrentRefreshRate().fps,
272 getProperty("debug.sf.late.sf.duration").value_or(-1),
273 getProperty("debug.sf.late.app.duration").value_or(-1),
274 getProperty("debug.sf.early.sf.duration").value_or(mSfDuration),
275 getProperty("debug.sf.early.app.duration").value_or(mAppDuration),
276 getProperty("debug.sf.earlyGl.sf.duration").value_or(mSfDuration),
277 getProperty("debug.sf.earlyGl.app.duration").value_or(mAppDuration)) {
278 validateSysprops();
279}
280
281PhaseDurations::PhaseDurations(const std::vector<float>& refreshRates, float currentFps,
282 nsecs_t sfDuration, nsecs_t appDuration, nsecs_t sfEarlyDuration,
283 nsecs_t appEarlyDuration, nsecs_t sfEarlyGlDuration,
284 nsecs_t appEarlyGlDuration)
285 : mSfDuration(sfDuration),
286 mAppDuration(appDuration),
287 mSfEarlyDuration(sfEarlyDuration),
288 mAppEarlyDuration(appEarlyDuration),
289 mSfEarlyGlDuration(sfEarlyGlDuration),
290 mAppEarlyGlDuration(appEarlyGlDuration),
291 mOffsets(initializeOffsets(refreshRates)),
292 mRefreshRateFps(currentFps) {}
293
294PhaseOffsets::Offsets PhaseDurations::getOffsetsForRefreshRate(float fps) const {
Ady Abraham090d42c2020-01-08 12:08:11 -0800295 const auto iter = std::find_if(mOffsets.begin(), mOffsets.end(), [=](const auto& candidateFps) {
296 return fpsEqualsWithMargin(fps, candidateFps.first);
297 });
Ady Abrahamdfa37362020-01-21 18:02:39 -0800298
299 if (iter != mOffsets.end()) {
300 return iter->second;
301 }
302
Sushil Chauhanbdb9e6d2020-03-19 16:15:46 -0700303 // Unknown refresh rate. This might happen if we get a hotplug event for an external display.
Ady Abrahamdfa37362020-01-21 18:02:39 -0800304 // In this case just construct the offset.
305 ALOGW("Can't find offset for %.2f fps", fps);
306 return constructOffsets(static_cast<nsecs_t>(1e9f / fps));
Ady Abraham9e16a482019-12-03 17:19:41 -0800307}
308
309void PhaseDurations::dump(std::string& result) const {
310 const auto [early, earlyGl, late] = getCurrentOffsets();
311 using base::StringAppendF;
312 StringAppendF(&result,
313 " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64
314 " ns\n"
315 " app duration: %9" PRId64 " ns\t SF duration: %9" PRId64
316 " ns\n"
317 " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64
318 " ns\n"
319 " early app duration: %9" PRId64 " ns\t early SF duration: %9" PRId64
320 " ns\n"
321 " GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64
322 " ns\n"
323 " GL early app duration: %9" PRId64 " ns\tGL early SF duration: %9" PRId64
324 " ns\n",
325 late.app,
326
327 late.sf,
328
329 mAppDuration, mSfDuration,
330
331 early.app, early.sf,
332
333 mAppEarlyDuration, mSfEarlyDuration,
334
335 earlyGl.app,
336
337 earlyGl.sf,
338
339 mAppEarlyGlDuration, mSfEarlyGlDuration);
Ana Krulec757f63a2019-01-25 10:46:18 -0800340}
341
342} // namespace impl
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700343} // namespace android::scheduler