xref: /aosp_15_r20/frameworks/native/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
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