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