| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2013 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 | #define ATRACE_TAG ATRACE_TAG_GRAPHICS | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 18 | //#define LOG_NDEBUG 0 | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 19 |  | 
 | 20 | // This is needed for stdint.h to define INT64_MAX in C++ | 
 | 21 | #define __STDC_LIMIT_MACROS | 
 | 22 |  | 
 | 23 | #include <math.h> | 
 | 24 |  | 
| Mark Salyzyn | a5e161b | 2016-09-29 08:08:05 -0700 | [diff] [blame] | 25 | #include <algorithm> | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 26 |  | 
| Yiwei Zhang | 5434a78 | 2018-12-05 18:06:32 -0800 | [diff] [blame] | 27 | #include <android-base/stringprintf.h> | 
| David Sodman | 1afa8b0 | 2018-10-15 11:20:48 -0700 | [diff] [blame] | 28 | #include <cutils/properties.h> | 
| Yiwei Zhang | 5434a78 | 2018-12-05 18:06:32 -0800 | [diff] [blame] | 29 | #include <log/log.h> | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 30 | #include <utils/Thread.h> | 
 | 31 | #include <utils/Trace.h> | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 32 |  | 
| Brian Anderson | fbc80ae | 2017-05-26 16:23:54 -0700 | [diff] [blame] | 33 | #include <ui/FenceTime.h> | 
| Mark Salyzyn | a5e161b | 2016-09-29 08:08:05 -0700 | [diff] [blame] | 34 |  | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 35 | #include "DispSync.h" | 
 | 36 | #include "EventLog/EventLog.h" | 
