blob: 3ee1e541c35f632315dcb6eab3d6a1fd5f39a968 [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 {
34 if (!FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
35 const size_t i = static_cast<size_t>(targetsVsyncsAhead<2>(minFramePeriod));
36 return {true, mPresentFencesLegacy[i]};
ramindani513e6502024-04-10 15:22:19 -070037 }
Ady Abrahamed1283a2024-07-24 15:49:16 -070038
39 bool wouldBackpressure = true;
40 auto expectedPresentTime = mExpectedPresentTime;
41 for (size_t i = mPresentFences.size(); i != 0; --i) {
42 const auto& fence = mPresentFences[i - 1];
43
44 if (fence.expectedPresentTime + minFramePeriod < expectedPresentTime - vsyncPeriod / 2) {
45 wouldBackpressure = false;
46 }
47
48 if (fence.expectedPresentTime <= mFrameBeginTime) {
49 return {wouldBackpressure, fence};
50 }
51
52 expectedPresentTime = fence.expectedPresentTime;
53 }
54 return {wouldBackpressure, PresentFence{}};
Dominik Laskowskib418dd72023-06-13 17:31:04 -040055}
56
Ady Abrahamed1283a2024-07-24 15:49:16 -070057bool FrameTarget::wouldPresentEarly(Period vsyncPeriod, Period minFramePeriod) const {
58 if (targetsVsyncsAhead<3>(minFramePeriod)) {
Dominik Laskowskib418dd72023-06-13 17:31:04 -040059 return true;
60 }
61
Ady Abrahamed1283a2024-07-24 15:49:16 -070062 const auto [wouldBackpressure, fence] =
63 expectedSignaledPresentFence(vsyncPeriod, minFramePeriod);
Ady Abraham74fe27e2024-07-26 10:56:54 -070064
65 return !wouldBackpressure ||
66 (fence.fenceTime->isValid() &&
67 fence.fenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING);
Ady Abrahamed1283a2024-07-24 15:49:16 -070068}
69
70const FenceTimePtr& FrameTarget::presentFenceForPreviousFrame() const {
71 if (FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
Ady Abraham3d04ea32024-08-08 23:48:57 -070072 if (mPresentFences.size() > 0) {
73 return mPresentFences.back().fenceTime;
74 }
75 return FenceTime::NO_FENCE;
Ady Abrahamed1283a2024-07-24 15:49:16 -070076 }
77
78 return mPresentFencesLegacy.front().fenceTime;
Dominik Laskowskib418dd72023-06-13 17:31:04 -040079}
80
81void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& vsyncSource) {
82 return beginFrame(args, vsyncSource, &FrameTargeter::isFencePending);
83}
84
85void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& vsyncSource,
86 IsFencePendingFuncPtr isFencePendingFuncPtr) {
87 mVsyncId = args.vsyncId;
88 mFrameBeginTime = args.frameBeginTime;
89
90 // The `expectedVsyncTime`, which was predicted when this frame was scheduled, is normally in
91 // the future relative to `frameBeginTime`, but may not be for delayed frames. Adjust
92 // `mExpectedPresentTime` accordingly, but not `mScheduledPresentTime`.
93 const TimePoint lastScheduledPresentTime = mScheduledPresentTime;
94 mScheduledPresentTime = args.expectedVsyncTime;
95
96 const Period vsyncPeriod = vsyncSource.period();
Ady Abraham3db8a3c2023-11-20 17:53:47 -080097 const Period minFramePeriod = vsyncSource.minFramePeriod();
Dominik Laskowskib418dd72023-06-13 17:31:04 -040098
99 // Calculate the expected present time once and use the cached value throughout this frame to
100 // make sure all layers are seeing this same value.
101 if (args.expectedVsyncTime >= args.frameBeginTime) {
102 mExpectedPresentTime = args.expectedVsyncTime;
103 } else {
104 mExpectedPresentTime = vsyncSource.vsyncDeadlineAfter(args.frameBeginTime);
105 if (args.sfWorkDuration > vsyncPeriod) {
106 // Inflate the expected present time if we're targeting the next VSYNC.
107 mExpectedPresentTime += vsyncPeriod;
108 }
109 }
110
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500111 if (!mSupportsExpectedPresentTime) {
Ady Abrahamed1283a2024-07-24 15:49:16 -0700112 mEarliestPresentTime =
113 computeEarliestPresentTime(vsyncPeriod, minFramePeriod, args.hwcMinWorkDuration);
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500114 }
115
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000116 SFTRACE_FORMAT("%s %" PRId64 " vsyncIn %.2fms%s", __func__, ftl::to_underlying(args.vsyncId),
117 ticks<std::milli, float>(mExpectedPresentTime - TimePoint::now()),
118 mExpectedPresentTime == args.expectedVsyncTime ? "" : " (adjusted)");
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400119
Ady Abrahamed1283a2024-07-24 15:49:16 -0700120 const auto [wouldBackpressure, fence] =
121 expectedSignaledPresentFence(vsyncPeriod, minFramePeriod);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400122
123 // In cases where the present fence is about to fire, give it a small grace period instead of
124 // giving up on the frame.
Ady Abrahamed1283a2024-07-24 15:49:16 -0700125 const int graceTimeForPresentFenceMs = [&] {
126 const bool considerBackpressure =
127 mBackpressureGpuComposition || !mCompositionCoverage.test(CompositionCoverage::Gpu);
128
129 if (!FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
130 return static_cast<int>(considerBackpressure);
131 }
132
133 if (!wouldBackpressure || !considerBackpressure) {
134 return 0;
135 }
136
137 return static_cast<int>((std::abs(fence.expectedPresentTime.ns() - mFrameBeginTime.ns()) <=
138 Duration(1ms).ns()));
139 }();
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400140
141 // Pending frames may trigger backpressure propagation.
142 const auto& isFencePending = *isFencePendingFuncPtr;
Ady Abrahamed1283a2024-07-24 15:49:16 -0700143 mFramePending = fence.fenceTime != FenceTime::NO_FENCE &&
144 isFencePending(fence.fenceTime, graceTimeForPresentFenceMs);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400145
146 // A frame is missed if the prior frame is still pending. If no longer pending, then we still
147 // count the frame as missed if the predicted present time was further in the past than when the
148 // fence actually fired. Add some slop to correct for drift. This should generally be smaller
149 // than a typical frame duration, but should not be so small that it reports reasonable drift as
150 // a missed frame.
151 mFrameMissed = mFramePending || [&] {
Ady Abrahamed1283a2024-07-24 15:49:16 -0700152 const nsecs_t pastPresentTime = fence.fenceTime->getSignalTime();
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400153 if (pastPresentTime < 0) return false;
ramindani7b32b3a2024-07-02 10:17:47 -0700154 mLastSignaledFrameTime = {.signalTime = TimePoint::fromNs(pastPresentTime),
Ady Abrahamed1283a2024-07-24 15:49:16 -0700155 .expectedPresentTime = fence.expectedPresentTime};
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400156 const nsecs_t frameMissedSlop = vsyncPeriod.ns() / 2;
157 return lastScheduledPresentTime.ns() < pastPresentTime - frameMissedSlop;
158 }();
159
160 mHwcFrameMissed = mFrameMissed && mCompositionCoverage.test(CompositionCoverage::Hwc);
161 mGpuFrameMissed = mFrameMissed && mCompositionCoverage.test(CompositionCoverage::Gpu);
162
163 if (mFrameMissed) mFrameMissedCount++;
164 if (mHwcFrameMissed) mHwcFrameMissedCount++;
165 if (mGpuFrameMissed) mGpuFrameMissedCount++;
Ady Abrahamed1283a2024-07-24 15:49:16 -0700166
167 mWouldBackpressureHwc = mFramePending && wouldBackpressure;
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400168}
169
Ady Abrahamed1283a2024-07-24 15:49:16 -0700170std::optional<TimePoint> FrameTargeter::computeEarliestPresentTime(Period vsyncPeriod,
171 Period minFramePeriod,
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500172 Duration hwcMinWorkDuration) {
Ady Abrahamed1283a2024-07-24 15:49:16 -0700173 if (wouldPresentEarly(vsyncPeriod, minFramePeriod)) {
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500174 return previousFrameVsyncTime(minFramePeriod) - hwcMinWorkDuration;
175 }
176 return {};
177}
178
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400179void FrameTargeter::endFrame(const CompositeResult& result) {
180 mCompositionCoverage = result.compositionCoverage;
181}
182
183FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence) {
184 auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
185 return setPresentFence(std::move(presentFence), std::move(presentFenceTime));
186}
187
188FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence, FenceTimePtr presentFenceTime) {
ramindani513e6502024-04-10 15:22:19 -0700189 if (FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
190 addFence(std::move(presentFence), presentFenceTime, mExpectedPresentTime);
191 } else {
Ady Abrahamed1283a2024-07-24 15:49:16 -0700192 mPresentFencesLegacy[1] = mPresentFencesLegacy[0];
193 mPresentFencesLegacy[0] = {std::move(presentFence), presentFenceTime, mExpectedPresentTime};
ramindani513e6502024-04-10 15:22:19 -0700194 }
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400195 return presentFenceTime;
196}
197
198void FrameTargeter::dump(utils::Dumper& dumper) const {
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400199 // There are scripts and tests that expect this (rather than "name=value") format.
200 dumper.dump({}, "Total missed frame count: " + std::to_string(mFrameMissedCount));
201 dumper.dump({}, "HWC missed frame count: " + std::to_string(mHwcFrameMissedCount));
202 dumper.dump({}, "GPU missed frame count: " + std::to_string(mGpuFrameMissedCount));
203}
204
205bool FrameTargeter::isFencePending(const FenceTimePtr& fence, int graceTimeMs) {
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000206 SFTRACE_CALL();
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400207 const status_t status = fence->wait(graceTimeMs);
208
209 // This is the same as Fence::Status::Unsignaled, but it saves a call to getStatus,
210 // which calls wait(0) again internally.
211 return status == -ETIME;
212}
213
214} // namespace android::scheduler