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