| 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 |