blob: 50199492cb8dd52e9adf4d507e70483fb491689b [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
ramindani513e6502024-04-10 15:22:19 -070017#include <common/FlagManager.h>
Vishnu Nairbe0ad902024-06-27 23:38:43 +000018#include <common/trace.h>
Dominik Laskowskib418dd72023-06-13 17:31:04 -040019#include <scheduler/FrameTargeter.h>
20#include <scheduler/IVsyncSource.h>
Ady Abrahamed1283a2024-07-24 15:49:16 -070021#include <utils/Log.h>
Dominik Laskowskib418dd72023-06-13 17:31:04 -040022
23namespace android::scheduler {
Ady Abrahamed1283a2024-07-24 15:49:16 -070024using namespace std::chrono_literals;
Dominik Laskowskib418dd72023-06-13 17:31:04 -040025
Dominik Laskowskiec0eac22023-01-28 16:16:19 -050026FrameTarget::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
Ady Abrahamed1283a2024-07-24 15:49:16 -070032std::pair<bool /* wouldBackpressure */, FrameTarget::PresentFence>
33FrameTarget::expectedSignaledPresentFence(Period vsyncPeriod, Period minFramePeriod) const {
Ady Abraham7abbc352024-11-19 16:19:28 -080034 SFTRACE_CALL();
Ady Abrahamed1283a2024-07-24 15:49:16 -070035 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]};
ramindani513e6502024-04-10 15:22:19 -070038 }
Ady Abrahamed1283a2024-07-24 15:49:16 -070039
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];
Ady Abraham7abbc352024-11-19 16:19:28 -080044 SFTRACE_FORMAT_INSTANT("fence at idx: %zu expectedPresentTime in %.2f", i - 1,
45 ticks<std::milli, float>(fence.expectedPresentTime -
46 TimePoint::now()));
Ady Abrahamed1283a2024-07-24 15:49:16 -070047
48 if (fence.expectedPresentTime + minFramePeriod < expectedPresentTime - vsyncPeriod / 2) {
Ady Abraham7abbc352024-11-19 16:19:28 -080049 SFTRACE_FORMAT_INSTANT("would not backpressure");
Ady Abrahamed1283a2024-07-24 15:49:16 -070050 wouldBackpressure = false;
51 }
52
53 if (fence.expectedPresentTime <= mFrameBeginTime) {
Ady Abraham7abbc352024-11-19 16:19:28 -080054 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");
Ady Abrahamed1283a2024-07-24 15:49:16 -070060 return {wouldBackpressure, fence};
61 }
62
63 expectedPresentTime = fence.expectedPresentTime;
64 }
Ady Abraham7abbc352024-11-19 16:19:28 -080065 SFTRACE_FORMAT_INSTANT("No fence found");
Ady Abrahamed1283a2024-07-24 15:49:16 -070066 return {wouldBackpressure, PresentFence{}};
Dominik Laskowskib418dd72023-06-13 17:31:04 -040067}
68
Ady Abrahamed1283a2024-07-24 15:49:16 -070069bool FrameTarget::wouldPresentEarly(Period vsyncPeriod, Period minFramePeriod) const {
70 if (targetsVsyncsAhead<3>(minFramePeriod)) {
Dominik Laskowskib418dd72023-06-13 17:31:04 -040071 return true;
72 }
73
Ady Abrahamed1283a2024-07-24 15:49:16 -070074 const auto [wouldBackpressure, fence] =
75 expectedSignaledPresentFence(vsyncPeriod, minFramePeriod);
Ady Abraham74fe27e2024-07-26 10:56:54 -070076
77 return !wouldBackpressure ||
78 (fence.fenceTime->isValid() &&
79 fence.fenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING);
Ady Abrahamed1283a2024-07-24 15:49:16 -070080}
81
82const FenceTimePtr& FrameTarget::presentFenceForPreviousFrame() const {
83 if (FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
Ady Abraham3d04ea32024-08-08 23:48:57 -070084 if (mPresentFences.size() > 0) {
85 return mPresentFences.back().fenceTime;
86 }
87 return FenceTime::NO_FENCE;
Ady Abrahamed1283a2024-07-24 15:49:16 -070088 }
89
90 return mPresentFencesLegacy.front().fenceTime;
Dominik Laskowskib418dd72023-06-13 17:31:04 -040091}
92
93void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& vsyncSource) {
94 return beginFrame(args, vsyncSource, &FrameTargeter::isFencePending);
95}
96
97void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& vsyncSource,
98 IsFencePendingFuncPtr isFencePendingFuncPtr) {
99 mVsyncId = args.vsyncId;
100 mFrameBeginTime = args.frameBeginTime;
Ady Abraham708ebfb2024-11-14 14:42:49 -0800101 mDebugPresentTimeDelay = args.debugPresentTimeDelay;
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400102
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();
Ady Abraham3db8a3c2023-11-20 17:53:47 -0800110 const Period minFramePeriod = vsyncSource.minFramePeriod();
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400111
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
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500124 if (!mSupportsExpectedPresentTime) {
Ady Abrahamed1283a2024-07-24 15:49:16 -0700125 mEarliestPresentTime =
126 computeEarliestPresentTime(vsyncPeriod, minFramePeriod, args.hwcMinWorkDuration);
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500127 }
128
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000129 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)");
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400132
Ady Abrahamed1283a2024-07-24 15:49:16 -0700133 const auto [wouldBackpressure, fence] =
134 expectedSignaledPresentFence(vsyncPeriod, minFramePeriod);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400135
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.
Ady Abrahamed1283a2024-07-24 15:49:16 -0700138 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 }();
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400153
154 // Pending frames may trigger backpressure propagation.
155 const auto& isFencePending = *isFencePendingFuncPtr;
Ady Abrahamed1283a2024-07-24 15:49:16 -0700156 mFramePending = fence.fenceTime != FenceTime::NO_FENCE &&
157 isFencePending(fence.fenceTime, graceTimeForPresentFenceMs);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400158
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 || [&] {
Ady Abrahamed1283a2024-07-24 15:49:16 -0700165 const nsecs_t pastPresentTime = fence.fenceTime->getSignalTime();
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400166 if (pastPresentTime < 0) return false;
ramindani7b32b3a2024-07-02 10:17:47 -0700167 mLastSignaledFrameTime = {.signalTime = TimePoint::fromNs(pastPresentTime),
Ady Abrahamed1283a2024-07-24 15:49:16 -0700168 .expectedPresentTime = fence.expectedPresentTime};
Ady Abraham7abbc352024-11-19 16:19:28 -0800169 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()));
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400175 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++;
Ady Abrahamed1283a2024-07-24 15:49:16 -0700185
186 mWouldBackpressureHwc = mFramePending && wouldBackpressure;
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400187}
188
Ady Abrahamed1283a2024-07-24 15:49:16 -0700189std::optional<TimePoint> FrameTargeter::computeEarliestPresentTime(Period vsyncPeriod,
190 Period minFramePeriod,
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500191 Duration hwcMinWorkDuration) {
Ady Abrahamed1283a2024-07-24 15:49:16 -0700192 if (wouldPresentEarly(vsyncPeriod, minFramePeriod)) {
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500193 return previousFrameVsyncTime(minFramePeriod) - hwcMinWorkDuration;
194 }
195 return {};
196}
197
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400198void FrameTargeter::endFrame(const CompositeResult& result) {
199 mCompositionCoverage = result.compositionCoverage;
200}
201
202FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence) {
203 auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
204 return setPresentFence(std::move(presentFence), std::move(presentFenceTime));
205}
206
207FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence, FenceTimePtr presentFenceTime) {
ramindani513e6502024-04-10 15:22:19 -0700208 if (FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
209 addFence(std::move(presentFence), presentFenceTime, mExpectedPresentTime);
210 } else {
Ady Abrahamed1283a2024-07-24 15:49:16 -0700211 mPresentFencesLegacy[1] = mPresentFencesLegacy[0];
212 mPresentFencesLegacy[0] = {std::move(presentFence), presentFenceTime, mExpectedPresentTime};
ramindani513e6502024-04-10 15:22:19 -0700213 }
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400214 return presentFenceTime;
215}
216
217void FrameTargeter::dump(utils::Dumper& dumper) const {
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400218 // 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
224bool FrameTargeter::isFencePending(const FenceTimePtr& fence, int graceTimeMs) {
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000225 SFTRACE_CALL();
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400226 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