• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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