1 /*
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 "VsyncConfiguration.h"
18
19 #include <chrono>
20 #include <cinttypes>
21 #include <optional>
22
23 #include <cutils/properties.h>
24 #include <log/log.h>
25
26 #include "SurfaceFlingerProperties.h"
27
28 namespace {
29
30 using namespace std::chrono_literals;
31
getProperty(const char * name)32 std::optional<nsecs_t> getProperty(const char* name) {
33 char value[PROPERTY_VALUE_MAX];
34 property_get(name, value, "-1");
35 if (const int i = atoi(value); i != -1) return i;
36 return std::nullopt;
37 }
38
39 } // namespace
40
41 namespace android::scheduler::impl {
42
VsyncConfiguration(Fps currentFps)43 VsyncConfiguration::VsyncConfiguration(Fps currentFps) : mRefreshRateFps(currentFps) {}
44
getConfigsForRefreshRate(Fps fps) const45 PhaseOffsets::VsyncConfigSet VsyncConfiguration::getConfigsForRefreshRate(Fps fps) const {
46 std::lock_guard lock(mLock);
47 return getConfigsForRefreshRateLocked(fps);
48 }
49
getConfigsForRefreshRateLocked(Fps fps) const50 PhaseOffsets::VsyncConfigSet VsyncConfiguration::getConfigsForRefreshRateLocked(Fps fps) const {
51 const auto iter = mOffsetsCache.find(fps);
52 if (iter != mOffsetsCache.end()) {
53 return iter->second;
54 }
55
56 const auto offset = constructOffsets(fps.getPeriodNsecs());
57 mOffsetsCache[fps] = offset;
58 return offset;
59 }
60
dump(std::string & result) const61 void VsyncConfiguration::dump(std::string& result) const {
62 const auto [early, earlyGpu, late, hwcMinWorkDuration] = getCurrentConfigs();
63 using base::StringAppendF;
64 StringAppendF(&result,
65 " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64
66 " ns\n"
67 " app duration: %9lld ns\t SF duration: %9lld ns\n"
68 " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64
69 " ns\n"
70 " early app duration: %9lld ns\t early SF duration: %9lld ns\n"
71 " GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64
72 " ns\n"
73 " GL early app duration: %9lld ns\tGL early SF duration: %9lld ns\n"
74 " HWC min duration: %9lld ns\n",
75 late.appOffset, late.sfOffset,
76
77 late.appWorkDuration.count(), late.sfWorkDuration.count(),
78
79 early.appOffset, early.sfOffset,
80
81 early.appWorkDuration.count(), early.sfWorkDuration.count(),
82
83 earlyGpu.appOffset, earlyGpu.sfOffset,
84
85 earlyGpu.appWorkDuration.count(), earlyGpu.sfWorkDuration.count(),
86
87 hwcMinWorkDuration.count());
88 }
89
PhaseOffsets(Fps currentRefreshRate)90 PhaseOffsets::PhaseOffsets(Fps currentRefreshRate)
91 : PhaseOffsets(currentRefreshRate, sysprop::vsync_event_phase_offset_ns(1000000),
92 sysprop::vsync_sf_event_phase_offset_ns(1000000),
93 getProperty("debug.sf.early_phase_offset_ns"),
94 getProperty("debug.sf.early_gl_phase_offset_ns"),
95 getProperty("debug.sf.early_app_phase_offset_ns"),
96 getProperty("debug.sf.early_gl_app_phase_offset_ns"),
97 getProperty("debug.sf.high_fps_late_app_phase_offset_ns").value_or(2000000),
98 getProperty("debug.sf.high_fps_late_sf_phase_offset_ns").value_or(1000000),
99 getProperty("debug.sf.high_fps_early_phase_offset_ns"),
100 getProperty("debug.sf.high_fps_early_gl_phase_offset_ns"),
101 getProperty("debug.sf.high_fps_early_app_phase_offset_ns"),
102 getProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns"),
103 // Below defines the threshold when an offset is considered to be negative,
104 // i.e. targeting for the N+2 vsync instead of N+1. This means that: For offset
105 // < threshold, SF wake up (vsync_duration - offset) before HW vsync. For
106 // offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW
107 // vsync.
108 getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns")
109 .value_or(std::numeric_limits<nsecs_t>::max()),
110 getProperty("debug.sf.hwc.min.duration").value_or(0)) {}
111
PhaseOffsets(Fps currentFps,nsecs_t vsyncPhaseOffsetNs,nsecs_t sfVSyncPhaseOffsetNs,std::optional<nsecs_t> earlySfOffsetNs,std::optional<nsecs_t> earlyGpuSfOffsetNs,std::optional<nsecs_t> earlyAppOffsetNs,std::optional<nsecs_t> earlyGpuAppOffsetNs,nsecs_t highFpsVsyncPhaseOffsetNs,nsecs_t highFpsSfVSyncPhaseOffsetNs,std::optional<nsecs_t> highFpsEarlySfOffsetNs,std::optional<nsecs_t> highFpsEarlyGpuSfOffsetNs,std::optional<nsecs_t> highFpsEarlyAppOffsetNs,std::optional<nsecs_t> highFpsEarlyGpuAppOffsetNs,nsecs_t thresholdForNextVsync,nsecs_t hwcMinWorkDuration)112 PhaseOffsets::PhaseOffsets(Fps currentFps, nsecs_t vsyncPhaseOffsetNs, nsecs_t sfVSyncPhaseOffsetNs,
113 std::optional<nsecs_t> earlySfOffsetNs,
114 std::optional<nsecs_t> earlyGpuSfOffsetNs,
115 std::optional<nsecs_t> earlyAppOffsetNs,
116 std::optional<nsecs_t> earlyGpuAppOffsetNs,
117 nsecs_t highFpsVsyncPhaseOffsetNs, nsecs_t highFpsSfVSyncPhaseOffsetNs,
118 std::optional<nsecs_t> highFpsEarlySfOffsetNs,
119 std::optional<nsecs_t> highFpsEarlyGpuSfOffsetNs,
120 std::optional<nsecs_t> highFpsEarlyAppOffsetNs,
121 std::optional<nsecs_t> highFpsEarlyGpuAppOffsetNs,
122 nsecs_t thresholdForNextVsync, nsecs_t hwcMinWorkDuration)
123 : VsyncConfiguration(currentFps),
124 mVSyncPhaseOffsetNs(vsyncPhaseOffsetNs),
125 mSfVSyncPhaseOffsetNs(sfVSyncPhaseOffsetNs),
126 mEarlySfOffsetNs(earlySfOffsetNs),
127 mEarlyGpuSfOffsetNs(earlyGpuSfOffsetNs),
128 mEarlyAppOffsetNs(earlyAppOffsetNs),
129 mEarlyGpuAppOffsetNs(earlyGpuAppOffsetNs),
130 mHighFpsVSyncPhaseOffsetNs(highFpsVsyncPhaseOffsetNs),
131 mHighFpsSfVSyncPhaseOffsetNs(highFpsSfVSyncPhaseOffsetNs),
132 mHighFpsEarlySfOffsetNs(highFpsEarlySfOffsetNs),
133 mHighFpsEarlyGpuSfOffsetNs(highFpsEarlyGpuSfOffsetNs),
134 mHighFpsEarlyAppOffsetNs(highFpsEarlyAppOffsetNs),
135 mHighFpsEarlyGpuAppOffsetNs(highFpsEarlyGpuAppOffsetNs),
136 mThresholdForNextVsync(thresholdForNextVsync),
137 mHwcMinWorkDuration(hwcMinWorkDuration) {}
138
constructOffsets(nsecs_t vsyncDuration) const139 PhaseOffsets::VsyncConfigSet PhaseOffsets::constructOffsets(nsecs_t vsyncDuration) const {
140 if (vsyncDuration < std::chrono::nanoseconds(15ms).count()) {
141 return getHighFpsOffsets(vsyncDuration);
142 } else {
143 return getDefaultOffsets(vsyncDuration);
144 }
145 }
146
147 namespace {
sfOffsetToDuration(nsecs_t sfOffset,nsecs_t vsyncDuration)148 std::chrono::nanoseconds sfOffsetToDuration(nsecs_t sfOffset, nsecs_t vsyncDuration) {
149 return std::chrono::nanoseconds(vsyncDuration - sfOffset);
150 }
151
appOffsetToDuration(nsecs_t appOffset,nsecs_t sfOffset,nsecs_t vsyncDuration)152 std::chrono::nanoseconds appOffsetToDuration(nsecs_t appOffset, nsecs_t sfOffset,
153 nsecs_t vsyncDuration) {
154 auto duration = vsyncDuration + (sfOffset - appOffset);
155 if (duration < vsyncDuration) {
156 duration += vsyncDuration;
157 }
158
159 return std::chrono::nanoseconds(duration);
160 }
161 } // namespace
162
getDefaultOffsets(nsecs_t vsyncDuration) const163 PhaseOffsets::VsyncConfigSet PhaseOffsets::getDefaultOffsets(nsecs_t vsyncDuration) const {
164 const auto earlySfOffset =
165 mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
166
167 ? mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs)
168 : mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) - vsyncDuration;
169 const auto earlyAppOffset = mEarlyAppOffsetNs.value_or(mVSyncPhaseOffsetNs);
170 const auto earlyGpuSfOffset =
171 mEarlyGpuSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
172
173 ? mEarlyGpuSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs)
174 : mEarlyGpuSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) - vsyncDuration;
175 const auto earlyGpuAppOffset = mEarlyGpuAppOffsetNs.value_or(mVSyncPhaseOffsetNs);
176 const auto lateSfOffset = mSfVSyncPhaseOffsetNs < mThresholdForNextVsync
177 ? mSfVSyncPhaseOffsetNs
178 : mSfVSyncPhaseOffsetNs - vsyncDuration;
179 const auto lateAppOffset = mVSyncPhaseOffsetNs;
180
181 return {
182 .early = {.sfOffset = earlySfOffset,
183 .appOffset = earlyAppOffset,
184 .sfWorkDuration = sfOffsetToDuration(earlySfOffset, vsyncDuration),
185 .appWorkDuration =
186 appOffsetToDuration(earlyAppOffset, earlySfOffset, vsyncDuration)},
187 .earlyGpu = {.sfOffset = earlyGpuSfOffset,
188 .appOffset = earlyGpuAppOffset,
189 .sfWorkDuration = sfOffsetToDuration(earlyGpuSfOffset, vsyncDuration),
190 .appWorkDuration = appOffsetToDuration(earlyGpuAppOffset, earlyGpuSfOffset,
191 vsyncDuration)},
192 .late = {.sfOffset = lateSfOffset,
193 .appOffset = lateAppOffset,
194 .sfWorkDuration = sfOffsetToDuration(lateSfOffset, vsyncDuration),
195 .appWorkDuration =
196 appOffsetToDuration(lateAppOffset, lateSfOffset, vsyncDuration)},
197 .hwcMinWorkDuration = std::chrono::nanoseconds(mHwcMinWorkDuration),
198 };
199 }
200
getHighFpsOffsets(nsecs_t vsyncDuration) const201 PhaseOffsets::VsyncConfigSet PhaseOffsets::getHighFpsOffsets(nsecs_t vsyncDuration) const {
202 const auto earlySfOffset =
203 mHighFpsEarlySfOffsetNs.value_or(mHighFpsSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
204 ? mHighFpsEarlySfOffsetNs.value_or(mHighFpsSfVSyncPhaseOffsetNs)
205 : mHighFpsEarlySfOffsetNs.value_or(mHighFpsSfVSyncPhaseOffsetNs) - vsyncDuration;
206 const auto earlyAppOffset = mHighFpsEarlyAppOffsetNs.value_or(mHighFpsVSyncPhaseOffsetNs);
207 const auto earlyGpuSfOffset = mHighFpsEarlyGpuSfOffsetNs.value_or(
208 mHighFpsSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
209
210 ? mHighFpsEarlyGpuSfOffsetNs.value_or(mHighFpsSfVSyncPhaseOffsetNs)
211 : mHighFpsEarlyGpuSfOffsetNs.value_or(mHighFpsSfVSyncPhaseOffsetNs) - vsyncDuration;
212 const auto earlyGpuAppOffset = mHighFpsEarlyGpuAppOffsetNs.value_or(mHighFpsVSyncPhaseOffsetNs);
213 const auto lateSfOffset = mHighFpsSfVSyncPhaseOffsetNs < mThresholdForNextVsync
214 ? mHighFpsSfVSyncPhaseOffsetNs
215 : mHighFpsSfVSyncPhaseOffsetNs - vsyncDuration;
216 const auto lateAppOffset = mHighFpsVSyncPhaseOffsetNs;
217
218 return {
219 .early =
220 {
221 .sfOffset = earlySfOffset,
222 .appOffset = earlyAppOffset,
223 .sfWorkDuration = sfOffsetToDuration(earlySfOffset, vsyncDuration),
224 .appWorkDuration = appOffsetToDuration(earlyAppOffset, earlySfOffset,
225 vsyncDuration),
226 },
227 .earlyGpu =
228 {
229 .sfOffset = earlyGpuSfOffset,
230 .appOffset = earlyGpuAppOffset,
231 .sfWorkDuration = sfOffsetToDuration(earlyGpuSfOffset, vsyncDuration),
232 .appWorkDuration = appOffsetToDuration(earlyGpuAppOffset,
233 earlyGpuSfOffset, vsyncDuration),
234 },
235 .late =
236 {
237 .sfOffset = lateSfOffset,
238 .appOffset = lateAppOffset,
239 .sfWorkDuration = sfOffsetToDuration(lateSfOffset, vsyncDuration),
240 .appWorkDuration =
241 appOffsetToDuration(lateAppOffset, lateSfOffset, vsyncDuration),
242 },
243 .hwcMinWorkDuration = std::chrono::nanoseconds(mHwcMinWorkDuration),
244 };
245 }
246
validateSysprops()247 static void validateSysprops() {
248 const auto validatePropertyBool = [](const char* prop) {
249 LOG_ALWAYS_FATAL_IF(!property_get_bool(prop, false), "%s is false", prop);
250 };
251
252 validatePropertyBool("debug.sf.use_phase_offsets_as_durations");
253
254 LOG_ALWAYS_FATAL_IF(sysprop::vsync_event_phase_offset_ns(-1) != -1,
255 "ro.surface_flinger.vsync_event_phase_offset_ns is set but expecting "
256 "duration");
257
258 LOG_ALWAYS_FATAL_IF(sysprop::vsync_sf_event_phase_offset_ns(-1) != -1,
259 "ro.surface_flinger.vsync_sf_event_phase_offset_ns is set but expecting "
260 "duration");
261
262 const auto validateProperty = [](const char* prop) {
263 LOG_ALWAYS_FATAL_IF(getProperty(prop).has_value(),
264 "%s is set to %" PRId64 " but expecting duration", prop,
265 getProperty(prop).value_or(-1));
266 };
267
268 validateProperty("debug.sf.early_phase_offset_ns");
269 validateProperty("debug.sf.early_gl_phase_offset_ns");
270 validateProperty("debug.sf.early_app_phase_offset_ns");
271 validateProperty("debug.sf.early_gl_app_phase_offset_ns");
272 validateProperty("debug.sf.high_fps_late_app_phase_offset_ns");
273 validateProperty("debug.sf.high_fps_late_sf_phase_offset_ns");
274 validateProperty("debug.sf.high_fps_early_phase_offset_ns");
275 validateProperty("debug.sf.high_fps_early_gl_phase_offset_ns");
276 validateProperty("debug.sf.high_fps_early_app_phase_offset_ns");
277 validateProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns");
278 }
279
280 namespace {
sfDurationToOffset(std::chrono::nanoseconds sfDuration,nsecs_t vsyncDuration)281 nsecs_t sfDurationToOffset(std::chrono::nanoseconds sfDuration, nsecs_t vsyncDuration) {
282 return vsyncDuration - sfDuration.count() % vsyncDuration;
283 }
284
appDurationToOffset(std::chrono::nanoseconds appDuration,std::chrono::nanoseconds sfDuration,nsecs_t vsyncDuration)285 nsecs_t appDurationToOffset(std::chrono::nanoseconds appDuration,
286 std::chrono::nanoseconds sfDuration, nsecs_t vsyncDuration) {
287 return vsyncDuration - (appDuration + sfDuration).count() % vsyncDuration;
288 }
289 } // namespace
290
constructOffsets(nsecs_t vsyncDuration) const291 WorkDuration::VsyncConfigSet WorkDuration::constructOffsets(nsecs_t vsyncDuration) const {
292 const auto sfDurationFixup = [vsyncDuration](nsecs_t duration) {
293 return duration == -1 ? std::chrono::nanoseconds(vsyncDuration) - 1ms
294 : std::chrono::nanoseconds(duration);
295 };
296
297 const auto appDurationFixup = [vsyncDuration](nsecs_t duration) {
298 return duration == -1 ? std::chrono::nanoseconds(vsyncDuration)
299 : std::chrono::nanoseconds(duration);
300 };
301
302 const auto sfEarlyDuration = sfDurationFixup(mSfEarlyDuration);
303 const auto appEarlyDuration = appDurationFixup(mAppEarlyDuration);
304 const auto sfEarlyGpuDuration = sfDurationFixup(mSfEarlyGpuDuration);
305 const auto appEarlyGpuDuration = appDurationFixup(mAppEarlyGpuDuration);
306 const auto sfDuration = sfDurationFixup(mSfDuration);
307 const auto appDuration = appDurationFixup(mAppDuration);
308
309 return {
310 .early =
311 {
312
313 .sfOffset = sfEarlyDuration.count() < vsyncDuration
314 ? sfDurationToOffset(sfEarlyDuration, vsyncDuration)
315 : sfDurationToOffset(sfEarlyDuration, vsyncDuration) -
316 vsyncDuration,
317
318 .appOffset = appDurationToOffset(appEarlyDuration, sfEarlyDuration,
319 vsyncDuration),
320
321 .sfWorkDuration = sfEarlyDuration,
322 .appWorkDuration = appEarlyDuration,
323 },
324 .earlyGpu =
325 {
326
327 .sfOffset = sfEarlyGpuDuration.count() < vsyncDuration
328
329 ? sfDurationToOffset(sfEarlyGpuDuration, vsyncDuration)
330 : sfDurationToOffset(sfEarlyGpuDuration, vsyncDuration) -
331 vsyncDuration,
332
333 .appOffset = appDurationToOffset(appEarlyGpuDuration,
334 sfEarlyGpuDuration, vsyncDuration),
335 .sfWorkDuration = sfEarlyGpuDuration,
336 .appWorkDuration = appEarlyGpuDuration,
337 },
338 .late =
339 {
340
341 .sfOffset = sfDuration.count() < vsyncDuration
342
343 ? sfDurationToOffset(sfDuration, vsyncDuration)
344 : sfDurationToOffset(sfDuration, vsyncDuration) - vsyncDuration,
345
346 .appOffset =
347 appDurationToOffset(appDuration, sfDuration, vsyncDuration),
348
349 .sfWorkDuration = sfDuration,
350 .appWorkDuration = appDuration,
351 },
352 .hwcMinWorkDuration = std::chrono::nanoseconds(mHwcMinWorkDuration),
353 };
354 }
355
WorkDuration(Fps currentRefreshRate)356 WorkDuration::WorkDuration(Fps currentRefreshRate)
357 : WorkDuration(currentRefreshRate, getProperty("debug.sf.late.sf.duration").value_or(-1),
358 getProperty("debug.sf.late.app.duration").value_or(-1),
359 getProperty("debug.sf.early.sf.duration").value_or(mSfDuration),
360 getProperty("debug.sf.early.app.duration").value_or(mAppDuration),
361 getProperty("debug.sf.earlyGl.sf.duration").value_or(mSfDuration),
362 getProperty("debug.sf.earlyGl.app.duration").value_or(mAppDuration),
363 getProperty("debug.sf.hwc.min.duration").value_or(0)) {
364 validateSysprops();
365 }
366
WorkDuration(Fps currentRefreshRate,nsecs_t sfDuration,nsecs_t appDuration,nsecs_t sfEarlyDuration,nsecs_t appEarlyDuration,nsecs_t sfEarlyGpuDuration,nsecs_t appEarlyGpuDuration,nsecs_t hwcMinWorkDuration)367 WorkDuration::WorkDuration(Fps currentRefreshRate, nsecs_t sfDuration, nsecs_t appDuration,
368 nsecs_t sfEarlyDuration, nsecs_t appEarlyDuration,
369 nsecs_t sfEarlyGpuDuration, nsecs_t appEarlyGpuDuration,
370 nsecs_t hwcMinWorkDuration)
371 : VsyncConfiguration(currentRefreshRate),
372 mSfDuration(sfDuration),
373 mAppDuration(appDuration),
374 mSfEarlyDuration(sfEarlyDuration),
375 mAppEarlyDuration(appEarlyDuration),
376 mSfEarlyGpuDuration(sfEarlyGpuDuration),
377 mAppEarlyGpuDuration(appEarlyGpuDuration),
378 mHwcMinWorkDuration(hwcMinWorkDuration) {}
379
380 } // namespace android::scheduler::impl
381