blob: 063f1b3d1dda25924af9cbf7e79e050ee705cd6a [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
Ady Abraham73e9ae32024-08-20 17:54:56 +000023namespace {
24size_t getPresentFenceShift(Period minFramePeriod) {
25 const bool isTwoVsyncsAhead = targetsVsyncsAhead<2>(minFramePeriod);
26 size_t shift = 0;
27 if (isTwoVsyncsAhead) {
28 shift = static_cast<size_t>(expectedFrameDuration.ns() / minFramePeriod.ns());
29 if (shift >= mPresentFences.size()) {
30 shift = mPresentFences.size() - 1;
31 }
32 }
33 return shift;
34}
35} // namespace
36
Dominik Laskowskib418dd72023-06-13 17:31:04 -040037namespace android::scheduler {
38
Dominik Laskowskiec0eac22023-01-28 16:16:19 -050039FrameTarget::FrameTarget(const std::string& displayLabel)
40 : mFramePending("PrevFramePending " + displayLabel, false),
41 mFrameMissed("PrevFrameMissed " + displayLabel, false),
42 mHwcFrameMissed("PrevHwcFrameMissed " + displayLabel, false),
43 mGpuFrameMissed("PrevGpuFrameMissed " + displayLabel, false) {}
44
Ady Abraham3db8a3c2023-11-20 17:53:47 -080045TimePoint FrameTarget::pastVsyncTime(Period minFramePeriod) const {
Dominik Laskowskib418dd72023-06-13 17:31:04 -040046 // TODO(b/267315508): Generalize to N VSYNCs.
Ady Abraham73e9ae32024-08-20 17:54:56 +000047 const size_t shift = getPresentFenceShift(minFramePeriod);
Ady Abraham3db8a3c2023-11-20 17:53:47 -080048 return mExpectedPresentTime - Period::fromNs(minFramePeriod.ns() << shift);
Dominik Laskowskib418dd72023-06-13 17:31:04 -040049}
50
ramindani513e6502024-04-10 15:22:19 -070051FenceTimePtr FrameTarget::presentFenceForPastVsync(Period minFramePeriod) const {
52 if (FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
53 return pastVsyncTimePtr();
54 }
Ady Abraham73e9ae32024-08-20 17:54:56 +000055
56 const size_t shift = getPresentFenceShift(minFramePeriod);
57 ATRACE_FORMAT("mPresentFences shift=%zu", shift);
58 return mPresentFences[shift].fenceTime;
Dominik Laskowskib418dd72023-06-13 17:31:04 -040059}
60
Ady Abraham3db8a3c2023-11-20 17:53:47 -080061bool FrameTarget::wouldPresentEarly(Period minFramePeriod) const {
Dominik Laskowskib418dd72023-06-13 17:31:04 -040062 // TODO(b/241285475): Since this is called during `composite`, the calls to `targetsVsyncsAhead`
63 // should use `TimePoint::now()` in case of delays since `mFrameBeginTime`.
64
65 // TODO(b/267315508): Generalize to N VSYNCs.
ramindani513e6502024-04-10 15:22:19 -070066 const bool allowNVsyncs = FlagManager::getInstance().allow_n_vsyncs_in_targeter();
67 if (!allowNVsyncs && targetsVsyncsAhead<3>(minFramePeriod)) {
Dominik Laskowskib418dd72023-06-13 17:31:04 -040068 return true;
69 }
70
Ady Abraham3db8a3c2023-11-20 17:53:47 -080071 const auto fence = presentFenceForPastVsync(minFramePeriod);
Dominik Laskowskib418dd72023-06-13 17:31:04 -040072 return fence->isValid() && fence->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
73}
74
75void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& vsyncSource) {
76 return beginFrame(args, vsyncSource, &FrameTargeter::isFencePending);
77}
78
79void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& vsyncSource,
80 IsFencePendingFuncPtr isFencePendingFuncPtr) {
81 mVsyncId = args.vsyncId;
82 mFrameBeginTime = args.frameBeginTime;
83
84 // The `expectedVsyncTime`, which was predicted when this frame was scheduled, is normally in
85 // the future relative to `frameBeginTime`, but may not be for delayed frames. Adjust
86 // `mExpectedPresentTime` accordingly, but not `mScheduledPresentTime`.
87 const TimePoint lastScheduledPresentTime = mScheduledPresentTime;
88 mScheduledPresentTime = args.expectedVsyncTime;
89
90 const Period vsyncPeriod = vsyncSource.period();
Ady Abraham3db8a3c2023-11-20 17:53:47 -080091 const Period minFramePeriod = vsyncSource.minFramePeriod();
Dominik Laskowskib418dd72023-06-13 17:31:04 -040092
93 // Calculate the expected present time once and use the cached value throughout this frame to
94 // make sure all layers are seeing this same value.
95 if (args.expectedVsyncTime >= args.frameBeginTime) {
96 mExpectedPresentTime = args.expectedVsyncTime;
97 } else {
98 mExpectedPresentTime = vsyncSource.vsyncDeadlineAfter(args.frameBeginTime);
99 if (args.sfWorkDuration > vsyncPeriod) {
100 // Inflate the expected present time if we're targeting the next VSYNC.
101 mExpectedPresentTime += vsyncPeriod;
102 }
103 }
104
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500105 if (!mSupportsExpectedPresentTime) {
106 mEarliestPresentTime = computeEarliestPresentTime(minFramePeriod, args.hwcMinWorkDuration);
107 }
108
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400109 ATRACE_FORMAT("%s %" PRId64 " vsyncIn %.2fms%s", __func__, ftl::to_underlying(args.vsyncId),
110 ticks<std::milli, float>(mExpectedPresentTime - TimePoint::now()),
111 mExpectedPresentTime == args.expectedVsyncTime ? "" : " (adjusted)");
112
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800113 const FenceTimePtr& pastPresentFence = presentFenceForPastVsync(minFramePeriod);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400114
115 // In cases where the present fence is about to fire, give it a small grace period instead of
116 // giving up on the frame.
117 //
118 // TODO(b/280667110): The grace period should depend on `sfWorkDuration` and `vsyncPeriod` being
119 // approximately equal, not whether backpressure propagation is enabled.
120 const int graceTimeForPresentFenceMs = static_cast<int>(
121 mBackpressureGpuComposition || !mCompositionCoverage.test(CompositionCoverage::Gpu));
122
123 // Pending frames may trigger backpressure propagation.
124 const auto& isFencePending = *isFencePendingFuncPtr;
125 mFramePending = pastPresentFence != FenceTime::NO_FENCE &&
126 isFencePending(pastPresentFence, graceTimeForPresentFenceMs);
127
128 // A frame is missed if the prior frame is still pending. If no longer pending, then we still
129 // count the frame as missed if the predicted present time was further in the past than when the
130 // fence actually fired. Add some slop to correct for drift. This should generally be smaller
131 // than a typical frame duration, but should not be so small that it reports reasonable drift as
132 // a missed frame.
133 mFrameMissed = mFramePending || [&] {
134 const nsecs_t pastPresentTime = pastPresentFence->getSignalTime();
135 if (pastPresentTime < 0) return false;
Ady Abrahamaa7ebd62024-03-26 02:27:57 +0000136 mLastSignaledFrameTime = TimePoint::fromNs(pastPresentTime);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400137 const nsecs_t frameMissedSlop = vsyncPeriod.ns() / 2;
138 return lastScheduledPresentTime.ns() < pastPresentTime - frameMissedSlop;
139 }();
140
141 mHwcFrameMissed = mFrameMissed && mCompositionCoverage.test(CompositionCoverage::Hwc);
142 mGpuFrameMissed = mFrameMissed && mCompositionCoverage.test(CompositionCoverage::Gpu);
143
144 if (mFrameMissed) mFrameMissedCount++;
145 if (mHwcFrameMissed) mHwcFrameMissedCount++;
146 if (mGpuFrameMissed) mGpuFrameMissedCount++;
147}
148
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500149std::optional<TimePoint> FrameTargeter::computeEarliestPresentTime(Period minFramePeriod,
150 Duration hwcMinWorkDuration) {
151 if (wouldPresentEarly(minFramePeriod)) {
152 return previousFrameVsyncTime(minFramePeriod) - hwcMinWorkDuration;
153 }
154 return {};
155}
156
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400157void FrameTargeter::endFrame(const CompositeResult& result) {
158 mCompositionCoverage = result.compositionCoverage;
159}
160
161FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence) {
162 auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
163 return setPresentFence(std::move(presentFence), std::move(presentFenceTime));
164}
165
166FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence, FenceTimePtr presentFenceTime) {
ramindani513e6502024-04-10 15:22:19 -0700167 if (FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
168 addFence(std::move(presentFence), presentFenceTime, mExpectedPresentTime);
169 } else {
Ady Abraham73e9ae32024-08-20 17:54:56 +0000170 for (size_t i = mPreviousPresentFences.size()-1; i >= 1; i--) {
171 mPresentFences[i] = mPresentFences[i-1];
172 }
ramindani513e6502024-04-10 15:22:19 -0700173 mPresentFences[0] = {std::move(presentFence), presentFenceTime, mExpectedPresentTime};
174 }
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400175 return presentFenceTime;
176}
177
178void FrameTargeter::dump(utils::Dumper& dumper) const {
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400179 // There are scripts and tests that expect this (rather than "name=value") format.
180 dumper.dump({}, "Total missed frame count: " + std::to_string(mFrameMissedCount));
181 dumper.dump({}, "HWC missed frame count: " + std::to_string(mHwcFrameMissedCount));
182 dumper.dump({}, "GPU missed frame count: " + std::to_string(mGpuFrameMissedCount));
183}
184
185bool FrameTargeter::isFencePending(const FenceTimePtr& fence, int graceTimeMs) {
186 ATRACE_CALL();
187 const status_t status = fence->wait(graceTimeMs);
188
189 // This is the same as Fence::Status::Unsignaled, but it saves a call to getStatus,
190 // which calls wait(0) again internally.
191 return status == -ETIME;
192}
193
194} // namespace android::scheduler