blob: aac2569044747abe5b65782ad788874422f9e1e2 [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
Ady Abraham8287e852020-08-12 14:44:58 -070054namespace android::scheduler::impl {
Dominik Laskowskieddeda12019-07-19 11:54:13 -070055
Ady Abraham8287e852020-08-12 14:44:58 -070056VsyncConfiguration::VsyncConfiguration(float currentFps) : mRefreshRateFps(currentFps) {}
Ana Krulec757f63a2019-01-25 10:46:18 -080057
Ady Abraham8287e852020-08-12 14:44:58 -070058PhaseOffsets::VsyncConfigSet VsyncConfiguration::getConfigsForRefreshRate(float fps) const {
Ady Abraham090d42c2020-01-08 12:08:11 -080059 const auto iter = std::find_if(mOffsets.begin(), mOffsets.end(),
Ady Abraham8287e852020-08-12 14:44:58 -070060 [&fps](const std::pair<float, VsyncConfigSet>& candidateFps) {
Ady Abraham090d42c2020-01-08 12:08:11 -080061 return fpsEqualsWithMargin(fps, candidateFps.first);
62 });
Sushil Chauhanbdb9e6d2020-03-19 16:15:46 -070063
64 if (iter != mOffsets.end()) {
65 return iter->second;
66 }
67
68 // Unknown refresh rate. This might happen if we get a hotplug event for an external display.
69 // In this case just construct the offset.
70 ALOGW("Can't find offset for %.2f fps", fps);
Ady Abraham8287e852020-08-12 14:44:58 -070071 return constructOffsets(static_cast<nsecs_t>(1e9f / fps));
72}
73
74void VsyncConfiguration::initializeOffsets(const std::vector<float>& refreshRates) {
75 for (const auto fps : refreshRates) {
76 mOffsets.emplace(fps, constructOffsets(static_cast<nsecs_t>(1e9f / fps)));
77 }
78}
79
80void VsyncConfiguration::dump(std::string& result) const {
81 const auto [early, earlyGpu, late] = getCurrentConfigs();
82 using base::StringAppendF;
83 StringAppendF(&result,
84 " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64
85 " ns\n"
86 " app duration: %9lld ns\t SF duration: %9lld ns\n"
87 " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64
88 " ns\n"
89 " early app duration: %9lld ns\t early SF duration: %9lld ns\n"
90 " GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64
91 " ns\n"
92 " GL early app duration: %9lld ns\tGL early SF duration: %9lld ns\n",
93 late.appOffset, late.sfOffset,
94
95 late.appWorkDuration.count(), late.sfWorkDuration.count(),
96
97 early.appOffset, early.sfOffset,
98
99 early.appWorkDuration.count(), early.sfWorkDuration.count(),
100
101 earlyGpu.appOffset, earlyGpu.sfOffset,
102
103 earlyGpu.appWorkDuration.count(), earlyGpu.sfWorkDuration.count());
104}
105
106PhaseOffsets::PhaseOffsets(const scheduler::RefreshRateConfigs& refreshRateConfigs)
107 : PhaseOffsets(getRefreshRatesFromConfigs(refreshRateConfigs),
108 refreshRateConfigs.getCurrentRefreshRate().getFps(),
109 sysprop::vsync_event_phase_offset_ns(1000000),
110 sysprop::vsync_sf_event_phase_offset_ns(1000000),
111 getProperty("debug.sf.early_phase_offset_ns"),
112 getProperty("debug.sf.early_gl_phase_offset_ns"),
113 getProperty("debug.sf.early_app_phase_offset_ns"),
114 getProperty("debug.sf.early_gl_app_phase_offset_ns"),
115 getProperty("debug.sf.high_fps_late_app_phase_offset_ns").value_or(2000000),
116 getProperty("debug.sf.high_fps_late_sf_phase_offset_ns").value_or(1000000),
117 getProperty("debug.sf.high_fps_early_phase_offset_ns"),
118 getProperty("debug.sf.high_fps_early_gl_phase_offset_ns"),
119 getProperty("debug.sf.high_fps_early_app_phase_offset_ns"),
120 getProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns"),
121 // Below defines the threshold when an offset is considered to be negative,
122 // i.e. targeting for the N+2 vsync instead of N+1. This means that: For offset
123 // < threshold, SF wake up (vsync_duration - offset) before HW vsync. For
124 // offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW
125 // vsync.
126 getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns")
127 .value_or(std::numeric_limits<nsecs_t>::max())) {}
128
129PhaseOffsets::PhaseOffsets(
130 const std::vector<float>& refreshRates, float currentFps, nsecs_t vsyncPhaseOffsetNs,
131 nsecs_t sfVSyncPhaseOffsetNs, std::optional<nsecs_t> earlySfOffsetNs,
132 std::optional<nsecs_t> earlyGpuSfOffsetNs, std::optional<nsecs_t> earlyAppOffsetNs,
133 std::optional<nsecs_t> earlyGpuAppOffsetNs, nsecs_t highFpsVsyncPhaseOffsetNs,
134 nsecs_t highFpsSfVSyncPhaseOffsetNs, std::optional<nsecs_t> highFpsEarlySfOffsetNs,
135 std::optional<nsecs_t> highFpsEarlyGpuSfOffsetNs,
136 std::optional<nsecs_t> highFpsEarlyAppOffsetNs,
137 std::optional<nsecs_t> highFpsEarlyGpuAppOffsetNs, nsecs_t thresholdForNextVsync)
138 : VsyncConfiguration(currentFps),
139 mVSyncPhaseOffsetNs(vsyncPhaseOffsetNs),
140 mSfVSyncPhaseOffsetNs(sfVSyncPhaseOffsetNs),
141 mEarlySfOffsetNs(earlySfOffsetNs),
142 mEarlyGpuSfOffsetNs(earlyGpuSfOffsetNs),
143 mEarlyAppOffsetNs(earlyAppOffsetNs),
144 mEarlyGpuAppOffsetNs(earlyGpuAppOffsetNs),
145 mHighFpsVSyncPhaseOffsetNs(highFpsVsyncPhaseOffsetNs),
146 mHighFpsSfVSyncPhaseOffsetNs(highFpsSfVSyncPhaseOffsetNs),
147 mHighFpsEarlySfOffsetNs(highFpsEarlySfOffsetNs),
148 mHighFpsEarlyGpuSfOffsetNs(highFpsEarlyGpuSfOffsetNs),
149 mHighFpsEarlyAppOffsetNs(highFpsEarlyAppOffsetNs),
150 mHighFpsEarlyGpuAppOffsetNs(highFpsEarlyGpuAppOffsetNs),
151 mThresholdForNextVsync(thresholdForNextVsync) {
152 initializeOffsets(refreshRates);
153}
154
155PhaseOffsets::VsyncConfigSet PhaseOffsets::constructOffsets(nsecs_t vsyncDuration) const {
156 if (vsyncDuration < std::chrono::nanoseconds(15ms).count()) {
157 return getHighFpsOffsets(vsyncDuration);
158 } else {
159 return getDefaultOffsets(vsyncDuration);
160 }
161}
162
163namespace {
164std::chrono::nanoseconds sfOffsetToDuration(nsecs_t sfOffset, nsecs_t vsyncDuration) {
165 return std::chrono::nanoseconds(vsyncDuration - sfOffset);
166}
167
168std::chrono::nanoseconds appOffsetToDuration(nsecs_t appOffset, nsecs_t sfOffset,
169 nsecs_t vsyncDuration) {
170 auto duration = vsyncDuration + (sfOffset - appOffset);
171 if (duration < vsyncDuration) {
172 duration += vsyncDuration;
173 }
174
175 return std::chrono::nanoseconds(duration);
176}
177} // namespace
178
179PhaseOffsets::VsyncConfigSet PhaseOffsets::getDefaultOffsets(nsecs_t vsyncDuration) const {
180 const auto earlySfOffset =
181 mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
182
183 ? mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs)
184 : mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) - vsyncDuration;
185 const auto earlyAppOffset = mEarlyAppOffsetNs.value_or(mVSyncPhaseOffsetNs);
186 const auto earlyGpuSfOffset =
187 mEarlyGpuSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
188
189 ? mEarlyGpuSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs)
190 : mEarlyGpuSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) - vsyncDuration;
191 const auto earlyGpuAppOffset = mEarlyGpuAppOffsetNs.value_or(mVSyncPhaseOffsetNs);
192 const auto lateSfOffset = mSfVSyncPhaseOffsetNs < mThresholdForNextVsync
193 ? mSfVSyncPhaseOffsetNs
194 : mSfVSyncPhaseOffsetNs - vsyncDuration;
195 const auto lateAppOffset = mVSyncPhaseOffsetNs;
196
197 return {
198 .early = {.sfOffset = earlySfOffset,
199 .appOffset = earlyAppOffset,
200 .sfWorkDuration = sfOffsetToDuration(earlySfOffset, vsyncDuration),
201 .appWorkDuration =
202 appOffsetToDuration(earlyAppOffset, earlySfOffset, vsyncDuration)},
203 .earlyGpu = {.sfOffset = earlyGpuSfOffset,
204 .appOffset = earlyGpuAppOffset,
205 .sfWorkDuration = sfOffsetToDuration(earlyGpuSfOffset, vsyncDuration),
206 .appWorkDuration = appOffsetToDuration(earlyGpuAppOffset, earlyGpuSfOffset,
207 vsyncDuration)},
208 .late = {.sfOffset = lateSfOffset,
209 .appOffset = lateAppOffset,
210 .sfWorkDuration = sfOffsetToDuration(lateSfOffset, vsyncDuration),
211 .appWorkDuration =
212 appOffsetToDuration(lateAppOffset, lateSfOffset, vsyncDuration)},
213 };
214}
215
216PhaseOffsets::VsyncConfigSet PhaseOffsets::getHighFpsOffsets(nsecs_t vsyncDuration) const {
217 const auto earlySfOffset =
218 mHighFpsEarlySfOffsetNs.value_or(mHighFpsSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
219 ? mHighFpsEarlySfOffsetNs.value_or(mHighFpsSfVSyncPhaseOffsetNs)
220 : mHighFpsEarlySfOffsetNs.value_or(mHighFpsSfVSyncPhaseOffsetNs) - vsyncDuration;
221 const auto earlyAppOffset = mHighFpsEarlyAppOffsetNs.value_or(mHighFpsVSyncPhaseOffsetNs);
222 const auto earlyGpuSfOffset = mHighFpsEarlyGpuSfOffsetNs.value_or(
223 mHighFpsSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
224
225 ? mHighFpsEarlyGpuSfOffsetNs.value_or(mHighFpsSfVSyncPhaseOffsetNs)
226 : mHighFpsEarlyGpuSfOffsetNs.value_or(mHighFpsSfVSyncPhaseOffsetNs) - vsyncDuration;
227 const auto earlyGpuAppOffset = mHighFpsEarlyGpuAppOffsetNs.value_or(mHighFpsVSyncPhaseOffsetNs);
228 const auto lateSfOffset = mHighFpsSfVSyncPhaseOffsetNs < mThresholdForNextVsync
229 ? mHighFpsSfVSyncPhaseOffsetNs
230 : mHighFpsSfVSyncPhaseOffsetNs - vsyncDuration;
231 const auto lateAppOffset = mHighFpsVSyncPhaseOffsetNs;
232
233 return {
234 .early =
235 {
236 .sfOffset = earlySfOffset,
237 .appOffset = earlyAppOffset,
238 .sfWorkDuration = sfOffsetToDuration(earlySfOffset, vsyncDuration),
239 .appWorkDuration = appOffsetToDuration(earlyAppOffset, earlySfOffset,
240 vsyncDuration),
241 },
242 .earlyGpu =
243 {
244 .sfOffset = earlyGpuSfOffset,
245 .appOffset = earlyGpuAppOffset,
246 .sfWorkDuration = sfOffsetToDuration(earlyGpuSfOffset, vsyncDuration),
247 .appWorkDuration = appOffsetToDuration(earlyGpuAppOffset,
248 earlyGpuSfOffset, vsyncDuration),
249 },
250 .late =
251 {
252 .sfOffset = lateSfOffset,
253 .appOffset = lateAppOffset,
254 .sfWorkDuration = sfOffsetToDuration(lateSfOffset, vsyncDuration),
255 .appWorkDuration =
256 appOffsetToDuration(lateAppOffset, lateSfOffset, vsyncDuration),
257 },
258 };
Ady Abraham090d42c2020-01-08 12:08:11 -0800259}
260
Ady Abraham9e16a482019-12-03 17:19:41 -0800261static void validateSysprops() {
262 const auto validatePropertyBool = [](const char* prop) {
263 LOG_ALWAYS_FATAL_IF(!property_get_bool(prop, false), "%s is false", prop);
264 };
265
266 validatePropertyBool("debug.sf.use_phase_offsets_as_durations");
267
268 LOG_ALWAYS_FATAL_IF(sysprop::vsync_event_phase_offset_ns(-1) != -1,
269 "ro.surface_flinger.vsync_event_phase_offset_ns is set but expecting "
270 "duration");
271
272 LOG_ALWAYS_FATAL_IF(sysprop::vsync_sf_event_phase_offset_ns(-1) != -1,
273 "ro.surface_flinger.vsync_sf_event_phase_offset_ns is set but expecting "
274 "duration");
275
276 const auto validateProperty = [](const char* prop) {
277 LOG_ALWAYS_FATAL_IF(getProperty(prop).has_value(),
278 "%s is set to %" PRId64 " but expecting duration", prop,
279 getProperty(prop).value_or(-1));
280 };
281
282 validateProperty("debug.sf.early_phase_offset_ns");
283 validateProperty("debug.sf.early_gl_phase_offset_ns");
284 validateProperty("debug.sf.early_app_phase_offset_ns");
285 validateProperty("debug.sf.early_gl_app_phase_offset_ns");
286 validateProperty("debug.sf.high_fps_late_app_phase_offset_ns");
287 validateProperty("debug.sf.high_fps_late_sf_phase_offset_ns");
288 validateProperty("debug.sf.high_fps_early_phase_offset_ns");
289 validateProperty("debug.sf.high_fps_early_gl_phase_offset_ns");
290 validateProperty("debug.sf.high_fps_early_app_phase_offset_ns");
291 validateProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns");
292}
293
Ady Abraham8287e852020-08-12 14:44:58 -0700294namespace {
295nsecs_t sfDurationToOffset(std::chrono::nanoseconds sfDuration, nsecs_t vsyncDuration) {
296 return vsyncDuration - sfDuration.count() % vsyncDuration;
Ady Abraham9e16a482019-12-03 17:19:41 -0800297}
298
Ady Abraham8287e852020-08-12 14:44:58 -0700299nsecs_t appDurationToOffset(std::chrono::nanoseconds appDuration,
300 std::chrono::nanoseconds sfDuration, nsecs_t vsyncDuration) {
301 return vsyncDuration - (appDuration + sfDuration).count() % vsyncDuration;
Ady Abraham9e16a482019-12-03 17:19:41 -0800302}
Ady Abraham8287e852020-08-12 14:44:58 -0700303} // namespace
Ady Abraham9e16a482019-12-03 17:19:41 -0800304
Ady Abraham8287e852020-08-12 14:44:58 -0700305WorkDuration::VsyncConfigSet WorkDuration::constructOffsets(nsecs_t vsyncDuration) const {
306 const auto sfDurationFixup = [vsyncDuration](nsecs_t duration) {
307 return duration == -1 ? std::chrono::nanoseconds(vsyncDuration) - 1ms
308 : std::chrono::nanoseconds(duration);
309 };
Ady Abrahamdfa37362020-01-21 18:02:39 -0800310
Ady Abraham8287e852020-08-12 14:44:58 -0700311 const auto appDurationFixup = [vsyncDuration](nsecs_t duration) {
312 return duration == -1 ? std::chrono::nanoseconds(vsyncDuration)
313 : std::chrono::nanoseconds(duration);
314 };
Ady Abrahamdfa37362020-01-21 18:02:39 -0800315
Ady Abraham8287e852020-08-12 14:44:58 -0700316 const auto sfEarlyDuration = sfDurationFixup(mSfEarlyDuration);
317 const auto appEarlyDuration = appDurationFixup(mAppEarlyDuration);
318 const auto sfEarlyGpuDuration = sfDurationFixup(mSfEarlyGpuDuration);
319 const auto appEarlyGpuDuration = appDurationFixup(mAppEarlyGpuDuration);
320 const auto sfDuration = sfDurationFixup(mSfDuration);
321 const auto appDuration = appDurationFixup(mAppDuration);
Ady Abrahamdfa37362020-01-21 18:02:39 -0800322
Ady Abraham8287e852020-08-12 14:44:58 -0700323 return {
324 .early =
325 {
326
327 .sfOffset = sfEarlyDuration.count() < vsyncDuration
328 ? sfDurationToOffset(sfEarlyDuration, vsyncDuration)
329 : sfDurationToOffset(sfEarlyDuration, vsyncDuration) -
330 vsyncDuration,
331
332 .appOffset = appDurationToOffset(appEarlyDuration, sfEarlyDuration,
333 vsyncDuration),
334
335 .sfWorkDuration = sfEarlyDuration,
336 .appWorkDuration = appEarlyDuration,
337 },
338 .earlyGpu =
339 {
340
341 .sfOffset = sfEarlyGpuDuration.count() < vsyncDuration
342
343 ? sfDurationToOffset(sfEarlyGpuDuration, vsyncDuration)
344 : sfDurationToOffset(sfEarlyGpuDuration, vsyncDuration) -
345 vsyncDuration,
346
347 .appOffset = appDurationToOffset(appEarlyGpuDuration,
348 sfEarlyGpuDuration, vsyncDuration),
349 .sfWorkDuration = sfEarlyGpuDuration,
350 .appWorkDuration = appEarlyGpuDuration,
351 },
352 .late =
353 {
354
355 .sfOffset = sfDuration.count() < vsyncDuration
356
357 ? sfDurationToOffset(sfDuration, vsyncDuration)
358 : sfDurationToOffset(sfDuration, vsyncDuration) - vsyncDuration,
359
360 .appOffset =
361 appDurationToOffset(appDuration, sfDuration, vsyncDuration),
362
363 .sfWorkDuration = sfDuration,
364 .appWorkDuration = appDuration,
365 },
Ady Abrahamdfa37362020-01-21 18:02:39 -0800366 };
367}
368
Ady Abraham8287e852020-08-12 14:44:58 -0700369WorkDuration::WorkDuration(const scheduler::RefreshRateConfigs& refreshRateConfigs)
370 : WorkDuration(getRefreshRatesFromConfigs(refreshRateConfigs),
371 refreshRateConfigs.getCurrentRefreshRate().getFps(),
372 getProperty("debug.sf.late.sf.duration").value_or(-1),
373 getProperty("debug.sf.late.app.duration").value_or(-1),
374 getProperty("debug.sf.early.sf.duration").value_or(mSfDuration),
375 getProperty("debug.sf.early.app.duration").value_or(mAppDuration),
376 getProperty("debug.sf.earlyGl.sf.duration").value_or(mSfDuration),
377 getProperty("debug.sf.earlyGl.app.duration").value_or(mAppDuration)) {
Ady Abraham9e16a482019-12-03 17:19:41 -0800378 validateSysprops();
379}
380
Ady Abraham8287e852020-08-12 14:44:58 -0700381WorkDuration::WorkDuration(const std::vector<float>& refreshRates, float currentFps,
382 nsecs_t sfDuration, nsecs_t appDuration, nsecs_t sfEarlyDuration,
383 nsecs_t appEarlyDuration, nsecs_t sfEarlyGpuDuration,
384 nsecs_t appEarlyGpuDuration)
385 : VsyncConfiguration(currentFps),
386 mSfDuration(sfDuration),
Ady Abraham9e16a482019-12-03 17:19:41 -0800387 mAppDuration(appDuration),
388 mSfEarlyDuration(sfEarlyDuration),
389 mAppEarlyDuration(appEarlyDuration),
Ady Abraham8287e852020-08-12 14:44:58 -0700390 mSfEarlyGpuDuration(sfEarlyGpuDuration),
391 mAppEarlyGpuDuration(appEarlyGpuDuration) {
392 initializeOffsets(refreshRates);
Ady Abraham9e16a482019-12-03 17:19:41 -0800393}
394
Ady Abraham8287e852020-08-12 14:44:58 -0700395} // namespace android::scheduler::impl