blob: 8431323888d17e6789de7a4da51cf282e67cff29 [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
Marin Shalamanove8a663d2020-11-24 17:48:00 +010034std::vector<android::Fps> getRefreshRatesFromConfigs(
Ady Abraham60120a02020-03-23 11:23:26 -070035 const android::scheduler::RefreshRateConfigs& refreshRateConfigs) {
36 const auto& allRefreshRates = refreshRateConfigs.getAllRefreshRates();
Marin Shalamanove8a663d2020-11-24 17:48:00 +010037 std::vector<android::Fps> refreshRates;
Ady Abraham60120a02020-03-23 11:23:26 -070038 refreshRates.reserve(allRefreshRates.size());
39
40 for (const auto& [ignored, refreshRate] : allRefreshRates) {
Ady Abrahamabc27602020-04-08 17:20:29 -070041 refreshRates.emplace_back(refreshRate->getFps());
Ady Abraham60120a02020-03-23 11:23:26 -070042 }
43
44 return refreshRates;
45}
46
Dominik Laskowskieddeda12019-07-19 11:54:13 -070047} // namespace
48
Ady Abraham8287e852020-08-12 14:44:58 -070049namespace android::scheduler::impl {
Dominik Laskowskieddeda12019-07-19 11:54:13 -070050
Marin Shalamanove8a663d2020-11-24 17:48:00 +010051VsyncConfiguration::VsyncConfiguration(Fps currentFps) : mRefreshRateFps(currentFps) {}
Ana Krulec757f63a2019-01-25 10:46:18 -080052
Marin Shalamanove8a663d2020-11-24 17:48:00 +010053PhaseOffsets::VsyncConfigSet VsyncConfiguration::getConfigsForRefreshRate(Fps fps) const {
Ady Abraham090d42c2020-01-08 12:08:11 -080054 const auto iter = std::find_if(mOffsets.begin(), mOffsets.end(),
Marin Shalamanove8a663d2020-11-24 17:48:00 +010055 [&fps](const std::pair<Fps, VsyncConfigSet>& candidateFps) {
56 return fps.equalsWithMargin(candidateFps.first);
Ady Abraham090d42c2020-01-08 12:08:11 -080057 });
Sushil Chauhanbdb9e6d2020-03-19 16:15:46 -070058
59 if (iter != mOffsets.end()) {
60 return iter->second;
61 }
62
63 // Unknown refresh rate. This might happen if we get a hotplug event for an external display.
64 // In this case just construct the offset.
Marin Shalamanove8a663d2020-11-24 17:48:00 +010065 ALOGW("Can't find offset for %s", to_string(fps).c_str());
66 return constructOffsets(fps.getPeriodNsecs());
Ady Abraham8287e852020-08-12 14:44:58 -070067}
68
Marin Shalamanove8a663d2020-11-24 17:48:00 +010069void VsyncConfiguration::initializeOffsets(const std::vector<Fps>& refreshRates) {
Ady Abraham8287e852020-08-12 14:44:58 -070070 for (const auto fps : refreshRates) {
Marin Shalamanove8a663d2020-11-24 17:48:00 +010071 mOffsets.emplace(fps, constructOffsets(fps.getPeriodNsecs()));
Ady Abraham8287e852020-08-12 14:44:58 -070072 }
73}
74
75void VsyncConfiguration::dump(std::string& result) const {
76 const auto [early, earlyGpu, late] = getCurrentConfigs();
77 using base::StringAppendF;
78 StringAppendF(&result,
79 " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64
80 " ns\n"
81 " app duration: %9lld ns\t SF duration: %9lld ns\n"
82 " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64
83 " ns\n"
84 " early app duration: %9lld ns\t early SF duration: %9lld ns\n"
85 " GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64
86 " ns\n"
87 " GL early app duration: %9lld ns\tGL early SF duration: %9lld ns\n",
88 late.appOffset, late.sfOffset,
89
90 late.appWorkDuration.count(), late.sfWorkDuration.count(),
91
92 early.appOffset, early.sfOffset,
93
94 early.appWorkDuration.count(), early.sfWorkDuration.count(),
95
96 earlyGpu.appOffset, earlyGpu.sfOffset,
97
98 earlyGpu.appWorkDuration.count(), earlyGpu.sfWorkDuration.count());
99}
100
101PhaseOffsets::PhaseOffsets(const scheduler::RefreshRateConfigs& refreshRateConfigs)
102 : PhaseOffsets(getRefreshRatesFromConfigs(refreshRateConfigs),
103 refreshRateConfigs.getCurrentRefreshRate().getFps(),
104 sysprop::vsync_event_phase_offset_ns(1000000),
105 sysprop::vsync_sf_event_phase_offset_ns(1000000),
106 getProperty("debug.sf.early_phase_offset_ns"),
107 getProperty("debug.sf.early_gl_phase_offset_ns"),
108 getProperty("debug.sf.early_app_phase_offset_ns"),
109 getProperty("debug.sf.early_gl_app_phase_offset_ns"),
110 getProperty("debug.sf.high_fps_late_app_phase_offset_ns").value_or(2000000),
111 getProperty("debug.sf.high_fps_late_sf_phase_offset_ns").value_or(1000000),
112 getProperty("debug.sf.high_fps_early_phase_offset_ns"),
113 getProperty("debug.sf.high_fps_early_gl_phase_offset_ns"),
114 getProperty("debug.sf.high_fps_early_app_phase_offset_ns"),
115 getProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns"),
116 // Below defines the threshold when an offset is considered to be negative,
117 // i.e. targeting for the N+2 vsync instead of N+1. This means that: For offset
118 // < threshold, SF wake up (vsync_duration - offset) before HW vsync. For
119 // offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW
120 // vsync.
121 getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns")
122 .value_or(std::numeric_limits<nsecs_t>::max())) {}
123
124PhaseOffsets::PhaseOffsets(
Marin Shalamanove8a663d2020-11-24 17:48:00 +0100125 const std::vector<Fps>& refreshRates, Fps currentFps, nsecs_t vsyncPhaseOffsetNs,
Ady Abraham8287e852020-08-12 14:44:58 -0700126 nsecs_t sfVSyncPhaseOffsetNs, std::optional<nsecs_t> earlySfOffsetNs,
127 std::optional<nsecs_t> earlyGpuSfOffsetNs, std::optional<nsecs_t> earlyAppOffsetNs,
128 std::optional<nsecs_t> earlyGpuAppOffsetNs, nsecs_t highFpsVsyncPhaseOffsetNs,
129 nsecs_t highFpsSfVSyncPhaseOffsetNs, std::optional<nsecs_t> highFpsEarlySfOffsetNs,
130 std::optional<nsecs_t> highFpsEarlyGpuSfOffsetNs,
131 std::optional<nsecs_t> highFpsEarlyAppOffsetNs,
132 std::optional<nsecs_t> highFpsEarlyGpuAppOffsetNs, nsecs_t thresholdForNextVsync)
133 : VsyncConfiguration(currentFps),
134 mVSyncPhaseOffsetNs(vsyncPhaseOffsetNs),
135 mSfVSyncPhaseOffsetNs(sfVSyncPhaseOffsetNs),
136 mEarlySfOffsetNs(earlySfOffsetNs),
137 mEarlyGpuSfOffsetNs(earlyGpuSfOffsetNs),
138 mEarlyAppOffsetNs(earlyAppOffsetNs),
139 mEarlyGpuAppOffsetNs(earlyGpuAppOffsetNs),
140 mHighFpsVSyncPhaseOffsetNs(highFpsVsyncPhaseOffsetNs),
141 mHighFpsSfVSyncPhaseOffsetNs(highFpsSfVSyncPhaseOffsetNs),
142 mHighFpsEarlySfOffsetNs(highFpsEarlySfOffsetNs),
143 mHighFpsEarlyGpuSfOffsetNs(highFpsEarlyGpuSfOffsetNs),
144 mHighFpsEarlyAppOffsetNs(highFpsEarlyAppOffsetNs),
145 mHighFpsEarlyGpuAppOffsetNs(highFpsEarlyGpuAppOffsetNs),
146 mThresholdForNextVsync(thresholdForNextVsync) {
147 initializeOffsets(refreshRates);
148}
149
150PhaseOffsets::VsyncConfigSet PhaseOffsets::constructOffsets(nsecs_t vsyncDuration) const {
151 if (vsyncDuration < std::chrono::nanoseconds(15ms).count()) {
152 return getHighFpsOffsets(vsyncDuration);
153 } else {
154 return getDefaultOffsets(vsyncDuration);
155 }
156}
157
158namespace {
159std::chrono::nanoseconds sfOffsetToDuration(nsecs_t sfOffset, nsecs_t vsyncDuration) {
160 return std::chrono::nanoseconds(vsyncDuration - sfOffset);
161}
162
163std::chrono::nanoseconds appOffsetToDuration(nsecs_t appOffset, nsecs_t sfOffset,
164 nsecs_t vsyncDuration) {
165 auto duration = vsyncDuration + (sfOffset - appOffset);
166 if (duration < vsyncDuration) {
167 duration += vsyncDuration;
168 }
169
170 return std::chrono::nanoseconds(duration);
171}
172} // namespace
173
174PhaseOffsets::VsyncConfigSet PhaseOffsets::getDefaultOffsets(nsecs_t vsyncDuration) const {
175 const auto earlySfOffset =
176 mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
177
178 ? mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs)
179 : mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) - vsyncDuration;
180 const auto earlyAppOffset = mEarlyAppOffsetNs.value_or(mVSyncPhaseOffsetNs);
181 const auto earlyGpuSfOffset =
182 mEarlyGpuSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
183
184 ? mEarlyGpuSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs)
185 : mEarlyGpuSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) - vsyncDuration;
186 const auto earlyGpuAppOffset = mEarlyGpuAppOffsetNs.value_or(mVSyncPhaseOffsetNs);
187 const auto lateSfOffset = mSfVSyncPhaseOffsetNs < mThresholdForNextVsync
188 ? mSfVSyncPhaseOffsetNs
189 : mSfVSyncPhaseOffsetNs - vsyncDuration;
190 const auto lateAppOffset = mVSyncPhaseOffsetNs;
191
192 return {
193 .early = {.sfOffset = earlySfOffset,
194 .appOffset = earlyAppOffset,
195 .sfWorkDuration = sfOffsetToDuration(earlySfOffset, vsyncDuration),
196 .appWorkDuration =
197 appOffsetToDuration(earlyAppOffset, earlySfOffset, vsyncDuration)},
198 .earlyGpu = {.sfOffset = earlyGpuSfOffset,
199 .appOffset = earlyGpuAppOffset,
200 .sfWorkDuration = sfOffsetToDuration(earlyGpuSfOffset, vsyncDuration),
201 .appWorkDuration = appOffsetToDuration(earlyGpuAppOffset, earlyGpuSfOffset,
202 vsyncDuration)},
203 .late = {.sfOffset = lateSfOffset,
204 .appOffset = lateAppOffset,
205 .sfWorkDuration = sfOffsetToDuration(lateSfOffset, vsyncDuration),
206 .appWorkDuration =
207 appOffsetToDuration(lateAppOffset, lateSfOffset, vsyncDuration)},
208 };
209}
210
211PhaseOffsets::VsyncConfigSet PhaseOffsets::getHighFpsOffsets(nsecs_t vsyncDuration) const {
212 const auto earlySfOffset =
213 mHighFpsEarlySfOffsetNs.value_or(mHighFpsSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
214 ? mHighFpsEarlySfOffsetNs.value_or(mHighFpsSfVSyncPhaseOffsetNs)
215 : mHighFpsEarlySfOffsetNs.value_or(mHighFpsSfVSyncPhaseOffsetNs) - vsyncDuration;
216 const auto earlyAppOffset = mHighFpsEarlyAppOffsetNs.value_or(mHighFpsVSyncPhaseOffsetNs);
217 const auto earlyGpuSfOffset = mHighFpsEarlyGpuSfOffsetNs.value_or(
218 mHighFpsSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
219
220 ? mHighFpsEarlyGpuSfOffsetNs.value_or(mHighFpsSfVSyncPhaseOffsetNs)
221 : mHighFpsEarlyGpuSfOffsetNs.value_or(mHighFpsSfVSyncPhaseOffsetNs) - vsyncDuration;
222 const auto earlyGpuAppOffset = mHighFpsEarlyGpuAppOffsetNs.value_or(mHighFpsVSyncPhaseOffsetNs);
223 const auto lateSfOffset = mHighFpsSfVSyncPhaseOffsetNs < mThresholdForNextVsync
224 ? mHighFpsSfVSyncPhaseOffsetNs
225 : mHighFpsSfVSyncPhaseOffsetNs - vsyncDuration;
226 const auto lateAppOffset = mHighFpsVSyncPhaseOffsetNs;
227
228 return {
229 .early =
230 {
231 .sfOffset = earlySfOffset,
232 .appOffset = earlyAppOffset,
233 .sfWorkDuration = sfOffsetToDuration(earlySfOffset, vsyncDuration),
234 .appWorkDuration = appOffsetToDuration(earlyAppOffset, earlySfOffset,
235 vsyncDuration),
236 },
237 .earlyGpu =
238 {
239 .sfOffset = earlyGpuSfOffset,
240 .appOffset = earlyGpuAppOffset,
241 .sfWorkDuration = sfOffsetToDuration(earlyGpuSfOffset, vsyncDuration),
242 .appWorkDuration = appOffsetToDuration(earlyGpuAppOffset,
243 earlyGpuSfOffset, vsyncDuration),
244 },
245 .late =
246 {
247 .sfOffset = lateSfOffset,
248 .appOffset = lateAppOffset,
249 .sfWorkDuration = sfOffsetToDuration(lateSfOffset, vsyncDuration),
250 .appWorkDuration =
251 appOffsetToDuration(lateAppOffset, lateSfOffset, vsyncDuration),
252 },
253 };
Ady Abraham090d42c2020-01-08 12:08:11 -0800254}
255
Ady Abraham9e16a482019-12-03 17:19:41 -0800256static void validateSysprops() {
257 const auto validatePropertyBool = [](const char* prop) {
258 LOG_ALWAYS_FATAL_IF(!property_get_bool(prop, false), "%s is false", prop);
259 };
260
261 validatePropertyBool("debug.sf.use_phase_offsets_as_durations");
262
263 LOG_ALWAYS_FATAL_IF(sysprop::vsync_event_phase_offset_ns(-1) != -1,
264 "ro.surface_flinger.vsync_event_phase_offset_ns is set but expecting "
265 "duration");
266
267 LOG_ALWAYS_FATAL_IF(sysprop::vsync_sf_event_phase_offset_ns(-1) != -1,
268 "ro.surface_flinger.vsync_sf_event_phase_offset_ns is set but expecting "
269 "duration");
270
271 const auto validateProperty = [](const char* prop) {
272 LOG_ALWAYS_FATAL_IF(getProperty(prop).has_value(),
273 "%s is set to %" PRId64 " but expecting duration", prop,
274 getProperty(prop).value_or(-1));
275 };
276
277 validateProperty("debug.sf.early_phase_offset_ns");
278 validateProperty("debug.sf.early_gl_phase_offset_ns");
279 validateProperty("debug.sf.early_app_phase_offset_ns");
280 validateProperty("debug.sf.early_gl_app_phase_offset_ns");
281 validateProperty("debug.sf.high_fps_late_app_phase_offset_ns");
282 validateProperty("debug.sf.high_fps_late_sf_phase_offset_ns");
283 validateProperty("debug.sf.high_fps_early_phase_offset_ns");
284 validateProperty("debug.sf.high_fps_early_gl_phase_offset_ns");
285 validateProperty("debug.sf.high_fps_early_app_phase_offset_ns");
286 validateProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns");
287}
288
Ady Abraham8287e852020-08-12 14:44:58 -0700289namespace {
290nsecs_t sfDurationToOffset(std::chrono::nanoseconds sfDuration, nsecs_t vsyncDuration) {
291 return vsyncDuration - sfDuration.count() % vsyncDuration;
Ady Abraham9e16a482019-12-03 17:19:41 -0800292}
293
Ady Abraham8287e852020-08-12 14:44:58 -0700294nsecs_t appDurationToOffset(std::chrono::nanoseconds appDuration,
295 std::chrono::nanoseconds sfDuration, nsecs_t vsyncDuration) {
296 return vsyncDuration - (appDuration + sfDuration).count() % vsyncDuration;
Ady Abraham9e16a482019-12-03 17:19:41 -0800297}
Ady Abraham8287e852020-08-12 14:44:58 -0700298} // namespace
Ady Abraham9e16a482019-12-03 17:19:41 -0800299
Ady Abraham8287e852020-08-12 14:44:58 -0700300WorkDuration::VsyncConfigSet WorkDuration::constructOffsets(nsecs_t vsyncDuration) const {
301 const auto sfDurationFixup = [vsyncDuration](nsecs_t duration) {
302 return duration == -1 ? std::chrono::nanoseconds(vsyncDuration) - 1ms
303 : std::chrono::nanoseconds(duration);
304 };
Ady Abrahamdfa37362020-01-21 18:02:39 -0800305
Ady Abraham8287e852020-08-12 14:44:58 -0700306 const auto appDurationFixup = [vsyncDuration](nsecs_t duration) {
307 return duration == -1 ? std::chrono::nanoseconds(vsyncDuration)
308 : std::chrono::nanoseconds(duration);
309 };
Ady Abrahamdfa37362020-01-21 18:02:39 -0800310
Ady Abraham8287e852020-08-12 14:44:58 -0700311 const auto sfEarlyDuration = sfDurationFixup(mSfEarlyDuration);
312 const auto appEarlyDuration = appDurationFixup(mAppEarlyDuration);
313 const auto sfEarlyGpuDuration = sfDurationFixup(mSfEarlyGpuDuration);
314 const auto appEarlyGpuDuration = appDurationFixup(mAppEarlyGpuDuration);
315 const auto sfDuration = sfDurationFixup(mSfDuration);
316 const auto appDuration = appDurationFixup(mAppDuration);
Ady Abrahamdfa37362020-01-21 18:02:39 -0800317
Ady Abraham8287e852020-08-12 14:44:58 -0700318 return {
319 .early =
320 {
321
322 .sfOffset = sfEarlyDuration.count() < vsyncDuration
323 ? sfDurationToOffset(sfEarlyDuration, vsyncDuration)
324 : sfDurationToOffset(sfEarlyDuration, vsyncDuration) -
325 vsyncDuration,
326
327 .appOffset = appDurationToOffset(appEarlyDuration, sfEarlyDuration,
328 vsyncDuration),
329
330 .sfWorkDuration = sfEarlyDuration,
331 .appWorkDuration = appEarlyDuration,
332 },
333 .earlyGpu =
334 {
335
336 .sfOffset = sfEarlyGpuDuration.count() < vsyncDuration
337
338 ? sfDurationToOffset(sfEarlyGpuDuration, vsyncDuration)
339 : sfDurationToOffset(sfEarlyGpuDuration, vsyncDuration) -
340 vsyncDuration,
341
342 .appOffset = appDurationToOffset(appEarlyGpuDuration,
343 sfEarlyGpuDuration, vsyncDuration),
344 .sfWorkDuration = sfEarlyGpuDuration,
345 .appWorkDuration = appEarlyGpuDuration,
346 },
347 .late =
348 {
349
350 .sfOffset = sfDuration.count() < vsyncDuration
351
352 ? sfDurationToOffset(sfDuration, vsyncDuration)
353 : sfDurationToOffset(sfDuration, vsyncDuration) - vsyncDuration,
354
355 .appOffset =
356 appDurationToOffset(appDuration, sfDuration, vsyncDuration),
357
358 .sfWorkDuration = sfDuration,
359 .appWorkDuration = appDuration,
360 },
Ady Abrahamdfa37362020-01-21 18:02:39 -0800361 };
362}
363
Ady Abraham8287e852020-08-12 14:44:58 -0700364WorkDuration::WorkDuration(const scheduler::RefreshRateConfigs& refreshRateConfigs)
365 : WorkDuration(getRefreshRatesFromConfigs(refreshRateConfigs),
366 refreshRateConfigs.getCurrentRefreshRate().getFps(),
367 getProperty("debug.sf.late.sf.duration").value_or(-1),
368 getProperty("debug.sf.late.app.duration").value_or(-1),
369 getProperty("debug.sf.early.sf.duration").value_or(mSfDuration),
370 getProperty("debug.sf.early.app.duration").value_or(mAppDuration),
371 getProperty("debug.sf.earlyGl.sf.duration").value_or(mSfDuration),
372 getProperty("debug.sf.earlyGl.app.duration").value_or(mAppDuration)) {
Ady Abraham9e16a482019-12-03 17:19:41 -0800373 validateSysprops();
374}
375
Marin Shalamanove8a663d2020-11-24 17:48:00 +0100376WorkDuration::WorkDuration(const std::vector<Fps>& refreshRates, Fps currentFps, nsecs_t sfDuration,
377 nsecs_t appDuration, nsecs_t sfEarlyDuration, nsecs_t appEarlyDuration,
378 nsecs_t sfEarlyGpuDuration, nsecs_t appEarlyGpuDuration)
Ady Abraham8287e852020-08-12 14:44:58 -0700379 : VsyncConfiguration(currentFps),
380 mSfDuration(sfDuration),
Ady Abraham9e16a482019-12-03 17:19:41 -0800381 mAppDuration(appDuration),
382 mSfEarlyDuration(sfEarlyDuration),
383 mAppEarlyDuration(appEarlyDuration),
Ady Abraham8287e852020-08-12 14:44:58 -0700384 mSfEarlyGpuDuration(sfEarlyGpuDuration),
385 mAppEarlyGpuDuration(appEarlyGpuDuration) {
386 initializeOffsets(refreshRates);
Ady Abraham9e16a482019-12-03 17:19:41 -0800387}
388
Ady Abraham8287e852020-08-12 14:44:58 -0700389} // namespace android::scheduler::impl