| Lloyd Pique | 78ce418 | 2018-01-31 16:39:51 -0800 | [diff] [blame] | 37 | #include "SurfaceFlinger.h" | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 38 |  | 
| Yiwei Zhang | 5434a78 | 2018-12-05 18:06:32 -0800 | [diff] [blame] | 39 | using android::base::StringAppendF; | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 40 | using std::max; | 
 | 41 | using std::min; | 
 | 42 |  | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 43 | namespace android { | 
 | 44 |  | 
| Lloyd Pique | 41be5d2 | 2018-06-21 13:11:48 -0700 | [diff] [blame] | 45 | DispSync::~DispSync() = default; | 
| Kevin DuBois | 7b743be | 2019-02-27 10:05:48 -0800 | [diff] [blame] | 46 | DispSync::Callback::~Callback() = default; | 
| Lloyd Pique | 41be5d2 | 2018-06-21 13:11:48 -0700 | [diff] [blame] | 47 |  | 
 | 48 | namespace impl { | 
 | 49 |  | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 50 | // Setting this to true adds a zero-phase tracer for correlating with hardware | 
 | 51 | // vsync events | 
 | 52 | static const bool kEnableZeroPhaseTracer = false; | 
 | 53 |  | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 54 | // This is the threshold used to determine when hardware vsync events are | 
 | 55 | // needed to re-synchronize the software vsync model with the hardware.  The | 
 | 56 | // error metric used is the mean of the squared difference between each | 
 | 57 | // present time and the nearest software-predicted vsync. | 
| Lloyd Pique | 78ce418 | 2018-01-31 16:39:51 -0800 | [diff] [blame] | 58 | static const nsecs_t kErrorThreshold = 160000000000; // 400 usec squared | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 59 |  | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 60 | #undef LOG_TAG | 
 | 61 | #define LOG_TAG "DispSyncThread" | 
| Lloyd Pique | 78ce418 | 2018-01-31 16:39:51 -0800 | [diff] [blame] | 62 | class DispSyncThread : public Thread { | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 63 | public: | 
| Ana Krulec | 064a82f | 2018-09-11 16:03:03 -0700 | [diff] [blame] | 64 |     DispSyncThread(const char* name, bool showTraceDetailedInfo) | 
| Lloyd Pique | 78ce418 | 2018-01-31 16:39:51 -0800 | [diff] [blame] | 65 |           : mName(name), | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 66 |             mStop(false), | 
| Alec Mouri | 016b8dd | 2019-04-24 15:16:05 -0700 | [diff] [blame] | 67 |             mModelLocked(false), | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 68 |             mPeriod(0), | 
 | 69 |             mPhase(0), | 
| Haixia Shi | 676b1f6 | 2015-10-28 16:19:01 -0700 | [diff] [blame] | 70 |             mReferenceTime(0), | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 71 |             mWakeupLatency(0), | 
| Ana Krulec | 064a82f | 2018-09-11 16:03:03 -0700 | [diff] [blame] | 72 |             mFrameNumber(0), | 
 | 73 |             mTraceDetailedInfo(showTraceDetailedInfo) {} | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 74 |  | 
 | 75 |     virtual ~DispSyncThread() {} | 
 | 76 |  | 
| Haixia Shi | 676b1f6 | 2015-10-28 16:19:01 -0700 | [diff] [blame] | 77 |     void updateModel(nsecs_t period, nsecs_t phase, nsecs_t referenceTime) { | 
| Ana Krulec | 064a82f | 2018-09-11 16:03:03 -0700 | [diff] [blame] | 78 |         if (mTraceDetailedInfo) ATRACE_CALL(); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 79 |         Mutex::Autolock lock(mMutex); | 
| Alec Mouri | 75b0b62 | 2019-03-12 18:56:00 +0000 | [diff] [blame] | 80 |  | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 81 |         mPhase = phase; | 
| Alec Mouri | c3a482d | 2019-05-21 00:51:01 -0700 | [diff] [blame] | 82 |         const bool referenceTimeChanged = mReferenceTime != referenceTime; | 
| Haixia Shi | 676b1f6 | 2015-10-28 16:19:01 -0700 | [diff] [blame] | 83 |         mReferenceTime = referenceTime; | 
| Alec Mouri | 75b0b62 | 2019-03-12 18:56:00 +0000 | [diff] [blame] | 84 |         if (mPeriod != 0 && mPeriod != period && mReferenceTime != 0) { | 
 | 85 |             // Inflate the reference time to be the most recent predicted | 
 | 86 |             // vsync before the current time. | 
 | 87 |             const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); | 
 | 88 |             const nsecs_t baseTime = now - mReferenceTime; | 
 | 89 |             const nsecs_t numOldPeriods = baseTime / mPeriod; | 
 | 90 |             mReferenceTime = mReferenceTime + (numOldPeriods)*mPeriod; | 
 | 91 |         } | 
 | 92 |         mPeriod = period; | 
| Alec Mouri | c3a482d | 2019-05-21 00:51:01 -0700 | [diff] [blame] | 93 |         if (!mModelLocked && referenceTimeChanged) { | 
 | 94 |             for (auto& eventListener : mEventListeners) { | 
| Ady Abraham | 81ca00f | 2019-06-19 17:01:57 -0700 | [diff] [blame] | 95 |                 eventListener.mLastEventTime = mReferenceTime + mPhase + eventListener.mPhase; | 
 | 96 |                 // If mLastEventTime is after mReferenceTime (can happen when positive phase offsets | 
 | 97 |                 // are used) we treat it as like it happened in previous period. | 
 | 98 |                 if (eventListener.mLastEventTime > mReferenceTime) { | 
 | 99 |                     eventListener.mLastEventTime -= mPeriod; | 
 | 100 |                 } | 
| Alec Mouri | c3a482d | 2019-05-21 00:51:01 -0700 | [diff] [blame] | 101 |             } | 
 | 102 |         } | 
| Alec Mouri | f5fe85c | 2019-02-22 13:40:36 -0800 | [diff] [blame] | 103 |         if (mTraceDetailedInfo) { | 
 | 104 |             ATRACE_INT64("DispSync:Period", mPeriod); | 
 | 105 |             ATRACE_INT64("DispSync:Phase", mPhase + mPeriod / 2); | 
 | 106 |             ATRACE_INT64("DispSync:Reference Time", mReferenceTime); | 
 | 107 |         } | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 108 |         ALOGV("[%s] updateModel: mPeriod = %" PRId64 ", mPhase = %" PRId64 | 
| Lloyd Pique | 78ce418 | 2018-01-31 16:39:51 -0800 | [diff] [blame] | 109 |               " mReferenceTime = %" PRId64, | 
 | 110 |               mName, ns2us(mPeriod), ns2us(mPhase), ns2us(mReferenceTime)); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 111 |         mCond.signal(); | 
 | 112 |     } | 
 | 113 |  | 
 | 114 |     void stop() { | 
| Ana Krulec | 064a82f | 2018-09-11 16:03:03 -0700 | [diff] [blame] | 115 |         if (mTraceDetailedInfo) ATRACE_CALL(); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 116 |         Mutex::Autolock lock(mMutex); | 
 | 117 |         mStop = true; | 
 | 118 |         mCond.signal(); | 
 | 119 |     } | 
 | 120 |  | 
| Alec Mouri | 016b8dd | 2019-04-24 15:16:05 -0700 | [diff] [blame] | 121 |     void lockModel() { | 
 | 122 |         Mutex::Autolock lock(mMutex); | 
 | 123 |         mModelLocked = true; | 
| Alec Mouri | f8e689c | 2019-05-20 18:32:22 -0700 | [diff] [blame] | 124 |         ATRACE_INT("DispSync:ModelLocked", mModelLocked); | 
| Alec Mouri | 016b8dd | 2019-04-24 15:16:05 -0700 | [diff] [blame] | 125 |     } | 
 | 126 |  | 
 | 127 |     void unlockModel() { | 
 | 128 |         Mutex::Autolock lock(mMutex); | 
 | 129 |         mModelLocked = false; | 
| Alec Mouri | f8e689c | 2019-05-20 18:32:22 -0700 | [diff] [blame] | 130 |         ATRACE_INT("DispSync:ModelLocked", mModelLocked); | 
| Alec Mouri | 016b8dd | 2019-04-24 15:16:05 -0700 | [diff] [blame] | 131 |     } | 
 | 132 |  | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 133 |     virtual bool threadLoop() { | 
 | 134 |         status_t err; | 
 | 135 |         nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 136 |  | 
 | 137 |         while (true) { | 
| Ana Krulec | 9a52b19 | 2018-07-12 18:18:47 -0400 | [diff] [blame] | 138 |             std::vector<CallbackInvocation> callbackInvocations; | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 139 |  | 
 | 140 |             nsecs_t targetTime = 0; | 
 | 141 |  | 
 | 142 |             { // Scope for lock | 
 | 143 |                 Mutex::Autolock lock(mMutex); | 
 | 144 |  | 
| Ana Krulec | 064a82f | 2018-09-11 16:03:03 -0700 | [diff] [blame] | 145 |                 if (mTraceDetailedInfo) { | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 146 |                     ATRACE_INT64("DispSync:Frame", mFrameNumber); | 
 | 147 |                 } | 
 | 148 |                 ALOGV("[%s] Frame %" PRId64, mName, mFrameNumber); | 
 | 149 |                 ++mFrameNumber; | 
 | 150 |  | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 151 |                 if (mStop) { | 
 | 152 |                     return false; | 
 | 153 |                 } | 
 | 154 |  | 
 | 155 |                 if (mPeriod == 0) { | 
 | 156 |                     err = mCond.wait(mMutex); | 
 | 157 |                     if (err != NO_ERROR) { | 
| Lloyd Pique | 78ce418 | 2018-01-31 16:39:51 -0800 | [diff] [blame] | 158 |                         ALOGE("error waiting for new events: %s (%d)", strerror(-err), err); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 159 |                         return false; | 
 | 160 |                     } | 
 | 161 |                     continue; | 
 | 162 |                 } | 
 | 163 |  | 
| Dan Stoza | 8f8374d | 2016-04-19 10:03:46 -0700 | [diff] [blame] | 164 |                 targetTime = computeNextEventTimeLocked(now); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 165 |  | 
 | 166 |                 bool isWakeup = false; | 
 | 167 |  | 
 | 168 |                 if (now < targetTime) { | 
| Ana Krulec | 064a82f | 2018-09-11 16:03:03 -0700 | [diff] [blame] | 169 |                     if (mTraceDetailedInfo) ATRACE_NAME("DispSync waiting"); | 
| Dan Stoza | 8f8374d | 2016-04-19 10:03:46 -0700 | [diff] [blame] | 170 |  | 
 | 171 |                     if (targetTime == INT64_MAX) { | 
 | 172 |                         ALOGV("[%s] Waiting forever", mName); | 
 | 173 |                         err = mCond.wait(mMutex); | 
 | 174 |                     } else { | 
| Lloyd Pique | 78ce418 | 2018-01-31 16:39:51 -0800 | [diff] [blame] | 175 |                         ALOGV("[%s] Waiting until %" PRId64, mName, ns2us(targetTime)); | 
| Dan Stoza | 8f8374d | 2016-04-19 10:03:46 -0700 | [diff] [blame] | 176 |                         err = mCond.waitRelative(mMutex, targetTime - now); | 
 | 177 |                     } | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 178 |  | 
 | 179 |                     if (err == TIMED_OUT) { | 
 | 180 |                         isWakeup = true; | 
 | 181 |                     } else if (err != NO_ERROR) { | 
| Lloyd Pique | 78ce418 | 2018-01-31 16:39:51 -0800 | [diff] [blame] | 182 |                         ALOGE("error waiting for next event: %s (%d)", strerror(-err), err); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 183 |                         return false; | 
 | 184 |                     } | 
 | 185 |                 } | 
 | 186 |  | 
 | 187 |                 now = systemTime(SYSTEM_TIME_MONOTONIC); | 
 | 188 |  | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 189 |                 // Don't correct by more than 1.5 ms | 
 | 190 |                 static const nsecs_t kMaxWakeupLatency = us2ns(1500); | 
 | 191 |  | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 192 |                 if (isWakeup) { | 
| Lloyd Pique | 78ce418 | 2018-01-31 16:39:51 -0800 | [diff] [blame] | 193 |                     mWakeupLatency = ((mWakeupLatency * 63) + (now - targetTime)) / 64; | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 194 |                     mWakeupLatency = min(mWakeupLatency, kMaxWakeupLatency); | 
| Ana Krulec | 064a82f | 2018-09-11 16:03:03 -0700 | [diff] [blame] | 195 |                     if (mTraceDetailedInfo) { | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 196 |                         ATRACE_INT64("DispSync:WakeupLat", now - targetTime); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 197 |                         ATRACE_INT64("DispSync:AvgWakeupLat", mWakeupLatency); | 
 | 198 |                     } | 
 | 199 |                 } | 
 | 200 |  | 
 | 201 |                 callbackInvocations = gatherCallbackInvocationsLocked(now); | 
 | 202 |             } | 
 | 203 |  | 
 | 204 |             if (callbackInvocations.size() > 0) { | 
| Andy McFadden | 645b1f7 | 2014-06-10 14:43:32 -0700 | [diff] [blame] | 205 |                 fireCallbackInvocations(callbackInvocations); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 206 |             } | 
 | 207 |         } | 
 | 208 |  | 
 | 209 |         return false; | 
 | 210 |     } | 
 | 211 |  | 
| Alec Mouri | 7355eb2 | 2019-03-05 14:19:10 -0800 | [diff] [blame] | 212 |     status_t addEventListener(const char* name, nsecs_t phase, DispSync::Callback* callback, | 
 | 213 |                               nsecs_t lastCallbackTime) { | 
| Ana Krulec | 064a82f | 2018-09-11 16:03:03 -0700 | [diff] [blame] | 214 |         if (mTraceDetailedInfo) ATRACE_CALL(); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 215 |         Mutex::Autolock lock(mMutex); | 
 | 216 |  | 
 | 217 |         for (size_t i = 0; i < mEventListeners.size(); i++) { | 
 | 218 |             if (mEventListeners[i].mCallback == callback) { | 
 | 219 |                 return BAD_VALUE; | 
 | 220 |             } | 
 | 221 |         } | 
 | 222 |  | 
 | 223 |         EventListener listener; | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 224 |         listener.mName = name; | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 225 |         listener.mPhase = phase; | 
 | 226 |         listener.mCallback = callback; | 
| Jamie Gennis | 629b987 | 2013-10-29 13:36:12 -0700 | [diff] [blame] | 227 |  | 
 | 228 |         // We want to allow the firstmost future event to fire without | 
| Alec Mouri | 8183598 | 2019-02-27 13:40:44 -0800 | [diff] [blame] | 229 |         // allowing any past events to fire. To do this extrapolate from | 
 | 230 |         // mReferenceTime the most recent hardware vsync, and pin the | 
 | 231 |         // last event time there. | 
 | 232 |         const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); | 
 | 233 |         if (mPeriod != 0) { | 
 | 234 |             const nsecs_t baseTime = now - mReferenceTime; | 
 | 235 |             const nsecs_t numPeriodsSinceReference = baseTime / mPeriod; | 
 | 236 |             const nsecs_t predictedReference = mReferenceTime + numPeriodsSinceReference * mPeriod; | 
| Alec Mouri | df3d2e1 | 2019-05-02 17:58:46 +0000 | [diff] [blame] | 237 |             const nsecs_t phaseCorrection = mPhase + listener.mPhase; | 
 | 238 |             const nsecs_t predictedLastEventTime = predictedReference + phaseCorrection; | 
 | 239 |             if (predictedLastEventTime >= now) { | 
 | 240 |                 // Make sure that the last event time does not exceed the current time. | 
 | 241 |                 // If it would, then back the last event time by a period. | 
 | 242 |                 listener.mLastEventTime = predictedLastEventTime - mPeriod; | 
 | 243 |             } else { | 
 | 244 |                 listener.mLastEventTime = predictedLastEventTime; | 
| Alec Mouri | 8183598 | 2019-02-27 13:40:44 -0800 | [diff] [blame] | 245 |             } | 
 | 246 |         } else { | 
 | 247 |             listener.mLastEventTime = now + mPhase - mWakeupLatency; | 
 | 248 |         } | 
| Jamie Gennis | 629b987 | 2013-10-29 13:36:12 -0700 | [diff] [blame] | 249 |  | 
| Alec Mouri | 7355eb2 | 2019-03-05 14:19:10 -0800 | [diff] [blame] | 250 |         if (lastCallbackTime <= 0) { | 
 | 251 |             // If there is no prior callback time, try to infer one based on the | 
 | 252 |             // logical last event time. | 
 | 253 |             listener.mLastCallbackTime = listener.mLastEventTime + mWakeupLatency; | 
 | 254 |         } else { | 
 | 255 |             listener.mLastCallbackTime = lastCallbackTime; | 
 | 256 |         } | 
 | 257 |  | 
| Ana Krulec | 9a52b19 | 2018-07-12 18:18:47 -0400 | [diff] [blame] | 258 |         mEventListeners.push_back(listener); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 259 |  | 
 | 260 |         mCond.signal(); | 
 | 261 |  | 
 | 262 |         return NO_ERROR; | 
 | 263 |     } | 
 | 264 |  | 
| Alec Mouri | 7355eb2 | 2019-03-05 14:19:10 -0800 | [diff] [blame] | 265 |     status_t removeEventListener(DispSync::Callback* callback, nsecs_t* outLastCallback) { | 
| Ana Krulec | 064a82f | 2018-09-11 16:03:03 -0700 | [diff] [blame] | 266 |         if (mTraceDetailedInfo) ATRACE_CALL(); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 267 |         Mutex::Autolock lock(mMutex); | 
 | 268 |  | 
| Ana Krulec | 9a52b19 | 2018-07-12 18:18:47 -0400 | [diff] [blame] | 269 |         for (std::vector<EventListener>::iterator it = mEventListeners.begin(); | 
 | 270 |              it != mEventListeners.end(); ++it) { | 
 | 271 |             if (it->mCallback == callback) { | 
| Alec Mouri | 7355eb2 | 2019-03-05 14:19:10 -0800 | [diff] [blame] | 272 |                 *outLastCallback = it->mLastCallbackTime; | 
| Ana Krulec | 9a52b19 | 2018-07-12 18:18:47 -0400 | [diff] [blame] | 273 |                 mEventListeners.erase(it); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 274 |                 mCond.signal(); | 
 | 275 |                 return NO_ERROR; | 
 | 276 |             } | 
 | 277 |         } | 
 | 278 |  | 
 | 279 |         return BAD_VALUE; | 
 | 280 |     } | 
 | 281 |  | 
| Dan Stoza | 84d619e | 2018-03-28 17:07:36 -0700 | [diff] [blame] | 282 |     status_t changePhaseOffset(DispSync::Callback* callback, nsecs_t phase) { | 
| Ana Krulec | 064a82f | 2018-09-11 16:03:03 -0700 | [diff] [blame] | 283 |         if (mTraceDetailedInfo) ATRACE_CALL(); | 
| Dan Stoza | 84d619e | 2018-03-28 17:07:36 -0700 | [diff] [blame] | 284 |         Mutex::Autolock lock(mMutex); | 
 | 285 |  | 
| Ana Krulec | 9a52b19 | 2018-07-12 18:18:47 -0400 | [diff] [blame] | 286 |         for (auto& eventListener : mEventListeners) { | 
 | 287 |             if (eventListener.mCallback == callback) { | 
 | 288 |                 const nsecs_t oldPhase = eventListener.mPhase; | 
 | 289 |                 eventListener.mPhase = phase; | 
| Dan Stoza | 84d619e | 2018-03-28 17:07:36 -0700 | [diff] [blame] | 290 |  | 
 | 291 |                 // Pretend that the last time this event was handled at the same frame but with the | 
 | 292 |                 // new offset to allow for a seamless offset change without double-firing or | 
 | 293 |                 // skipping. | 
| Jorim Jaggi | 22ec38b | 2018-06-19 15:57:08 +0200 | [diff] [blame] | 294 |                 nsecs_t diff = oldPhase - phase; | 
| Ana Krulec | 9a52b19 | 2018-07-12 18:18:47 -0400 | [diff] [blame] | 295 |                 eventListener.mLastEventTime -= diff; | 
| Ady Abraham | 45e4e36 | 2019-06-07 18:20:51 -0700 | [diff] [blame] | 296 |                 eventListener.mLastCallbackTime -= diff; | 
| Dan Stoza | 84d619e | 2018-03-28 17:07:36 -0700 | [diff] [blame] | 297 |                 mCond.signal(); | 
 | 298 |                 return NO_ERROR; | 
 | 299 |             } | 
 | 300 |         } | 
| Dan Stoza | 84d619e | 2018-03-28 17:07:36 -0700 | [diff] [blame] | 301 |         return BAD_VALUE; | 
 | 302 |     } | 
 | 303 |  | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 304 | private: | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 305 |     struct EventListener { | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 306 |         const char* mName; | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 307 |         nsecs_t mPhase; | 
 | 308 |         nsecs_t mLastEventTime; | 
| Alec Mouri | 7355eb2 | 2019-03-05 14:19:10 -0800 | [diff] [blame] | 309 |         nsecs_t mLastCallbackTime; | 
| Lloyd Pique | e83f931 | 2018-02-01 12:53:17 -0800 | [diff] [blame] | 310 |         DispSync::Callback* mCallback; | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 311 |     }; | 
 | 312 |  | 
 | 313 |     struct CallbackInvocation { | 
| Lloyd Pique | e83f931 | 2018-02-01 12:53:17 -0800 | [diff] [blame] | 314 |         DispSync::Callback* mCallback; | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 315 |         nsecs_t mEventTime; | 
 | 316 |     }; | 
 | 317 |  | 
 | 318 |     nsecs_t computeNextEventTimeLocked(nsecs_t now) { | 
| Ana Krulec | 064a82f | 2018-09-11 16:03:03 -0700 | [diff] [blame] | 319 |         if (mTraceDetailedInfo) ATRACE_CALL(); | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 320 |         ALOGV("[%s] computeNextEventTimeLocked", mName); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 321 |         nsecs_t nextEventTime = INT64_MAX; | 
 | 322 |         for (size_t i = 0; i < mEventListeners.size(); i++) { | 
| Lloyd Pique | 78ce418 | 2018-01-31 16:39:51 -0800 | [diff] [blame] | 323 |             nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i], now); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 324 |  | 
 | 325 |             if (t < nextEventTime) { | 
 | 326 |                 nextEventTime = t; | 
 | 327 |             } | 
 | 328 |         } | 
 | 329 |  | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 330 |         ALOGV("[%s] nextEventTime = %" PRId64, mName, ns2us(nextEventTime)); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 331 |         return nextEventTime; | 
 | 332 |     } | 
 | 333 |  | 
