1 /*
2 * Copyright 2023 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 <common/FlagManager.h>
18 #include <common/trace.h>
19 #include <scheduler/FrameTargeter.h>
20 #include <scheduler/IVsyncSource.h>
21 #include <utils/Log.h>
22
23 namespace android::scheduler {
24 using namespace std::chrono_literals;
25
FrameTarget(const std::string & displayLabel)26 FrameTarget::FrameTarget(const std::string& displayLabel)
27 : mFramePending("PrevFramePending " + displayLabel, false),
28 mFrameMissed("PrevFrameMissed " + displayLabel, false),
29 mHwcFrameMissed("PrevHwcFrameMissed " + displayLabel, false),
30 mGpuFrameMissed("PrevGpuFrameMissed " + displayLabel, false) {}
31
32 std::pair<bool /* wouldBackpressure */, FrameTarget::PresentFence>
expectedSignaledPresentFence(Period vsyncPeriod,Period minFramePeriod) const33 FrameTarget::expectedSignaledPresentFence(Period vsyncPeriod, Period minFramePeriod) const {
34 SFTRACE_CALL();
35 if (!FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
36 const size_t i = static_cast<size_t>(targetsVsyncsAhead<2>(minFramePeriod));
37 return {true, mPresentFencesLegacy[i]};
38 }
39
40 bool wouldBackpressure = true;
41 auto expectedPresentTime = mExpectedPresentTime;
42 for (size_t i = mPresentFences.size(); i != 0; --i) {
43 const auto& fence = mPresentFences[i - 1];
44 SFTRACE_FORMAT_INSTANT("fence at idx: %zu expectedPresentTime in %.2f", i - 1,
45 ticks<std::milli, float>(fence.expectedPresentTime -
46 TimePoint::now()));
47
48 if (fence.expectedPresentTime + minFramePeriod < expectedPresentTime - vsyncPeriod / 2) {
49 SFTRACE_FORMAT_INSTANT("would not backpressure");
50 wouldBackpressure = false;
51 }
52
53 if (fence.expectedPresentTime <= mFrameBeginTime) {
54 SFTRACE_FORMAT_INSTANT("fence at idx: %zu is %.2f before frame begin "
55 "(wouldBackpressure=%s)",
56 i - 1,
57 ticks<std::milli, float>(mFrameBeginTime -
58 fence.expectedPresentTime),
59 wouldBackpressure ? "true" : "false");
60 return {wouldBackpressure, fence};
61 }
62
63 expectedPresentTime = fence.expectedPresentTime;
64 }
65 SFTRACE_FORMAT_INSTANT("No fence found");
66 return {wouldBackpressure, PresentFence{}};
67 }
68
wouldPresentEarly(Period vsyncPeriod,Period minFramePeriod) const69 bool FrameTarget::wouldPresentEarly(Period vsyncPeriod, Period minFramePeriod) const {
70 if (targetsVsyncsAhead<3>(minFramePeriod)) {
71 return true;
72 }
73
74 const auto [wouldBackpressure, fence] =
75 expectedSignaledPresentFence(vsyncPeriod, minFramePeriod);
76
77 return !wouldBackpressure ||
78 (fence.fenceTime->isValid() &&
79 fence.fenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING);
80 }
81
presentFenceForPreviousFrame() const82 const FenceTimePtr& FrameTarget::presentFenceForPreviousFrame() const {
83 if (FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
84 if (mPresentFences.size() > 0) {
85 return mPresentFences.back().fenceTime;
86 }
87 return FenceTime::NO_FENCE;
88 }
89
90 return mPresentFencesLegacy.front().fenceTime;
91 }
92
beginFrame(const BeginFrameArgs & args,const IVsyncSource & vsyncSource)93 void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& vsyncSource) {
94 return beginFrame(args, vsyncSource, &FrameTargeter::isFencePending);
95 }
96
beginFrame(const BeginFrameArgs & args,const IVsyncSource & vsyncSource,IsFencePendingFuncPtr isFencePendingFuncPtr)97 void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& vsyncSource,
98 IsFencePendingFuncPtr isFencePendingFuncPtr) {
99 mVsyncId = args.vsyncId;
100 mFrameBeginTime = args.frameBeginTime;
101 mDebugPresentTimeDelay = args.debugPresentTimeDelay;
102
103 // The `expectedVsyncTime`, which was predicted when this frame was scheduled, is normally in
104 // the future relative to `frameBeginTime`, but may not be for delayed frames. Adjust
105 // `mExpectedPresentTime` accordingly, but not `mScheduledPresentTime`.
106 const TimePoint lastScheduledPresentTime = mScheduledPresentTime;
107 mScheduledPresentTime = args.expectedVsyncTime;
108
109 const Period vsyncPeriod = vsyncSource.period();
110 const Period minFramePeriod = vsyncSource.minFramePeriod();
111
112 // Calculate the expected present time once and use the cached value throughout this frame to
113 // make sure all layers are seeing this same value.
114 if (args.expectedVsyncTime >= args.frameBeginTime) {
115 mExpectedPresentTime = args.expectedVsyncTime;
116 } else {
117 mExpectedPresentTime = vsyncSource.vsyncDeadlineAfter(args.frameBeginTime);
118 if (args.sfWorkDuration > vsyncPeriod) {
119 // Inflate the expected present time if we're targeting the next VSYNC.
120 mExpectedPresentTime += vsyncPeriod;
121 }
122 }
123
124 if (!mSupportsExpectedPresentTime) {
125 mEarliestPresentTime =
126 computeEarliestPresentTime(vsyncPeriod, minFramePeriod, args.hwcMinWorkDuration);
127 }
128
129 SFTRACE_FORMAT("%s %" PRId64 " vsyncIn %.2fms%s", __func__, ftl::to_underlying(args.vsyncId),
130 ticks<std::milli, float>(mExpectedPresentTime - TimePoint::now()),
131 mExpectedPresentTime == args.expectedVsyncTime ? "" : " (adjusted)");
132
133 const auto [wouldBackpressure, fence] =
134 expectedSignaledPresentFence(vsyncPeriod, minFramePeriod);
135
136 // In cases where the present fence is about to fire, give it a small grace period instead of
137 // giving up on the frame.
138 const int graceTimeForPresentFenceMs = [&] {
139 const bool considerBackpressure =
140 mBackpressureGpuComposition || !mCompositionCoverage.test(CompositionCoverage::Gpu);
141
142 if (!FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
143 return static_cast<int>(considerBackpressure);
144 }
145
146 if (!wouldBackpressure || !considerBackpressure) {
147 return 0;
148 }
149
150 return static_cast<int>((std::abs(fence.expectedPresentTime.ns() - mFrameBeginTime.ns()) <=
151 Duration(1ms).ns()));
152 }();
153
154 // Pending frames may trigger backpressure propagation.
155 const auto& isFencePending = *isFencePendingFuncPtr;
156 mFramePending = fence.fenceTime != FenceTime::NO_FENCE &&
157 isFencePending(fence.fenceTime, graceTimeForPresentFenceMs);
158
159 // A frame is missed if the prior frame is still pending. If no longer pending, then we still
160 // count the frame as missed if the predicted present time was further in the past than when the
161 // fence actually fired. Add some slop to correct for drift. This should generally be smaller
162 // than a typical frame duration, but should not be so small that it reports reasonable drift as
163 // a missed frame.
164 mFrameMissed = mFramePending || [&] {
165 const nsecs_t pastPresentTime = fence.fenceTime->getSignalTime();
166 if (pastPresentTime < 0) return false;
167 mLastSignaledFrameTime = {.signalTime = TimePoint::fromNs(pastPresentTime),
168 .expectedPresentTime = fence.expectedPresentTime};
169 SFTRACE_FORMAT_INSTANT("LastSignaledFrameTime expectedPresentTime %.2f ago, signalTime "
170 "%.2f ago",
171 ticks<std::milli, float>(mLastSignaledFrameTime.expectedPresentTime -
172 TimePoint::now()),
173 ticks<std::milli, float>(mLastSignaledFrameTime.signalTime -
174 TimePoint::now()));
175 const nsecs_t frameMissedSlop = vsyncPeriod.ns() / 2;
176 return lastScheduledPresentTime.ns() < pastPresentTime - frameMissedSlop;
177 }();
178
179 mHwcFrameMissed = mFrameMissed && mCompositionCoverage.test(CompositionCoverage::Hwc);
180 mGpuFrameMissed = mFrameMissed && mCompositionCoverage.test(CompositionCoverage::Gpu);
181
182 if (mFrameMissed) mFrameMissedCount++;
183 if (mHwcFrameMissed) mHwcFrameMissedCount++;
184 if (mGpuFrameMissed) mGpuFrameMissedCount++;
185
186 mWouldBackpressureHwc = mFramePending && wouldBackpressure;
187 }
188
computeEarliestPresentTime(Period vsyncPeriod,Period minFramePeriod,Duration hwcMinWorkDuration)189 std::optional<TimePoint> FrameTargeter::computeEarliestPresentTime(Period vsyncPeriod,
190 Period minFramePeriod,
191 Duration hwcMinWorkDuration) {
192 if (wouldPresentEarly(vsyncPeriod, minFramePeriod)) {
193 return previousFrameVsyncTime(minFramePeriod) - hwcMinWorkDuration;
194 }
195 return {};
196 }
197
endFrame(const CompositeResult & result)198 void FrameTargeter::endFrame(const CompositeResult& result) {
199 mCompositionCoverage = result.compositionCoverage;
200 }
201
setPresentFence(sp<Fence> presentFence)202 FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence) {
203 auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
204 return setPresentFence(std::move(presentFence), std::move(presentFenceTime));
205 }
206
setPresentFence(sp<Fence> presentFence,FenceTimePtr presentFenceTime)207 FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence, FenceTimePtr presentFenceTime) {
208 if (FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
209 addFence(std::move(presentFence), presentFenceTime, mExpectedPresentTime);
210 } else {
211 mPresentFencesLegacy[1] = mPresentFencesLegacy[0];
212 mPresentFencesLegacy[0] = {std::move(presentFence), presentFenceTime, mExpectedPresentTime};
213 }
214 return presentFenceTime;
215 }
216
dump(utils::Dumper & dumper) const217 void FrameTargeter::dump(utils::Dumper& dumper) const {
218 // There are scripts and tests that expect this (rather than "name=value") format.
219 dumper.dump({}, "Total missed frame count: " + std::to_string(mFrameMissedCount));
220 dumper.dump({}, "HWC missed frame count: " + std::to_string(mHwcFrameMissedCount));
221 dumper.dump({}, "GPU missed frame count: " + std::to_string(mGpuFrameMissedCount));
222 }
223
isFencePending(const FenceTimePtr & fence,int graceTimeMs)224 bool FrameTargeter::isFencePending(const FenceTimePtr& fence, int graceTimeMs) {
225 SFTRACE_CALL();
226 const status_t status = fence->wait(graceTimeMs);
227
228 // This is the same as Fence::Status::Unsignaled, but it saves a call to getStatus,
229 // which calls wait(0) again internally.
230 return status == -ETIME;
231 }
232
233 } // namespace android::scheduler
234