blob: badd21ef86b3af5e4a736f20f992e634426a9409 [file] [log] [blame]
Dominik Laskowskib418dd72023-06-13 17:31:04 -04001/*
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
ramindani513e6502024-04-10 15:22:19 -070019#include <common/FlagManager.h>
Dominik Laskowskib418dd72023-06-13 17:31:04 -040020#include <scheduler/FrameTargeter.h>
21#include <scheduler/IVsyncSource.h>
22
23namespace android::scheduler {
24
Dominik Laskowskiec0eac22023-01-28 16:16:19 -050025FrameTarget::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
Ady Abraham3db8a3c2023-11-20 17:53:47 -080031TimePoint FrameTarget::pastVsyncTime(Period minFramePeriod) const {
Dominik Laskowskib418dd72023-06-13 17:31:04 -040032 // TODO(b/267315508): Generalize to N VSYNCs.
Ady Abraham3db8a3c2023-11-20 17:53:47 -080033 const int shift = static_cast<int>(targetsVsyncsAhead<2>(minFramePeriod));
34 return mExpectedPresentTime - Period::fromNs(minFramePeriod.ns() << shift);
Dominik Laskowskib418dd72023-06-13 17:31:04 -040035}
36
ramindani513e6502024-04-10 15:22:19 -070037FenceTimePtr FrameTarget::presentFenceForPastVsync(Period minFramePeriod) const {
38 if (FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
39 return pastVsyncTimePtr();
40 }
Ady Abraham3db8a3c2023-11-20 17:53:47 -080041 const size_t i = static_cast<size_t>(targetsVsyncsAhead<2>(minFramePeriod));
Dominik Laskowskib418dd72023-06-13 17:31:04 -040042 return mPresentFences[i].fenceTime;
43}
44
Ady Abraham3db8a3c2023-11-20 17:53:47 -080045bool FrameTarget::wouldPresentEarly(Period minFramePeriod) const {
Dominik Laskowskib418dd72023-06-13 17:31:04 -040046 // 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.
ramindani513e6502024-04-10 15:22:19 -070050 const bool allowNVsyncs = FlagManager::getInstance().allow_n_vsyncs_in_targeter();
51 if (!allowNVsyncs && targetsVsyncsAhead<3>(minFramePeriod)) {
Dominik Laskowskib418dd72023-06-13 17:31:04 -040052 return true;
53 }
54
Ady Abraham3db8a3c2023-11-20 17:53:47 -080055 const auto fence = presentFenceForPastVsync(minFramePeriod);
Dominik Laskowskib418dd72023-06-13 17:31:04 -040056 return fence->isValid() && fence->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
57}
58
59void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& vsyncSource) {
60 return beginFrame(args, vsyncSource, &FrameTargeter::isFencePending);
61}
62
63void 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();
Ady Abraham3db8a3c2023-11-20 17:53:47 -080075 const Period minFramePeriod = vsyncSource.minFramePeriod();
Dominik Laskowskib418dd72023-06-13 17:31:04 -040076
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
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -050089 if (!mSupportsExpectedPresentTime) {
90 mEarliestPresentTime = computeEarliestPresentTime(minFramePeriod, args.hwcMinWorkDuration);
91 }
92
Dominik Laskowskib418dd72023-06-13 17:31:04 -040093 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
Ady Abraham3db8a3c2023-11-20 17:53:47 -080097 const FenceTimePtr& pastPresentFence = presentFenceForPastVsync(minFramePeriod);
Dominik Laskowskib418dd72023-06-13 17:31:04 -040098
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;
Ady Abrahamaa7ebd62024-03-26 02:27:57 +0000120 mLastSignaledFrameTime = TimePoint::fromNs(pastPresentTime);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400121 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
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500133std::optional<TimePoint> FrameTargeter::computeEarliestPresentTime(Period minFramePeriod,
134 Duration hwcMinWorkDuration) {
135 if (wouldPresentEarly(minFramePeriod)) {
136 return previousFrameVsyncTime(minFramePeriod) - hwcMinWorkDuration;
137 }
138 return {};
139}
140
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400141void FrameTargeter::endFrame(const CompositeResult& result) {
142 mCompositionCoverage = result.compositionCoverage;
143}
144
145FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence) {
146 auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
147 return setPresentFence(std::move(presentFence), std::move(presentFenceTime));
148}
149
150FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence, FenceTimePtr presentFenceTime) {
ramindani513e6502024-04-10 15:22:19 -0700151 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 }
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400157 return presentFenceTime;
158}
159
160void FrameTargeter::dump(utils::Dumper& dumper) const {
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400161 // 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
167bool 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