| Alec Mouri | 7355eb2 | 2019-03-05 14:19:10 -0800 | [diff] [blame] | 334 |     // Sanity check that the duration is close enough in length to a period without | 
 | 335 |     // falling into double-rate vsyncs. | 
| Alec Mouri | df3d2e1 | 2019-05-02 17:58:46 +0000 | [diff] [blame] | 336 |     bool isCloseToPeriod(nsecs_t duration) { | 
| Alec Mouri | 7355eb2 | 2019-03-05 14:19:10 -0800 | [diff] [blame] | 337 |         // Ratio of 3/5 is arbitrary, but it must be greater than 1/2. | 
 | 338 |         return duration < (3 * mPeriod) / 5; | 
 | 339 |     } | 
 | 340 |  | 
| Ana Krulec | 9a52b19 | 2018-07-12 18:18:47 -0400 | [diff] [blame] | 341 |     std::vector<CallbackInvocation> gatherCallbackInvocationsLocked(nsecs_t now) { | 
| Ana Krulec | 064a82f | 2018-09-11 16:03:03 -0700 | [diff] [blame] | 342 |         if (mTraceDetailedInfo) ATRACE_CALL(); | 
| Lloyd Pique | 78ce418 | 2018-01-31 16:39:51 -0800 | [diff] [blame] | 343 |         ALOGV("[%s] gatherCallbackInvocationsLocked @ %" PRId64, mName, ns2us(now)); | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 344 |  | 
| Ana Krulec | 9a52b19 | 2018-07-12 18:18:47 -0400 | [diff] [blame] | 345 |         std::vector<CallbackInvocation> callbackInvocations; | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 346 |         nsecs_t onePeriodAgo = now - mPeriod; | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 347 |  | 
| Ana Krulec | 9a52b19 | 2018-07-12 18:18:47 -0400 | [diff] [blame] | 348 |         for (auto& eventListener : mEventListeners) { | 
 | 349 |             nsecs_t t = computeListenerNextEventTimeLocked(eventListener, onePeriodAgo); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 350 |  | 
| Jamie Gennis | 0d5c60e | 2013-10-09 17:49:37 -0700 | [diff] [blame] | 351 |             if (t < now) { | 
| Alec Mouri | df3d2e1 | 2019-05-02 17:58:46 +0000 | [diff] [blame] | 352 |                 if (isCloseToPeriod(now - eventListener.mLastCallbackTime)) { | 
| Alec Mouri | 7355eb2 | 2019-03-05 14:19:10 -0800 | [diff] [blame] | 353 |                     eventListener.mLastEventTime = t; | 
| Alec Mouri | 7355eb2 | 2019-03-05 14:19:10 -0800 | [diff] [blame] | 354 |                     ALOGV("[%s] [%s] Skipping event due to model error", mName, | 
 | 355 |                           eventListener.mName); | 
 | 356 |                     continue; | 
 | 357 |                 } | 
| Ady Abraham | 45e4e36 | 2019-06-07 18:20:51 -0700 | [diff] [blame] | 358 |  | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 359 |                 CallbackInvocation ci; | 
| Ana Krulec | 9a52b19 | 2018-07-12 18:18:47 -0400 | [diff] [blame] | 360 |                 ci.mCallback = eventListener.mCallback; | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 361 |                 ci.mEventTime = t; | 
| Alec Mouri | 7355eb2 | 2019-03-05 14:19:10 -0800 | [diff] [blame] | 362 |                 ALOGV("[%s] [%s] Preparing to fire, latency: %" PRId64, mName, eventListener.mName, | 
 | 363 |                       t - eventListener.mLastEventTime); | 
| Ana Krulec | 9a52b19 | 2018-07-12 18:18:47 -0400 | [diff] [blame] | 364 |                 callbackInvocations.push_back(ci); | 
 | 365 |                 eventListener.mLastEventTime = t; | 
| Alec Mouri | 7355eb2 | 2019-03-05 14:19:10 -0800 | [diff] [blame] | 366 |                 eventListener.mLastCallbackTime = now; | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 367 |             } | 
 | 368 |         } | 
 | 369 |  | 
 | 370 |         return callbackInvocations; | 
 | 371 |     } | 
 | 372 |  | 
