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 #pragma once 18 19 #include <deque> 20 #include <mutex> 21 #include <unordered_map> 22 #include <vector> 23 24 #include <android-base/thread_annotations.h> 25 #include <scheduler/TimeKeeper.h> 26 #include <ui/DisplayId.h> 27 28 #include "VSyncTracker.h" 29 30 namespace android::scheduler { 31 32 class VSyncPredictor : public VSyncTracker { 33 public: 34 /* 35 * \param [in] Clock The clock abstraction. Useful for unit tests. 36 * \param [in] PhysicalDisplayid The display this corresponds to. 37 * \param [in] modePtr The initial display mode 38 * \param [in] historySize The internal amount of entries to store in the model. 39 * \param [in] minimumSamplesForPrediction The minimum number of samples to collect before 40 * predicting. \param [in] outlierTolerancePercent a number 0 to 100 that will be used to filter 41 * samples that fall outlierTolerancePercent from an anticipated vsync event. 42 */ 43 VSyncPredictor(std::unique_ptr<Clock>, ftl::NonNull<DisplayModePtr> modePtr, size_t historySize, 44 size_t minimumSamplesForPrediction, uint32_t outlierTolerancePercent); 45 ~VSyncPredictor(); 46 47 bool addVsyncTimestamp(nsecs_t timestamp) final EXCLUDES(mMutex); 48 nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint, 49 std::optional<nsecs_t> lastVsyncOpt = {}) final 50 EXCLUDES(mMutex); 51 nsecs_t currentPeriod() const final EXCLUDES(mMutex); 52 Period minFramePeriod() const final EXCLUDES(mMutex); 53 void resetModel() final EXCLUDES(mMutex); 54 55 /* Query if the model is in need of more samples to make a prediction. 56 * \return True, if model would benefit from more samples, False if not. 57 */ 58 bool needsMoreSamples() const final EXCLUDES(mMutex); 59 60 struct Model { 61 nsecs_t slope; 62 nsecs_t intercept; 63 }; 64 65 VSyncPredictor::Model getVSyncPredictionModel() const EXCLUDES(mMutex); 66 67 bool isVSyncInPhase(nsecs_t timePoint, Fps frameRate) final EXCLUDES(mMutex); 68 69 void setDisplayModePtr(ftl::NonNull<DisplayModePtr>) final EXCLUDES(mMutex); 70 isCurrentMode(const ftl::NonNull<DisplayModePtr> & modePtr)71 bool isCurrentMode(const ftl::NonNull<DisplayModePtr>& modePtr) const EXCLUDES(mMutex) { 72 std::lock_guard lock(mMutex); 73 return mDisplayModePtr->getId() == modePtr->getId() && 74 mDisplayModePtr->getVsyncRate().getPeriodNsecs() == 75 mRateMap.find(idealPeriod())->second.slope; 76 } 77 78 void setRenderRate(Fps, bool applyImmediately) final EXCLUDES(mMutex); 79 80 void onFrameBegin(TimePoint expectedPresentTime, TimePoint lastConfirmedPresentTime) final 81 EXCLUDES(mMutex); 82 void onFrameMissed(TimePoint expectedPresentTime) final EXCLUDES(mMutex); 83 84 void dump(std::string& result) const final EXCLUDES(mMutex); 85 86 private: 87 struct VsyncSequence { 88 nsecs_t vsyncTime; 89 int64_t seq; 90 }; 91 92 struct MissedVsync { 93 TimePoint vsync = TimePoint::fromNs(0); 94 Duration fixup = Duration::fromNs(0); 95 }; 96 97 class VsyncTimeline { 98 public: 99 VsyncTimeline(TimePoint knownVsync, Period idealPeriod, std::optional<Fps> renderRateOpt); 100 std::optional<TimePoint> nextAnticipatedVSyncTimeFrom( 101 Model model, std::optional<Period> minFramePeriodOpt, nsecs_t vsyncTime, 102 MissedVsync lastMissedVsync, std::optional<nsecs_t> lastVsyncOpt = {}); 103 void freeze(TimePoint lastVsync); validUntil()104 std::optional<TimePoint> validUntil() const { return mValidUntil; } 105 bool isVSyncInPhase(Model, nsecs_t vsync, Fps frameRate); 106 void shiftVsyncSequence(Duration phase); setRenderRate(std::optional<Fps> renderRateOpt)107 void setRenderRate(std::optional<Fps> renderRateOpt) { mRenderRateOpt = renderRateOpt; } 108 109 private: 110 nsecs_t snapToVsyncAlignedWithRenderRate(Model model, nsecs_t vsync); 111 VsyncSequence getVsyncSequenceLocked(Model, nsecs_t vsync); 112 std::optional<VsyncSequence> makeVsyncSequence(TimePoint knownVsync); 113 114 const Period mIdealPeriod = Duration::fromNs(0); 115 std::optional<Fps> mRenderRateOpt; 116 std::optional<TimePoint> mValidUntil; 117 std::optional<VsyncSequence> mLastVsyncSequence; 118 }; 119 120 VSyncPredictor(VSyncPredictor const&) = delete; 121 VSyncPredictor& operator=(VSyncPredictor const&) = delete; 122 void clearTimestamps() REQUIRES(mMutex); 123 124 const std::unique_ptr<Clock> mClock; 125 const PhysicalDisplayId mId; 126 127 inline void traceInt64If(const char* name, int64_t value) const; 128 inline void traceInt64(const char* name, int64_t value) const; 129 130 size_t next(size_t i) const REQUIRES(mMutex); 131 bool validate(nsecs_t timestamp) const REQUIRES(mMutex); 132 Model getVSyncPredictionModelLocked() const REQUIRES(mMutex); 133 nsecs_t snapToVsync(nsecs_t timePoint) const REQUIRES(mMutex); 134 Period minFramePeriodLocked() const REQUIRES(mMutex); 135 Duration ensureMinFrameDurationIsKept(TimePoint, TimePoint) REQUIRES(mMutex); 136 void purgeTimelines(android::TimePoint now) REQUIRES(mMutex); 137 138 nsecs_t idealPeriod() const REQUIRES(mMutex); 139 140 bool const mTraceOn; 141 size_t const kHistorySize; 142 size_t const kMinimumSamplesForPrediction; 143 size_t const kOutlierTolerancePercent; 144 std::mutex mutable mMutex; 145 146 std::optional<nsecs_t> mKnownTimestamp GUARDED_BY(mMutex); 147 148 // Map between ideal vsync period and the calculated model 149 std::unordered_map<nsecs_t, Model> mutable mRateMap GUARDED_BY(mMutex); 150 151 size_t mLastTimestampIndex GUARDED_BY(mMutex) = 0; 152 std::vector<nsecs_t> mTimestamps GUARDED_BY(mMutex); 153 154 ftl::NonNull<DisplayModePtr> mDisplayModePtr GUARDED_BY(mMutex); 155 int mNumVsyncsForFrame GUARDED_BY(mMutex); 156 157 std::deque<TimePoint> mPastExpectedPresentTimes GUARDED_BY(mMutex); 158 159 MissedVsync mMissedVsync GUARDED_BY(mMutex); 160 161 std::deque<VsyncTimeline> mTimelines GUARDED_BY(mMutex); 162 TimePoint mLastCommittedVsync GUARDED_BY(mMutex) = TimePoint::fromNs(0); 163 Period mIdealPeriod GUARDED_BY(mMutex) = Duration::fromNs(0); 164 std::optional<Fps> mRenderRateOpt GUARDED_BY(mMutex); 165 }; 166 167 } // namespace android::scheduler 168