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