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 #include "VSyncReactor.h"
22 #include <cutils/properties.h>
23 #include <log/log.h>
24 #include <utils/Trace.h>
25 #include "../TracedOrdinal.h"
26 #include "TimeKeeper.h"
27 #include "VSyncDispatch.h"
28 #include "VSyncTracker.h"
29
30 namespace android::scheduler {
31 using base::StringAppendF;
32
33 VsyncController::~VsyncController() = default;
34
35 Clock::~Clock() = default;
now() const36 nsecs_t SystemClock::now() const {
37 return systemTime(SYSTEM_TIME_MONOTONIC);
38 }
39
VSyncReactor(std::unique_ptr<Clock> clock,VSyncTracker & tracker,size_t pendingFenceLimit,bool supportKernelIdleTimer)40 VSyncReactor::VSyncReactor(std::unique_ptr<Clock> clock, VSyncTracker& tracker,
41 size_t pendingFenceLimit, bool supportKernelIdleTimer)
42 : mClock(std::move(clock)),
43 mTracker(tracker),
44 mPendingLimit(pendingFenceLimit),
45 // TODO(adyabr): change mSupportKernelIdleTimer when the active display changes
46 mSupportKernelIdleTimer(supportKernelIdleTimer) {}
47
48 VSyncReactor::~VSyncReactor() = default;
49
addPresentFence(const std::shared_ptr<android::FenceTime> & fence)50 bool VSyncReactor::addPresentFence(const std::shared_ptr<android::FenceTime>& fence) {
51 if (!fence) {
52 return false;
53 }
54
55 nsecs_t const signalTime = fence->getCachedSignalTime();
56 if (signalTime == Fence::SIGNAL_TIME_INVALID) {
57 return true;
58 }
59
60 std::lock_guard lock(mMutex);
61 if (mExternalIgnoreFences || mInternalIgnoreFences) {
62 return true;
63 }
64
65 bool timestampAccepted = true;
66 for (auto it = mUnfiredFences.begin(); it != mUnfiredFences.end();) {
67 auto const time = (*it)->getCachedSignalTime();
68 if (time == Fence::SIGNAL_TIME_PENDING) {
69 it++;
70 } else if (time == Fence::SIGNAL_TIME_INVALID) {
71 it = mUnfiredFences.erase(it);
72 } else {
73 timestampAccepted &= mTracker.addVsyncTimestamp(time);
74
75 it = mUnfiredFences.erase(it);
76 }
77 }
78
79 if (signalTime == Fence::SIGNAL_TIME_PENDING) {
80 if (mPendingLimit == mUnfiredFences.size()) {
81 mUnfiredFences.erase(mUnfiredFences.begin());
82 }
83 mUnfiredFences.push_back(fence);
84 } else {
85 timestampAccepted &= mTracker.addVsyncTimestamp(signalTime);
86 }
87
88 if (!timestampAccepted) {
89 mMoreSamplesNeeded = true;
90 setIgnorePresentFencesInternal(true);
91 mPeriodConfirmationInProgress = true;
92 }
93
94 return mMoreSamplesNeeded;
95 }
96
setIgnorePresentFences(bool ignore)97 void VSyncReactor::setIgnorePresentFences(bool ignore) {
98 std::lock_guard lock(mMutex);
99 mExternalIgnoreFences = ignore;
100 updateIgnorePresentFencesInternal();
101 }
102
setIgnorePresentFencesInternal(bool ignore)103 void VSyncReactor::setIgnorePresentFencesInternal(bool ignore) {
104 mInternalIgnoreFences = ignore;
105 updateIgnorePresentFencesInternal();
106 }
107
updateIgnorePresentFencesInternal()108 void VSyncReactor::updateIgnorePresentFencesInternal() {
109 if (mExternalIgnoreFences || mInternalIgnoreFences) {
110 mUnfiredFences.clear();
111 }
112 }
113
startPeriodTransitionInternal(nsecs_t newPeriod)114 void VSyncReactor::startPeriodTransitionInternal(nsecs_t newPeriod) {
115 ATRACE_CALL();
116 mPeriodConfirmationInProgress = true;
117 mPeriodTransitioningTo = newPeriod;
118 mMoreSamplesNeeded = true;
119 setIgnorePresentFencesInternal(true);
120 }
121
endPeriodTransition()122 void VSyncReactor::endPeriodTransition() {
123 ATRACE_CALL();
124 mPeriodTransitioningTo.reset();
125 mPeriodConfirmationInProgress = false;
126 mLastHwVsync.reset();
127 }
128
startPeriodTransition(nsecs_t period)129 void VSyncReactor::startPeriodTransition(nsecs_t period) {
130 ATRACE_INT64("VSR-setPeriod", period);
131 std::lock_guard lock(mMutex);
132 mLastHwVsync.reset();
133
134 if (!mSupportKernelIdleTimer && period == mTracker.currentPeriod()) {
135 endPeriodTransition();
136 setIgnorePresentFencesInternal(false);
137 mMoreSamplesNeeded = false;
138 } else {
139 startPeriodTransitionInternal(period);
140 }
141 }
142
periodConfirmed(nsecs_t vsync_timestamp,std::optional<nsecs_t> HwcVsyncPeriod)143 bool VSyncReactor::periodConfirmed(nsecs_t vsync_timestamp, std::optional<nsecs_t> HwcVsyncPeriod) {
144 if (!mPeriodConfirmationInProgress) {
145 return false;
146 }
147
148 if (!mLastHwVsync && !HwcVsyncPeriod) {
149 return false;
150 }
151
152 const bool periodIsChanging =
153 mPeriodTransitioningTo && (*mPeriodTransitioningTo != mTracker.currentPeriod());
154 if (mSupportKernelIdleTimer && !periodIsChanging) {
155 // Clear out the Composer-provided period and use the allowance logic below
156 HwcVsyncPeriod = {};
157 }
158
159 auto const period = mPeriodTransitioningTo ? *mPeriodTransitioningTo : mTracker.currentPeriod();
160 static constexpr int allowancePercent = 10;
161 static constexpr std::ratio<allowancePercent, 100> allowancePercentRatio;
162 auto const allowance = period * allowancePercentRatio.num / allowancePercentRatio.den;
163 if (HwcVsyncPeriod) {
164 return std::abs(*HwcVsyncPeriod - period) < allowance;
165 }
166
167 auto const distance = vsync_timestamp - *mLastHwVsync;
168 return std::abs(distance - period) < allowance;
169 }
170
addHwVsyncTimestamp(nsecs_t timestamp,std::optional<nsecs_t> hwcVsyncPeriod,bool * periodFlushed)171 bool VSyncReactor::addHwVsyncTimestamp(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod,
172 bool* periodFlushed) {
173 assert(periodFlushed);
174
175 std::lock_guard lock(mMutex);
176 if (periodConfirmed(timestamp, hwcVsyncPeriod)) {
177 ATRACE_NAME("VSR: period confirmed");
178 if (mPeriodTransitioningTo) {
179 mTracker.setPeriod(*mPeriodTransitioningTo);
180 *periodFlushed = true;
181 }
182
183 if (mLastHwVsync) {
184 mTracker.addVsyncTimestamp(*mLastHwVsync);
185 }
186 mTracker.addVsyncTimestamp(timestamp);
187
188 endPeriodTransition();
189 mMoreSamplesNeeded = mTracker.needsMoreSamples();
190 } else if (mPeriodConfirmationInProgress) {
191 ATRACE_NAME("VSR: still confirming period");
192 mLastHwVsync = timestamp;
193 mMoreSamplesNeeded = true;
194 *periodFlushed = false;
195 } else {
196 ATRACE_NAME("VSR: adding sample");
197 *periodFlushed = false;
198 mTracker.addVsyncTimestamp(timestamp);
199 mMoreSamplesNeeded = mTracker.needsMoreSamples();
200 }
201
202 if (!mMoreSamplesNeeded) {
203 setIgnorePresentFencesInternal(false);
204 }
205 return mMoreSamplesNeeded;
206 }
207
dump(std::string & result) const208 void VSyncReactor::dump(std::string& result) const {
209 std::lock_guard lock(mMutex);
210 StringAppendF(&result, "VsyncReactor in use\n");
211 StringAppendF(&result, "Has %zu unfired fences\n", mUnfiredFences.size());
212 StringAppendF(&result, "mInternalIgnoreFences=%d mExternalIgnoreFences=%d\n",
213 mInternalIgnoreFences, mExternalIgnoreFences);
214 StringAppendF(&result, "mMoreSamplesNeeded=%d mPeriodConfirmationInProgress=%d\n",
215 mMoreSamplesNeeded, mPeriodConfirmationInProgress);
216 if (mPeriodTransitioningTo) {
217 StringAppendF(&result, "mPeriodTransitioningTo=%" PRId64 "\n", *mPeriodTransitioningTo);
218 } else {
219 StringAppendF(&result, "mPeriodTransitioningTo=nullptr\n");
220 }
221
222 if (mLastHwVsync) {
223 StringAppendF(&result, "Last HW vsync was %.2fms ago\n",
224 (mClock->now() - *mLastHwVsync) / 1e6f);
225 } else {
226 StringAppendF(&result, "No Last HW vsync\n");
227 }
228
229 StringAppendF(&result, "VSyncTracker:\n");
230 mTracker.dump(result);
231 }
232
233 } // namespace android::scheduler
234