blob: 13014c789bfd50088fc47be9dfa4ba10ea5737a3 [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
Ady Abraham090d42c2020-01-08 12:08:11 -080034bool fpsEqualsWithMargin(float fpsA, float fpsB) {
35 static constexpr float MARGIN = 0.01f;
36 return std::abs(fpsA - fpsB) <= MARGIN;
37}
38
Dominik Laskowskieddeda12019-07-19 11:54:13 -070039} // namespace
40
41namespace android::scheduler {
42
Ady Abraham9e16a482019-12-03 17:19:41 -080043PhaseConfiguration::~PhaseConfiguration() = default;
Ana Krulec757f63a2019-01-25 10:46:18 -080044
45namespace impl {
Dominik Laskowskieddeda12019-07-19 11:54:13 -070046
Ady Abraham9e16a482019-12-03 17:19:41 -080047PhaseOffsets::PhaseOffsets(const scheduler::RefreshRateConfigs& refreshRateConfigs)
48 : // Below defines the threshold when an offset is considered to be negative, i.e. targeting
49 // for the N+2 vsync instead of N+1. This means that:
50 // For offset < threshold, SF wake up (vsync_duration - offset) before HW vsync.
51 // For offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW vsync.
52 mThresholdForNextVsync(getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns")
53 .value_or(std::numeric_limits<nsecs_t>::max())),
54 mOffsets(initializeOffsets(refreshRateConfigs)),
55 mRefreshRateFps(refreshRateConfigs.getCurrentRefreshRate().fps) {}
Ana Krulec757f63a2019-01-25 10:46:18 -080056
57void PhaseOffsets::dump(std::string& result) const {
Ady Abraham9e16a482019-12-03 17:19:41 -080058 const auto [early, earlyGl, late] = getCurrentOffsets();
Dominik Laskowski98041832019-08-01 18:35:59 -070059 using base::StringAppendF;
60 StringAppendF(&result,
61 " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64 " ns\n"
62 " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64 " ns\n"
63 " GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n"
64 "next VSYNC threshold: %9" PRId64 " ns\n",
Ady Abraham9e16a482019-12-03 17:19:41 -080065 late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf,
66 mThresholdForNextVsync);
Ana Krulec757f63a2019-01-25 10:46:18 -080067}
68
Ady Abraham090d42c2020-01-08 12:08:11 -080069std::unordered_map<float, PhaseOffsets::Offsets> PhaseOffsets::initializeOffsets(
Ady Abraham9e16a482019-12-03 17:19:41 -080070 const scheduler::RefreshRateConfigs& refreshRateConfigs) const {
Ady Abraham090d42c2020-01-08 12:08:11 -080071 std::unordered_map<float, Offsets> offsets;
Ady Abraham9e16a482019-12-03 17:19:41 -080072
73 for (const auto& [ignored, refreshRate] : refreshRateConfigs.getAllRefreshRates()) {
Ady Abraham9e16a482019-12-03 17:19:41 -080074 if (refreshRate.fps > 65.0f) {
Ady Abraham090d42c2020-01-08 12:08:11 -080075 offsets.emplace(refreshRate.fps, getHighFpsOffsets(refreshRate.vsyncPeriod));
Ady Abraham9e16a482019-12-03 17:19:41 -080076 } else {
Ady Abraham090d42c2020-01-08 12:08:11 -080077 offsets.emplace(refreshRate.fps, getDefaultOffsets(refreshRate.vsyncPeriod));
Ady Abraham9e16a482019-12-03 17:19:41 -080078 }
79 }
80 return offsets;
81}
82
83PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t vsyncDuration) const {
Dominik Laskowskieddeda12019-07-19 11:54:13 -070084 const int64_t vsyncPhaseOffsetNs = sysprop::vsync_event_phase_offset_ns(1000000);
85 const int64_t sfVsyncPhaseOffsetNs = sysprop::vsync_sf_event_phase_offset_ns(1000000);
86
87 const auto earlySfOffsetNs = getProperty("debug.sf.early_phase_offset_ns");
88 const auto earlyGlSfOffsetNs = getProperty("debug.sf.early_gl_phase_offset_ns");
89 const auto earlyAppOffsetNs = getProperty("debug.sf.early_app_phase_offset_ns");
90 const auto earlyGlAppOffsetNs = getProperty("debug.sf.early_gl_app_phase_offset_ns");
91
Ady Abraham9e16a482019-12-03 17:19:41 -080092 return {
93 {
94 earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs) < mThresholdForNextVsync
95 ? earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs)
96 : earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs) - vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -070097
Ady Abraham9e16a482019-12-03 17:19:41 -080098 earlyAppOffsetNs.value_or(vsyncPhaseOffsetNs),
99 },
100 {
101 earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs) < mThresholdForNextVsync
102 ? earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs)
103 : earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs) - vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700104
Ady Abraham9e16a482019-12-03 17:19:41 -0800105 earlyGlAppOffsetNs.value_or(vsyncPhaseOffsetNs),
106 },
107 {
108 sfVsyncPhaseOffsetNs < mThresholdForNextVsync
109 ? sfVsyncPhaseOffsetNs
110 : sfVsyncPhaseOffsetNs - vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700111
Ady Abraham9e16a482019-12-03 17:19:41 -0800112 vsyncPhaseOffsetNs,
113 },
114 };
Ana Krulec757f63a2019-01-25 10:46:18 -0800115}
116
Ady Abraham9e16a482019-12-03 17:19:41 -0800117PhaseOffsets::Offsets PhaseOffsets::getHighFpsOffsets(nsecs_t vsyncDuration) const {
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700118 const int highFpsLateAppOffsetNs =
119 getProperty("debug.sf.high_fps_late_app_phase_offset_ns").value_or(2000000);
120 const int highFpsLateSfOffsetNs =
121 getProperty("debug.sf.high_fps_late_sf_phase_offset_ns").value_or(1000000);
122
123 const auto highFpsEarlySfOffsetNs = getProperty("debug.sf.high_fps_early_phase_offset_ns");
124 const auto highFpsEarlyGlSfOffsetNs = getProperty("debug.sf.high_fps_early_gl_phase_offset_ns");
125 const auto highFpsEarlyAppOffsetNs = getProperty("debug.sf.high_fps_early_app_phase_offset_ns");
126 const auto highFpsEarlyGlAppOffsetNs =
127 getProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns");
128
Ady Abraham9e16a482019-12-03 17:19:41 -0800129 return {
130 {
131 highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs) < mThresholdForNextVsync
132 ? highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs)
133 : highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs) -
134 vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700135
Ady Abraham9e16a482019-12-03 17:19:41 -0800136 highFpsEarlyAppOffsetNs.value_or(highFpsLateAppOffsetNs),
137 },
138 {
139 highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs) <
140 mThresholdForNextVsync
141 ? highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs)
142 : highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs) -
143 vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700144
Ady Abraham9e16a482019-12-03 17:19:41 -0800145 highFpsEarlyGlAppOffsetNs.value_or(highFpsLateAppOffsetNs),
146 },
147 {
148 highFpsLateSfOffsetNs < mThresholdForNextVsync
149 ? highFpsLateSfOffsetNs
150 : highFpsLateSfOffsetNs - vsyncDuration,
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700151
Ady Abraham9e16a482019-12-03 17:19:41 -0800152 highFpsLateAppOffsetNs,
153 },
154 };
155}
156
Ady Abraham090d42c2020-01-08 12:08:11 -0800157PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate(float fps) const {
158 const auto iter = std::find_if(mOffsets.begin(), mOffsets.end(),
159 [&fps](const std::pair<float, Offsets>& candidateFps) {
160 return fpsEqualsWithMargin(fps, candidateFps.first);
161 });
162 LOG_ALWAYS_FATAL_IF(iter == mOffsets.end());
163 return iter->second;
164}
165
Ady Abraham9e16a482019-12-03 17:19:41 -0800166static void validateSysprops() {
167 const auto validatePropertyBool = [](const char* prop) {
168 LOG_ALWAYS_FATAL_IF(!property_get_bool(prop, false), "%s is false", prop);
169 };
170
171 validatePropertyBool("debug.sf.use_phase_offsets_as_durations");
172
173 LOG_ALWAYS_FATAL_IF(sysprop::vsync_event_phase_offset_ns(-1) != -1,
174 "ro.surface_flinger.vsync_event_phase_offset_ns is set but expecting "
175 "duration");
176
177 LOG_ALWAYS_FATAL_IF(sysprop::vsync_sf_event_phase_offset_ns(-1) != -1,
178 "ro.surface_flinger.vsync_sf_event_phase_offset_ns is set but expecting "
179 "duration");
180
181 const auto validateProperty = [](const char* prop) {
182 LOG_ALWAYS_FATAL_IF(getProperty(prop).has_value(),
183 "%s is set to %" PRId64 " but expecting duration", prop,
184 getProperty(prop).value_or(-1));
185 };
186
187 validateProperty("debug.sf.early_phase_offset_ns");
188 validateProperty("debug.sf.early_gl_phase_offset_ns");
189 validateProperty("debug.sf.early_app_phase_offset_ns");
190 validateProperty("debug.sf.early_gl_app_phase_offset_ns");
191 validateProperty("debug.sf.high_fps_late_app_phase_offset_ns");
192 validateProperty("debug.sf.high_fps_late_sf_phase_offset_ns");
193 validateProperty("debug.sf.high_fps_early_phase_offset_ns");
194 validateProperty("debug.sf.high_fps_early_gl_phase_offset_ns");
195 validateProperty("debug.sf.high_fps_early_app_phase_offset_ns");
196 validateProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns");
197}
198
199static nsecs_t sfDurationToOffset(nsecs_t sfDuration, nsecs_t vsyncDuration) {
200 return sfDuration == -1 ? 1'000'000 : vsyncDuration - sfDuration % vsyncDuration;
201}
202
203static nsecs_t appDurationToOffset(nsecs_t appDuration, nsecs_t sfDuration, nsecs_t vsyncDuration) {
204 return sfDuration == -1 ? 1'000'000
205 : vsyncDuration - (appDuration + sfDuration) % vsyncDuration;
206}
207
208static std::vector<float> getRefreshRatesFromConfigs(
209 const android::scheduler::RefreshRateConfigs& refreshRateConfigs) {
210 const auto& allRefreshRates = refreshRateConfigs.getAllRefreshRates();
211 std::vector<float> refreshRates;
212 refreshRates.reserve(allRefreshRates.size());
213
214 for (const auto& [ignored, refreshRate] : allRefreshRates) {
215 refreshRates.emplace_back(refreshRate.fps);
216 }
217
218 return refreshRates;
219}
220
221std::unordered_map<float, PhaseDurations::Offsets> PhaseDurations::initializeOffsets(
222 const std::vector<float>& refreshRates) const {
Ady Abraham090d42c2020-01-08 12:08:11 -0800223 std::unordered_map<float, Offsets> offsets;
Ady Abraham9e16a482019-12-03 17:19:41 -0800224
225 for (const auto fps : refreshRates) {
226 const nsecs_t vsyncDuration = static_cast<nsecs_t>(1e9f / fps);
227 offsets.emplace(fps,
228 Offsets{
229 {
230 mSfEarlyDuration < vsyncDuration
231 ? sfDurationToOffset(mSfEarlyDuration,
232 vsyncDuration)
233 : sfDurationToOffset(mSfEarlyDuration,
234 vsyncDuration) -
235 vsyncDuration,
236
237 appDurationToOffset(mAppEarlyDuration, mSfEarlyDuration,
238 vsyncDuration),
239 },
240 {
241 mSfEarlyGlDuration < vsyncDuration
242 ? sfDurationToOffset(mSfEarlyGlDuration,
243 vsyncDuration)
244 : sfDurationToOffset(mSfEarlyGlDuration,
245 vsyncDuration) -
246 vsyncDuration,
247
248 appDurationToOffset(mAppEarlyGlDuration, mSfEarlyGlDuration,
249 vsyncDuration),
250 },
251 {
252 mSfDuration < vsyncDuration
253 ? sfDurationToOffset(mSfDuration, vsyncDuration)
254 : sfDurationToOffset(mSfDuration, vsyncDuration) -
255 vsyncDuration,
256
257 appDurationToOffset(mAppDuration, mSfDuration,
258 vsyncDuration),
259 },
260 });
261 }
262 return offsets;
263}
264
265PhaseDurations::PhaseDurations(const scheduler::RefreshRateConfigs& refreshRateConfigs)
266 : PhaseDurations(getRefreshRatesFromConfigs(refreshRateConfigs),
267 refreshRateConfigs.getCurrentRefreshRate().fps,
268 getProperty("debug.sf.late.sf.duration").value_or(-1),
269 getProperty("debug.sf.late.app.duration").value_or(-1),
270 getProperty("debug.sf.early.sf.duration").value_or(mSfDuration),
271 getProperty("debug.sf.early.app.duration").value_or(mAppDuration),
272 getProperty("debug.sf.earlyGl.sf.duration").value_or(mSfDuration),
273 getProperty("debug.sf.earlyGl.app.duration").value_or(mAppDuration)) {
274 validateSysprops();
275}
276
277PhaseDurations::PhaseDurations(const std::vector<float>& refreshRates, float currentFps,
278 nsecs_t sfDuration, nsecs_t appDuration, nsecs_t sfEarlyDuration,
279 nsecs_t appEarlyDuration, nsecs_t sfEarlyGlDuration,
280 nsecs_t appEarlyGlDuration)
281 : mSfDuration(sfDuration),
282 mAppDuration(appDuration),
283 mSfEarlyDuration(sfEarlyDuration),
284 mAppEarlyDuration(appEarlyDuration),
285 mSfEarlyGlDuration(sfEarlyGlDuration),
286 mAppEarlyGlDuration(appEarlyGlDuration),
287 mOffsets(initializeOffsets(refreshRates)),
288 mRefreshRateFps(currentFps) {}
289
290PhaseOffsets::Offsets PhaseDurations::getOffsetsForRefreshRate(float fps) const {
Ady Abraham090d42c2020-01-08 12:08:11 -0800291 const auto iter = std::find_if(mOffsets.begin(), mOffsets.end(), [=](const auto& candidateFps) {
292 return fpsEqualsWithMargin(fps, candidateFps.first);
293 });
Ady Abraham9e16a482019-12-03 17:19:41 -0800294 LOG_ALWAYS_FATAL_IF(iter == mOffsets.end());
295 return iter->second;
296}
297
298void PhaseDurations::dump(std::string& result) const {
299 const auto [early, earlyGl, late] = getCurrentOffsets();
300 using base::StringAppendF;
301 StringAppendF(&result,
302 " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64
303 " ns\n"
304 " app duration: %9" PRId64 " ns\t SF duration: %9" PRId64
305 " ns\n"
306 " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64
307 " ns\n"
308 " early app duration: %9" PRId64 " ns\t early SF duration: %9" PRId64
309 " ns\n"
310 " GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64
311 " ns\n"
312 " GL early app duration: %9" PRId64 " ns\tGL early SF duration: %9" PRId64
313 " ns\n",
314 late.app,
315
316 late.sf,
317
318 mAppDuration, mSfDuration,
319
320 early.app, early.sf,
321
322 mAppEarlyDuration, mSfEarlyDuration,
323
324 earlyGl.app,
325
326 earlyGl.sf,
327
328 mAppEarlyGlDuration, mSfEarlyGlDuration);
Ana Krulec757f63a2019-01-25 10:46:18 -0800329}
330
331} // namespace impl
Dominik Laskowskieddeda12019-07-19 11:54:13 -0700332} // namespace android::scheduler