blob: cb57aeace5be7bd85c77ff4063745bdf4f270a15 [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
Marin Shalamanov526c3382020-12-10 15:22:29 +010019#include <chrono>
20#include <cinttypes>
Dominik Laskowskieddeda12019-07-19 11:54:13 -070021#include <optional>
22
Marin Shalamanov526c3382020-12-10 15:22:29 +010023#include <cutils/properties.h>
24#include <log/log.h>
25
Ana Krulec757f63a2019-01-25 10:46:18 -080026#include "SurfaceFlingerProperties.h"
27
Dominik Laskowskieddeda12019-07-19 11:54:13 -070028namespace {
Ana Krulec757f63a2019-01-25 10:46:18 -080029
Marin Shalamanov526c3382020-12-10 15:22:29 +010030using namespace std::chrono_literals;
31
Dominik Laskowskif83570c2019-08-26 12:04:07 -070032std::optional<nsecs_t> getProperty(const char* name) {
Dominik Laskowskieddeda12019-07-19 11:54:13 -070033 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}
Ana Krulec757f63a2019-01-25 10:46:18 -080038
Dominik Laskowskieddeda12019-07-19 11:54:13 -070039} // namespace
40
Ady Abraham8287e852020-08-12 14:44:58 -070041namespace android::scheduler::impl {
Dominik Laskowskieddeda12019-07-19 11:54:13 -070042
Marin Shalamanove8a663d2020-11-24 17:48:00 +010043VsyncConfiguration::VsyncConfiguration(Fps currentFps) : mRefreshRateFps(currentFps) {}
Ana Krulec757f63a2019-01-25 10:46:18 -080044
Marin Shalamanove8a663d2020-11-24 17:48:00 +010045PhaseOffsets::VsyncConfigSet VsyncConfiguration::getConfigsForRefreshRate(Fps fps) const {
Marin Shalamanov526c3382020-12-10 15:22:29 +010046 std::lock_guard lock(mLock);
47 return getConfigsForRefreshRateLocked(fps);
48}
Sushil Chauhanbdb9e6d2020-03-19 16:15:46 -070049
Marin Shalamanov526c3382020-12-10 15:22:29 +010050PhaseOffsets::VsyncConfigSet VsyncConfiguration::getConfigsForRefreshRateLocked(Fps fps) const {
51 const auto iter = mOffsetsCache.find(fps);
52 if (iter != mOffsetsCache.end()) {
Sushil Chauhanbdb9e6d2020-03-19 16:15:46 -070053 return iter->second;
54 }
55
Marin Shalamanov526c3382020-12-10 15:22:29 +010056 const auto offset = constructOffsets(fps.getPeriodNsecs());
57 mOffsetsCache[fps] = offset;
58 return offset;
Ady Abraham8287e852020-08-12 14:44:58 -070059}
60
61void VsyncConfiguration::dump(std::string& result) const {
62 const auto [early, earlyGpu, late] = 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 late.appOffset, late.sfOffset,
75
76 late.appWorkDuration.count(), late.sfWorkDuration.count(),
77
78 early.appOffset, early.sfOffset,
79
80 early.appWorkDuration.count(), early.sfWorkDuration.count(),
81
82 earlyGpu.appOffset, earlyGpu.sfOffset,
83
84 earlyGpu.appWorkDuration.count(), earlyGpu.sfWorkDuration.count());
85}
86
Marin Shalamanov526c3382020-12-10 15:22:29 +010087PhaseOffsets::PhaseOffsets(Fps currentRefreshRate)
88 : PhaseOffsets(currentRefreshRate, sysprop::vsync_event_phase_offset_ns(1000000),
Ady Abraham8287e852020-08-12 14:44:58 -070089 sysprop::vsync_sf_event_phase_offset_ns(1000000),
90 getProperty("debug.sf.early_phase_offset_ns"),
91 getProperty("debug.sf.early_gl_phase_offset_ns"),
92 getProperty("debug.sf.early_app_phase_offset_ns"),
93 getProperty("debug.sf.early_gl_app_phase_offset_ns"),
94 getProperty("debug.sf.high_fps_late_app_phase_offset_ns").value_or(2000000),
95 getProperty("debug.sf.high_fps_late_sf_phase_offset_ns").value_or(1000000),
96 getProperty("debug.sf.high_fps_early_phase_offset_ns"),
97 getProperty("debug.sf.high_fps_early_gl_phase_offset_ns"),
98 getProperty("debug.sf.high_fps_early_app_phase_offset_ns"),
99 getProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns"),
100 // Below defines the threshold when an offset is considered to be negative,
101 // i.e. targeting for the N+2 vsync instead of N+1. This means that: For offset
102 // < threshold, SF wake up (vsync_duration - offset) before HW vsync. For
103 // offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW
104 // vsync.
105 getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns")
106 .value_or(std::numeric_limits<nsecs_t>::max())) {}
107
Marin Shalamanov526c3382020-12-10 15:22:29 +0100108PhaseOffsets::PhaseOffsets(Fps currentFps, nsecs_t vsyncPhaseOffsetNs, nsecs_t sfVSyncPhaseOffsetNs,
109 std::optional<nsecs_t> earlySfOffsetNs,
110 std::optional<nsecs_t> earlyGpuSfOffsetNs,
111 std::optional<nsecs_t> earlyAppOffsetNs,
112 std::optional<nsecs_t> earlyGpuAppOffsetNs,
113 nsecs_t highFpsVsyncPhaseOffsetNs, nsecs_t highFpsSfVSyncPhaseOffsetNs,
114 std::optional<nsecs_t> highFpsEarlySfOffsetNs,
115 std::optional<nsecs_t> highFpsEarlyGpuSfOffsetNs,
116 std::optional<nsecs_t> highFpsEarlyAppOffsetNs,
117 std::optional<nsecs_t> highFpsEarlyGpuAppOffsetNs,
118 nsecs_t thresholdForNextVsync)
Ady Abraham8287e852020-08-12 14:44:58 -0700119 : VsyncConfiguration(currentFps),
120 mVSyncPhaseOffsetNs(vsyncPhaseOffsetNs),
121 mSfVSyncPhaseOffsetNs(sfVSyncPhaseOffsetNs),
122 mEarlySfOffsetNs(earlySfOffsetNs),
123 mEarlyGpuSfOffsetNs(earlyGpuSfOffsetNs),
124 mEarlyAppOffsetNs(earlyAppOffsetNs),
125 mEarlyGpuAppOffsetNs(earlyGpuAppOffsetNs),
126 mHighFpsVSyncPhaseOffsetNs(highFpsVsyncPhaseOffsetNs),
127 mHighFpsSfVSyncPhaseOffsetNs(highFpsSfVSyncPhaseOffsetNs),
128 mHighFpsEarlySfOffsetNs(highFpsEarlySfOffsetNs),
129 mHighFpsEarlyGpuSfOffsetNs(highFpsEarlyGpuSfOffsetNs),
130 mHighFpsEarlyAppOffsetNs(highFpsEarlyAppOffsetNs),
131 mHighFpsEarlyGpuAppOffsetNs(highFpsEarlyGpuAppOffsetNs),
Marin Shalamanov526c3382020-12-10 15:22:29 +0100132 mThresholdForNextVsync(thresholdForNextVsync) {}
Ady Abraham8287e852020-08-12 14:44:58 -0700133
134PhaseOffsets::VsyncConfigSet PhaseOffsets::constructOffsets(nsecs_t vsyncDuration) const {
135 if (vsyncDuration < std::chrono::nanoseconds(15ms).count()) {
136 return getHighFpsOffsets(vsyncDuration);
137 } else {
138 return getDefaultOffsets(vsyncDuration);
139 }
140}
141
142namespace {
143std::chrono::nanoseconds sfOffsetToDuration(nsecs_t sfOffset, nsecs_t vsyncDuration) {
144 return std::chrono::nanoseconds(vsyncDuration - sfOffset);
145}
146
147std::chrono::nanoseconds appOffsetToDuration(nsecs_t appOffset, nsecs_t sfOffset,
148 nsecs_t vsyncDuration) {
149 auto duration = vsyncDuration + (sfOffset - appOffset);
150 if (duration < vsyncDuration) {
151 duration += vsyncDuration;
152 }
153
154 return std::chrono::nanoseconds(duration);
155}
156} // namespace
157
158PhaseOffsets::VsyncConfigSet PhaseOffsets::getDefaultOffsets(nsecs_t vsyncDuration) const {
159 const auto earlySfOffset =
160 mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
161
162 ? mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs)
163 : mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) - vsyncDuration;
164 const auto earlyAppOffset = mEarlyAppOffsetNs.value_or(mVSyncPhaseOffsetNs);
165 const auto earlyGpuSfOffset =
166 mEarlyGpuSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
167
168 ? mEarlyGpuSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs)
169 : mEarlyGpuSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) - vsyncDuration;
170 const auto earlyGpuAppOffset = mEarlyGpuAppOffsetNs.value_or(mVSyncPhaseOffsetNs);
171 const auto lateSfOffset = mSfVSyncPhaseOffsetNs < mThresholdForNextVsync
172 ? mSfVSyncPhaseOffsetNs
173 : mSfVSyncPhaseOffsetNs - vsyncDuration;
174 const auto lateAppOffset = mVSyncPhaseOffsetNs;
175
176 return {
177 .early = {.sfOffset = earlySfOffset,
178 .appOffset = earlyAppOffset,
179 .sfWorkDuration = sfOffsetToDuration(earlySfOffset, vsyncDuration),
180 .appWorkDuration =
181 appOffsetToDuration(earlyAppOffset, earlySfOffset, vsyncDuration)},
182 .earlyGpu = {.sfOffset = earlyGpuSfOffset,
183 .appOffset = earlyGpuAppOffset,
184 .sfWorkDuration = sfOffsetToDuration(earlyGpuSfOffset, vsyncDuration),
185 .appWorkDuration = appOffsetToDuration(earlyGpuAppOffset, earlyGpuSfOffset,
186 vsyncDuration)},
187 .late = {.sfOffset = lateSfOffset,
188 .appOffset = lateAppOffset,
189 .sfWorkDuration = sfOffsetToDuration(lateSfOffset, vsyncDuration),
190 .appWorkDuration =
191 appOffsetToDuration(lateAppOffset, lateSfOffset, vsyncDuration)},
192 };
193}
194
195PhaseOffsets::VsyncConfigSet PhaseOffsets::getHighFpsOffsets(nsecs_t vsyncDuration) const {
196 const auto earlySfOffset =
197 mHighFpsEarlySfOffsetNs.value_or(mHighFpsSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
198 ? mHighFpsEarlySfOffsetNs.value_or(mHighFpsSfVSyncPhaseOffsetNs)
199 : mHighFpsEarlySfOffsetNs.value_or(mHighFpsSfVSyncPhaseOffsetNs) - vsyncDuration;
200 const auto earlyAppOffset = mHighFpsEarlyAppOffsetNs.value_or(mHighFpsVSyncPhaseOffsetNs);
201 const auto earlyGpuSfOffset = mHighFpsEarlyGpuSfOffsetNs.value_or(
202 mHighFpsSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
203
204 ? mHighFpsEarlyGpuSfOffsetNs.value_or(mHighFpsSfVSyncPhaseOffsetNs)
205 : mHighFpsEarlyGpuSfOffsetNs.value_or(mHighFpsSfVSyncPhaseOffsetNs) - vsyncDuration;
206 const auto earlyGpuAppOffset = mHighFpsEarlyGpuAppOffsetNs.value_or(mHighFpsVSyncPhaseOffsetNs);
207 const auto lateSfOffset = mHighFpsSfVSyncPhaseOffsetNs < mThresholdForNextVsync
208 ? mHighFpsSfVSyncPhaseOffsetNs
209 : mHighFpsSfVSyncPhaseOffsetNs - vsyncDuration;
210 const auto lateAppOffset = mHighFpsVSyncPhaseOffsetNs;
211
212 return {
213 .early =
214 {
215 .sfOffset = earlySfOffset,
216 .appOffset = earlyAppOffset,
217 .sfWorkDuration = sfOffsetToDuration(earlySfOffset, vsyncDuration),
218 .appWorkDuration = appOffsetToDuration(earlyAppOffset, earlySfOffset,
219 vsyncDuration),
220 },
221 .earlyGpu =
222 {
223 .sfOffset = earlyGpuSfOffset,
224 .appOffset = earlyGpuAppOffset,
225 .sfWorkDuration = sfOffsetToDuration(earlyGpuSfOffset, vsyncDuration),
226 .appWorkDuration = appOffsetToDuration(earlyGpuAppOffset,
227 earlyGpuSfOffset, vsyncDuration),
228 },
229 .late =
230 {
231 .sfOffset = lateSfOffset,
232 .appOffset = lateAppOffset,
233 .sfWorkDuration = sfOffsetToDuration(lateSfOffset, vsyncDuration),
234 .appWorkDuration =
235 appOffsetToDuration(lateAppOffset, lateSfOffset, vsyncDuration),
236 },
237 };
Ady Abraham090d42c2020-01-08 12:08:11 -0800238}
239
Ady Abraham9e16a482019-12-03 17:19:41 -0800240static void validateSysprops() {
241 const auto validatePropertyBool = [](const char* prop) {
242 LOG_ALWAYS_FATAL_IF(!property_get_bool(prop, false), "%s is false", prop);
243 };
244
245 validatePropertyBool("debug.sf.use_phase_offsets_as_durations");
246
247 LOG_ALWAYS_FATAL_IF(sysprop::vsync_event_phase_offset_ns(-1) != -1,
248 "ro.surface_flinger.vsync_event_phase_offset_ns is set but expecting "
249 "duration");
250
251 LOG_ALWAYS_FATAL_IF(sysprop::vsync_sf_event_phase_offset_ns(-1) != -1,
252 "ro.surface_flinger.vsync_sf_event_phase_offset_ns is set but expecting "
253 "duration");
254
255 const auto validateProperty = [](const char* prop) {
256 LOG_ALWAYS_FATAL_IF(getProperty(prop).has_value(),
257 "%s is set to %" PRId64 " but expecting duration", prop,
258 getProperty(prop).value_or(-1));
259 };
260
261 validateProperty("debug.sf.early_phase_offset_ns");
262 validateProperty("debug.sf.early_gl_phase_offset_ns");
263 validateProperty("debug.sf.early_app_phase_offset_ns");
264 validateProperty("debug.sf.early_gl_app_phase_offset_ns");
265 validateProperty("debug.sf.high_fps_late_app_phase_offset_ns");
266 validateProperty("debug.sf.high_fps_late_sf_phase_offset_ns");
267 validateProperty("debug.sf.high_fps_early_phase_offset_ns");
268 validateProperty("debug.sf.high_fps_early_gl_phase_offset_ns");
269 validateProperty("debug.sf.high_fps_early_app_phase_offset_ns");
270 validateProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns");
271}
272
Ady Abraham8287e852020-08-12 14:44:58 -0700273namespace {
274nsecs_t sfDurationToOffset(std::chrono::nanoseconds sfDuration, nsecs_t vsyncDuration) {
275 return vsyncDuration - sfDuration.count() % vsyncDuration;
Ady Abraham9e16a482019-12-03 17:19:41 -0800276}
277
Ady Abraham8287e852020-08-12 14:44:58 -0700278nsecs_t appDurationToOffset(std::chrono::nanoseconds appDuration,
279 std::chrono::nanoseconds sfDuration, nsecs_t vsyncDuration) {
280 return vsyncDuration - (appDuration + sfDuration).count() % vsyncDuration;
Ady Abraham9e16a482019-12-03 17:19:41 -0800281}
Ady Abraham8287e852020-08-12 14:44:58 -0700282} // namespace
Ady Abraham9e16a482019-12-03 17:19:41 -0800283
Ady Abraham8287e852020-08-12 14:44:58 -0700284WorkDuration::VsyncConfigSet WorkDuration::constructOffsets(nsecs_t vsyncDuration) const {
285 const auto sfDurationFixup = [vsyncDuration](nsecs_t duration) {
286 return duration == -1 ? std::chrono::nanoseconds(vsyncDuration) - 1ms
287 : std::chrono::nanoseconds(duration);
288 };
Ady Abrahamdfa37362020-01-21 18:02:39 -0800289
Ady Abraham8287e852020-08-12 14:44:58 -0700290 const auto appDurationFixup = [vsyncDuration](nsecs_t duration) {
291 return duration == -1 ? std::chrono::nanoseconds(vsyncDuration)
292 : std::chrono::nanoseconds(duration);
293 };
Ady Abrahamdfa37362020-01-21 18:02:39 -0800294
Ady Abraham8287e852020-08-12 14:44:58 -0700295 const auto sfEarlyDuration = sfDurationFixup(mSfEarlyDuration);
296 const auto appEarlyDuration = appDurationFixup(mAppEarlyDuration);
297 const auto sfEarlyGpuDuration = sfDurationFixup(mSfEarlyGpuDuration);
298 const auto appEarlyGpuDuration = appDurationFixup(mAppEarlyGpuDuration);
299 const auto sfDuration = sfDurationFixup(mSfDuration);
300 const auto appDuration = appDurationFixup(mAppDuration);
Ady Abrahamdfa37362020-01-21 18:02:39 -0800301
Ady Abraham8287e852020-08-12 14:44:58 -0700302 return {
303 .early =
304 {
305
306 .sfOffset = sfEarlyDuration.count() < vsyncDuration
307 ? sfDurationToOffset(sfEarlyDuration, vsyncDuration)
308 : sfDurationToOffset(sfEarlyDuration, vsyncDuration) -
309 vsyncDuration,
310
311 .appOffset = appDurationToOffset(appEarlyDuration, sfEarlyDuration,
312 vsyncDuration),
313
314 .sfWorkDuration = sfEarlyDuration,
315 .appWorkDuration = appEarlyDuration,
316 },
317 .earlyGpu =
318 {
319
320 .sfOffset = sfEarlyGpuDuration.count() < vsyncDuration
321
322 ? sfDurationToOffset(sfEarlyGpuDuration, vsyncDuration)
323 : sfDurationToOffset(sfEarlyGpuDuration, vsyncDuration) -
324 vsyncDuration,
325
326 .appOffset = appDurationToOffset(appEarlyGpuDuration,
327 sfEarlyGpuDuration, vsyncDuration),
328 .sfWorkDuration = sfEarlyGpuDuration,
329 .appWorkDuration = appEarlyGpuDuration,
330 },
331 .late =
332 {
333
334 .sfOffset = sfDuration.count() < vsyncDuration
335
336 ? sfDurationToOffset(sfDuration, vsyncDuration)
337 : sfDurationToOffset(sfDuration, vsyncDuration) - vsyncDuration,
338
339 .appOffset =
340 appDurationToOffset(appDuration, sfDuration, vsyncDuration),
341
342 .sfWorkDuration = sfDuration,
343 .appWorkDuration = appDuration,
344 },
Ady Abrahamdfa37362020-01-21 18:02:39 -0800345 };
346}
347
Marin Shalamanov526c3382020-12-10 15:22:29 +0100348WorkDuration::WorkDuration(Fps currentRefreshRate)
349 : WorkDuration(currentRefreshRate, getProperty("debug.sf.late.sf.duration").value_or(-1),
Ady Abraham8287e852020-08-12 14:44:58 -0700350 getProperty("debug.sf.late.app.duration").value_or(-1),
351 getProperty("debug.sf.early.sf.duration").value_or(mSfDuration),
352 getProperty("debug.sf.early.app.duration").value_or(mAppDuration),
353 getProperty("debug.sf.earlyGl.sf.duration").value_or(mSfDuration),
354 getProperty("debug.sf.earlyGl.app.duration").value_or(mAppDuration)) {
Ady Abraham9e16a482019-12-03 17:19:41 -0800355 validateSysprops();
356}
357
Marin Shalamanov526c3382020-12-10 15:22:29 +0100358WorkDuration::WorkDuration(Fps currentRefreshRate, nsecs_t sfDuration, nsecs_t appDuration,
359 nsecs_t sfEarlyDuration, nsecs_t appEarlyDuration,
Marin Shalamanove8a663d2020-11-24 17:48:00 +0100360 nsecs_t sfEarlyGpuDuration, nsecs_t appEarlyGpuDuration)
Marin Shalamanov526c3382020-12-10 15:22:29 +0100361 : VsyncConfiguration(currentRefreshRate),
Ady Abraham8287e852020-08-12 14:44:58 -0700362 mSfDuration(sfDuration),
Ady Abraham9e16a482019-12-03 17:19:41 -0800363 mAppDuration(appDuration),
364 mSfEarlyDuration(sfEarlyDuration),
365 mAppEarlyDuration(appEarlyDuration),
Ady Abraham8287e852020-08-12 14:44:58 -0700366 mSfEarlyGpuDuration(sfEarlyGpuDuration),
Marin Shalamanov526c3382020-12-10 15:22:29 +0100367 mAppEarlyGpuDuration(appEarlyGpuDuration) {}
Ady Abraham9e16a482019-12-03 17:19:41 -0800368
Ady Abraham8287e852020-08-12 14:44:58 -0700369} // namespace android::scheduler::impl