| Lloyd Pique | 78ce418 | 2018-01-31 16:39:51 -0800 | [diff] [blame] | 373 |     nsecs_t computeListenerNextEventTimeLocked(const EventListener& listener, nsecs_t baseTime) { | 
| Ana Krulec | 064a82f | 2018-09-11 16:03:03 -0700 | [diff] [blame] | 374 |         if (mTraceDetailedInfo) ATRACE_CALL(); | 
| Lloyd Pique | 78ce418 | 2018-01-31 16:39:51 -0800 | [diff] [blame] | 375 |         ALOGV("[%s] [%s] computeListenerNextEventTimeLocked(%" PRId64 ")", mName, listener.mName, | 
 | 376 |               ns2us(baseTime)); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 377 |  | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 378 |         nsecs_t lastEventTime = listener.mLastEventTime + mWakeupLatency; | 
 | 379 |         ALOGV("[%s] lastEventTime: %" PRId64, mName, ns2us(lastEventTime)); | 
 | 380 |         if (baseTime < lastEventTime) { | 
 | 381 |             baseTime = lastEventTime; | 
| Lloyd Pique | 78ce418 | 2018-01-31 16:39:51 -0800 | [diff] [blame] | 382 |             ALOGV("[%s] Clamping baseTime to lastEventTime -> %" PRId64, mName, ns2us(baseTime)); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 383 |         } | 
 | 384 |  | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 385 |         baseTime -= mReferenceTime; | 
 | 386 |         ALOGV("[%s] Relative baseTime = %" PRId64, mName, ns2us(baseTime)); | 
 | 387 |         nsecs_t phase = mPhase + listener.mPhase; | 
 | 388 |         ALOGV("[%s] Phase = %" PRId64, mName, ns2us(phase)); | 
 | 389 |         baseTime -= phase; | 
 | 390 |         ALOGV("[%s] baseTime - phase = %" PRId64, mName, ns2us(baseTime)); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 391 |  | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 392 |         // If our previous time is before the reference (because the reference | 
 | 393 |         // has since been updated), the division by mPeriod will truncate | 
 | 394 |         // towards zero instead of computing the floor. Since in all cases | 
 | 395 |         // before the reference we want the next time to be effectively now, we | 
 | 396 |         // set baseTime to -mPeriod so that numPeriods will be -1. | 
 | 397 |         // When we add 1 and the phase, we will be at the correct event time for | 
 | 398 |         // this period. | 
 | 399 |         if (baseTime < 0) { | 
 | 400 |             ALOGV("[%s] Correcting negative baseTime", mName); | 
 | 401 |             baseTime = -mPeriod; | 
 | 402 |         } | 
 | 403 |  | 
 | 404 |         nsecs_t numPeriods = baseTime / mPeriod; | 
 | 405 |         ALOGV("[%s] numPeriods = %" PRId64, mName, numPeriods); | 
 | 406 |         nsecs_t t = (numPeriods + 1) * mPeriod + phase; | 
 | 407 |         ALOGV("[%s] t = %" PRId64, mName, ns2us(t)); | 
 | 408 |         t += mReferenceTime; | 
 | 409 |         ALOGV("[%s] Absolute t = %" PRId64, mName, ns2us(t)); | 
 | 410 |  | 
 | 411 |         // Check that it's been slightly more than half a period since the last | 
 | 412 |         // event so that we don't accidentally fall into double-rate vsyncs | 
| Alec Mouri | df3d2e1 | 2019-05-02 17:58:46 +0000 | [diff] [blame] | 413 |         if (isCloseToPeriod(t - listener.mLastEventTime)) { | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 414 |             t += mPeriod; | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 415 |             ALOGV("[%s] Modifying t -> %" PRId64, mName, ns2us(t)); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 416 |         } | 
 | 417 |  | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 418 |         t -= mWakeupLatency; | 
 | 419 |         ALOGV("[%s] Corrected for wakeup latency -> %" PRId64, mName, ns2us(t)); | 
 | 420 |  | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 421 |         return t; | 
 | 422 |     } | 
 | 423 |  | 
| Ana Krulec | 9a52b19 | 2018-07-12 18:18:47 -0400 | [diff] [blame] | 424 |     void fireCallbackInvocations(const std::vector<CallbackInvocation>& callbacks) { | 
| Ana Krulec | 064a82f | 2018-09-11 16:03:03 -0700 | [diff] [blame] | 425 |         if (mTraceDetailedInfo) ATRACE_CALL(); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 426 |         for (size_t i = 0; i < callbacks.size(); i++) { | 
 | 427 |             callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime); | 
 | 428 |         } | 
 | 429 |     } | 
 | 430 |  | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 431 |     const char* const mName; | 
 | 432 |  | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 433 |     bool mStop; | 
| Alec Mouri | 016b8dd | 2019-04-24 15:16:05 -0700 | [diff] [blame] | 434 |     bool mModelLocked; | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 435 |  | 
 | 436 |     nsecs_t mPeriod; | 
 | 437 |     nsecs_t mPhase; | 
| Haixia Shi | 676b1f6 | 2015-10-28 16:19:01 -0700 | [diff] [blame] | 438 |     nsecs_t mReferenceTime; | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 439 |     nsecs_t mWakeupLatency; | 
 | 440 |  | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 441 |     int64_t mFrameNumber; | 
 | 442 |  | 
| Ana Krulec | 9a52b19 | 2018-07-12 18:18:47 -0400 | [diff] [blame] | 443 |     std::vector<EventListener> mEventListeners; | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 444 |  | 
 | 445 |     Mutex mMutex; | 
 | 446 |     Condition mCond; | 
| Ana Krulec | 064a82f | 2018-09-11 16:03:03 -0700 | [diff] [blame] | 447 |  | 
 | 448 |     // Flag to turn on logging in systrace. | 
 | 449 |     const bool mTraceDetailedInfo; | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 450 | }; | 
 | 451 |  | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 452 | #undef LOG_TAG | 
 | 453 | #define LOG_TAG "DispSync" | 
 | 454 |  | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 455 | class ZeroPhaseTracer : public DispSync::Callback { | 
 | 456 | public: | 
 | 457 |     ZeroPhaseTracer() : mParity(false) {} | 
 | 458 |  | 
| Mark Salyzyn | 92dc3fc | 2014-03-12 13:12:44 -0700 | [diff] [blame] | 459 |     virtual void onDispSyncEvent(nsecs_t /*when*/) { | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 460 |         mParity = !mParity; | 
 | 461 |         ATRACE_INT("ZERO_PHASE_VSYNC", mParity ? 1 : 0); | 
 | 462 |     } | 
 | 463 |  | 
 | 464 | private: | 
 | 465 |     bool mParity; | 
 | 466 | }; | 
 | 467 |  | 
