blob: 4330742bf14ae94437ed5a6d744c1ef15fbba35d [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
17#include "PhaseOffsets.h"
18
19#include <cutils/properties.h>
20
Dominik Laskowskieddeda12019-07-19 11:54:13 -070021#include <optional>
22
Ana Krulec757f63a2019-01-25 10:46:18 -080023#include "SurfaceFlingerProperties.h"
24
Dominik Laskowskieddeda12019-07-19 11:54:13 -070025namespace {
Ana Krulec757f63a2019-01-25 10:46:18 -080026
Dominik Laskowskif83570c2019-08-26 12:04:07 -070027std::optional<nsecs_t> getProperty(const char* name) {
Dominik Laskowskieddeda12019-07-19 11:54:13 -070028 char value[PROPERTY_VALUE_MAX];
29 property_get(name, value, "-1");
30 if (const int i = atoi(value); i != -1) return i;
31 return std::nullopt;
32}
Ana Krulec757f63a2019-01-25 10:46:18 -080033
Dominik Laskowskieddeda12019-07-19 11:54:13 -070034} // namespace
35
36namespace android::scheduler {
37
Ady Abraham9e16a482019-12-03 17:19:41 -080038PhaseConfiguration::~PhaseConfiguration() = default;
Ana Krulec757f63a2019-01-25 10:46:18 -080039
40namespace impl {
Dominik Laskowskieddeda12019-07-19 11:54:13 -070041
Ady Abraham9e16a482019-12-03 17:19:41 -080042PhaseOffsets::PhaseOffsets(const scheduler::RefreshRateConfigs& refreshRateConfigs)
43 : // Below defines the threshold when an offset is considered to be negative, i.e. targeting
44 // for the N+2 vsync instead of N+1. This means that:
45 // For offset < threshold, SF wake up (vsync_duration - offset) before HW vsync.
46 // For offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW vsync.
47 mThresholdForNextVsync(getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns")
48 .value_or(std::numeric_limits<nsecs_t>::max())),
49 mOffsets(initializeOffsets(refreshRateConfigs)),
50 mRefreshRateFps(refreshRateConfigs.getCurrentRefreshRate().fps) {}
Ana Krulec757f63a2019-01-25 10:46:18 -080051
52void PhaseOffsets::dump(std::string& result) const {
Ady Abraham9e16a482019-12-03 17:19:41 -080053 const auto [early, earlyGl, late] = getCurrentOffsets();
Dominik Laskowski98041832019-08-01 18:35:59 -070054 using base::StringAppendF;
55 StringAppendF(&result,
56 " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64 " ns\n"
57 " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64 " ns\n"
58 " GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n"
59 "next VSYNC threshold: %9" PRId64 " ns\n",
Ady Abraham9e16a482019-12-03 17:19:41 -080060 late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf,
61 mThresholdForNextVsync);
Ana Krulec757f63a2019-01-25 10:46:18 -080062}
63
Ady Abraham9e16a482019-12-03 17:19:41 -080064std::unordered_map<float, PhaseDurations::Offsets> PhaseOffsets::initializeOffsets(
65 const scheduler::RefreshRateConfigs& refreshRateConfigs) const {
66 std::unordered_map<float, PhaseDurations::Offsets> offsets;
67
68 for (const auto& [ignored, refreshRate] : refreshRateConfigs.getAllRefreshRates()) {
69 const nsecs_t vsyncDuration = static_cast<nsecs_t>(1e9f / refreshRate.fps);
70 if (refreshRate.fps > 65.0f) {
71 offsets.emplace(refreshRate.fps, getHighFpsOffsets(vsyncDuration));
72 } else {
73 offsets.emplace(refreshRate.fps, getDefaultOffsets(vsyncDuration));
74 }
75 }
76 return offsets;
77}
78
79PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t vsyncDuration) const {
Dominik Laskowskieddeda12019-07-19 11:54:13 -070080 const int64_t vsyncPhaseOffsetNs = sysprop::vsync_event_phase_offset_ns(1000000);
81 const int64_t sfVsyncPhaseOffsetNs = sysprop::vsync_sf_event_phase_offset_ns(1000000);
82
83 const auto earlySfOffsetNs = getProperty("debug.sf.early_phase_offset_ns");
84 const auto earlyGlSfOffsetNs = getProperty("debug.sf.early_gl_phase_offset_ns");
85 const auto earlyAppOffsetNs = getProperty("debug.sf.early_app_phase_offset_ns");
86 const auto earlyGlAppOffsetNs = getProperty("debug.sf.early_gl_app_phase_offset_ns");
87
Ady Abraham9e16a482019-12-03 17:19:41 -080088 return {
89 {
90 earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs) < mThresholdForNextVsync
91 ? earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs)
92 : earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs) - vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -070093
Ady Abraham9e16a482019-12-03 17:19:41 -080094 earlyAppOffsetNs.value_or(vsyncPhaseOffsetNs),
95 },
96 {
97 earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs) < mThresholdForNextVsync
98 ? earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs)
99 : earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs) - vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700100
Ady Abraham9e16a482019-12-03 17:19:41 -0800101 earlyGlAppOffsetNs.value_or(vsyncPhaseOffsetNs),
102 },
103 {
104 sfVsyncPhaseOffsetNs < mThresholdForNextVsync
105 ? sfVsyncPhaseOffsetNs
106 : sfVsyncPhaseOffsetNs - vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700107
Ady Abraham9e16a482019-12-03 17:19:41 -0800108 vsyncPhaseOffsetNs,
109 },
110 };
Ana Krulec757f63a2019-01-25 10:46:18 -0800111}
112
Ady Abraham9e16a482019-12-03 17:19:41 -0800113PhaseOffsets::Offsets PhaseOffsets::getHighFpsOffsets(nsecs_t vsyncDuration) const {
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700114 const int highFpsLateAppOffsetNs =
115 getProperty("debug.sf.high_fps_late_app_phase_offset_ns").value_or(2000000);
116 const int highFpsLateSfOffsetNs =
117 getProperty("debug.sf.high_fps_late_sf_phase_offset_ns").value_or(1000000);
118
119 const auto highFpsEarlySfOffsetNs = getProperty("debug.sf.high_fps_early_phase_offset_ns");
120 const auto highFpsEarlyGlSfOffsetNs = getProperty("debug.sf.high_fps_early_gl_phase_offset_ns");
121 const auto highFpsEarlyAppOffsetNs = getProperty("debug.sf.high_fps_early_app_phase_offset_ns");
122 const auto highFpsEarlyGlAppOffsetNs =
123 getProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns");
124
Ady Abraham9e16a482019-12-03 17:19:41 -0800125 return {
126 {
127 highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs) < mThresholdForNextVsync
128 ? highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs)
129 : highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs) -
130 vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700131
Ady Abraham9e16a482019-12-03 17:19:41 -0800132 highFpsEarlyAppOffsetNs.value_or(highFpsLateAppOffsetNs),
133 },
134 {
135 highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs) <
136 mThresholdForNextVsync
137 ? highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs)
138 : highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs) -
139 vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700140
Ady Abraham9e16a482019-12-03 17:19:41 -0800141 highFpsEarlyGlAppOffsetNs.value_or(highFpsLateAppOffsetNs),
142 },
143 {
144 highFpsLateSfOffsetNs < mThresholdForNextVsync
145 ? highFpsLateSfOffsetNs
146 : highFpsLateSfOffsetNs - vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700147
Ady Abraham9e16a482019-12-03 17:19:41 -0800148 highFpsLateAppOffsetNs,
149 },
150 };
151}
152
153static void validateSysprops() {
154 const auto validatePropertyBool = [](const char* prop) {
155 LOG_ALWAYS_FATAL_IF(!property_get_bool(prop, false), "%s is false", prop);
156 };
157
158 validatePropertyBool("debug.sf.use_phase_offsets_as_durations");
159
160 LOG_ALWAYS_FATAL_IF(sysprop::vsync_event_phase_offset_ns(-1) != -1,
161 "ro.surface_flinger.vsync_event_phase_offset_ns is set but expecting "
162 "duration");
163
164 LOG_ALWAYS_FATAL_IF(sysprop::vsync_sf_event_phase_offset_ns(-1) != -1,
165 "ro.surface_flinger.vsync_sf_event_phase_offset_ns is set but expecting "
166 "duration");
167
168 const auto validateProperty = [](const char* prop) {
169 LOG_ALWAYS_FATAL_IF(getProperty(prop).has_value(),
170 "%s is set to %" PRId64 " but expecting duration", prop,
171 getProperty(prop).value_or(-1));
172 };
173
174 validateProperty("debug.sf.early_phase_offset_ns");
175 validateProperty("debug.sf.early_gl_phase_offset_ns");
176 validateProperty("debug.sf.early_app_phase_offset_ns");
177 validateProperty("debug.sf.early_gl_app_phase_offset_ns");
178 validateProperty("debug.sf.high_fps_late_app_phase_offset_ns");
179 validateProperty("debug.sf.high_fps_late_sf_phase_offset_ns");
180 validateProperty("debug.sf.high_fps_early_phase_offset_ns");
181 validateProperty("debug.sf.high_fps_early_gl_phase_offset_ns");
182 validateProperty("debug.sf.high_fps_early_app_phase_offset_ns");
183 validateProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns");
184}
185
186static nsecs_t sfDurationToOffset(nsecs_t sfDuration, nsecs_t vsyncDuration) {
187 return sfDuration == -1 ? 1'000'000 : vsyncDuration - sfDuration % vsyncDuration;
188}
189
190static nsecs_t appDurationToOffset(nsecs_t appDuration, nsecs_t sfDuration, nsecs_t vsyncDuration) {
191 return sfDuration == -1 ? 1'000'000
192 : vsyncDuration - (appDuration + sfDuration) % vsyncDuration;
193}
194
195static std::vector<float> getRefreshRatesFromConfigs(
196 const android::scheduler::RefreshRateConfigs& refreshRateConfigs) {
197 const auto& allRefreshRates = refreshRateConfigs.getAllRefreshRates();
198 std::vector<float> refreshRates;
199 refreshRates.reserve(allRefreshRates.size());
200
201 for (const auto& [ignored, refreshRate] : allRefreshRates) {
202 refreshRates.emplace_back(refreshRate.fps);
203 }
204
205 return refreshRates;
206}
207
208std::unordered_map<float, PhaseDurations::Offsets> PhaseDurations::initializeOffsets(
209 const std::vector<float>& refreshRates) const {
210 std::unordered_map<float, PhaseDurations::Offsets> offsets;
211
212 for (const auto fps : refreshRates) {
213 const nsecs_t vsyncDuration = static_cast<nsecs_t>(1e9f / fps);
214 offsets.emplace(fps,
215 Offsets{
216 {
217 mSfEarlyDuration < vsyncDuration
218 ? sfDurationToOffset(mSfEarlyDuration,
219 vsyncDuration)
220 : sfDurationToOffset(mSfEarlyDuration,
221 vsyncDuration) -
222 vsyncDuration,
223
224 appDurationToOffset(mAppEarlyDuration, mSfEarlyDuration,
225 vsyncDuration),
226 },
227 {
228 mSfEarlyGlDuration < vsyncDuration
229 ? sfDurationToOffset(mSfEarlyGlDuration,
230 vsyncDuration)
231 : sfDurationToOffset(mSfEarlyGlDuration,
232 vsyncDuration) -
233 vsyncDuration,
234
235 appDurationToOffset(mAppEarlyGlDuration, mSfEarlyGlDuration,
236 vsyncDuration),
237 },
238 {
239 mSfDuration < vsyncDuration
240 ? sfDurationToOffset(mSfDuration, vsyncDuration)
241 : sfDurationToOffset(mSfDuration, vsyncDuration) -
242 vsyncDuration,
243
244 appDurationToOffset(mAppDuration, mSfDuration,
245 vsyncDuration),
246 },
247 });
248 }
249 return offsets;
250}
251
252PhaseDurations::PhaseDurations(const scheduler::RefreshRateConfigs& refreshRateConfigs)
253 : PhaseDurations(getRefreshRatesFromConfigs(refreshRateConfigs),
254 refreshRateConfigs.getCurrentRefreshRate().fps,
255 getProperty("debug.sf.late.sf.duration").value_or(-1),
256 getProperty("debug.sf.late.app.duration").value_or(-1),
257 getProperty("debug.sf.early.sf.duration").value_or(mSfDuration),
258 getProperty("debug.sf.early.app.duration").value_or(mAppDuration),
259 getProperty("debug.sf.earlyGl.sf.duration").value_or(mSfDuration),
260 getProperty("debug.sf.earlyGl.app.duration").value_or(mAppDuration)) {
261 validateSysprops();
262}
263
264PhaseDurations::PhaseDurations(const std::vector<float>& refreshRates, float currentFps,
265 nsecs_t sfDuration, nsecs_t appDuration, nsecs_t sfEarlyDuration,
266 nsecs_t appEarlyDuration, nsecs_t sfEarlyGlDuration,
267 nsecs_t appEarlyGlDuration)
268 : mSfDuration(sfDuration),
269 mAppDuration(appDuration),
270 mSfEarlyDuration(sfEarlyDuration),
271 mAppEarlyDuration(appEarlyDuration),
272 mSfEarlyGlDuration(sfEarlyGlDuration),
273 mAppEarlyGlDuration(appEarlyGlDuration),
274 mOffsets(initializeOffsets(refreshRates)),
275 mRefreshRateFps(currentFps) {}
276
277PhaseOffsets::Offsets PhaseDurations::getOffsetsForRefreshRate(float fps) const {
278 const auto iter = mOffsets.find(fps);
279 LOG_ALWAYS_FATAL_IF(iter == mOffsets.end());
280 return iter->second;
281}
282
283void PhaseDurations::dump(std::string& result) const {
284 const auto [early, earlyGl, late] = getCurrentOffsets();
285 using base::StringAppendF;
286 StringAppendF(&result,
287 " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64
288 " ns\n"
289 " app duration: %9" PRId64 " ns\t SF duration: %9" PRId64
290 " ns\n"
291 " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64
292 " ns\n"
293 " early app duration: %9" PRId64 " ns\t early SF duration: %9" PRId64
294 " ns\n"
295 " GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64
296 " ns\n"
297 " GL early app duration: %9" PRId64 " ns\tGL early SF duration: %9" PRId64
298 " ns\n",
299 late.app,
300
301 late.sf,
302
303 mAppDuration, mSfDuration,
304
305 early.app, early.sf,
306
307 mAppEarlyDuration, mSfEarlyDuration,
308
309 earlyGl.app,
310
311 earlyGl.sf,
312
313 mAppEarlyGlDuration, mSfEarlyGlDuration);
Ana Krulec757f63a2019-01-25 10:46:18 -0800314}
315
316} // namespace impl
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700317} // namespace android::scheduler