| Ana Krulec | 757f63a | 2019-01-25 10:46:18 -0800 | [diff] [blame] | 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 "PhaseOffsets.h" | 
|  | 18 |  | 
|  | 19 | #include <cutils/properties.h> | 
|  | 20 |  | 
| Dominik Laskowski | eddeda1 | 2019-07-19 11:54:13 -0700 | [diff] [blame] | 21 | #include <optional> | 
|  | 22 |  | 
| Ana Krulec | 757f63a | 2019-01-25 10:46:18 -0800 | [diff] [blame] | 23 | #include "SurfaceFlingerProperties.h" | 
|  | 24 |  | 
| Dominik Laskowski | eddeda1 | 2019-07-19 11:54:13 -0700 | [diff] [blame] | 25 | namespace { | 
| Ana Krulec | 757f63a | 2019-01-25 10:46:18 -0800 | [diff] [blame] | 26 |  | 
| Dominik Laskowski | f83570c | 2019-08-26 12:04:07 -0700 | [diff] [blame] | 27 | std::optional<nsecs_t> getProperty(const char* name) { | 
| Dominik Laskowski | eddeda1 | 2019-07-19 11:54:13 -0700 | [diff] [blame] | 28 | 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 Krulec | 757f63a | 2019-01-25 10:46:18 -0800 | [diff] [blame] | 33 |  | 
| Ady Abraham | 090d42c | 2020-01-08 12:08:11 -0800 | [diff] [blame] | 34 | bool fpsEqualsWithMargin(float fpsA, float fpsB) { | 
|  | 35 | static constexpr float MARGIN = 0.01f; | 
|  | 36 | return std::abs(fpsA - fpsB) <= MARGIN; | 
|  | 37 | } | 
|  | 38 |  | 
| Ady Abraham | 60120a0 | 2020-03-23 11:23:26 -0700 | [diff] [blame] | 39 | std::vector<float> getRefreshRatesFromConfigs( | 
|  | 40 | const android::scheduler::RefreshRateConfigs& refreshRateConfigs) { | 
|  | 41 | const auto& allRefreshRates = refreshRateConfigs.getAllRefreshRates(); | 
|  | 42 | std::vector<float> refreshRates; | 
|  | 43 | refreshRates.reserve(allRefreshRates.size()); | 
|  | 44 |  | 
|  | 45 | for (const auto& [ignored, refreshRate] : allRefreshRates) { | 
| Ady Abraham | abc2760 | 2020-04-08 17:20:29 -0700 | [diff] [blame] | 46 | refreshRates.emplace_back(refreshRate->getFps()); | 
| Ady Abraham | 60120a0 | 2020-03-23 11:23:26 -0700 | [diff] [blame] | 47 | } | 
|  | 48 |  | 
|  | 49 | return refreshRates; | 
|  | 50 | } | 
|  | 51 |  | 
| Dominik Laskowski | eddeda1 | 2019-07-19 11:54:13 -0700 | [diff] [blame] | 52 | } // namespace | 
|  | 53 |  | 
|  | 54 | namespace android::scheduler { | 
|  | 55 |  | 
| Ady Abraham | 9e16a48 | 2019-12-03 17:19:41 -0800 | [diff] [blame] | 56 | PhaseConfiguration::~PhaseConfiguration() = default; | 
| Ana Krulec | 757f63a | 2019-01-25 10:46:18 -0800 | [diff] [blame] | 57 |  | 
|  | 58 | namespace impl { | 
| Dominik Laskowski | eddeda1 | 2019-07-19 11:54:13 -0700 | [diff] [blame] | 59 |  | 
| Ady Abraham | 9e16a48 | 2019-12-03 17:19:41 -0800 | [diff] [blame] | 60 | PhaseOffsets::PhaseOffsets(const scheduler::RefreshRateConfigs& refreshRateConfigs) | 
| Ady Abraham | 60120a0 | 2020-03-23 11:23:26 -0700 | [diff] [blame] | 61 | : PhaseOffsets(getRefreshRatesFromConfigs(refreshRateConfigs), | 
| Ady Abraham | abc2760 | 2020-04-08 17:20:29 -0700 | [diff] [blame] | 62 | refreshRateConfigs.getCurrentRefreshRate().getFps(), | 
| Ady Abraham | c6c8182 | 2020-04-28 10:28:00 -0700 | [diff] [blame] | 63 | sysprop::vsync_event_phase_offset_ns(1000000), | 
|  | 64 | sysprop::vsync_sf_event_phase_offset_ns(1000000), | 
|  | 65 | getProperty("debug.sf.early_phase_offset_ns"), | 
|  | 66 | getProperty("debug.sf.early_gl_phase_offset_ns"), | 
|  | 67 | getProperty("debug.sf.early_app_phase_offset_ns"), | 
|  | 68 | getProperty("debug.sf.early_gl_app_phase_offset_ns"), | 
| Ady Abraham | 60120a0 | 2020-03-23 11:23:26 -0700 | [diff] [blame] | 69 | // Below defines the threshold when an offset is considered to be negative, | 
|  | 70 | // i.e. targeting for the N+2 vsync instead of N+1. This means that: For offset | 
|  | 71 | // < threshold, SF wake up (vsync_duration - offset) before HW vsync. For | 
|  | 72 | // offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW | 
|  | 73 | // vsync. | 
|  | 74 | getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns") | 
|  | 75 | .value_or(std::numeric_limits<nsecs_t>::max())) {} | 
|  | 76 |  | 
|  | 77 | PhaseOffsets::PhaseOffsets(const std::vector<float>& refreshRates, float currentFps, | 
| Ady Abraham | c6c8182 | 2020-04-28 10:28:00 -0700 | [diff] [blame] | 78 | nsecs_t vsyncPhaseOffsetNs, nsecs_t sfVSyncPhaseOffsetNs, | 
|  | 79 | std::optional<nsecs_t> earlySfOffsetNs, | 
|  | 80 | std::optional<nsecs_t> earlyGlSfOffsetNs, | 
|  | 81 | std::optional<nsecs_t> earlyAppOffsetNs, | 
|  | 82 | std::optional<nsecs_t> earlyGlAppOffsetNs, nsecs_t thresholdForNextVsync) | 
|  | 83 | : mVSyncPhaseOffsetNs(vsyncPhaseOffsetNs), | 
|  | 84 | mSfVSyncPhaseOffsetNs(sfVSyncPhaseOffsetNs), | 
|  | 85 | mEarlySfOffsetNs(earlySfOffsetNs), | 
|  | 86 | mEarlyGlSfOffsetNs(earlyGlSfOffsetNs), | 
|  | 87 | mEarlyAppOffsetNs(earlyAppOffsetNs), | 
|  | 88 | mEarlyGlAppOffsetNs(earlyGlAppOffsetNs), | 
|  | 89 | mThresholdForNextVsync(thresholdForNextVsync), | 
| Ady Abraham | 60120a0 | 2020-03-23 11:23:26 -0700 | [diff] [blame] | 90 | mOffsets(initializeOffsets(refreshRates)), | 
|  | 91 | mRefreshRateFps(currentFps) {} | 
| Ana Krulec | 757f63a | 2019-01-25 10:46:18 -0800 | [diff] [blame] | 92 |  | 
|  | 93 | void PhaseOffsets::dump(std::string& result) const { | 
| Ady Abraham | 9e16a48 | 2019-12-03 17:19:41 -0800 | [diff] [blame] | 94 | const auto [early, earlyGl, late] = getCurrentOffsets(); | 
| Dominik Laskowski | 9804183 | 2019-08-01 18:35:59 -0700 | [diff] [blame] | 95 | using base::StringAppendF; | 
|  | 96 | StringAppendF(&result, | 
|  | 97 | "           app phase: %9" PRId64 " ns\t         SF phase: %9" PRId64 " ns\n" | 
|  | 98 | "     early app phase: %9" PRId64 " ns\t   early SF phase: %9" PRId64 " ns\n" | 
|  | 99 | "  GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n" | 
|  | 100 | "next VSYNC threshold: %9" PRId64 " ns\n", | 
| Ady Abraham | 9e16a48 | 2019-12-03 17:19:41 -0800 | [diff] [blame] | 101 | late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf, | 
|  | 102 | mThresholdForNextVsync); | 
| Ana Krulec | 757f63a | 2019-01-25 10:46:18 -0800 | [diff] [blame] | 103 | } | 
|  | 104 |  | 
| Ady Abraham | 090d42c | 2020-01-08 12:08:11 -0800 | [diff] [blame] | 105 | std::unordered_map<float, PhaseOffsets::Offsets> PhaseOffsets::initializeOffsets( | 
| Ady Abraham | 60120a0 | 2020-03-23 11:23:26 -0700 | [diff] [blame] | 106 | const std::vector<float>& refreshRates) const { | 
| Ady Abraham | 090d42c | 2020-01-08 12:08:11 -0800 | [diff] [blame] | 107 | std::unordered_map<float, Offsets> offsets; | 
| Ady Abraham | 9e16a48 | 2019-12-03 17:19:41 -0800 | [diff] [blame] | 108 |  | 
| Ady Abraham | 60120a0 | 2020-03-23 11:23:26 -0700 | [diff] [blame] | 109 | for (const auto& refreshRate : refreshRates) { | 
|  | 110 | offsets.emplace(refreshRate, | 
|  | 111 | getPhaseOffsets(refreshRate, static_cast<nsecs_t>(1e9f / refreshRate))); | 
| Ady Abraham | 9e16a48 | 2019-12-03 17:19:41 -0800 | [diff] [blame] | 112 | } | 
|  | 113 | return offsets; | 
|  | 114 | } | 
|  | 115 |  | 
| Sushil Chauhan | bdb9e6d | 2020-03-19 16:15:46 -0700 | [diff] [blame] | 116 | PhaseOffsets::Offsets PhaseOffsets::getPhaseOffsets(float fps, nsecs_t vsyncPeriod) const { | 
|  | 117 | if (fps > 65.0f) { | 
|  | 118 | return getHighFpsOffsets(vsyncPeriod); | 
|  | 119 | } else { | 
|  | 120 | return getDefaultOffsets(vsyncPeriod); | 
|  | 121 | } | 
|  | 122 | } | 
|  | 123 |  | 
| Ady Abraham | 9e16a48 | 2019-12-03 17:19:41 -0800 | [diff] [blame] | 124 | PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t vsyncDuration) const { | 
| Ady Abraham | 9e16a48 | 2019-12-03 17:19:41 -0800 | [diff] [blame] | 125 | return { | 
|  | 126 | { | 
| Ady Abraham | c6c8182 | 2020-04-28 10:28:00 -0700 | [diff] [blame] | 127 | mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) < mThresholdForNextVsync | 
|  | 128 | ? mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) | 
|  | 129 | : mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) - vsyncDuration, | 
| Dominik Laskowski | eddeda1 | 2019-07-19 11:54:13 -0700 | [diff] [blame] | 130 |  | 
| Ady Abraham | c6c8182 | 2020-04-28 10:28:00 -0700 | [diff] [blame] | 131 | mEarlyAppOffsetNs.value_or(mVSyncPhaseOffsetNs), | 
| Ady Abraham | 9e16a48 | 2019-12-03 17:19:41 -0800 | [diff] [blame] | 132 | }, | 
|  | 133 | { | 
| Ady Abraham | c6c8182 | 2020-04-28 10:28:00 -0700 | [diff] [blame] | 134 | mEarlyGlSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) < mThresholdForNextVsync | 
|  | 135 | ? mEarlyGlSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) | 
|  | 136 | : mEarlyGlSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) - vsyncDuration, | 
| Dominik Laskowski | eddeda1 | 2019-07-19 11:54:13 -0700 | [diff] [blame] | 137 |  | 
| Ady Abraham | c6c8182 | 2020-04-28 10:28:00 -0700 | [diff] [blame] | 138 | mEarlyGlAppOffsetNs.value_or(mVSyncPhaseOffsetNs), | 
| Ady Abraham | 9e16a48 | 2019-12-03 17:19:41 -0800 | [diff] [blame] | 139 | }, | 
|  | 140 | { | 
| Ady Abraham | c6c8182 | 2020-04-28 10:28:00 -0700 | [diff] [blame] | 141 | mSfVSyncPhaseOffsetNs < mThresholdForNextVsync | 
|  | 142 | ? mSfVSyncPhaseOffsetNs | 
|  | 143 | : mSfVSyncPhaseOffsetNs - vsyncDuration, | 
| Dominik Laskowski | eddeda1 | 2019-07-19 11:54:13 -0700 | [diff] [blame] | 144 |  | 
| Ady Abraham | c6c8182 | 2020-04-28 10:28:00 -0700 | [diff] [blame] | 145 | mVSyncPhaseOffsetNs, | 
| Ady Abraham | 9e16a48 | 2019-12-03 17:19:41 -0800 | [diff] [blame] | 146 | }, | 
|  | 147 | }; | 
| Ana Krulec | 757f63a | 2019-01-25 10:46:18 -0800 | [diff] [blame] | 148 | } | 
|  | 149 |  | 
| Ady Abraham | 9e16a48 | 2019-12-03 17:19:41 -0800 | [diff] [blame] | 150 | PhaseOffsets::Offsets PhaseOffsets::getHighFpsOffsets(nsecs_t vsyncDuration) const { | 
| Ady Abraham | dec1a41 | 2020-01-24 10:23:50 -0800 | [diff] [blame] | 151 | const auto highFpsLateAppOffsetNs = | 
| Dominik Laskowski | eddeda1 | 2019-07-19 11:54:13 -0700 | [diff] [blame] | 152 | getProperty("debug.sf.high_fps_late_app_phase_offset_ns").value_or(2000000); | 
| Ady Abraham | dec1a41 | 2020-01-24 10:23:50 -0800 | [diff] [blame] | 153 | const auto highFpsLateSfOffsetNs = | 
| Dominik Laskowski | eddeda1 | 2019-07-19 11:54:13 -0700 | [diff] [blame] | 154 | getProperty("debug.sf.high_fps_late_sf_phase_offset_ns").value_or(1000000); | 
|  | 155 |  | 
|  | 156 | const auto highFpsEarlySfOffsetNs = getProperty("debug.sf.high_fps_early_phase_offset_ns"); | 
|  | 157 | const auto highFpsEarlyGlSfOffsetNs = getProperty("debug.sf.high_fps_early_gl_phase_offset_ns"); | 
|  | 158 | const auto highFpsEarlyAppOffsetNs = getProperty("debug.sf.high_fps_early_app_phase_offset_ns"); | 
|  | 159 | const auto highFpsEarlyGlAppOffsetNs = | 
|  | 160 | getProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns"); | 
|  | 161 |  | 
| Ady Abraham | 9e16a48 | 2019-12-03 17:19:41 -0800 | [diff] [blame] | 162 | return { | 
|  | 163 | { | 
|  | 164 | highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs) < mThresholdForNextVsync | 
|  | 165 | ? highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs) | 
|  | 166 | : highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs) - | 
|  | 167 | vsyncDuration, | 
| Dominik Laskowski | eddeda1 | 2019-07-19 11:54:13 -0700 | [diff] [blame] | 168 |  | 
| Ady Abraham | 9e16a48 | 2019-12-03 17:19:41 -0800 | [diff] [blame] | 169 | highFpsEarlyAppOffsetNs.value_or(highFpsLateAppOffsetNs), | 
|  | 170 | }, | 
|  | 171 | { | 
|  | 172 | highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs) < | 
|  | 173 | mThresholdForNextVsync | 
|  | 174 | ? highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs) | 
|  | 175 | : highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs) - | 
|  | 176 | vsyncDuration, | 
| Dominik Laskowski | eddeda1 | 2019-07-19 11:54:13 -0700 | [diff] [blame] | 177 |  | 
| Ady Abraham | 9e16a48 | 2019-12-03 17:19:41 -0800 | [diff] [blame] | 178 | highFpsEarlyGlAppOffsetNs.value_or(highFpsLateAppOffsetNs), | 
|  | 179 | }, | 
|  | 180 | { | 
|  | 181 | highFpsLateSfOffsetNs < mThresholdForNextVsync | 
|  | 182 | ? highFpsLateSfOffsetNs | 
|  | 183 | : highFpsLateSfOffsetNs - vsyncDuration, | 
| Dominik Laskowski | eddeda1 | 2019-07-19 11:54:13 -0700 | [diff] [blame] | 184 |  | 
| Ady Abraham | 9e16a48 | 2019-12-03 17:19:41 -0800 | [diff] [blame] | 185 | highFpsLateAppOffsetNs, | 
|  | 186 | }, | 
|  | 187 | }; | 
|  | 188 | } | 
|  | 189 |  | 
| Ady Abraham | 090d42c | 2020-01-08 12:08:11 -0800 | [diff] [blame] | 190 | PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate(float fps) const { | 
|  | 191 | const auto iter = std::find_if(mOffsets.begin(), mOffsets.end(), | 
|  | 192 | [&fps](const std::pair<float, Offsets>& candidateFps) { | 
|  | 193 | return fpsEqualsWithMargin(fps, candidateFps.first); | 
|  | 194 | }); | 
| Sushil Chauhan | bdb9e6d | 2020-03-19 16:15:46 -0700 | [diff] [blame] | 195 |  | 
|  | 196 | if (iter != mOffsets.end()) { | 
|  | 197 | return iter->second; | 
|  | 198 | } | 
|  | 199 |  | 
|  | 200 | // Unknown refresh rate. This might happen if we get a hotplug event for an external display. | 
|  | 201 | // In this case just construct the offset. | 
|  | 202 | ALOGW("Can't find offset for %.2f fps", fps); | 
|  | 203 | return getPhaseOffsets(fps, static_cast<nsecs_t>(1e9f / fps)); | 
| Ady Abraham | 090d42c | 2020-01-08 12:08:11 -0800 | [diff] [blame] | 204 | } | 
|  | 205 |  | 
| Ady Abraham | 9e16a48 | 2019-12-03 17:19:41 -0800 | [diff] [blame] | 206 | static void validateSysprops() { | 
|  | 207 | const auto validatePropertyBool = [](const char* prop) { | 
|  | 208 | LOG_ALWAYS_FATAL_IF(!property_get_bool(prop, false), "%s is false", prop); | 
|  | 209 | }; | 
|  | 210 |  | 
|  | 211 | validatePropertyBool("debug.sf.use_phase_offsets_as_durations"); | 
|  | 212 |  | 
|  | 213 | LOG_ALWAYS_FATAL_IF(sysprop::vsync_event_phase_offset_ns(-1) != -1, | 
|  | 214 | "ro.surface_flinger.vsync_event_phase_offset_ns is set but expecting " | 
|  | 215 | "duration"); | 
|  | 216 |  | 
|  | 217 | LOG_ALWAYS_FATAL_IF(sysprop::vsync_sf_event_phase_offset_ns(-1) != -1, | 
|  | 218 | "ro.surface_flinger.vsync_sf_event_phase_offset_ns is set but expecting " | 
|  | 219 | "duration"); | 
|  | 220 |  | 
|  | 221 | const auto validateProperty = [](const char* prop) { | 
|  | 222 | LOG_ALWAYS_FATAL_IF(getProperty(prop).has_value(), | 
|  | 223 | "%s is set to %" PRId64 " but expecting duration", prop, | 
|  | 224 | getProperty(prop).value_or(-1)); | 
|  | 225 | }; | 
|  | 226 |  | 
|  | 227 | validateProperty("debug.sf.early_phase_offset_ns"); | 
|  | 228 | validateProperty("debug.sf.early_gl_phase_offset_ns"); | 
|  | 229 | validateProperty("debug.sf.early_app_phase_offset_ns"); | 
|  | 230 | validateProperty("debug.sf.early_gl_app_phase_offset_ns"); | 
|  | 231 | validateProperty("debug.sf.high_fps_late_app_phase_offset_ns"); | 
|  | 232 | validateProperty("debug.sf.high_fps_late_sf_phase_offset_ns"); | 
|  | 233 | validateProperty("debug.sf.high_fps_early_phase_offset_ns"); | 
|  | 234 | validateProperty("debug.sf.high_fps_early_gl_phase_offset_ns"); | 
|  | 235 | validateProperty("debug.sf.high_fps_early_app_phase_offset_ns"); | 
|  | 236 | validateProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns"); | 
|  | 237 | } | 
|  | 238 |  | 
|  | 239 | static nsecs_t sfDurationToOffset(nsecs_t sfDuration, nsecs_t vsyncDuration) { | 
|  | 240 | return sfDuration == -1 ? 1'000'000 : vsyncDuration - sfDuration % vsyncDuration; | 
|  | 241 | } | 
|  | 242 |  | 
|  | 243 | static nsecs_t appDurationToOffset(nsecs_t appDuration, nsecs_t sfDuration, nsecs_t vsyncDuration) { | 
|  | 244 | return sfDuration == -1 ? 1'000'000 | 
|  | 245 | : vsyncDuration - (appDuration + sfDuration) % vsyncDuration; | 
|  | 246 | } | 
|  | 247 |  | 
| Ady Abraham | dfa3736 | 2020-01-21 18:02:39 -0800 | [diff] [blame] | 248 | PhaseDurations::Offsets PhaseDurations::constructOffsets(nsecs_t vsyncDuration) const { | 
|  | 249 | return Offsets{ | 
|  | 250 | { | 
|  | 251 | mSfEarlyDuration < vsyncDuration | 
|  | 252 | ? sfDurationToOffset(mSfEarlyDuration, vsyncDuration) | 
|  | 253 | : sfDurationToOffset(mSfEarlyDuration, vsyncDuration) - vsyncDuration, | 
|  | 254 |  | 
|  | 255 | appDurationToOffset(mAppEarlyDuration, mSfEarlyDuration, vsyncDuration), | 
|  | 256 | }, | 
|  | 257 | { | 
|  | 258 | mSfEarlyGlDuration < vsyncDuration | 
|  | 259 | ? sfDurationToOffset(mSfEarlyGlDuration, vsyncDuration) | 
|  | 260 | : sfDurationToOffset(mSfEarlyGlDuration, vsyncDuration) - vsyncDuration, | 
|  | 261 |  | 
|  | 262 | appDurationToOffset(mAppEarlyGlDuration, mSfEarlyGlDuration, vsyncDuration), | 
|  | 263 | }, | 
|  | 264 | { | 
|  | 265 | mSfDuration < vsyncDuration | 
|  | 266 | ? sfDurationToOffset(mSfDuration, vsyncDuration) | 
|  | 267 | : sfDurationToOffset(mSfDuration, vsyncDuration) - vsyncDuration, | 
|  | 268 |  | 
|  | 269 | appDurationToOffset(mAppDuration, mSfDuration, vsyncDuration), | 
|  | 270 | }, | 
|  | 271 | }; | 
|  | 272 | } | 
|  | 273 |  | 
| Ady Abraham | 9e16a48 | 2019-12-03 17:19:41 -0800 | [diff] [blame] | 274 | std::unordered_map<float, PhaseDurations::Offsets> PhaseDurations::initializeOffsets( | 
|  | 275 | const std::vector<float>& refreshRates) const { | 
| Ady Abraham | 090d42c | 2020-01-08 12:08:11 -0800 | [diff] [blame] | 276 | std::unordered_map<float, Offsets> offsets; | 
| Ady Abraham | 9e16a48 | 2019-12-03 17:19:41 -0800 | [diff] [blame] | 277 |  | 
|  | 278 | for (const auto fps : refreshRates) { | 
| Ady Abraham | dfa3736 | 2020-01-21 18:02:39 -0800 | [diff] [blame] | 279 | offsets.emplace(fps, constructOffsets(static_cast<nsecs_t>(1e9f / fps))); | 
| Ady Abraham | 9e16a48 | 2019-12-03 17:19:41 -0800 | [diff] [blame] | 280 | } | 
|  | 281 | return offsets; | 
|  | 282 | } | 
|  | 283 |  | 
|  | 284 | PhaseDurations::PhaseDurations(const scheduler::RefreshRateConfigs& refreshRateConfigs) | 
|  | 285 | : PhaseDurations(getRefreshRatesFromConfigs(refreshRateConfigs), | 
| Ady Abraham | abc2760 | 2020-04-08 17:20:29 -0700 | [diff] [blame] | 286 | refreshRateConfigs.getCurrentRefreshRate().getFps(), | 
| Ady Abraham | 9e16a48 | 2019-12-03 17:19:41 -0800 | [diff] [blame] | 287 | getProperty("debug.sf.late.sf.duration").value_or(-1), | 
|  | 288 | getProperty("debug.sf.late.app.duration").value_or(-1), | 
|  | 289 | getProperty("debug.sf.early.sf.duration").value_or(mSfDuration), | 
|  | 290 | getProperty("debug.sf.early.app.duration").value_or(mAppDuration), | 
|  | 291 | getProperty("debug.sf.earlyGl.sf.duration").value_or(mSfDuration), | 
|  | 292 | getProperty("debug.sf.earlyGl.app.duration").value_or(mAppDuration)) { | 
|  | 293 | validateSysprops(); | 
|  | 294 | } | 
|  | 295 |  | 
|  | 296 | PhaseDurations::PhaseDurations(const std::vector<float>& refreshRates, float currentFps, | 
|  | 297 | nsecs_t sfDuration, nsecs_t appDuration, nsecs_t sfEarlyDuration, | 
|  | 298 | nsecs_t appEarlyDuration, nsecs_t sfEarlyGlDuration, | 
|  | 299 | nsecs_t appEarlyGlDuration) | 
|  | 300 | : mSfDuration(sfDuration), | 
|  | 301 | mAppDuration(appDuration), | 
|  | 302 | mSfEarlyDuration(sfEarlyDuration), | 
|  | 303 | mAppEarlyDuration(appEarlyDuration), | 
|  | 304 | mSfEarlyGlDuration(sfEarlyGlDuration), | 
|  | 305 | mAppEarlyGlDuration(appEarlyGlDuration), | 
|  | 306 | mOffsets(initializeOffsets(refreshRates)), | 
|  | 307 | mRefreshRateFps(currentFps) {} | 
|  | 308 |  | 
|  | 309 | PhaseOffsets::Offsets PhaseDurations::getOffsetsForRefreshRate(float fps) const { | 
| Ady Abraham | 090d42c | 2020-01-08 12:08:11 -0800 | [diff] [blame] | 310 | const auto iter = std::find_if(mOffsets.begin(), mOffsets.end(), [=](const auto& candidateFps) { | 
|  | 311 | return fpsEqualsWithMargin(fps, candidateFps.first); | 
|  | 312 | }); | 
| Ady Abraham | dfa3736 | 2020-01-21 18:02:39 -0800 | [diff] [blame] | 313 |  | 
|  | 314 | if (iter != mOffsets.end()) { | 
|  | 315 | return iter->second; | 
|  | 316 | } | 
|  | 317 |  | 
| Sushil Chauhan | bdb9e6d | 2020-03-19 16:15:46 -0700 | [diff] [blame] | 318 | // Unknown refresh rate. This might happen if we get a hotplug event for an external display. | 
| Ady Abraham | dfa3736 | 2020-01-21 18:02:39 -0800 | [diff] [blame] | 319 | // In this case just construct the offset. | 
|  | 320 | ALOGW("Can't find offset for %.2f fps", fps); | 
|  | 321 | return constructOffsets(static_cast<nsecs_t>(1e9f / fps)); | 
| Ady Abraham | 9e16a48 | 2019-12-03 17:19:41 -0800 | [diff] [blame] | 322 | } | 
|  | 323 |  | 
|  | 324 | void PhaseDurations::dump(std::string& result) const { | 
|  | 325 | const auto [early, earlyGl, late] = getCurrentOffsets(); | 
|  | 326 | using base::StringAppendF; | 
|  | 327 | StringAppendF(&result, | 
|  | 328 | "           app phase:    %9" PRId64 " ns\t         SF phase:    %9" PRId64 | 
|  | 329 | " ns\n" | 
|  | 330 | "           app duration: %9" PRId64 " ns\t         SF duration: %9" PRId64 | 
|  | 331 | " ns\n" | 
|  | 332 | "     early app phase:    %9" PRId64 " ns\t   early SF phase:    %9" PRId64 | 
|  | 333 | " ns\n" | 
|  | 334 | "     early app duration: %9" PRId64 " ns\t   early SF duration: %9" PRId64 | 
|  | 335 | " ns\n" | 
|  | 336 | "  GL early app phase:    %9" PRId64 " ns\tGL early SF phase:    %9" PRId64 | 
|  | 337 | " ns\n" | 
|  | 338 | "  GL early app duration: %9" PRId64 " ns\tGL early SF duration: %9" PRId64 | 
|  | 339 | " ns\n", | 
|  | 340 | late.app, | 
|  | 341 |  | 
|  | 342 | late.sf, | 
|  | 343 |  | 
|  | 344 | mAppDuration, mSfDuration, | 
|  | 345 |  | 
|  | 346 | early.app, early.sf, | 
|  | 347 |  | 
|  | 348 | mAppEarlyDuration, mSfEarlyDuration, | 
|  | 349 |  | 
|  | 350 | earlyGl.app, | 
|  | 351 |  | 
|  | 352 | earlyGl.sf, | 
|  | 353 |  | 
|  | 354 | mAppEarlyGlDuration, mSfEarlyGlDuration); | 
| Ana Krulec | 757f63a | 2019-01-25 10:46:18 -0800 | [diff] [blame] | 355 | } | 
|  | 356 |  | 
|  | 357 | } // namespace impl | 
| Dominik Laskowski | eddeda1 | 2019-07-19 11:54:13 -0700 | [diff] [blame] | 358 | } // namespace android::scheduler |