blob: 4f16130aa571d11d7d91fe155b5a949702434d5f [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;
Ady Abraham708ebfb2024-11-14 14:42:49 -080089 mDebugPresentTimeDelay = args.debugPresentTimeDelay;
Dominik Laskowskib418dd72023-06-13 17:31:04 -040090
91 // The `expectedVsyncTime`, which was predicted when this frame was scheduled, is normally in
92 // the future relative to `frameBeginTime`, but may not be for delayed frames. Adjust
93 // `mExpectedPresentTime` accordingly, but not `mScheduledPresentTime`.
94 const TimePoint lastScheduledPresentTime = mScheduledPresentTime;
95 mScheduledPresentTime = args.expectedVsyncTime;
96
97 const Period vsyncPeriod = vsyncSource.period();
Ady Abraham3db8a3c2023-11-20 17:53:47 -080098 const Period minFramePeriod = vsyncSource.minFramePeriod();
Dominik Laskowskib418dd72023-06-13 17:31:04 -040099
100 // Calculate the expected present time once and use the cached value throughout this frame to
101 // make sure all layers are seeing this same value.
102 if (args.expectedVsyncTime >= args.frameBeginTime) {
103 mExpectedPresentTime = args.expectedVsyncTime;
104 } else {
105 mExpectedPresentTime = vsyncSource.vsyncDeadlineAfter(args.frameBeginTime);
106 if (args.sfWorkDuration > vsyncPeriod) {
107 // Inflate the expected present time if we're targeting the next VSYNC.
108 mExpectedPresentTime += vsyncPeriod;
109 }
110 }
111
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500112 if (!mSupportsExpectedPresentTime) {
Ady Abrahamed1283a2024-07-24 15:49:16 -0700113 mEarliestPresentTime =
114 computeEarliestPresentTime(vsyncPeriod, minFramePeriod, args.hwcMinWorkDuration);
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500115 }
116
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000117 SFTRACE_FORMAT("%s %" PRId64 " vsyncIn %.2fms%s", __func__, ftl::to_underlying(args.vsyncId),
118 ticks<std::milli, float>(mExpectedPresentTime - TimePoint::now()),
119 mExpectedPresentTime == args.expectedVsyncTime ? "" : " (adjusted)");
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400120
Ady Abrahamed1283a2024-07-24 15:49:16 -0700121 const auto [wouldBackpressure, fence] =
122 expectedSignaledPresentFence(vsyncPeriod, minFramePeriod);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400123
124 // In cases where the present fence is about to fire, give it a small grace period instead of
125 // giving up on the frame.
Ady Abrahamed1283a2024-07-24 15:49:16 -0700126 const int graceTimeForPresentFenceMs = [&] {
127 const bool considerBackpressure =
128 mBackpressureGpuComposition || !mCompositionCoverage.test(CompositionCoverage::Gpu);
129
130 if (!FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
131 return static_cast<int>(considerBackpressure);
132 }
133
134 if (!wouldBackpressure || !considerBackpressure) {
135 return 0;
136 }
137
138 return static_cast<int>((std::abs(fence.expectedPresentTime.ns() - mFrameBeginTime.ns()) <=
139 Duration(1ms).ns()));
140 }();
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400141
142 // Pending frames may trigger backpressure propagation.
143 const auto& isFencePending = *isFencePendingFuncPtr;
Ady Abrahamed1283a2024-07-24 15:49:16 -0700144 mFramePending = fence.fenceTime != FenceTime::NO_FENCE &&
145 isFencePending(fence.fenceTime, graceTimeForPresentFenceMs);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400146
147 // A frame is missed if the prior frame is still pending. If no longer pending, then we still
148 // count the frame as missed if the predicted present time was further in the past than when the
149 // fence actually fired. Add some slop to correct for drift. This should generally be smaller
150 // than a typical frame duration, but should not be so small that it reports reasonable drift as
151 // a missed frame.
152 mFrameMissed = mFramePending || [&] {
Ady Abrahamed1283a2024-07-24 15:49:16 -0700153 const nsecs_t pastPresentTime = fence.fenceTime->getSignalTime();
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400154 if (pastPresentTime < 0) return false;
ramindani7b32b3a2024-07-02 10:17:47 -0700155 mLastSignaledFrameTime = {.signalTime = TimePoint::fromNs(pastPresentTime),
Ady Abrahamed1283a2024-07-24 15:49:16 -0700156 .expectedPresentTime = fence.expectedPresentTime};
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400157 const nsecs_t frameMissedSlop = vsyncPeriod.ns() / 2;
158 return lastScheduledPresentTime.ns() < pastPresentTime - frameMissedSlop;
159 }();
160
161 mHwcFrameMissed = mFrameMissed && mCompositionCoverage.test(CompositionCoverage::Hwc);
162 mGpuFrameMissed = mFrameMissed && mCompositionCoverage.test(CompositionCoverage::Gpu);
163
164 if (mFrameMissed) mFrameMissedCount++;
165 if (mHwcFrameMissed) mHwcFrameMissedCount++;
166 if (mGpuFrameMissed) mGpuFrameMissedCount++;
Ady Abrahamed1283a2024-07-24 15:49:16 -0700167
168 mWouldBackpressureHwc = mFramePending && wouldBackpressure;
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400169}
170
Ady Abrahamed1283a2024-07-24 15:49:16 -0700171std::optional<TimePoint> FrameTargeter::computeEarliestPresentTime(Period vsyncPeriod,
172 Period minFramePeriod,
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500173 Duration hwcMinWorkDuration) {
Ady Abrahamed1283a2024-07-24 15:49:16 -0700174 if (wouldPresentEarly(vsyncPeriod, minFramePeriod)) {
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500175 return previousFrameVsyncTime(minFramePeriod) - hwcMinWorkDuration;
176 }
177 return {};
178}
179
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400180void FrameTargeter::endFrame(const CompositeResult& result) {
181 mCompositionCoverage = result.compositionCoverage;
182}
183
184FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence) {
185 auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
186 return setPresentFence(std::move(presentFence), std::move(presentFenceTime));
187}
188
189FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence, FenceTimePtr presentFenceTime) {
ramindani513e6502024-04-10 15:22:19 -0700190 if (FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
191 addFence(std::move(presentFence), presentFenceTime, mExpectedPresentTime);
192 } else {
Ady Abrahamed1283a2024-07-24 15:49:16 -0700193 mPresentFencesLegacy[1] = mPresentFencesLegacy[0];
194 mPresentFencesLegacy[0] = {std::move(presentFence), presentFenceTime, mExpectedPresentTime};
ramindani513e6502024-04-10 15:22:19 -0700195 }
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400196 return presentFenceTime;
197}
198
199void FrameTargeter::dump(utils::Dumper& dumper) const {
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400200 // There are scripts and tests that expect this (rather than "name=value") format.
201 dumper.dump({}, "Total missed frame count: " + std::to_string(mFrameMissedCount));
202 dumper.dump({}, "HWC missed frame count: " + std::to_string(mHwcFrameMissedCount));
203 dumper.dump({}, "GPU missed frame count: " + std::to_string(mGpuFrameMissedCount));
204}
205
206bool FrameTargeter::isFencePending(const FenceTimePtr& fence, int graceTimeMs) {
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000207 SFTRACE_CALL();
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400208 const status_t status = fence->wait(graceTimeMs);
209
210 // This is the same as Fence::Status::Unsignaled, but it saves a call to getStatus,
211 // which calls wait(0) again internally.
212 return status == -ETIME;
213}
214
215} // namespace android::scheduler