| Ana Krulec | 064a82f | 2018-09-11 16:03:03 -0700 | [diff] [blame] | 468 | DispSync::DispSync(const char* name) : mName(name), mRefreshSkipCount(0) { | 
 | 469 |     // This flag offers the ability to turn on systrace logging from the shell. | 
 | 470 |     char value[PROPERTY_VALUE_MAX]; | 
 | 471 |     property_get("debug.sf.dispsync_trace_detailed_info", value, "0"); | 
 | 472 |     mTraceDetailedInfo = atoi(value); | 
 | 473 |     mThread = new DispSyncThread(name, mTraceDetailedInfo); | 
 | 474 | } | 
| Andy McFadden | 645b1f7 | 2014-06-10 14:43:32 -0700 | [diff] [blame] | 475 |  | 
| Ady Abraham | 50c202a | 2019-03-14 11:44:38 -0700 | [diff] [blame] | 476 | DispSync::~DispSync() { | 
 | 477 |     mThread->stop(); | 
 | 478 |     mThread->requestExitAndWait(); | 
 | 479 | } | 
| Saurabh Shah | f417453 | 2017-07-13 10:45:07 -0700 | [diff] [blame] | 480 |  | 
 | 481 | void DispSync::init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset) { | 
 | 482 |     mIgnorePresentFences = !hasSyncFramework; | 
 | 483 |     mPresentTimeOffset = dispSyncPresentTimeOffset; | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 484 |     mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE); | 
| Saurabh Shah | f417453 | 2017-07-13 10:45:07 -0700 | [diff] [blame] | 485 |  | 
| Tim Murray | acff43d | 2016-07-29 13:57:24 -0700 | [diff] [blame] | 486 |     // set DispSync to SCHED_FIFO to minimize jitter | 
 | 487 |     struct sched_param param = {0}; | 
| Tim Murray | 3552063 | 2016-09-07 12:18:17 -0700 | [diff] [blame] | 488 |     param.sched_priority = 2; | 
| Tim Murray | acff43d | 2016-07-29 13:57:24 -0700 | [diff] [blame] | 489 |     if (sched_setscheduler(mThread->getTid(), SCHED_FIFO, ¶m) != 0) { | 
 | 490 |         ALOGE("Couldn't set SCHED_FIFO for DispSyncThread"); | 
 | 491 |     } | 
 | 492 |  | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 493 |     beginResync(); | 
 | 494 |  | 
| Ana Krulec | 064a82f | 2018-09-11 16:03:03 -0700 | [diff] [blame] | 495 |     if (mTraceDetailedInfo && kEnableZeroPhaseTracer) { | 
| Steven Thomas | dfde8fa | 2018-04-19 16:00:58 -0700 | [diff] [blame] | 496 |         mZeroPhaseTracer = std::make_unique<ZeroPhaseTracer>(); | 
| Alec Mouri | 7355eb2 | 2019-03-05 14:19:10 -0800 | [diff] [blame] | 497 |         addEventListener("ZeroPhaseTracer", 0, mZeroPhaseTracer.get(), 0); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 498 |     } | 
 | 499 | } | 
 | 500 |  | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 501 | void DispSync::reset() { | 
 | 502 |     Mutex::Autolock lock(mMutex); | 
| Steven Thomas | dfde8fa | 2018-04-19 16:00:58 -0700 | [diff] [blame] | 503 |     resetLocked(); | 
 | 504 | } | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 505 |  | 
| Steven Thomas | dfde8fa | 2018-04-19 16:00:58 -0700 | [diff] [blame] | 506 | void DispSync::resetLocked() { | 
| Haixia Shi | 676b1f6 | 2015-10-28 16:19:01 -0700 | [diff] [blame] | 507 |     mPhase = 0; | 
| Alec Mouri | 75b0b62 | 2019-03-12 18:56:00 +0000 | [diff] [blame] | 508 |     const size_t lastSampleIdx = (mFirstResyncSample + mNumResyncSamples - 1) % MAX_RESYNC_SAMPLES; | 
 | 509 |     // Keep the most recent sample, when we resync to hardware we'll overwrite this | 
 | 510 |     // with a more accurate signal | 
 | 511 |     if (mResyncSamples[lastSampleIdx] != 0) { | 
 | 512 |         mReferenceTime = mResyncSamples[lastSampleIdx]; | 
 | 513 |     } | 
| Haixia Shi | 676b1f6 | 2015-10-28 16:19:01 -0700 | [diff] [blame] | 514 |     mModelUpdated = false; | 
| Alec Mouri | 75b0b62 | 2019-03-12 18:56:00 +0000 | [diff] [blame] | 515 |     for (size_t i = 0; i < MAX_RESYNC_SAMPLES; i++) { | 
 | 516 |         mResyncSamples[i] = 0; | 
 | 517 |     } | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 518 |     mNumResyncSamples = 0; | 
 | 519 |     mFirstResyncSample = 0; | 
 | 520 |     mNumResyncSamplesSincePresent = 0; | 
| Alec Mouri | 016b8dd | 2019-04-24 15:16:05 -0700 | [diff] [blame] | 521 |     mThread->unlockModel(); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 522 |     resetErrorLocked(); | 
 | 523 | } | 
 | 524 |  | 
| Brian Anderson | fbc80ae | 2017-05-26 16:23:54 -0700 | [diff] [blame] | 525 | bool DispSync::addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) { | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 526 |     Mutex::Autolock lock(mMutex); | 
 | 527 |  | 
| Steven Thomas | dfde8fa | 2018-04-19 16:00:58 -0700 | [diff] [blame] | 528 |     if (mIgnorePresentFences) { | 
 | 529 |         return true; | 
 | 530 |     } | 
 | 531 |  | 
| Brian Anderson | fbc80ae | 2017-05-26 16:23:54 -0700 | [diff] [blame] | 532 |     mPresentFences[mPresentSampleOffset] = fenceTime; | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 533 |     mPresentSampleOffset = (mPresentSampleOffset + 1) % NUM_PRESENT_SAMPLES; | 
 | 534 |     mNumResyncSamplesSincePresent = 0; | 
 | 535 |  | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 536 |     updateErrorLocked(); | 
 | 537 |  | 
| Haixia Shi | 676b1f6 | 2015-10-28 16:19:01 -0700 | [diff] [blame] | 538 |     return !mModelUpdated || mError > kErrorThreshold; | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 539 | } | 
 | 540 |  | 
 | 541 | void DispSync::beginResync() { | 
 | 542 |     Mutex::Autolock lock(mMutex); | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 543 |     ALOGV("[%s] beginResync", mName); | 
| Alec Mouri | f8e689c | 2019-05-20 18:32:22 -0700 | [diff] [blame] | 544 |     resetLocked(); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 545 | } | 
 | 546 |  | 
