blob: 68c277d4992dc2200d3473a97e1d2820493650fe [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
17#include <gui/TraceUtils.h>
18
19#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
Ady Abraham3db8a3c2023-11-20 17:53:47 -080036const FenceTimePtr& FrameTarget::presentFenceForPastVsync(Period minFramePeriod) const {
Dominik Laskowskib418dd72023-06-13 17:31:04 -040037 // TODO(b/267315508): Generalize to N VSYNCs.
Ady Abraham3db8a3c2023-11-20 17:53:47 -080038 const size_t i = static_cast<size_t>(targetsVsyncsAhead<2>(minFramePeriod));
Dominik Laskowskib418dd72023-06-13 17:31:04 -040039 return mPresentFences[i].fenceTime;
40}
41
Ady Abraham3db8a3c2023-11-20 17:53:47 -080042bool FrameTarget::wouldPresentEarly(Period minFramePeriod) const {
Dominik Laskowskib418dd72023-06-13 17:31:04 -040043 // TODO(b/241285475): Since this is called during `composite`, the calls to `targetsVsyncsAhead`
44 // should use `TimePoint::now()` in case of delays since `mFrameBeginTime`.
45
46 // TODO(b/267315508): Generalize to N VSYNCs.
Ady Abraham3db8a3c2023-11-20 17:53:47 -080047 if (targetsVsyncsAhead<3>(minFramePeriod)) {
Dominik Laskowskib418dd72023-06-13 17:31:04 -040048 return true;
49 }
50
Ady Abraham3db8a3c2023-11-20 17:53:47 -080051 const auto fence = presentFenceForPastVsync(minFramePeriod);
Dominik Laskowskib418dd72023-06-13 17:31:04 -040052 return fence->isValid() && fence->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
53}
54
55void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& vsyncSource) {
56 return beginFrame(args, vsyncSource, &FrameTargeter::isFencePending);
57}
58
59void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& vsyncSource,
60 IsFencePendingFuncPtr isFencePendingFuncPtr) {
61 mVsyncId = args.vsyncId;
62 mFrameBeginTime = args.frameBeginTime;
63
64 // The `expectedVsyncTime`, which was predicted when this frame was scheduled, is normally in
65 // the future relative to `frameBeginTime`, but may not be for delayed frames. Adjust
66 // `mExpectedPresentTime` accordingly, but not `mScheduledPresentTime`.
67 const TimePoint lastScheduledPresentTime = mScheduledPresentTime;
68 mScheduledPresentTime = args.expectedVsyncTime;
69
70 const Period vsyncPeriod = vsyncSource.period();
Ady Abraham3db8a3c2023-11-20 17:53:47 -080071 const Period minFramePeriod = vsyncSource.minFramePeriod();
Dominik Laskowskib418dd72023-06-13 17:31:04 -040072
73 // Calculate the expected present time once and use the cached value throughout this frame to
74 // make sure all layers are seeing this same value.
75 if (args.expectedVsyncTime >= args.frameBeginTime) {
76 mExpectedPresentTime = args.expectedVsyncTime;
77 } else {
78 mExpectedPresentTime = vsyncSource.vsyncDeadlineAfter(args.frameBeginTime);
79 if (args.sfWorkDuration > vsyncPeriod) {
80 // Inflate the expected present time if we're targeting the next VSYNC.
81 mExpectedPresentTime += vsyncPeriod;
82 }
83 }
84
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -050085 if (!mSupportsExpectedPresentTime) {
86 mEarliestPresentTime = computeEarliestPresentTime(minFramePeriod, args.hwcMinWorkDuration);
87 }
88
Dominik Laskowskib418dd72023-06-13 17:31:04 -040089 ATRACE_FORMAT("%s %" PRId64 " vsyncIn %.2fms%s", __func__, ftl::to_underlying(args.vsyncId),
90 ticks<std::milli, float>(mExpectedPresentTime - TimePoint::now()),
91 mExpectedPresentTime == args.expectedVsyncTime ? "" : " (adjusted)");
92
Ady Abraham3db8a3c2023-11-20 17:53:47 -080093 const FenceTimePtr& pastPresentFence = presentFenceForPastVsync(minFramePeriod);
Dominik Laskowskib418dd72023-06-13 17:31:04 -040094
95 // In cases where the present fence is about to fire, give it a small grace period instead of
96 // giving up on the frame.
97 //
98 // TODO(b/280667110): The grace period should depend on `sfWorkDuration` and `vsyncPeriod` being
99 // approximately equal, not whether backpressure propagation is enabled.
100 const int graceTimeForPresentFenceMs = static_cast<int>(
101 mBackpressureGpuComposition || !mCompositionCoverage.test(CompositionCoverage::Gpu));
102
103 // Pending frames may trigger backpressure propagation.
104 const auto& isFencePending = *isFencePendingFuncPtr;
105 mFramePending = pastPresentFence != FenceTime::NO_FENCE &&
106 isFencePending(pastPresentFence, graceTimeForPresentFenceMs);
107
108 // A frame is missed if the prior frame is still pending. If no longer pending, then we still
109 // count the frame as missed if the predicted present time was further in the past than when the
110 // fence actually fired. Add some slop to correct for drift. This should generally be smaller
111 // than a typical frame duration, but should not be so small that it reports reasonable drift as
112 // a missed frame.
113 mFrameMissed = mFramePending || [&] {
114 const nsecs_t pastPresentTime = pastPresentFence->getSignalTime();
115 if (pastPresentTime < 0) return false;
116 const nsecs_t frameMissedSlop = vsyncPeriod.ns() / 2;
117 return lastScheduledPresentTime.ns() < pastPresentTime - frameMissedSlop;
118 }();
119
120 mHwcFrameMissed = mFrameMissed && mCompositionCoverage.test(CompositionCoverage::Hwc);
121 mGpuFrameMissed = mFrameMissed && mCompositionCoverage.test(CompositionCoverage::Gpu);
122
123 if (mFrameMissed) mFrameMissedCount++;
124 if (mHwcFrameMissed) mHwcFrameMissedCount++;
125 if (mGpuFrameMissed) mGpuFrameMissedCount++;
126}
127
Leon Scroggins III0bd0d4c2022-12-08 13:20:45 -0500128std::optional<TimePoint> FrameTargeter::computeEarliestPresentTime(Period minFramePeriod,
129 Duration hwcMinWorkDuration) {
130 if (wouldPresentEarly(minFramePeriod)) {
131 return previousFrameVsyncTime(minFramePeriod) - hwcMinWorkDuration;
132 }
133 return {};
134}
135
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400136void FrameTargeter::endFrame(const CompositeResult& result) {
137 mCompositionCoverage = result.compositionCoverage;
138}
139
140FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence) {
141 auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
142 return setPresentFence(std::move(presentFence), std::move(presentFenceTime));
143}
144
145FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence, FenceTimePtr presentFenceTime) {
146 mPresentFences[1] = mPresentFences[0];
147 mPresentFences[0] = {std::move(presentFence), presentFenceTime};
148 return presentFenceTime;
149}
150
151void FrameTargeter::dump(utils::Dumper& dumper) const {
Dominik Laskowskib418dd72023-06-13 17:31:04 -0400152 // There are scripts and tests that expect this (rather than "name=value") format.
153 dumper.dump({}, "Total missed frame count: " + std::to_string(mFrameMissedCount));
154 dumper.dump({}, "HWC missed frame count: " + std::to_string(mHwcFrameMissedCount));
155 dumper.dump({}, "GPU missed frame count: " + std::to_string(mGpuFrameMissedCount));
156}
157
158bool FrameTargeter::isFencePending(const FenceTimePtr& fence, int graceTimeMs) {
159 ATRACE_CALL();
160 const status_t status = fence->wait(graceTimeMs);
161
162 // This is the same as Fence::Status::Unsignaled, but it saves a call to getStatus,
163 // which calls wait(0) again internally.
164 return status == -ETIME;
165}
166
167} // namespace android::scheduler