• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <gui/TraceUtils.h>
18 
19 #include <common/FlagManager.h>
20 #include <scheduler/FrameTargeter.h>
21 #include <scheduler/IVsyncSource.h>
22 
23 namespace android::scheduler {
24 
FrameTarget(const std::string & displayLabel)25 FrameTarget::FrameTarget(const std::string& displayLabel)
26       : mFramePending("PrevFramePending " + displayLabel, false),
27         mFrameMissed("PrevFrameMissed " + displayLabel, false),
28         mHwcFrameMissed("PrevHwcFrameMissed " + displayLabel, false),
29         mGpuFrameMissed("PrevGpuFrameMissed " + displayLabel, false) {}
30 
pastVsyncTime(Period minFramePeriod) const31 TimePoint FrameTarget::pastVsyncTime(Period minFramePeriod) const {
32     // TODO(b/267315508): Generalize to N VSYNCs.
33     const int shift = static_cast<int>(targetsVsyncsAhead<2>(minFramePeriod));
34     return mExpectedPresentTime - Period::fromNs(minFramePeriod.ns() << shift);
35 }
36 
presentFenceForPastVsync(Period minFramePeriod) const37 FenceTimePtr FrameTarget::presentFenceForPastVsync(Period minFramePeriod) const {
38     if (FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
39         return pastVsyncTimePtr();
40     }
41     const size_t i = static_cast<size_t>(targetsVsyncsAhead<2>(minFramePeriod));
42     return mPresentFences[i].fenceTime;
43 }
44 
wouldPresentEarly(Period minFramePeriod) const45 bool FrameTarget::wouldPresentEarly(Period minFramePeriod) const {
46     // TODO(b/241285475): Since this is called during `composite`, the calls to `targetsVsyncsAhead`
47     // should use `TimePoint::now()` in case of delays since `mFrameBeginTime`.
48 
49     // TODO(b/267315508): Generalize to N VSYNCs.
50     const bool allowNVsyncs = FlagManager::getInstance().allow_n_vsyncs_in_targeter();
51     if (!allowNVsyncs && targetsVsyncsAhead<3>(minFramePeriod)) {
52         return true;
53     }
54 
55     const auto fence = presentFenceForPastVsync(minFramePeriod);
56     return fence->isValid() && fence->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
57 }
58 
beginFrame(const BeginFrameArgs & args,const IVsyncSource & vsyncSource)59 void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& vsyncSource) {
60     return beginFrame(args, vsyncSource, &FrameTargeter::isFencePending);
61 }
62 
beginFrame(const BeginFrameArgs & args,const IVsyncSource & vsyncSource,IsFencePendingFuncPtr isFencePendingFuncPtr)63 void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& vsyncSource,
64                                IsFencePendingFuncPtr isFencePendingFuncPtr) {
65     mVsyncId = args.vsyncId;
66     mFrameBeginTime = args.frameBeginTime;
67 
68     // The `expectedVsyncTime`, which was predicted when this frame was scheduled, is normally in
69     // the future relative to `frameBeginTime`, but may not be for delayed frames. Adjust
70     // `mExpectedPresentTime` accordingly, but not `mScheduledPresentTime`.
71     const TimePoint lastScheduledPresentTime = mScheduledPresentTime;
72     mScheduledPresentTime = args.expectedVsyncTime;
73 
74     const Period vsyncPeriod = vsyncSource.period();
75     const Period minFramePeriod = vsyncSource.minFramePeriod();
76 
77     // Calculate the expected present time once and use the cached value throughout this frame to
78     // make sure all layers are seeing this same value.
79     if (args.expectedVsyncTime >= args.frameBeginTime) {
80         mExpectedPresentTime = args.expectedVsyncTime;
81     } else {
82         mExpectedPresentTime = vsyncSource.vsyncDeadlineAfter(args.frameBeginTime);
83         if (args.sfWorkDuration > vsyncPeriod) {
84             // Inflate the expected present time if we're targeting the next VSYNC.
85             mExpectedPresentTime += vsyncPeriod;
86         }
87     }
88 
89     if (!mSupportsExpectedPresentTime) {
90         mEarliestPresentTime = computeEarliestPresentTime(minFramePeriod, args.hwcMinWorkDuration);
91     }
92 
93     ATRACE_FORMAT("%s %" PRId64 " vsyncIn %.2fms%s", __func__, ftl::to_underlying(args.vsyncId),
94                   ticks<std::milli, float>(mExpectedPresentTime - TimePoint::now()),
95                   mExpectedPresentTime == args.expectedVsyncTime ? "" : " (adjusted)");
96 
97     const FenceTimePtr& pastPresentFence = presentFenceForPastVsync(minFramePeriod);
98 
99     // In cases where the present fence is about to fire, give it a small grace period instead of
100     // giving up on the frame.
101     //
102     // TODO(b/280667110): The grace period should depend on `sfWorkDuration` and `vsyncPeriod` being
103     // approximately equal, not whether backpressure propagation is enabled.
104     const int graceTimeForPresentFenceMs = static_cast<int>(
105             mBackpressureGpuComposition || !mCompositionCoverage.test(CompositionCoverage::Gpu));
106 
107     // Pending frames may trigger backpressure propagation.
108     const auto& isFencePending = *isFencePendingFuncPtr;
109     mFramePending = pastPresentFence != FenceTime::NO_FENCE &&
110             isFencePending(pastPresentFence, graceTimeForPresentFenceMs);
111 
112     // A frame is missed if the prior frame is still pending. If no longer pending, then we still
113     // count the frame as missed if the predicted present time was further in the past than when the
114     // fence actually fired. Add some slop to correct for drift. This should generally be smaller
115     // than a typical frame duration, but should not be so small that it reports reasonable drift as
116     // a missed frame.
117     mFrameMissed = mFramePending || [&] {
118         const nsecs_t pastPresentTime = pastPresentFence->getSignalTime();
119         if (pastPresentTime < 0) return false;
120         mLastSignaledFrameTime = TimePoint::fromNs(pastPresentTime);
121         const nsecs_t frameMissedSlop = vsyncPeriod.ns() / 2;
122         return lastScheduledPresentTime.ns() < pastPresentTime - frameMissedSlop;
123     }();
124 
125     mHwcFrameMissed = mFrameMissed && mCompositionCoverage.test(CompositionCoverage::Hwc);
126     mGpuFrameMissed = mFrameMissed && mCompositionCoverage.test(CompositionCoverage::Gpu);
127 
128     if (mFrameMissed) mFrameMissedCount++;
129     if (mHwcFrameMissed) mHwcFrameMissedCount++;
130     if (mGpuFrameMissed) mGpuFrameMissedCount++;
131 }
132 
computeEarliestPresentTime(Period minFramePeriod,Duration hwcMinWorkDuration)133 std::optional<TimePoint> FrameTargeter::computeEarliestPresentTime(Period minFramePeriod,
134                                                                    Duration hwcMinWorkDuration) {
135     if (wouldPresentEarly(minFramePeriod)) {
136         return previousFrameVsyncTime(minFramePeriod) - hwcMinWorkDuration;
137     }
138     return {};
139 }
140 
endFrame(const CompositeResult & result)141 void FrameTargeter::endFrame(const CompositeResult& result) {
142     mCompositionCoverage = result.compositionCoverage;
143 }
144 
setPresentFence(sp<Fence> presentFence)145 FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence) {
146     auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
147     return setPresentFence(std::move(presentFence), std::move(presentFenceTime));
148 }
149 
setPresentFence(sp<Fence> presentFence,FenceTimePtr presentFenceTime)150 FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence, FenceTimePtr presentFenceTime) {
151     if (FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
152         addFence(std::move(presentFence), presentFenceTime, mExpectedPresentTime);
153     } else {
154         mPresentFences[1] = mPresentFences[0];
155         mPresentFences[0] = {std::move(presentFence), presentFenceTime, mExpectedPresentTime};
156     }
157     return presentFenceTime;
158 }
159 
dump(utils::Dumper & dumper) const160 void FrameTargeter::dump(utils::Dumper& dumper) const {
161     // There are scripts and tests that expect this (rather than "name=value") format.
162     dumper.dump({}, "Total missed frame count: " + std::to_string(mFrameMissedCount));
163     dumper.dump({}, "HWC missed frame count: " + std::to_string(mHwcFrameMissedCount));
164     dumper.dump({}, "GPU missed frame count: " + std::to_string(mGpuFrameMissedCount));
165 }
166 
isFencePending(const FenceTimePtr & fence,int graceTimeMs)167 bool FrameTargeter::isFencePending(const FenceTimePtr& fence, int graceTimeMs) {
168     ATRACE_CALL();
169     const status_t status = fence->wait(graceTimeMs);
170 
171     // This is the same as Fence::Status::Unsignaled, but it saves a call to getStatus,
172     // which calls wait(0) again internally.
173     return status == -ETIME;
174 }
175 
176 } // namespace android::scheduler
177