| Alec Mouri | f8e689c | 2019-05-20 18:32:22 -0700 | [diff] [blame] | 547 | bool DispSync::addResyncSample(nsecs_t timestamp, bool* periodFlushed) { | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 548 |     Mutex::Autolock lock(mMutex); | 
 | 549 |  | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 550 |     ALOGV("[%s] addResyncSample(%" PRId64 ")", mName, ns2us(timestamp)); | 
 | 551 |  | 
| Alec Mouri | f8e689c | 2019-05-20 18:32:22 -0700 | [diff] [blame] | 552 |     *periodFlushed = false; | 
| Alec Mouri | 754c98a | 2019-03-18 18:53:42 -0700 | [diff] [blame] | 553 |     const size_t idx = (mFirstResyncSample + mNumResyncSamples) % MAX_RESYNC_SAMPLES; | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 554 |     mResyncSamples[idx] = timestamp; | 
| Haixia Shi | 664339a | 2015-10-28 13:22:22 -0700 | [diff] [blame] | 555 |     if (mNumResyncSamples == 0) { | 
| Haixia Shi | 676b1f6 | 2015-10-28 16:19:01 -0700 | [diff] [blame] | 556 |         mPhase = 0; | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 557 |         ALOGV("[%s] First resync sample: mPeriod = %" PRId64 ", mPhase = 0, " | 
| Lloyd Pique | 78ce418 | 2018-01-31 16:39:51 -0800 | [diff] [blame] | 558 |               "mReferenceTime = %" PRId64, | 
| Alec Mouri | 754c98a | 2019-03-18 18:53:42 -0700 | [diff] [blame] | 559 |               mName, ns2us(mPeriod), ns2us(timestamp)); | 
 | 560 |     } else if (mPendingPeriod > 0) { | 
 | 561 |         // mNumResyncSamples > 0, so priorIdx won't overflow | 
 | 562 |         const size_t priorIdx = (mFirstResyncSample + mNumResyncSamples - 1) % MAX_RESYNC_SAMPLES; | 
 | 563 |         const nsecs_t lastTimestamp = mResyncSamples[priorIdx]; | 
 | 564 |  | 
 | 565 |         const nsecs_t observedVsync = std::abs(timestamp - lastTimestamp); | 
| Alec Mouri | f8e689c | 2019-05-20 18:32:22 -0700 | [diff] [blame] | 566 |         if (std::abs(observedVsync - mPendingPeriod) <= std::abs(observedVsync - mIntendedPeriod)) { | 
 | 567 |             // Either the observed vsync is closer to the pending period, (and | 
 | 568 |             // thus we detected a period change), or the period change will | 
 | 569 |             // no-op. In either case, reset the model and flush the pending | 
 | 570 |             // period. | 
| Alec Mouri | 754c98a | 2019-03-18 18:53:42 -0700 | [diff] [blame] | 571 |             resetLocked(); | 
| Alec Mouri | f8e689c | 2019-05-20 18:32:22 -0700 | [diff] [blame] | 572 |             mIntendedPeriod = mPendingPeriod; | 
| Alec Mouri | 754c98a | 2019-03-18 18:53:42 -0700 | [diff] [blame] | 573 |             mPeriod = mPendingPeriod; | 
 | 574 |             mPendingPeriod = 0; | 
 | 575 |             if (mTraceDetailedInfo) { | 
 | 576 |                 ATRACE_INT("DispSync:PendingPeriod", mPendingPeriod); | 
| Alec Mouri | f8e689c | 2019-05-20 18:32:22 -0700 | [diff] [blame] | 577 |                 ATRACE_INT("DispSync:IntendedPeriod", mIntendedPeriod); | 
| Alec Mouri | 754c98a | 2019-03-18 18:53:42 -0700 | [diff] [blame] | 578 |             } | 
| Alec Mouri | f8e689c | 2019-05-20 18:32:22 -0700 | [diff] [blame] | 579 |             *periodFlushed = true; | 
| Alec Mouri | 754c98a | 2019-03-18 18:53:42 -0700 | [diff] [blame] | 580 |         } | 
| Haixia Shi | 664339a | 2015-10-28 13:22:22 -0700 | [diff] [blame] | 581 |     } | 
| Alec Mouri | 754c98a | 2019-03-18 18:53:42 -0700 | [diff] [blame] | 582 |     // Always update the reference time with the most recent timestamp. | 
 | 583 |     mReferenceTime = timestamp; | 
 | 584 |     mThread->updateModel(mPeriod, mPhase, mReferenceTime); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 585 |  | 
 | 586 |     if (mNumResyncSamples < MAX_RESYNC_SAMPLES) { | 
 | 587 |         mNumResyncSamples++; | 
 | 588 |     } else { | 
 | 589 |         mFirstResyncSample = (mFirstResyncSample + 1) % MAX_RESYNC_SAMPLES; | 
 | 590 |     } | 
 | 591 |  | 
 | 592 |     updateModelLocked(); | 
 | 593 |  | 
 | 594 |     if (mNumResyncSamplesSincePresent++ > MAX_RESYNC_SAMPLES_WITHOUT_PRESENT) { | 
 | 595 |         resetErrorLocked(); | 
 | 596 |     } | 
 | 597 |  | 
| Fabien Sanglard | cbf153b | 2017-03-10 17:57:12 -0800 | [diff] [blame] | 598 |     if (mIgnorePresentFences) { | 
| Steven Thomas | dfde8fa | 2018-04-19 16:00:58 -0700 | [diff] [blame] | 599 |         // If we're ignoring the present fences we have no way to know whether | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 600 |         // or not we're synchronized with the HW vsyncs, so we just request | 
| Steven Thomas | dfde8fa | 2018-04-19 16:00:58 -0700 | [diff] [blame] | 601 |         // that the HW vsync events be turned on. | 
 | 602 |         return true; | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 603 |     } | 
 | 604 |  | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 605 |     // Check against kErrorThreshold / 2 to add some hysteresis before having to | 
 | 606 |     // resync again | 
| Alec Mouri | 754c98a | 2019-03-18 18:53:42 -0700 | [diff] [blame] | 607 |     bool modelLocked = mModelUpdated && mError < (kErrorThreshold / 2) && mPendingPeriod == 0; | 
| Lloyd Pique | 78ce418 | 2018-01-31 16:39:51 -0800 | [diff] [blame] | 608 |     ALOGV("[%s] addResyncSample returning %s", mName, modelLocked ? "locked" : "unlocked"); | 
| Alec Mouri | 016b8dd | 2019-04-24 15:16:05 -0700 | [diff] [blame] | 609 |     if (modelLocked) { | 
| Alec Mouri | f8e689c | 2019-05-20 18:32:22 -0700 | [diff] [blame] | 610 |         *periodFlushed = true; | 
| Alec Mouri | 016b8dd | 2019-04-24 15:16:05 -0700 | [diff] [blame] | 611 |         mThread->lockModel(); | 
 | 612 |     } | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 613 |     return !modelLocked; | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 614 | } | 
 | 615 |  | 
| Alec Mouri | 016b8dd | 2019-04-24 15:16:05 -0700 | [diff] [blame] | 616 | void DispSync::endResync() { | 
 | 617 |     mThread->lockModel(); | 
 | 618 | } | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 619 |  | 
| Alec Mouri | 7355eb2 | 2019-03-05 14:19:10 -0800 | [diff] [blame] | 620 | status_t DispSync::addEventListener(const char* name, nsecs_t phase, Callback* callback, | 
 | 621 |                                     nsecs_t lastCallbackTime) { | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 622 |     Mutex::Autolock lock(mMutex); | 
| Alec Mouri | 7355eb2 | 2019-03-05 14:19:10 -0800 | [diff] [blame] | 623 |     return mThread->addEventListener(name, phase, callback, lastCallbackTime); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 624 | } | 
 | 625 |  | 
| Andy McFadden | 645b1f7 | 2014-06-10 14:43:32 -0700 | [diff] [blame] | 626 | void DispSync::setRefreshSkipCount(int count) { | 
 | 627 |     Mutex::Autolock lock(mMutex); | 
 | 628 |     ALOGD("setRefreshSkipCount(%d)", count); | 
 | 629 |     mRefreshSkipCount = count; | 
 | 630 |     updateModelLocked(); | 
| Ruchi Kandoi | f52b3c8 | 2014-04-24 16:42:35 -0700 | [diff] [blame] | 631 | } | 
 | 632 |  | 
| Alec Mouri | 7355eb2 | 2019-03-05 14:19:10 -0800 | [diff] [blame] | 633 | status_t DispSync::removeEventListener(Callback* callback, nsecs_t* outLastCallbackTime) { | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 634 |     Mutex::Autolock lock(mMutex); | 
| Alec Mouri | 7355eb2 | 2019-03-05 14:19:10 -0800 | [diff] [blame] | 635 |     return mThread->removeEventListener(callback, outLastCallbackTime); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 636 | } | 
 | 637 |  | 
| Dan Stoza | 84d619e | 2018-03-28 17:07:36 -0700 | [diff] [blame] | 638 | status_t DispSync::changePhaseOffset(Callback* callback, nsecs_t phase) { | 
 | 639 |     Mutex::Autolock lock(mMutex); | 
 | 640 |     return mThread->changePhaseOffset(callback, phase); | 
 | 641 | } | 
 | 642 |  | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 643 | void DispSync::setPeriod(nsecs_t period) { | 
 | 644 |     Mutex::Autolock lock(mMutex); | 
| Alec Mouri | f8e689c | 2019-05-20 18:32:22 -0700 | [diff] [blame] | 645 |  | 
 | 646 |     const bool pendingPeriodShouldChange = | 
 | 647 |             period != mIntendedPeriod || (period == mIntendedPeriod && mPendingPeriod != 0); | 
 | 648 |  | 
 | 649 |     if (pendingPeriodShouldChange) { | 
 | 650 |         mPendingPeriod = period; | 
| Alec Mouri | 754c98a | 2019-03-18 18:53:42 -0700 | [diff] [blame] | 651 |     } | 
| Alec Mouri | f8e689c | 2019-05-20 18:32:22 -0700 | [diff] [blame] | 652 |     if (mTraceDetailedInfo) { | 
 | 653 |         ATRACE_INT("DispSync:IntendedPeriod", mIntendedPeriod); | 
 | 654 |         ATRACE_INT("DispSync:PendingPeriod", mPendingPeriod); | 
 | 655 |     } | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 656 | } | 
 | 657 |  | 
