blob: 1d248fbbe27a680118e987986c6d441740454df7 [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>
21
22namespace android::scheduler {
23
Dominik Laskowskiec0eac22023-01-28 16:16:19 -050024FrameTarget::FrameTarget(const std::string& displayLabel)
25 : mFramePending("PrevFramePending " + displayLabel, false),
26 mFrameMissed("PrevFrameMissed " + displayLabel, false),
27 mHwcFrameMissed("PrevHwcFrameMissed " + displayLabel, false),
28 mGpuFrameMissed("PrevGpuFrameMissed " + displayLabel, false) {}
29
Ady Abraham3db8a3c2023-11-20 17:53:47 -080030TimePoint FrameTarget::pastVsyncTime(Period minFramePeriod) const {
Dominik Laskowskib418dd72023-06-13 17:31:04 -040031 // TODO(b/267315508): Generalize to N VSYNCs.
Ady Abraham3db8a3c2023-11-20 17:53:47 -080032 const int shift = static_cast<int>(targetsVsyncsAhead<2>(minFramePeriod));
33 return mExpectedPresentTime - Period::fromNs(minFramePeriod.ns() << shift);
Dominik Laskowskib418dd72023-06-13 17:31:04 -040034}
35
ramindani7b32b3a2024-07-02 10:17:47 -070036FrameTarget::FenceWithFenceTime FrameTarget::presentFenceForPastVsync(Period minFramePeriod) const {
ramindani513e6502024-04-10 15:22:19 -070037 if (FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
38 return pastVsyncTimePtr();
39 }
Ady Abraham3db8a3c2023-11-20 17:53:47 -080040 const size_t i = static_cast<size_t>(targetsVsyncsAhead<2>(minFramePeriod));
ramindani7b32b3a2024-07-02 10:17:47 -070041 return mPresentFences[i];
Dominik Laskowskib418dd72023-06-13 17:31:04 -040042}
43
Ady Abraham3db8a3c2023-11-20 17:53:47 -080044bool FrameTarget::wouldPresentEarly(Period minFramePeriod) const {
Dominik Laskowskib418dd72023-06-13 17:31:04 -040045 // TODO(b/241285475): Since this is called during `composite`, the calls to `targetsVsyncsAhead`
46 // should use `TimePoint::now()` in case of delays since `mFrameBeginTime`.
47
48 // TODO(b/267315508): Generalize to N VSYNCs.
ramindani513e6502024-04-10 15:22:19 -070049 const bool allowNVsyncs = FlagManager::getInstance().allow_n_vsyncs_in_targeter();
50 if (!allowNVsyncs && targetsVsyncsAhead<3>(minFramePeriod)) {
Dominik Laskowskib418dd72023-06-13 17:31:04 -040051 return true;
52 }
53
ramindani7b32b3a2024-07-02 10:17:47 -070054 const auto fence = presentFenceForPastVsync(minFramePeriod).fenceTime;
Dominik Laskowskib418dd72023-06-13 17:31:04 -040055 return fence->isValid() && fence->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
56}
57
58void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& vsyncSource) {
59 return beginFrame(args, vsyncSource, &FrameTargeter::isFencePending);
60}
61
62void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& vsyncSource,
63 IsFencePendingFuncPtr isFencePendingFuncPtr) {
64 mVsyncId = args.vsyncId;
65 mFrameBeginTime = args.frameBeginTime;
66
67 // The `expectedVsyncTime`, which was predicted when this frame was scheduled, is normally in
68 // the future relative to `frameBeginTime`, but may not be for delayed frames. Adjust
69 // `mExpectedPresentTime` accordingly, but not `mScheduledPresentTime`.
70 const TimePoint lastScheduledPresentTime = mScheduledPresentTime;
71 mScheduledPresentTime = args.expectedVsyncTime;
72
73 const Period vsyncPeriod = vsyncSource.period();
Ady Abraham3db8a3c2023-11-20 17:53:47 -080074 const Period minFramePeriod = vsyncSource.minFramePeriod();
Dominik Laskowskib418dd72023-06-13 17:31:04 -040075
76 // Calculate the expected present time once and use the cached value throughout this frame to
77 // make sure all layers are seeing this same value.
78 if (args.expectedVsyncTime >= args.frameBeginTime) {
79 mExpectedPresentTime = args.expectedVsyncTime;
80 } else {
81 mExpectedPresentTime = vsyncSource.vsyncDeadlineAfter(args.frameBeginTime);
82 if (args.sfWorkDuration > vsyncPeriod) {
83 // Inflate the expected present time if we're targeting the next VSYNC.
84 mExpectedPresentTime += vsyncPeriod;
85 }
86 }
87
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -050088 if (!mSupportsExpectedPresentTime) {
89 mEarliestPresentTime = computeEarliestPresentTime(minFramePeriod, args.hwcMinWorkDuration);
90 }
91
Vishnu Nairbe0ad902024-06-27 23:38:43 +000092 SFTRACE_FORMAT("%s %" PRId64 " vsyncIn %.2fms%s", __func__, ftl::to_underlying(args.vsyncId),
93 ticks<std::milli, float>(mExpectedPresentTime - TimePoint::now()),
94 mExpectedPresentTime == args.expectedVsyncTime ? "" : " (adjusted)");
Dominik Laskowskib418dd72023-06-13 17:31:04 -040095
ramindani7b32b3a2024-07-02 10:17:47 -070096 FenceWithFenceTime pastPresentFence = presentFenceForPastVsync(minFramePeriod);
Dominik Laskowskib418dd72023-06-13 17:31:04 -040097
98 // In cases where the present fence is about to fire, give it a small grace period instead of
99 // giving up on the frame.
100 //
101 // TODO(b/280667110): The grace period should depend on `sfWorkDuration` and `vsyncPeriod` being
102 // approximately equal, not whether backpressure propagation is enabled.
103 const int graceTimeForPresentFenceMs = static_cast<int>(
104 mBackpressureGpuComposition || !mCompositionCoverage.test(CompositionCoverage::Gpu));
105
106 // Pending frames may trigger backpressure propagation.
107 const auto& isFencePending = *isFencePendingFuncPtr;
ramindani7b32b3a2024-07-02 10:17:47 -0700108 mFramePending = pastPresentFence.fenceTime != FenceTime::NO_FENCE &&
109 isFencePending(pastPresentFence.fenceTime, graceTimeForPresentFenceMs);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400110
111 // A frame is missed if the prior frame is still pending. If no longer pending, then we still
112 // count the frame as missed if the predicted present time was further in the past than when the
113 // fence actually fired. Add some slop to correct for drift. This should generally be smaller
114 // than a typical frame duration, but should not be so small that it reports reasonable drift as
115 // a missed frame.
116 mFrameMissed = mFramePending || [&] {
ramindani7b32b3a2024-07-02 10:17:47 -0700117 const nsecs_t pastPresentTime = pastPresentFence.fenceTime->getSignalTime();
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400118 if (pastPresentTime < 0) return false;
ramindani7b32b3a2024-07-02 10:17:47 -0700119 mLastSignaledFrameTime = {.signalTime = TimePoint::fromNs(pastPresentTime),
120 .expectedPresentTime = pastPresentFence.expectedPresentTime};
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) {
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000168 SFTRACE_CALL();
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400169 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