blob: 60694b96a4da19be8178eb195869a56d1da15e2f [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
ramindani513e6502024-04-10 15:22:19 -070036FenceTimePtr FrameTarget::presentFenceForPastVsync(Period minFramePeriod) const {
37 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));
Dominik Laskowskib418dd72023-06-13 17:31:04 -040041 return mPresentFences[i].fenceTime;
42}
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
Ady Abraham3db8a3c2023-11-20 17:53:47 -080054 const auto fence = presentFenceForPastVsync(minFramePeriod);
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
Ady Abraham3db8a3c2023-11-20 17:53:47 -080096 const FenceTimePtr& 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;
108 mFramePending = pastPresentFence != FenceTime::NO_FENCE &&
109 isFencePending(pastPresentFence, graceTimeForPresentFenceMs);
110
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 || [&] {
117 const nsecs_t pastPresentTime = pastPresentFence->getSignalTime();
118 if (pastPresentTime < 0) return false;
Ady Abrahamaa7ebd62024-03-26 02:27:57 +0000119 mLastSignaledFrameTime = TimePoint::fromNs(pastPresentTime);
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400120 const nsecs_t frameMissedSlop = vsyncPeriod.ns() / 2;
121 return lastScheduledPresentTime.ns() < pastPresentTime - frameMissedSlop;
122 }();
123
124 mHwcFrameMissed = mFrameMissed && mCompositionCoverage.test(CompositionCoverage::Hwc);
125 mGpuFrameMissed = mFrameMissed && mCompositionCoverage.test(CompositionCoverage::Gpu);
126
127 if (mFrameMissed) mFrameMissedCount++;
128 if (mHwcFrameMissed) mHwcFrameMissedCount++;
129 if (mGpuFrameMissed) mGpuFrameMissedCount++;
130}
131
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500132std::optional<TimePoint> FrameTargeter::computeEarliestPresentTime(Period minFramePeriod,
133 Duration hwcMinWorkDuration) {
134 if (wouldPresentEarly(minFramePeriod)) {
135 return previousFrameVsyncTime(minFramePeriod) - hwcMinWorkDuration;
136 }
137 return {};
138}
139
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400140void FrameTargeter::endFrame(const CompositeResult& result) {
141 mCompositionCoverage = result.compositionCoverage;
142}
143
144FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence) {
145 auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
146 return setPresentFence(std::move(presentFence), std::move(presentFenceTime));
147}
148
149FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence, FenceTimePtr presentFenceTime) {
ramindani513e6502024-04-10 15:22:19 -0700150 if (FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
151 addFence(std::move(presentFence), presentFenceTime, mExpectedPresentTime);
152 } else {
153 mPresentFences[1] = mPresentFences[0];
154 mPresentFences[0] = {std::move(presentFence), presentFenceTime, mExpectedPresentTime};
155 }
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400156 return presentFenceTime;
157}
158
159void FrameTargeter::dump(utils::Dumper& dumper) const {
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400160 // There are scripts and tests that expect this (rather than "name=value") format.
161 dumper.dump({}, "Total missed frame count: " + std::to_string(mFrameMissedCount));
162 dumper.dump({}, "HWC missed frame count: " + std::to_string(mHwcFrameMissedCount));
163 dumper.dump({}, "GPU missed frame count: " + std::to_string(mGpuFrameMissedCount));
164}
165
166bool FrameTargeter::isFencePending(const FenceTimePtr& fence, int graceTimeMs) {
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000167 SFTRACE_CALL();
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400168 const status_t status = fence->wait(graceTimeMs);
169
170 // This is the same as Fence::Status::Unsignaled, but it saves a call to getStatus,
171 // which calls wait(0) again internally.
172 return status == -ETIME;
173}
174
175} // namespace android::scheduler