Reland "SF: Encapsulate frame targeting"

Introduce FrameTargeter to isolate a display's per-frame metrics around
past/upcoming deadline targets. The Scheduler updates the FrameTargeter
on frame begin/end, whereas ICompositor (concretely SurfaceFlinger) has
read-only access via the FrameTarget interface.

For now, only instantiate the pacesetter's FrameTargeter.

The reverted Idf9f43b37f3479c94a478d154eaa46f43e0c6c9d had an incorrect
functional change that adjusted `earliestPresentTime` based on the past
VSYNC, which differs from the previous frame's VSYNC when targeting two
VSYNCs ahead. This CL restores the `earliestPresentTime` to be relative
to the previous frame.

Bug: 262269033
Bug: 241285475
Bug: 241285191
Test: Perfetto
Test: dumpsys SurfaceFlinger --scheduler
Test: atest libscheduler_test:FrameTargeterTest
Test: systemui-bubble-1-jank-suite on raven-userdebug
Change-Id: I584e299e8af55baae1125f45fd47b13f705a268c
diff --git a/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp b/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp
new file mode 100644
index 0000000..7138afd
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/TraceUtils.h>
+
+#include <scheduler/FrameTargeter.h>
+#include <scheduler/IVsyncSource.h>
+
+namespace android::scheduler {
+
+TimePoint FrameTarget::pastVsyncTime(Period vsyncPeriod) const {
+    // TODO(b/267315508): Generalize to N VSYNCs.
+    const int shift = static_cast<int>(targetsVsyncsAhead<2>(vsyncPeriod));
+    return mExpectedPresentTime - Period::fromNs(vsyncPeriod.ns() << shift);
+}
+
+const FenceTimePtr& FrameTarget::presentFenceForPastVsync(Period vsyncPeriod) const {
+    // TODO(b/267315508): Generalize to N VSYNCs.
+    const size_t i = static_cast<size_t>(targetsVsyncsAhead<2>(vsyncPeriod));
+    return mPresentFences[i].fenceTime;
+}
+
+bool FrameTarget::wouldPresentEarly(Period vsyncPeriod) const {
+    // TODO(b/241285475): Since this is called during `composite`, the calls to `targetsVsyncsAhead`
+    // should use `TimePoint::now()` in case of delays since `mFrameBeginTime`.
+
+    // TODO(b/267315508): Generalize to N VSYNCs.
+    if (targetsVsyncsAhead<3>(vsyncPeriod)) {
+        return true;
+    }
+
+    const auto fence = presentFenceForPastVsync(vsyncPeriod);
+    return fence->isValid() && fence->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
+}
+
+void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& vsyncSource) {
+    return beginFrame(args, vsyncSource, &FrameTargeter::isFencePending);
+}
+
+void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& vsyncSource,
+                               IsFencePendingFuncPtr isFencePendingFuncPtr) {
+    mVsyncId = args.vsyncId;
+    mFrameBeginTime = args.frameBeginTime;
+
+    // The `expectedVsyncTime`, which was predicted when this frame was scheduled, is normally in
+    // the future relative to `frameBeginTime`, but may not be for delayed frames. Adjust
+    // `mExpectedPresentTime` accordingly, but not `mScheduledPresentTime`.
+    const TimePoint lastScheduledPresentTime = mScheduledPresentTime;
+    mScheduledPresentTime = args.expectedVsyncTime;
+
+    const Period vsyncPeriod = vsyncSource.period();
+
+    // Calculate the expected present time once and use the cached value throughout this frame to
+    // make sure all layers are seeing this same value.
+    if (args.expectedVsyncTime >= args.frameBeginTime) {
+        mExpectedPresentTime = args.expectedVsyncTime;
+    } else {
+        mExpectedPresentTime = vsyncSource.vsyncDeadlineAfter(args.frameBeginTime);
+        if (args.sfWorkDuration > vsyncPeriod) {
+            // Inflate the expected present time if we're targeting the next VSYNC.
+            mExpectedPresentTime += vsyncPeriod;
+        }
+    }
+
+    ATRACE_FORMAT("%s %" PRId64 " vsyncIn %.2fms%s", __func__, ftl::to_underlying(args.vsyncId),
+                  ticks<std::milli, float>(mExpectedPresentTime - TimePoint::now()),
+                  mExpectedPresentTime == args.expectedVsyncTime ? "" : " (adjusted)");
+
+    const FenceTimePtr& pastPresentFence = presentFenceForPastVsync(vsyncPeriod);
+
+    // In cases where the present fence is about to fire, give it a small grace period instead of
+    // giving up on the frame.
+    //
+    // TODO(b/280667110): The grace period should depend on `sfWorkDuration` and `vsyncPeriod` being
+    // approximately equal, not whether backpressure propagation is enabled.
+    const int graceTimeForPresentFenceMs = static_cast<int>(
+            mBackpressureGpuComposition || !mCompositionCoverage.test(CompositionCoverage::Gpu));
+
+    // Pending frames may trigger backpressure propagation.
+    const auto& isFencePending = *isFencePendingFuncPtr;
+    mFramePending = pastPresentFence != FenceTime::NO_FENCE &&
+            isFencePending(pastPresentFence, graceTimeForPresentFenceMs);
+
+    // A frame is missed if the prior frame is still pending. If no longer pending, then we still
+    // count the frame as missed if the predicted present time was further in the past than when the
+    // fence actually fired. Add some slop to correct for drift. This should generally be smaller
+    // than a typical frame duration, but should not be so small that it reports reasonable drift as
+    // a missed frame.
+    mFrameMissed = mFramePending || [&] {
+        const nsecs_t pastPresentTime = pastPresentFence->getSignalTime();
+        if (pastPresentTime < 0) return false;
+        const nsecs_t frameMissedSlop = vsyncPeriod.ns() / 2;
+        return lastScheduledPresentTime.ns() < pastPresentTime - frameMissedSlop;
+    }();
+
+    mHwcFrameMissed = mFrameMissed && mCompositionCoverage.test(CompositionCoverage::Hwc);
+    mGpuFrameMissed = mFrameMissed && mCompositionCoverage.test(CompositionCoverage::Gpu);
+
+    if (mFrameMissed) mFrameMissedCount++;
+    if (mHwcFrameMissed) mHwcFrameMissedCount++;
+    if (mGpuFrameMissed) mGpuFrameMissedCount++;
+}
+
+void FrameTargeter::endFrame(const CompositeResult& result) {
+    mCompositionCoverage = result.compositionCoverage;
+}
+
+FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence) {
+    auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
+    return setPresentFence(std::move(presentFence), std::move(presentFenceTime));
+}
+
+FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence, FenceTimePtr presentFenceTime) {
+    mPresentFences[1] = mPresentFences[0];
+    mPresentFences[0] = {std::move(presentFence), presentFenceTime};
+    return presentFenceTime;
+}
+
+void FrameTargeter::dump(utils::Dumper& dumper) const {
+    using namespace std::string_view_literals;
+
+    utils::Dumper::Section section(dumper, "Frame Targeting"sv);
+
+    // There are scripts and tests that expect this (rather than "name=value") format.
+    dumper.dump({}, "Total missed frame count: " + std::to_string(mFrameMissedCount));
+    dumper.dump({}, "HWC missed frame count: " + std::to_string(mHwcFrameMissedCount));
+    dumper.dump({}, "GPU missed frame count: " + std::to_string(mGpuFrameMissedCount));
+}
+
+bool FrameTargeter::isFencePending(const FenceTimePtr& fence, int graceTimeMs) {
+    ATRACE_CALL();
+    const status_t status = fence->wait(graceTimeMs);
+
+    // This is the same as Fence::Status::Unsignaled, but it saves a call to getStatus,
+    // which calls wait(0) again internally.
+    return status == -ETIME;
+}
+
+} // namespace android::scheduler