xref: /aosp_15_r20/frameworks/native/services/surfaceflinger/Scheduler/VSyncReactor.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
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 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
18 #undef LOG_TAG
19 #define LOG_TAG "VSyncReactor"
20 //#define LOG_NDEBUG 0
21 
22 #include <assert.h>
23 #include <common/trace.h>
24 #include <cutils/properties.h>
25 #include <ftl/concat.h>
26 #include <log/log.h>
27 
28 #include "../TracedOrdinal.h"
29 #include "VSyncDispatch.h"
30 #include "VSyncReactor.h"
31 #include "VSyncTracker.h"
32 
33 namespace android::scheduler {
34 
35 using base::StringAppendF;
36 
37 VsyncController::~VsyncController() = default;
38 
now() const39 nsecs_t SystemClock::now() const {
40     return systemTime(SYSTEM_TIME_MONOTONIC);
41 }
42 
VSyncReactor(PhysicalDisplayId id,std::unique_ptr<Clock> clock,VSyncTracker & tracker,size_t pendingFenceLimit,bool supportKernelIdleTimer)43 VSyncReactor::VSyncReactor(PhysicalDisplayId id, std::unique_ptr<Clock> clock,
44                            VSyncTracker& tracker, size_t pendingFenceLimit,
45                            bool supportKernelIdleTimer)
46       : mId(id),
47         mClock(std::move(clock)),
48         mTracker(tracker),
49         mPendingLimit(pendingFenceLimit),
50         mSupportKernelIdleTimer(supportKernelIdleTimer) {}
51 
52 VSyncReactor::~VSyncReactor() = default;
53 
addPresentFence(std::shared_ptr<FenceTime> fence)54 bool VSyncReactor::addPresentFence(std::shared_ptr<FenceTime> fence) {
55     SFTRACE_CALL();
56 
57     if (!fence) {
58         return false;
59     }
60 
61     nsecs_t const signalTime = fence->getCachedSignalTime();
62     if (signalTime == Fence::SIGNAL_TIME_INVALID) {
63         return true;
64     }
65 
66     std::lock_guard lock(mMutex);
67     if (mExternalIgnoreFences || mInternalIgnoreFences) {
68         SFTRACE_FORMAT_INSTANT("mExternalIgnoreFences=%d mInternalIgnoreFences=%d",
69                                mExternalIgnoreFences, mInternalIgnoreFences);
70         return true;
71     }
72 
73     bool timestampAccepted = true;
74     for (auto it = mUnfiredFences.begin(); it != mUnfiredFences.end();) {
75         auto const time = (*it)->getCachedSignalTime();
76         if (time == Fence::SIGNAL_TIME_PENDING) {
77             it++;
78         } else if (time == Fence::SIGNAL_TIME_INVALID) {
79             it = mUnfiredFences.erase(it);
80         } else {
81             timestampAccepted &= mTracker.addVsyncTimestamp(time);
82 
83             it = mUnfiredFences.erase(it);
84         }
85     }
86 
87     if (signalTime == Fence::SIGNAL_TIME_PENDING) {
88         if (mPendingLimit == mUnfiredFences.size()) {
89             mUnfiredFences.erase(mUnfiredFences.begin());
90         }
91         mUnfiredFences.push_back(std::move(fence));
92     } else {
93         timestampAccepted &= mTracker.addVsyncTimestamp(signalTime);
94     }
95 
96     if (!timestampAccepted) {
97         mMoreSamplesNeeded = true;
98         setIgnorePresentFencesInternal(true);
99         mPeriodConfirmationInProgress = true;
100     }
101 
102     return mMoreSamplesNeeded;
103 }
104 
setIgnorePresentFences(bool ignore)105 void VSyncReactor::setIgnorePresentFences(bool ignore) {
106     std::lock_guard lock(mMutex);
107     mExternalIgnoreFences = ignore;
108     updateIgnorePresentFencesInternal();
109 }
110 
setIgnorePresentFencesInternal(bool ignore)111 void VSyncReactor::setIgnorePresentFencesInternal(bool ignore) {
112     mInternalIgnoreFences = ignore;
113     updateIgnorePresentFencesInternal();
114 }
115 
updateIgnorePresentFencesInternal()116 void VSyncReactor::updateIgnorePresentFencesInternal() {
117     if (mExternalIgnoreFences || mInternalIgnoreFences) {
118         mUnfiredFences.clear();
119     }
120 }
121 
startPeriodTransitionInternal(ftl::NonNull<DisplayModePtr> modePtr)122 void VSyncReactor::startPeriodTransitionInternal(ftl::NonNull<DisplayModePtr> modePtr) {
123     SFTRACE_FORMAT("%s %" PRIu64, __func__, mId.value);
124     mPeriodConfirmationInProgress = true;
125     mModePtrTransitioningTo = modePtr.get();
126     mMoreSamplesNeeded = true;
127     setIgnorePresentFencesInternal(true);
128 }
129 
endPeriodTransition()130 void VSyncReactor::endPeriodTransition() {
131     SFTRACE_FORMAT("%s %" PRIu64, __func__, mId.value);
132     mModePtrTransitioningTo.reset();
133     mPeriodConfirmationInProgress = false;
134     mLastHwVsync.reset();
135 }
136 
onDisplayModeChanged(ftl::NonNull<DisplayModePtr> modePtr,bool force)137 void VSyncReactor::onDisplayModeChanged(ftl::NonNull<DisplayModePtr> modePtr, bool force) {
138     SFTRACE_INT64(ftl::Concat("VSR-", __func__, " ", mId.value).c_str(),
139                   modePtr->getVsyncRate().getPeriodNsecs());
140     std::lock_guard lock(mMutex);
141     mLastHwVsync.reset();
142 
143     // kernel idle timer is not applicable for VRR
144     const bool supportKernelIdleTimer = mSupportKernelIdleTimer && !modePtr->getVrrConfig();
145     if (!supportKernelIdleTimer && mTracker.isCurrentMode(modePtr) && !force) {
146         endPeriodTransition();
147         setIgnorePresentFencesInternal(false);
148         mMoreSamplesNeeded = false;
149     } else {
150         startPeriodTransitionInternal(modePtr);
151     }
152 }
153 
periodConfirmed(nsecs_t vsync_timestamp,std::optional<nsecs_t> HwcVsyncPeriod)154 bool VSyncReactor::periodConfirmed(nsecs_t vsync_timestamp, std::optional<nsecs_t> HwcVsyncPeriod) {
155     if (!mPeriodConfirmationInProgress) {
156         return false;
157     }
158 
159     if (mDisplayPowerMode == hal::PowerMode::DOZE ||
160         mDisplayPowerMode == hal::PowerMode::DOZE_SUSPEND) {
161         return true;
162     }
163 
164     if (!mLastHwVsync && !HwcVsyncPeriod) {
165         return false;
166     }
167 
168     const std::optional<Period> newPeriod = mModePtrTransitioningTo
169             ? mModePtrTransitioningTo->getVsyncRate().getPeriod()
170             : std::optional<Period>{};
171     const bool periodIsChanging = newPeriod && (newPeriod->ns() != mTracker.currentPeriod());
172     if (mSupportKernelIdleTimer && !periodIsChanging) {
173         // Clear out the Composer-provided period and use the allowance logic below
174         HwcVsyncPeriod = {};
175     }
176 
177     auto const period = newPeriod ? newPeriod->ns() : mTracker.currentPeriod();
178     static constexpr int allowancePercent = 10;
179     static constexpr std::ratio<allowancePercent, 100> allowancePercentRatio;
180     auto const allowance = period * allowancePercentRatio.num / allowancePercentRatio.den;
181     if (HwcVsyncPeriod) {
182         return std::abs(*HwcVsyncPeriod - period) < allowance;
183     }
184 
185     auto const distance = vsync_timestamp - *mLastHwVsync;
186     return std::abs(distance - period) < allowance;
187 }
188 
addHwVsyncTimestamp(nsecs_t timestamp,std::optional<nsecs_t> hwcVsyncPeriod,bool * periodFlushed)189 bool VSyncReactor::addHwVsyncTimestamp(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod,
190                                        bool* periodFlushed) {
191     assert(periodFlushed);
192 
193     std::lock_guard lock(mMutex);
194     if (periodConfirmed(timestamp, hwcVsyncPeriod)) {
195         SFTRACE_FORMAT("VSR %" PRIu64 ": period confirmed", mId.value);
196         if (mModePtrTransitioningTo) {
197             mTracker.setDisplayModePtr(ftl::as_non_null(mModePtrTransitioningTo));
198             *periodFlushed = true;
199         }
200 
201         if (mLastHwVsync) {
202             mTracker.addVsyncTimestamp(*mLastHwVsync);
203         }
204         mTracker.addVsyncTimestamp(timestamp);
205 
206         endPeriodTransition();
207         mMoreSamplesNeeded = mTracker.needsMoreSamples();
208     } else if (mPeriodConfirmationInProgress) {
209         SFTRACE_FORMAT("VSR %" PRIu64 ": still confirming period", mId.value);
210         mLastHwVsync = timestamp;
211         mMoreSamplesNeeded = true;
212         *periodFlushed = false;
213     } else {
214         SFTRACE_FORMAT("VSR %" PRIu64 ": adding sample", mId.value);
215         *periodFlushed = false;
216         mTracker.addVsyncTimestamp(timestamp);
217         mMoreSamplesNeeded = mTracker.needsMoreSamples();
218     }
219 
220     if (mExternalIgnoreFences) {
221       // keep HWVSync on as long as we ignore present fences.
222       mMoreSamplesNeeded = true;
223     }
224 
225     if (!mMoreSamplesNeeded) {
226         setIgnorePresentFencesInternal(false);
227     }
228     return mMoreSamplesNeeded;
229 }
230 
setDisplayPowerMode(hal::PowerMode powerMode)231 void VSyncReactor::setDisplayPowerMode(hal::PowerMode powerMode) {
232     std::scoped_lock lock(mMutex);
233     mDisplayPowerMode = powerMode;
234 }
235 
dump(std::string & result) const236 void VSyncReactor::dump(std::string& result) const {
237     std::lock_guard lock(mMutex);
238     StringAppendF(&result, "VsyncReactor in use\n");
239     StringAppendF(&result, "Has %zu unfired fences\n", mUnfiredFences.size());
240     StringAppendF(&result, "mInternalIgnoreFences=%d mExternalIgnoreFences=%d\n",
241                   mInternalIgnoreFences, mExternalIgnoreFences);
242     StringAppendF(&result, "mMoreSamplesNeeded=%d mPeriodConfirmationInProgress=%d\n",
243                   mMoreSamplesNeeded, mPeriodConfirmationInProgress);
244     if (mModePtrTransitioningTo) {
245         StringAppendF(&result, "mModePtrTransitioningTo=%s\n",
246                       to_string(*mModePtrTransitioningTo).c_str());
247     } else {
248         StringAppendF(&result, "mModePtrTransitioningTo=nullptr\n");
249     }
250 
251     if (mLastHwVsync) {
252         StringAppendF(&result, "Last HW vsync was %.2fms ago\n",
253                       (mClock->now() - *mLastHwVsync) / 1e6f);
254     } else {
255         StringAppendF(&result, "No Last HW vsync\n");
256     }
257 
258     StringAppendF(&result, "VSyncTracker:\n");
259     mTracker.dump(result);
260 }
261 
262 } // namespace android::scheduler
263