blob: cf4c0a0d7f17c5f144040005d9c9203826e27108 [file] [log] [blame]
Dominik Laskowskic183eed2023-01-21 10:02:15 -05001/*
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
24TimePoint FrameTarget::pastVsyncTime(Period vsyncPeriod) const {
25 // TODO(b/267315508): Generalize to N VSYNCs.
26 const int shift = static_cast<int>(targetsVsyncsAhead<2>(vsyncPeriod));
27 return mExpectedPresentTime - Period::fromNs(vsyncPeriod.ns() << shift);
28}
29
30const FenceTimePtr& FrameTarget::presentFenceForPastVsync(Period vsyncPeriod) const {
31 // TODO(b/267315508): Generalize to N VSYNCs.
32 const size_t i = static_cast<size_t>(targetsVsyncsAhead<2>(vsyncPeriod));
33 return mPresentFences[i].fenceTime;
34}
35
36bool FrameTarget::wouldPresentEarly(Period vsyncPeriod) const {
37 // TODO(b/267315508): Generalize to N VSYNCs.
38 if (targetsVsyncsAhead<3>(vsyncPeriod)) {
39 return true;
40 }
41
42 const auto fence = presentFenceForPastVsync(vsyncPeriod);
43 return fence->isValid() && fence->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
44}
45
46void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& vsyncSource) {
47 return beginFrame(args, vsyncSource, &FrameTargeter::isFencePending);
48}
49
50void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& vsyncSource,
51 IsFencePendingFuncPtr isFencePendingFuncPtr) {
52 mVsyncId = args.vsyncId;
53 mFrameBeginTime = args.frameBeginTime;
54
55 // The `expectedVsyncTime`, which was predicted when this frame was scheduled, is normally in
56 // the future relative to `frameBeginTime`, but may not be for delayed frames. Adjust
57 // `mExpectedPresentTime` accordingly, but not `mScheduledPresentTime`.
58 const TimePoint lastScheduledPresentTime = mScheduledPresentTime;
59 mScheduledPresentTime = args.expectedVsyncTime;
60
61 const Period vsyncPeriod = vsyncSource.period();
62
63 // Calculate the expected present time once and use the cached value throughout this frame to
64 // make sure all layers are seeing this same value.
65 if (args.expectedVsyncTime >= args.frameBeginTime) {
66 mExpectedPresentTime = args.expectedVsyncTime;
67 } else {
68 mExpectedPresentTime = vsyncSource.vsyncDeadlineAfter(args.frameBeginTime);
69 if (args.sfWorkDuration > vsyncPeriod) {
70 // Inflate the expected present time if we're targeting the next VSYNC.
71 mExpectedPresentTime += vsyncPeriod;
72 }
73 }
74
75 ATRACE_FORMAT("%s %" PRId64 " vsyncIn %.2fms%s", __func__, ftl::to_underlying(args.vsyncId),
76 ticks<std::milli, float>(mExpectedPresentTime - TimePoint::now()),
77 mExpectedPresentTime == args.expectedVsyncTime ? "" : " (adjusted)");
78
79 const FenceTimePtr& pastPresentFence = presentFenceForPastVsync(vsyncPeriod);
80
81 // In cases where the present fence is about to fire, give it a small grace period instead of
82 // giving up on the frame.
83 //
84 // TODO(b/280667110): The grace period should depend on `sfWorkDuration` and `vsyncPeriod` being
85 // approximately equal, not whether backpressure propagation is enabled.
86 const int graceTimeForPresentFenceMs = static_cast<int>(
87 mBackpressureGpuComposition || !mCompositionCoverage.test(CompositionCoverage::Gpu));
88
89 // Pending frames may trigger backpressure propagation.
90 const auto& isFencePending = *isFencePendingFuncPtr;
91 mFramePending = pastPresentFence != FenceTime::NO_FENCE &&
92 isFencePending(pastPresentFence, graceTimeForPresentFenceMs);
93
94 // A frame is missed if the prior frame is still pending. If no longer pending, then we still
95 // count the frame as missed if the predicted present time was further in the past than when the
96 // fence actually fired. Add some slop to correct for drift. This should generally be smaller
97 // than a typical frame duration, but should not be so small that it reports reasonable drift as
98 // a missed frame.
99 mFrameMissed = mFramePending || [&] {
100 const nsecs_t pastPresentTime = pastPresentFence->getSignalTime();
101 if (pastPresentTime < 0) return false;
102 const nsecs_t frameMissedSlop = vsyncPeriod.ns() / 2;
103 return lastScheduledPresentTime.ns() < pastPresentTime - frameMissedSlop;
104 }();
105
106 mHwcFrameMissed = mFrameMissed && mCompositionCoverage.test(CompositionCoverage::Hwc);
107 mGpuFrameMissed = mFrameMissed && mCompositionCoverage.test(CompositionCoverage::Gpu);
108
109 if (mFrameMissed) mFrameMissedCount++;
110 if (mHwcFrameMissed) mHwcFrameMissedCount++;
111 if (mGpuFrameMissed) mGpuFrameMissedCount++;
112}
113
114void FrameTargeter::endFrame(const CompositeResult& result) {
115 mCompositionCoverage = result.compositionCoverage;
116}
117
118FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence) {
119 auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
120 return setPresentFence(std::move(presentFence), std::move(presentFenceTime));
121}
122
123FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence, FenceTimePtr presentFenceTime) {
124 mPresentFences[1] = mPresentFences[0];
125 mPresentFences[0] = {std::move(presentFence), presentFenceTime};
126 return presentFenceTime;
127}
128
129void FrameTargeter::dump(utils::Dumper& dumper) const {
130 using namespace std::string_view_literals;
131
132 utils::Dumper::Section section(dumper, "Frame Targeting"sv);
133
134 dumper.dump("frameMissedCount"sv, mFrameMissedCount);
135 dumper.dump("hwcFrameMissedCount"sv, mHwcFrameMissedCount);
136 dumper.dump("gpuFrameMissedCount"sv, mGpuFrameMissedCount);
137}
138
139bool FrameTargeter::isFencePending(const FenceTimePtr& fence, int graceTimeMs) {
140 ATRACE_CALL();
141 const status_t status = fence->wait(graceTimeMs);
142
143 // This is the same as Fence::Status::Unsignaled, but it saves a call to getStatus,
144 // which calls wait(0) again internally.
145 return status == -ETIME;
146}
147
148} // namespace android::scheduler