| Lajos Molnar | 67d8bd6 | 2014-09-11 14:58:45 -0700 | [diff] [blame] | 658 | nsecs_t DispSync::getPeriod() { | 
 | 659 |     // lock mutex as mPeriod changes multiple times in updateModelLocked | 
 | 660 |     Mutex::Autolock lock(mMutex); | 
 | 661 |     return mPeriod; | 
 | 662 | } | 
 | 663 |  | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 664 | void DispSync::updateModelLocked() { | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 665 |     ALOGV("[%s] updateModelLocked %zu", mName, mNumResyncSamples); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 666 |     if (mNumResyncSamples >= MIN_RESYNC_SAMPLES_FOR_UPDATE) { | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 667 |         ALOGV("[%s] Computing...", mName); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 668 |         nsecs_t durationSum = 0; | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 669 |         nsecs_t minDuration = INT64_MAX; | 
 | 670 |         nsecs_t maxDuration = 0; | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 671 |         for (size_t i = 1; i < mNumResyncSamples; i++) { | 
 | 672 |             size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES; | 
 | 673 |             size_t prev = (idx + MAX_RESYNC_SAMPLES - 1) % MAX_RESYNC_SAMPLES; | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 674 |             nsecs_t duration = mResyncSamples[idx] - mResyncSamples[prev]; | 
 | 675 |             durationSum += duration; | 
 | 676 |             minDuration = min(minDuration, duration); | 
 | 677 |             maxDuration = max(maxDuration, duration); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 678 |         } | 
 | 679 |  | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 680 |         // Exclude the min and max from the average | 
 | 681 |         durationSum -= minDuration + maxDuration; | 
| David Sodman | 1afa8b0 | 2018-10-15 11:20:48 -0700 | [diff] [blame] | 682 |         mPeriod = durationSum / (mNumResyncSamples - 3); | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 683 |  | 
 | 684 |         ALOGV("[%s] mPeriod = %" PRId64, mName, ns2us(mPeriod)); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 685 |  | 
 | 686 |         double sampleAvgX = 0; | 
 | 687 |         double sampleAvgY = 0; | 
 | 688 |         double scale = 2.0 * M_PI / double(mPeriod); | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 689 |         // Intentionally skip the first sample | 
 | 690 |         for (size_t i = 1; i < mNumResyncSamples; i++) { | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 691 |             size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES; | 
| Haixia Shi | 676b1f6 | 2015-10-28 16:19:01 -0700 | [diff] [blame] | 692 |             nsecs_t sample = mResyncSamples[idx] - mReferenceTime; | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 693 |             double samplePhase = double(sample % mPeriod) * scale; | 
 | 694 |             sampleAvgX += cos(samplePhase); | 
 | 695 |             sampleAvgY += sin(samplePhase); | 
 | 696 |         } | 
 | 697 |  | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 698 |         sampleAvgX /= double(mNumResyncSamples - 1); | 
 | 699 |         sampleAvgY /= double(mNumResyncSamples - 1); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 700 |  | 
 | 701 |         mPhase = nsecs_t(atan2(sampleAvgY, sampleAvgX) / scale); | 
 | 702 |  | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 703 |         ALOGV("[%s] mPhase = %" PRId64, mName, ns2us(mPhase)); | 
 | 704 |  | 
 | 705 |         if (mPhase < -(mPeriod / 2)) { | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 706 |             mPhase += mPeriod; | 
| Tim Murray | 4a4e4a2 | 2016-04-19 16:29:23 +0000 | [diff] [blame] | 707 |             ALOGV("[%s] Adjusting mPhase -> %" PRId64, mName, ns2us(mPhase)); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 708 |         } | 
 | 709 |  | 
| Andy McFadden | 645b1f7 | 2014-06-10 14:43:32 -0700 | [diff] [blame] | 710 |         // Artificially inflate the period if requested. | 
 | 711 |         mPeriod += mPeriod * mRefreshSkipCount; | 
 | 712 |  | 
| Haixia Shi | 676b1f6 | 2015-10-28 16:19:01 -0700 | [diff] [blame] | 713 |         mThread->updateModel(mPeriod, mPhase, mReferenceTime); | 
 | 714 |         mModelUpdated = true; | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 715 |     } | 
 | 716 | } | 
 | 717 |  | 
 | 718 | void DispSync::updateErrorLocked() { | 
| Haixia Shi | 676b1f6 | 2015-10-28 16:19:01 -0700 | [diff] [blame] | 719 |     if (!mModelUpdated) { | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 720 |         return; | 
 | 721 |     } | 
 | 722 |  | 
| Andy McFadden | 645b1f7 | 2014-06-10 14:43:32 -0700 | [diff] [blame] | 723 |     // Need to compare present fences against the un-adjusted refresh period, | 
 | 724 |     // since they might arrive between two events. | 
 | 725 |     nsecs_t period = mPeriod / (1 + mRefreshSkipCount); | 
 | 726 |  | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 727 |     int numErrSamples = 0; | 
 | 728 |     nsecs_t sqErrSum = 0; | 
 | 729 |  | 
 | 730 |     for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) { | 
| Brian Anderson | fbc80ae | 2017-05-26 16:23:54 -0700 | [diff] [blame] | 731 |         // Only check for the cached value of signal time to avoid unecessary | 
 | 732 |         // syscalls. It is the responsibility of the DispSync owner to | 
 | 733 |         // call getSignalTime() periodically so the cache is updated when the | 
 | 734 |         // fence signals. | 
 | 735 |         nsecs_t time = mPresentFences[i]->getCachedSignalTime(); | 
| Lloyd Pique | 78ce418 | 2018-01-31 16:39:51 -0800 | [diff] [blame] | 736 |         if (time == Fence::SIGNAL_TIME_PENDING || time == Fence::SIGNAL_TIME_INVALID) { | 
| Brian Anderson | fbc80ae | 2017-05-26 16:23:54 -0700 | [diff] [blame] | 737 |             continue; | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 738 |         } | 
| Brian Anderson | fbc80ae | 2017-05-26 16:23:54 -0700 | [diff] [blame] | 739 |  | 
 | 740 |         nsecs_t sample = time - mReferenceTime; | 
 | 741 |         if (sample <= mPhase) { | 
 | 742 |             continue; | 
 | 743 |         } | 
 | 744 |  | 
 | 745 |         nsecs_t sampleErr = (sample - mPhase) % period; | 
 | 746 |         if (sampleErr > period / 2) { | 
 | 747 |             sampleErr -= period; | 
 | 748 |         } | 
 | 749 |         sqErrSum += sampleErr * sampleErr; | 
 | 750 |         numErrSamples++; | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 751 |     } | 
 | 752 |  | 
 | 753 |     if (numErrSamples > 0) { | 
 | 754 |         mError = sqErrSum / numErrSamples; | 
| Brian Anderson | fbc80ae | 2017-05-26 16:23:54 -0700 | [diff] [blame] | 755 |         mZeroErrSamplesCount = 0; | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 756 |     } else { | 
 | 757 |         mError = 0; | 
| Brian Anderson | fbc80ae | 2017-05-26 16:23:54 -0700 | [diff] [blame] | 758 |         // Use mod ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT to avoid log spam. | 
 | 759 |         mZeroErrSamplesCount++; | 
| Lloyd Pique | 78ce418 | 2018-01-31 16:39:51 -0800 | [diff] [blame] | 760 |         ALOGE_IF((mZeroErrSamplesCount % ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT) == 0, | 
 | 761 |                  "No present times for model error."); | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 762 |     } | 
 | 763 |  | 
| Ana Krulec | 064a82f | 2018-09-11 16:03:03 -0700 | [diff] [blame] | 764 |     if (mTraceDetailedInfo) { | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 765 |         ATRACE_INT64("DispSync:Error", mError); | 
 | 766 |     } | 
 | 767 | } | 
 | 768 |  | 
 | 769 | void DispSync::resetErrorLocked() { | 
 | 770 |     mPresentSampleOffset = 0; | 
 | 771 |     mError = 0; | 
| Brian Anderson | fbc80ae | 2017-05-26 16:23:54 -0700 | [diff] [blame] | 772 |     mZeroErrSamplesCount = 0; | 
| Alec Mouri | f8e689c | 2019-05-20 18:32:22 -0700 | [diff] [blame] | 773 |     if (mTraceDetailedInfo) { | 
 | 774 |         ATRACE_INT64("DispSync:Error", mError); | 
 | 775 |     } | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 776 |     for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) { | 
| Brian Anderson | fbc80ae | 2017-05-26 16:23:54 -0700 | [diff] [blame] | 777 |         mPresentFences[i] = FenceTime::NO_FENCE; | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 778 |     } | 
 | 779 | } | 
 | 780 |  | 
| Andy McFadden | 41d67d7 | 2014-04-25 16:58:34 -0700 | [diff] [blame] | 781 | nsecs_t DispSync::computeNextRefresh(int periodOffset) const { | 
| Andy McFadden | 150ecd8 | 2014-05-08 14:56:50 -0700 | [diff] [blame] | 782 |     Mutex::Autolock lock(mMutex); | 
| Andy McFadden | 41d67d7 | 2014-04-25 16:58:34 -0700 | [diff] [blame] | 783 |     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); | 
| Haixia Shi | 676b1f6 | 2015-10-28 16:19:01 -0700 | [diff] [blame] | 784 |     nsecs_t phase = mReferenceTime + mPhase; | 
| Marissa Wall | 17b4e45 | 2018-12-26 16:32:34 -0800 | [diff] [blame] | 785 |     if (mPeriod == 0) { | 
 | 786 |         return 0; | 
 | 787 |     } | 
