blob: 5373742411a96d47c20dd36ad4a88a43c97a52f5 [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 Abrahamc581d3c2020-08-06 17:34:27 -070017#include "VsyncConfiguration.h"
Ana Krulec757f63a2019-01-25 10:46:18 -080018
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 Abrahamc6c81822020-04-28 10:28:00 -070063 sysprop::vsync_event_phase_offset_ns(1000000),
64 sysprop::vsync_sf_event_phase_offset_ns(1000000),
65 getProperty("debug.sf.early_phase_offset_ns"),
66 getProperty("debug.sf.early_gl_phase_offset_ns"),
67 getProperty("debug.sf.early_app_phase_offset_ns"),
68 getProperty("debug.sf.early_gl_app_phase_offset_ns"),
Ady Abraham60120a02020-03-23 11:23:26 -070069 // Below defines the threshold when an offset is considered to be negative,
70 // i.e. targeting for the N+2 vsync instead of N+1. This means that: For offset
71 // < threshold, SF wake up (vsync_duration - offset) before HW vsync. For
72 // offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW
73 // vsync.
74 getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns")
75 .value_or(std::numeric_limits<nsecs_t>::max())) {}
76
77PhaseOffsets::PhaseOffsets(const std::vector<float>& refreshRates, float currentFps,
Ady Abrahamc6c81822020-04-28 10:28:00 -070078 nsecs_t vsyncPhaseOffsetNs, nsecs_t sfVSyncPhaseOffsetNs,
79 std::optional<nsecs_t> earlySfOffsetNs,
80 std::optional<nsecs_t> earlyGlSfOffsetNs,
81 std::optional<nsecs_t> earlyAppOffsetNs,
82 std::optional<nsecs_t> earlyGlAppOffsetNs, nsecs_t thresholdForNextVsync)
83 : mVSyncPhaseOffsetNs(vsyncPhaseOffsetNs),
84 mSfVSyncPhaseOffsetNs(sfVSyncPhaseOffsetNs),
85 mEarlySfOffsetNs(earlySfOffsetNs),
86 mEarlyGlSfOffsetNs(earlyGlSfOffsetNs),
87 mEarlyAppOffsetNs(earlyAppOffsetNs),
88 mEarlyGlAppOffsetNs(earlyGlAppOffsetNs),
89 mThresholdForNextVsync(thresholdForNextVsync),
Ady Abraham60120a02020-03-23 11:23:26 -070090 mOffsets(initializeOffsets(refreshRates)),
91 mRefreshRateFps(currentFps) {}
Ana Krulec757f63a2019-01-25 10:46:18 -080092
93void PhaseOffsets::dump(std::string& result) const {
Ady Abraham9e16a482019-12-03 17:19:41 -080094 const auto [early, earlyGl, late] = getCurrentOffsets();
Dominik Laskowski98041832019-08-01 18:35:59 -070095 using base::StringAppendF;
96 StringAppendF(&result,
97 " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64 " ns\n"
98 " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64 " ns\n"
99 " GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n"
100 "next VSYNC threshold: %9" PRId64 " ns\n",
Ady Abraham9e16a482019-12-03 17:19:41 -0800101 late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf,
102 mThresholdForNextVsync);
Ana Krulec757f63a2019-01-25 10:46:18 -0800103}
104
Ady Abraham090d42c2020-01-08 12:08:11 -0800105std::unordered_map<float, PhaseOffsets::Offsets> PhaseOffsets::initializeOffsets(
Ady Abraham60120a02020-03-23 11:23:26 -0700106 const std::vector<float>& refreshRates) const {
Ady Abraham090d42c2020-01-08 12:08:11 -0800107 std::unordered_map<float, Offsets> offsets;
Ady Abraham9e16a482019-12-03 17:19:41 -0800108
Ady Abraham60120a02020-03-23 11:23:26 -0700109 for (const auto& refreshRate : refreshRates) {
110 offsets.emplace(refreshRate,
111 getPhaseOffsets(refreshRate, static_cast<nsecs_t>(1e9f / refreshRate)));
Ady Abraham9e16a482019-12-03 17:19:41 -0800112 }
113 return offsets;
114}
115
Sushil Chauhanbdb9e6d2020-03-19 16:15:46 -0700116PhaseOffsets::Offsets PhaseOffsets::getPhaseOffsets(float fps, nsecs_t vsyncPeriod) const {
117 if (fps > 65.0f) {
118 return getHighFpsOffsets(vsyncPeriod);
119 } else {
120 return getDefaultOffsets(vsyncPeriod);
121 }
122}
123
Ady Abraham9e16a482019-12-03 17:19:41 -0800124PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t vsyncDuration) const {
Ady Abraham9e16a482019-12-03 17:19:41 -0800125 return {
126 {
Ady Abrahamc6c81822020-04-28 10:28:00 -0700127 mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
128 ? mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs)
129 : mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) - vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700130
Ady Abrahamc6c81822020-04-28 10:28:00 -0700131 mEarlyAppOffsetNs.value_or(mVSyncPhaseOffsetNs),
Ady Abraham9e16a482019-12-03 17:19:41 -0800132 },
133 {
Ady Abrahamc6c81822020-04-28 10:28:00 -0700134 mEarlyGlSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
135 ? mEarlyGlSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs)
136 : mEarlyGlSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) - vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700137
Ady Abrahamc6c81822020-04-28 10:28:00 -0700138 mEarlyGlAppOffsetNs.value_or(mVSyncPhaseOffsetNs),
Ady Abraham9e16a482019-12-03 17:19:41 -0800139 },
140 {
Ady Abrahamc6c81822020-04-28 10:28:00 -0700141 mSfVSyncPhaseOffsetNs < mThresholdForNextVsync
142 ? mSfVSyncPhaseOffsetNs
143 : mSfVSyncPhaseOffsetNs - vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700144
Ady Abrahamc6c81822020-04-28 10:28:00 -0700145 mVSyncPhaseOffsetNs,
Ady Abraham9e16a482019-12-03 17:19:41 -0800146 },
147 };
Ana Krulec757f63a2019-01-25 10:46:18 -0800148}
149
Ady Abraham9e16a482019-12-03 17:19:41 -0800150PhaseOffsets::Offsets PhaseOffsets::getHighFpsOffsets(nsecs_t vsyncDuration) const {
Ady Abrahamdec1a412020-01-24 10:23:50 -0800151 const auto highFpsLateAppOffsetNs =
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700152 getProperty("debug.sf.high_fps_late_app_phase_offset_ns").value_or(2000000);
Ady Abrahamdec1a412020-01-24 10:23:50 -0800153 const auto highFpsLateSfOffsetNs =
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700154 getProperty("debug.sf.high_fps_late_sf_phase_offset_ns").value_or(1000000);
155
156 const auto highFpsEarlySfOffsetNs = getProperty("debug.sf.high_fps_early_phase_offset_ns");
157 const auto highFpsEarlyGlSfOffsetNs = getProperty("debug.sf.high_fps_early_gl_phase_offset_ns");
158 const auto highFpsEarlyAppOffsetNs = getProperty("debug.sf.high_fps_early_app_phase_offset_ns");
159 const auto highFpsEarlyGlAppOffsetNs =
160 getProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns");
161
Ady Abraham9e16a482019-12-03 17:19:41 -0800162 return {
163 {
164 highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs) < mThresholdForNextVsync
165 ? highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs)
166 : highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs) -
167 vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700168
Ady Abraham9e16a482019-12-03 17:19:41 -0800169 highFpsEarlyAppOffsetNs.value_or(highFpsLateAppOffsetNs),
170 },
171 {
172 highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs) <
173 mThresholdForNextVsync
174 ? highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs)
175 : highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs) -
176 vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700177
Ady Abraham9e16a482019-12-03 17:19:41 -0800178 highFpsEarlyGlAppOffsetNs.value_or(highFpsLateAppOffsetNs),
179 },
180 {
181 highFpsLateSfOffsetNs < mThresholdForNextVsync
182 ? highFpsLateSfOffsetNs
183 : highFpsLateSfOffsetNs - vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700184
Ady Abraham9e16a482019-12-03 17:19:41 -0800185 highFpsLateAppOffsetNs,
186 },
187 };
188}
189
Ady Abraham090d42c2020-01-08 12:08:11 -0800190PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate(float fps) const {
191 const auto iter = std::find_if(mOffsets.begin(), mOffsets.end(),
192 [&fps](const std::pair<float, Offsets>& candidateFps) {
193 return fpsEqualsWithMargin(fps, candidateFps.first);
194 });
Sushil Chauhanbdb9e6d2020-03-19 16:15:46 -0700195
196 if (iter != mOffsets.end()) {
197 return iter->second;
198 }
199
200 // Unknown refresh rate. This might happen if we get a hotplug event for an external display.
201 // In this case just construct the offset.
202 ALOGW("Can't find offset for %.2f fps", fps);
203 return getPhaseOffsets(fps, static_cast<nsecs_t>(1e9f / fps));
Ady Abraham090d42c2020-01-08 12:08:11 -0800204}
205
Ady Abraham9e16a482019-12-03 17:19:41 -0800206static void validateSysprops() {
207 const auto validatePropertyBool = [](const char* prop) {
208 LOG_ALWAYS_FATAL_IF(!property_get_bool(prop, false), "%s is false", prop);
209 };
210
211 validatePropertyBool("debug.sf.use_phase_offsets_as_durations");
212
213 LOG_ALWAYS_FATAL_IF(sysprop::vsync_event_phase_offset_ns(-1) != -1,
214 "ro.surface_flinger.vsync_event_phase_offset_ns is set but expecting "
215 "duration");
216
217 LOG_ALWAYS_FATAL_IF(sysprop::vsync_sf_event_phase_offset_ns(-1) != -1,
218 "ro.surface_flinger.vsync_sf_event_phase_offset_ns is set but expecting "
219 "duration");
220
221 const auto validateProperty = [](const char* prop) {
222 LOG_ALWAYS_FATAL_IF(getProperty(prop).has_value(),
223 "%s is set to %" PRId64 " but expecting duration", prop,
224 getProperty(prop).value_or(-1));
225 };
226
227 validateProperty("debug.sf.early_phase_offset_ns");
228 validateProperty("debug.sf.early_gl_phase_offset_ns");
229 validateProperty("debug.sf.early_app_phase_offset_ns");
230 validateProperty("debug.sf.early_gl_app_phase_offset_ns");
231 validateProperty("debug.sf.high_fps_late_app_phase_offset_ns");
232 validateProperty("debug.sf.high_fps_late_sf_phase_offset_ns");
233 validateProperty("debug.sf.high_fps_early_phase_offset_ns");
234 validateProperty("debug.sf.high_fps_early_gl_phase_offset_ns");
235 validateProperty("debug.sf.high_fps_early_app_phase_offset_ns");
236 validateProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns");
237}
238
239static nsecs_t sfDurationToOffset(nsecs_t sfDuration, nsecs_t vsyncDuration) {
240 return sfDuration == -1 ? 1'000'000 : vsyncDuration - sfDuration % vsyncDuration;
241}
242
243static nsecs_t appDurationToOffset(nsecs_t appDuration, nsecs_t sfDuration, nsecs_t vsyncDuration) {
244 return sfDuration == -1 ? 1'000'000
245 : vsyncDuration - (appDuration + sfDuration) % vsyncDuration;
246}
247
Ady Abrahamdfa37362020-01-21 18:02:39 -0800248PhaseDurations::Offsets PhaseDurations::constructOffsets(nsecs_t vsyncDuration) const {
249 return Offsets{
250 {
251 mSfEarlyDuration < vsyncDuration
252 ? sfDurationToOffset(mSfEarlyDuration, vsyncDuration)
253 : sfDurationToOffset(mSfEarlyDuration, vsyncDuration) - vsyncDuration,
254
255 appDurationToOffset(mAppEarlyDuration, mSfEarlyDuration, vsyncDuration),
256 },
257 {
258 mSfEarlyGlDuration < vsyncDuration
259 ? sfDurationToOffset(mSfEarlyGlDuration, vsyncDuration)
260 : sfDurationToOffset(mSfEarlyGlDuration, vsyncDuration) - vsyncDuration,
261
262 appDurationToOffset(mAppEarlyGlDuration, mSfEarlyGlDuration, vsyncDuration),
263 },
264 {
265 mSfDuration < vsyncDuration
266 ? sfDurationToOffset(mSfDuration, vsyncDuration)
267 : sfDurationToOffset(mSfDuration, vsyncDuration) - vsyncDuration,
268
269 appDurationToOffset(mAppDuration, mSfDuration, vsyncDuration),
270 },
271 };
272}
273
Ady Abraham9e16a482019-12-03 17:19:41 -0800274std::unordered_map<float, PhaseDurations::Offsets> PhaseDurations::initializeOffsets(
275 const std::vector<float>& refreshRates) const {
Ady Abraham090d42c2020-01-08 12:08:11 -0800276 std::unordered_map<float, Offsets> offsets;
Ady Abraham9e16a482019-12-03 17:19:41 -0800277
278 for (const auto fps : refreshRates) {
Ady Abrahamdfa37362020-01-21 18:02:39 -0800279 offsets.emplace(fps, constructOffsets(static_cast<nsecs_t>(1e9f / fps)));
Ady Abraham9e16a482019-12-03 17:19:41 -0800280 }
281 return offsets;
282}
283
284PhaseDurations::PhaseDurations(const scheduler::RefreshRateConfigs& refreshRateConfigs)
285 : PhaseDurations(getRefreshRatesFromConfigs(refreshRateConfigs),
Ady Abrahamabc27602020-04-08 17:20:29 -0700286 refreshRateConfigs.getCurrentRefreshRate().getFps(),
Ady Abraham9e16a482019-12-03 17:19:41 -0800287 getProperty("debug.sf.late.sf.duration").value_or(-1),
288 getProperty("debug.sf.late.app.duration").value_or(-1),
289 getProperty("debug.sf.early.sf.duration").value_or(mSfDuration),
290 getProperty("debug.sf.early.app.duration").value_or(mAppDuration),
291 getProperty("debug.sf.earlyGl.sf.duration").value_or(mSfDuration),
292 getProperty("debug.sf.earlyGl.app.duration").value_or(mAppDuration)) {
293 validateSysprops();
294}
295
296PhaseDurations::PhaseDurations(const std::vector<float>& refreshRates, float currentFps,
297 nsecs_t sfDuration, nsecs_t appDuration, nsecs_t sfEarlyDuration,
298 nsecs_t appEarlyDuration, nsecs_t sfEarlyGlDuration,
299 nsecs_t appEarlyGlDuration)
300 : mSfDuration(sfDuration),
301 mAppDuration(appDuration),
302 mSfEarlyDuration(sfEarlyDuration),
303 mAppEarlyDuration(appEarlyDuration),
304 mSfEarlyGlDuration(sfEarlyGlDuration),
305 mAppEarlyGlDuration(appEarlyGlDuration),
306 mOffsets(initializeOffsets(refreshRates)),
307 mRefreshRateFps(currentFps) {}
308
309PhaseOffsets::Offsets PhaseDurations::getOffsetsForRefreshRate(float fps) const {
Ady Abraham090d42c2020-01-08 12:08:11 -0800310 const auto iter = std::find_if(mOffsets.begin(), mOffsets.end(), [=](const auto& candidateFps) {
311 return fpsEqualsWithMargin(fps, candidateFps.first);
312 });
Ady Abrahamdfa37362020-01-21 18:02:39 -0800313
314 if (iter != mOffsets.end()) {
315 return iter->second;
316 }
317
Sushil Chauhanbdb9e6d2020-03-19 16:15:46 -0700318 // Unknown refresh rate. This might happen if we get a hotplug event for an external display.
Ady Abrahamdfa37362020-01-21 18:02:39 -0800319 // In this case just construct the offset.
320 ALOGW("Can't find offset for %.2f fps", fps);
321 return constructOffsets(static_cast<nsecs_t>(1e9f / fps));
Ady Abraham9e16a482019-12-03 17:19:41 -0800322}
323
324void PhaseDurations::dump(std::string& result) const {
325 const auto [early, earlyGl, late] = getCurrentOffsets();
326 using base::StringAppendF;
327 StringAppendF(&result,
328 " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64
329 " ns\n"
330 " app duration: %9" PRId64 " ns\t SF duration: %9" PRId64
331 " ns\n"
332 " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64
333 " ns\n"
334 " early app duration: %9" PRId64 " ns\t early SF duration: %9" PRId64
335 " ns\n"
336 " GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64
337 " ns\n"
338 " GL early app duration: %9" PRId64 " ns\tGL early SF duration: %9" PRId64
339 " ns\n",
340 late.app,
341
342 late.sf,
343
344 mAppDuration, mSfDuration,
345
346 early.app, early.sf,
347
348 mAppEarlyDuration, mSfEarlyDuration,
349
350 earlyGl.app,
351
352 earlyGl.sf,
353
354 mAppEarlyGlDuration, mSfEarlyGlDuration);
Ana Krulec757f63a2019-01-25 10:46:18 -0800355}
356
357} // namespace impl
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700358} // namespace android::scheduler