blob: d9aaa05d96702918f03c763de2fbab1f468a68e4 [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
Ady Abraham60120a02020-03-23 11:23:26 -070039std::vector<float> getRefreshRatesFromConfigs(
40 const android::scheduler::RefreshRateConfigs& refreshRateConfigs) {
41 const auto& allRefreshRates = refreshRateConfigs.getAllRefreshRates();
42 std::vector<float> refreshRates;
43 refreshRates.reserve(allRefreshRates.size());
44
45 for (const auto& [ignored, refreshRate] : allRefreshRates) {
Ady Abrahamabc27602020-04-08 17:20:29 -070046 refreshRates.emplace_back(refreshRate->getFps());
Ady Abraham60120a02020-03-23 11:23:26 -070047 }
48
49 return refreshRates;
50}
51
Dominik Laskowskieddeda12019-07-19 11:54:13 -070052} // namespace
53
54namespace android::scheduler {
55
Ady Abraham9e16a482019-12-03 17:19:41 -080056PhaseConfiguration::~PhaseConfiguration() = default;
Ana Krulec757f63a2019-01-25 10:46:18 -080057
58namespace impl {
Dominik Laskowskieddeda12019-07-19 11:54:13 -070059
Ady Abraham9e16a482019-12-03 17:19:41 -080060PhaseOffsets::PhaseOffsets(const scheduler::RefreshRateConfigs& refreshRateConfigs)
Ady Abraham60120a02020-03-23 11:23:26 -070061 : PhaseOffsets(getRefreshRatesFromConfigs(refreshRateConfigs),
Ady Abrahamabc27602020-04-08 17:20:29 -070062 refreshRateConfigs.getCurrentRefreshRate().getFps(),
Ady Abraham60120a02020-03-23 11:23:26 -070063 // Below defines the threshold when an offset is considered to be negative,
64 // i.e. targeting for the N+2 vsync instead of N+1. This means that: For offset
65 // < threshold, SF wake up (vsync_duration - offset) before HW vsync. For
66 // offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW
67 // vsync.
68 getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns")
69 .value_or(std::numeric_limits<nsecs_t>::max())) {}
70
71PhaseOffsets::PhaseOffsets(const std::vector<float>& refreshRates, float currentFps,
72 nsecs_t thresholdForNextVsync)
73 : mThresholdForNextVsync(thresholdForNextVsync),
74 mOffsets(initializeOffsets(refreshRates)),
75 mRefreshRateFps(currentFps) {}
Ana Krulec757f63a2019-01-25 10:46:18 -080076
77void PhaseOffsets::dump(std::string& result) const {
Ady Abraham9e16a482019-12-03 17:19:41 -080078 const auto [early, earlyGl, late] = getCurrentOffsets();
Dominik Laskowski98041832019-08-01 18:35:59 -070079 using base::StringAppendF;
80 StringAppendF(&result,
81 " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64 " ns\n"
82 " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64 " ns\n"
83 " GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n"
84 "next VSYNC threshold: %9" PRId64 " ns\n",
Ady Abraham9e16a482019-12-03 17:19:41 -080085 late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf,
86 mThresholdForNextVsync);
Ana Krulec757f63a2019-01-25 10:46:18 -080087}
88
Ady Abraham090d42c2020-01-08 12:08:11 -080089std::unordered_map<float, PhaseOffsets::Offsets> PhaseOffsets::initializeOffsets(
Ady Abraham60120a02020-03-23 11:23:26 -070090 const std::vector<float>& refreshRates) const {
Ady Abraham090d42c2020-01-08 12:08:11 -080091 std::unordered_map<float, Offsets> offsets;
Ady Abraham9e16a482019-12-03 17:19:41 -080092
Ady Abraham60120a02020-03-23 11:23:26 -070093 for (const auto& refreshRate : refreshRates) {
94 offsets.emplace(refreshRate,
95 getPhaseOffsets(refreshRate, static_cast<nsecs_t>(1e9f / refreshRate)));
Ady Abraham9e16a482019-12-03 17:19:41 -080096 }
97 return offsets;
98}
99
Sushil Chauhanbdb9e6d2020-03-19 16:15:46 -0700100PhaseOffsets::Offsets PhaseOffsets::getPhaseOffsets(float fps, nsecs_t vsyncPeriod) const {
101 if (fps > 65.0f) {
102 return getHighFpsOffsets(vsyncPeriod);
103 } else {
104 return getDefaultOffsets(vsyncPeriod);
105 }
106}
107
Ady Abraham9e16a482019-12-03 17:19:41 -0800108PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t vsyncDuration) const {
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700109 const int64_t vsyncPhaseOffsetNs = sysprop::vsync_event_phase_offset_ns(1000000);
110 const int64_t sfVsyncPhaseOffsetNs = sysprop::vsync_sf_event_phase_offset_ns(1000000);
111
112 const auto earlySfOffsetNs = getProperty("debug.sf.early_phase_offset_ns");
113 const auto earlyGlSfOffsetNs = getProperty("debug.sf.early_gl_phase_offset_ns");
114 const auto earlyAppOffsetNs = getProperty("debug.sf.early_app_phase_offset_ns");
115 const auto earlyGlAppOffsetNs = getProperty("debug.sf.early_gl_app_phase_offset_ns");
116
Ady Abraham9e16a482019-12-03 17:19:41 -0800117 return {
118 {
119 earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs) < mThresholdForNextVsync
120 ? earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs)
121 : earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs) - vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700122
Ady Abraham9e16a482019-12-03 17:19:41 -0800123 earlyAppOffsetNs.value_or(vsyncPhaseOffsetNs),
124 },
125 {
126 earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs) < mThresholdForNextVsync
127 ? earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs)
128 : earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs) - vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700129
Ady Abraham9e16a482019-12-03 17:19:41 -0800130 earlyGlAppOffsetNs.value_or(vsyncPhaseOffsetNs),
131 },
132 {
133 sfVsyncPhaseOffsetNs < mThresholdForNextVsync
134 ? sfVsyncPhaseOffsetNs
135 : sfVsyncPhaseOffsetNs - vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700136
Ady Abraham9e16a482019-12-03 17:19:41 -0800137 vsyncPhaseOffsetNs,
138 },
139 };
Ana Krulec757f63a2019-01-25 10:46:18 -0800140}
141
Ady Abraham9e16a482019-12-03 17:19:41 -0800142PhaseOffsets::Offsets PhaseOffsets::getHighFpsOffsets(nsecs_t vsyncDuration) const {
Ady Abrahamdec1a412020-01-24 10:23:50 -0800143 const auto highFpsLateAppOffsetNs =
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700144 getProperty("debug.sf.high_fps_late_app_phase_offset_ns").value_or(2000000);
Ady Abrahamdec1a412020-01-24 10:23:50 -0800145 const auto highFpsLateSfOffsetNs =
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700146 getProperty("debug.sf.high_fps_late_sf_phase_offset_ns").value_or(1000000);
147
148 const auto highFpsEarlySfOffsetNs = getProperty("debug.sf.high_fps_early_phase_offset_ns");
149 const auto highFpsEarlyGlSfOffsetNs = getProperty("debug.sf.high_fps_early_gl_phase_offset_ns");
150 const auto highFpsEarlyAppOffsetNs = getProperty("debug.sf.high_fps_early_app_phase_offset_ns");
151 const auto highFpsEarlyGlAppOffsetNs =
152 getProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns");
153
Ady Abraham9e16a482019-12-03 17:19:41 -0800154 return {
155 {
156 highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs) < mThresholdForNextVsync
157 ? highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs)
158 : highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs) -
159 vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700160
Ady Abraham9e16a482019-12-03 17:19:41 -0800161 highFpsEarlyAppOffsetNs.value_or(highFpsLateAppOffsetNs),
162 },
163 {
164 highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs) <
165 mThresholdForNextVsync
166 ? highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs)
167 : highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs) -
168 vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700169
Ady Abraham9e16a482019-12-03 17:19:41 -0800170 highFpsEarlyGlAppOffsetNs.value_or(highFpsLateAppOffsetNs),
171 },
172 {
173 highFpsLateSfOffsetNs < mThresholdForNextVsync
174 ? highFpsLateSfOffsetNs
175 : highFpsLateSfOffsetNs - vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700176
Ady Abraham9e16a482019-12-03 17:19:41 -0800177 highFpsLateAppOffsetNs,
178 },
179 };
180}
181
Ady Abraham090d42c2020-01-08 12:08:11 -0800182PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate(float fps) const {
183 const auto iter = std::find_if(mOffsets.begin(), mOffsets.end(),
184 [&fps](const std::pair<float, Offsets>& candidateFps) {
185 return fpsEqualsWithMargin(fps, candidateFps.first);
186 });
Sushil Chauhanbdb9e6d2020-03-19 16:15:46 -0700187
188 if (iter != mOffsets.end()) {
189 return iter->second;
190 }
191
192 // Unknown refresh rate. This might happen if we get a hotplug event for an external display.
193 // In this case just construct the offset.
194 ALOGW("Can't find offset for %.2f fps", fps);
195 return getPhaseOffsets(fps, static_cast<nsecs_t>(1e9f / fps));
Ady Abraham090d42c2020-01-08 12:08:11 -0800196}
197
Ady Abraham9e16a482019-12-03 17:19:41 -0800198static void validateSysprops() {
199 const auto validatePropertyBool = [](const char* prop) {
200 LOG_ALWAYS_FATAL_IF(!property_get_bool(prop, false), "%s is false", prop);
201 };
202
203 validatePropertyBool("debug.sf.use_phase_offsets_as_durations");
204
205 LOG_ALWAYS_FATAL_IF(sysprop::vsync_event_phase_offset_ns(-1) != -1,
206 "ro.surface_flinger.vsync_event_phase_offset_ns is set but expecting "
207 "duration");
208
209 LOG_ALWAYS_FATAL_IF(sysprop::vsync_sf_event_phase_offset_ns(-1) != -1,
210 "ro.surface_flinger.vsync_sf_event_phase_offset_ns is set but expecting "
211 "duration");
212
213 const auto validateProperty = [](const char* prop) {
214 LOG_ALWAYS_FATAL_IF(getProperty(prop).has_value(),
215 "%s is set to %" PRId64 " but expecting duration", prop,
216 getProperty(prop).value_or(-1));
217 };
218
219 validateProperty("debug.sf.early_phase_offset_ns");
220 validateProperty("debug.sf.early_gl_phase_offset_ns");
221 validateProperty("debug.sf.early_app_phase_offset_ns");
222 validateProperty("debug.sf.early_gl_app_phase_offset_ns");
223 validateProperty("debug.sf.high_fps_late_app_phase_offset_ns");
224 validateProperty("debug.sf.high_fps_late_sf_phase_offset_ns");
225 validateProperty("debug.sf.high_fps_early_phase_offset_ns");
226 validateProperty("debug.sf.high_fps_early_gl_phase_offset_ns");
227 validateProperty("debug.sf.high_fps_early_app_phase_offset_ns");
228 validateProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns");
229}
230
231static nsecs_t sfDurationToOffset(nsecs_t sfDuration, nsecs_t vsyncDuration) {
232 return sfDuration == -1 ? 1'000'000 : vsyncDuration - sfDuration % vsyncDuration;
233}
234
235static nsecs_t appDurationToOffset(nsecs_t appDuration, nsecs_t sfDuration, nsecs_t vsyncDuration) {
236 return sfDuration == -1 ? 1'000'000
237 : vsyncDuration - (appDuration + sfDuration) % vsyncDuration;
238}
239
Ady Abrahamdfa37362020-01-21 18:02:39 -0800240PhaseDurations::Offsets PhaseDurations::constructOffsets(nsecs_t vsyncDuration) const {
241 return Offsets{
242 {
243 mSfEarlyDuration < vsyncDuration
244 ? sfDurationToOffset(mSfEarlyDuration, vsyncDuration)
245 : sfDurationToOffset(mSfEarlyDuration, vsyncDuration) - vsyncDuration,
246
247 appDurationToOffset(mAppEarlyDuration, mSfEarlyDuration, vsyncDuration),
248 },
249 {
250 mSfEarlyGlDuration < vsyncDuration
251 ? sfDurationToOffset(mSfEarlyGlDuration, vsyncDuration)
252 : sfDurationToOffset(mSfEarlyGlDuration, vsyncDuration) - vsyncDuration,
253
254 appDurationToOffset(mAppEarlyGlDuration, mSfEarlyGlDuration, vsyncDuration),
255 },
256 {
257 mSfDuration < vsyncDuration
258 ? sfDurationToOffset(mSfDuration, vsyncDuration)
259 : sfDurationToOffset(mSfDuration, vsyncDuration) - vsyncDuration,
260
261 appDurationToOffset(mAppDuration, mSfDuration, vsyncDuration),
262 },
263 };
264}
265
Ady Abraham9e16a482019-12-03 17:19:41 -0800266std::unordered_map<float, PhaseDurations::Offsets> PhaseDurations::initializeOffsets(
267 const std::vector<float>& refreshRates) const {
Ady Abraham090d42c2020-01-08 12:08:11 -0800268 std::unordered_map<float, Offsets> offsets;
Ady Abraham9e16a482019-12-03 17:19:41 -0800269
270 for (const auto fps : refreshRates) {
Ady Abrahamdfa37362020-01-21 18:02:39 -0800271 offsets.emplace(fps, constructOffsets(static_cast<nsecs_t>(1e9f / fps)));
Ady Abraham9e16a482019-12-03 17:19:41 -0800272 }
273 return offsets;
274}
275
276PhaseDurations::PhaseDurations(const scheduler::RefreshRateConfigs& refreshRateConfigs)
277 : PhaseDurations(getRefreshRatesFromConfigs(refreshRateConfigs),
Ady Abrahamabc27602020-04-08 17:20:29 -0700278 refreshRateConfigs.getCurrentRefreshRate().getFps(),
Ady Abraham9e16a482019-12-03 17:19:41 -0800279 getProperty("debug.sf.late.sf.duration").value_or(-1),
280 getProperty("debug.sf.late.app.duration").value_or(-1),
281 getProperty("debug.sf.early.sf.duration").value_or(mSfDuration),
282 getProperty("debug.sf.early.app.duration").value_or(mAppDuration),
283 getProperty("debug.sf.earlyGl.sf.duration").value_or(mSfDuration),
284 getProperty("debug.sf.earlyGl.app.duration").value_or(mAppDuration)) {
285 validateSysprops();
286}
287
288PhaseDurations::PhaseDurations(const std::vector<float>& refreshRates, float currentFps,
289 nsecs_t sfDuration, nsecs_t appDuration, nsecs_t sfEarlyDuration,
290 nsecs_t appEarlyDuration, nsecs_t sfEarlyGlDuration,
291 nsecs_t appEarlyGlDuration)
292 : mSfDuration(sfDuration),
293 mAppDuration(appDuration),
294 mSfEarlyDuration(sfEarlyDuration),
295 mAppEarlyDuration(appEarlyDuration),
296 mSfEarlyGlDuration(sfEarlyGlDuration),
297 mAppEarlyGlDuration(appEarlyGlDuration),
298 mOffsets(initializeOffsets(refreshRates)),
299 mRefreshRateFps(currentFps) {}
300
301PhaseOffsets::Offsets PhaseDurations::getOffsetsForRefreshRate(float fps) const {
Ady Abraham090d42c2020-01-08 12:08:11 -0800302 const auto iter = std::find_if(mOffsets.begin(), mOffsets.end(), [=](const auto& candidateFps) {
303 return fpsEqualsWithMargin(fps, candidateFps.first);
304 });
Ady Abrahamdfa37362020-01-21 18:02:39 -0800305
306 if (iter != mOffsets.end()) {
307 return iter->second;
308 }
309
Sushil Chauhanbdb9e6d2020-03-19 16:15:46 -0700310 // Unknown refresh rate. This might happen if we get a hotplug event for an external display.
Ady Abrahamdfa37362020-01-21 18:02:39 -0800311 // In this case just construct the offset.
312 ALOGW("Can't find offset for %.2f fps", fps);
313 return constructOffsets(static_cast<nsecs_t>(1e9f / fps));
Ady Abraham9e16a482019-12-03 17:19:41 -0800314}
315
316void PhaseDurations::dump(std::string& result) const {
317 const auto [early, earlyGl, late] = getCurrentOffsets();
318 using base::StringAppendF;
319 StringAppendF(&result,
320 " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64
321 " ns\n"
322 " app duration: %9" PRId64 " ns\t SF duration: %9" PRId64
323 " ns\n"
324 " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64
325 " ns\n"
326 " early app duration: %9" PRId64 " ns\t early SF duration: %9" PRId64
327 " ns\n"
328 " GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64
329 " ns\n"
330 " GL early app duration: %9" PRId64 " ns\tGL early SF duration: %9" PRId64
331 " ns\n",
332 late.app,
333
334 late.sf,
335
336 mAppDuration, mSfDuration,
337
338 early.app, early.sf,
339
340 mAppEarlyDuration, mSfEarlyDuration,
341
342 earlyGl.app,
343
344 earlyGl.sf,
345
346 mAppEarlyGlDuration, mSfEarlyGlDuration);
Ana Krulec757f63a2019-01-25 10:46:18 -0800347}
348
349} // namespace impl
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700350} // namespace android::scheduler