| Haixia Shi | 676b1f6 | 2015-10-28 16:19:01 -0700 | [diff] [blame] | 788 |     return (((now - phase) / mPeriod) + periodOffset + 1) * mPeriod + phase; | 
| Andy McFadden | 41d67d7 | 2014-04-25 16:58:34 -0700 | [diff] [blame] | 789 | } | 
 | 790 |  | 
| Steven Thomas | dfde8fa | 2018-04-19 16:00:58 -0700 | [diff] [blame] | 791 | void DispSync::setIgnorePresentFences(bool ignore) { | 
 | 792 |     Mutex::Autolock lock(mMutex); | 
 | 793 |     if (mIgnorePresentFences != ignore) { | 
 | 794 |         mIgnorePresentFences = ignore; | 
 | 795 |         resetLocked(); | 
 | 796 |     } | 
 | 797 | } | 
 | 798 |  | 
| Yiwei Zhang | 5434a78 | 2018-12-05 18:06:32 -0800 | [diff] [blame] | 799 | void DispSync::dump(std::string& result) const { | 
| Andy McFadden | c751e92 | 2014-05-08 14:53:26 -0700 | [diff] [blame] | 800 |     Mutex::Autolock lock(mMutex); | 
| Yiwei Zhang | 5434a78 | 2018-12-05 18:06:32 -0800 | [diff] [blame] | 801 |     StringAppendF(&result, "present fences are %s\n", mIgnorePresentFences ? "ignored" : "used"); | 
 | 802 |     StringAppendF(&result, "mPeriod: %" PRId64 " ns (%.3f fps; skipCount=%d)\n", mPeriod, | 
 | 803 |                   1000000000.0 / mPeriod, mRefreshSkipCount); | 
 | 804 |     StringAppendF(&result, "mPhase: %" PRId64 " ns\n", mPhase); | 
 | 805 |     StringAppendF(&result, "mError: %" PRId64 " ns (sqrt=%.1f)\n", mError, sqrt(mError)); | 
 | 806 |     StringAppendF(&result, "mNumResyncSamplesSincePresent: %d (limit %d)\n", | 
 | 807 |                   mNumResyncSamplesSincePresent, MAX_RESYNC_SAMPLES_WITHOUT_PRESENT); | 
 | 808 |     StringAppendF(&result, "mNumResyncSamples: %zd (max %d)\n", mNumResyncSamples, | 
 | 809 |                   MAX_RESYNC_SAMPLES); | 
| Andy McFadden | c751e92 | 2014-05-08 14:53:26 -0700 | [diff] [blame] | 810 |  | 
| Yiwei Zhang | 5434a78 | 2018-12-05 18:06:32 -0800 | [diff] [blame] | 811 |     result.append("mResyncSamples:\n"); | 
| Andy McFadden | c751e92 | 2014-05-08 14:53:26 -0700 | [diff] [blame] | 812 |     nsecs_t previous = -1; | 
 | 813 |     for (size_t i = 0; i < mNumResyncSamples; i++) { | 
 | 814 |         size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES; | 
 | 815 |         nsecs_t sampleTime = mResyncSamples[idx]; | 
 | 816 |         if (i == 0) { | 
| Yiwei Zhang | 5434a78 | 2018-12-05 18:06:32 -0800 | [diff] [blame] | 817 |             StringAppendF(&result, "  %" PRId64 "\n", sampleTime); | 
| Andy McFadden | c751e92 | 2014-05-08 14:53:26 -0700 | [diff] [blame] | 818 |         } else { | 
| Yiwei Zhang | 5434a78 | 2018-12-05 18:06:32 -0800 | [diff] [blame] | 819 |             StringAppendF(&result, "  %" PRId64 " (+%" PRId64 ")\n", sampleTime, | 
 | 820 |                           sampleTime - previous); | 
| Andy McFadden | c751e92 | 2014-05-08 14:53:26 -0700 | [diff] [blame] | 821 |         } | 
 | 822 |         previous = sampleTime; | 
 | 823 |     } | 
 | 824 |  | 
| Yiwei Zhang | 5434a78 | 2018-12-05 18:06:32 -0800 | [diff] [blame] | 825 |     StringAppendF(&result, "mPresentFences [%d]:\n", NUM_PRESENT_SAMPLES); | 
| Andy McFadden | 5167ec6 | 2014-05-22 13:08:43 -0700 | [diff] [blame] | 826 |     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); | 
| Brian Anderson | fbc80ae | 2017-05-26 16:23:54 -0700 | [diff] [blame] | 827 |     previous = Fence::SIGNAL_TIME_INVALID; | 
| Andy McFadden | c751e92 | 2014-05-08 14:53:26 -0700 | [diff] [blame] | 828 |     for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) { | 
 | 829 |         size_t idx = (i + mPresentSampleOffset) % NUM_PRESENT_SAMPLES; | 
| Brian Anderson | fbc80ae | 2017-05-26 16:23:54 -0700 | [diff] [blame] | 830 |         nsecs_t presentTime = mPresentFences[idx]->getSignalTime(); | 
 | 831 |         if (presentTime == Fence::SIGNAL_TIME_PENDING) { | 
| Yiwei Zhang | 5434a78 | 2018-12-05 18:06:32 -0800 | [diff] [blame] | 832 |             StringAppendF(&result, "  [unsignaled fence]\n"); | 
| Lloyd Pique | 78ce418 | 2018-01-31 16:39:51 -0800 | [diff] [blame] | 833 |         } else if (presentTime == Fence::SIGNAL_TIME_INVALID) { | 
| Yiwei Zhang | 5434a78 | 2018-12-05 18:06:32 -0800 | [diff] [blame] | 834 |             StringAppendF(&result, "  [invalid fence]\n"); | 
| Brian Anderson | fbc80ae | 2017-05-26 16:23:54 -0700 | [diff] [blame] | 835 |         } else if (previous == Fence::SIGNAL_TIME_PENDING || | 
| Lloyd Pique | 78ce418 | 2018-01-31 16:39:51 -0800 | [diff] [blame] | 836 |                    previous == Fence::SIGNAL_TIME_INVALID) { | 
| Yiwei Zhang | 5434a78 | 2018-12-05 18:06:32 -0800 | [diff] [blame] | 837 |             StringAppendF(&result, "  %" PRId64 "  (%.3f ms ago)\n", presentTime, | 
 | 838 |                           (now - presentTime) / 1000000.0); | 
| Andy McFadden | c751e92 | 2014-05-08 14:53:26 -0700 | [diff] [blame] | 839 |         } else { | 
| Yiwei Zhang | 5434a78 | 2018-12-05 18:06:32 -0800 | [diff] [blame] | 840 |             StringAppendF(&result, "  %" PRId64 " (+%" PRId64 " / %.3f)  (%.3f ms ago)\n", | 
 | 841 |                           presentTime, presentTime - previous, | 
 | 842 |                           (presentTime - previous) / (double)mPeriod, | 
 | 843 |                           (now - presentTime) / 1000000.0); | 
| Andy McFadden | c751e92 | 2014-05-08 14:53:26 -0700 | [diff] [blame] | 844 |         } | 
 | 845 |         previous = presentTime; | 
 | 846 |     } | 
| Andy McFadden | 5167ec6 | 2014-05-22 13:08:43 -0700 | [diff] [blame] | 847 |  | 
| Yiwei Zhang | 5434a78 | 2018-12-05 18:06:32 -0800 | [diff] [blame] | 848 |     StringAppendF(&result, "current monotonic time: %" PRId64 "\n", now); | 
| Andy McFadden | c751e92 | 2014-05-08 14:53:26 -0700 | [diff] [blame] | 849 | } | 
 | 850 |  | 
| Ana Krulec | 010d219 | 2018-10-08 06:29:54 -0700 | [diff] [blame] | 851 | nsecs_t DispSync::expectedPresentTime() { | 
 | 852 |     // The HWC doesn't currently have a way to report additional latency. | 
 | 853 |     // Assume that whatever we submit now will appear right after the flip. | 
 | 854 |     // For a smart panel this might be 1.  This is expressed in frames, | 
 | 855 |     // rather than time, because we expect to have a constant frame delay | 
 | 856 |     // regardless of the refresh rate. | 
 | 857 |     const uint32_t hwcLatency = 0; | 
 | 858 |  | 
 | 859 |     // Ask DispSync when the next refresh will be (CLOCK_MONOTONIC). | 
| Ana Krulec | 757f63a | 2019-01-25 10:46:18 -0800 | [diff] [blame] | 860 |     return computeNextRefresh(hwcLatency); | 
| Ana Krulec | 010d219 | 2018-10-08 06:29:54 -0700 | [diff] [blame] | 861 | } | 
 | 862 |  | 
| Lloyd Pique | 41be5d2 | 2018-06-21 13:11:48 -0700 | [diff] [blame] | 863 | } // namespace impl | 
 | 864 |  | 
| Jamie Gennis | faf77cc | 2013-07-30 15:10:32 -0700 | [diff] [blame] | 865 | } // namespace android |