/* * 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. */ #pragma once #include #include #include #include #include #include #include #include #include #include #include // TODO(b/185536303): Pull to FTL. #include "../../../TracedOrdinal.h" #include "../../../Utils/Dumper.h" #include "../../../Utils/RingBuffer.h" namespace android::scheduler { struct IVsyncSource; // Read-only interface to the metrics computed by FrameTargeter for the latest frame. class FrameTarget { public: VsyncId vsyncId() const { return mVsyncId; } // The time when the frame actually began, as opposed to when it had been scheduled to begin. TimePoint frameBeginTime() const { return mFrameBeginTime; } // Relative to when the frame actually began, as opposed to when it had been scheduled to begin. Duration expectedFrameDuration() const { return mExpectedPresentTime - mFrameBeginTime; } TimePoint expectedPresentTime() const { return mExpectedPresentTime; } std::optional earliestPresentTime() const { return mEarliestPresentTime; } // The time of the VSYNC that preceded this frame. See `presentFenceForPastVsync` for details. TimePoint pastVsyncTime(Period minFramePeriod) const; // The present fence for the frame that had targeted the most recent VSYNC before this frame. // If the target VSYNC for any given frame is more than `vsyncPeriod` in the future, then the // VSYNC of at least one previous frame has not yet passed. In other words, this is NOT the // `presentFenceForPreviousFrame` if running N VSYNCs ahead, but the one that should have been // signaled by now (unless that frame missed). FenceTimePtr presentFenceForPastVsync(Period minFramePeriod) const; // Equivalent to `presentFenceForPastVsync` unless running N VSYNCs ahead. const FenceTimePtr& presentFenceForPreviousFrame() const { return mPresentFences.front().fenceTime; } bool isFramePending() const { return mFramePending; } bool didMissFrame() const { return mFrameMissed; } bool didMissHwcFrame() const { return mHwcFrameMissed && !mGpuFrameMissed; } TimePoint lastSignaledFrameTime() const { return mLastSignaledFrameTime; }; protected: explicit FrameTarget(const std::string& displayLabel); ~FrameTarget() = default; bool wouldPresentEarly(Period minFramePeriod) const; // Equivalent to `pastVsyncTime` unless running N VSYNCs ahead. TimePoint previousFrameVsyncTime(Period minFramePeriod) const { return mExpectedPresentTime - minFramePeriod; } void addFence(sp presentFence, FenceTimePtr presentFenceTime, TimePoint expectedPresentTime) { mFenceWithFenceTimes.next() = {std::move(presentFence), presentFenceTime, expectedPresentTime}; } VsyncId mVsyncId; TimePoint mFrameBeginTime; TimePoint mExpectedPresentTime; std::optional mEarliestPresentTime; TracedOrdinal mFramePending; TracedOrdinal mFrameMissed; TracedOrdinal mHwcFrameMissed; TracedOrdinal mGpuFrameMissed; struct FenceWithFenceTime { sp fence = Fence::NO_FENCE; FenceTimePtr fenceTime = FenceTime::NO_FENCE; TimePoint expectedPresentTime = TimePoint(); }; std::array mPresentFences; utils::RingBuffer mFenceWithFenceTimes; TimePoint mLastSignaledFrameTime; private: friend class FrameTargeterTestBase; template inline bool targetsVsyncsAhead(Period minFramePeriod) const { static_assert(N > 1); return expectedFrameDuration() > (N - 1) * minFramePeriod; } const FenceTimePtr pastVsyncTimePtr() const { auto pastFenceTimePtr = FenceTime::NO_FENCE; for (size_t i = 0; i < mFenceWithFenceTimes.size(); i++) { const auto& [_, fenceTimePtr, expectedPresentTime] = mFenceWithFenceTimes[i]; if (expectedPresentTime > mFrameBeginTime) { return pastFenceTimePtr; } pastFenceTimePtr = fenceTimePtr; } return pastFenceTimePtr; } }; // Computes a display's per-frame metrics about past/upcoming targeting of present deadlines. class FrameTargeter final : private FrameTarget { public: FrameTargeter(PhysicalDisplayId displayId, FeatureFlags flags) : FrameTarget(to_string(displayId)), mBackpressureGpuComposition(flags.test(Feature::kBackpressureGpuComposition)), mSupportsExpectedPresentTime(flags.test(Feature::kExpectedPresentTime)) {} const FrameTarget& target() const { return *this; } struct BeginFrameArgs { TimePoint frameBeginTime; VsyncId vsyncId; TimePoint expectedVsyncTime; Duration sfWorkDuration; Duration hwcMinWorkDuration; }; void beginFrame(const BeginFrameArgs&, const IVsyncSource&); std::optional computeEarliestPresentTime(Period minFramePeriod, Duration hwcMinWorkDuration); // TODO(b/241285191): Merge with FrameTargeter::endFrame. FenceTimePtr setPresentFence(sp); void endFrame(const CompositeResult&); void dump(utils::Dumper&) const; private: friend class FrameTargeterTestBase; // For tests. using IsFencePendingFuncPtr = bool (*)(const FenceTimePtr&, int graceTimeMs); void beginFrame(const BeginFrameArgs&, const IVsyncSource&, IsFencePendingFuncPtr); FenceTimePtr setPresentFence(sp, FenceTimePtr); static bool isFencePending(const FenceTimePtr&, int graceTimeMs); const bool mBackpressureGpuComposition; const bool mSupportsExpectedPresentTime; TimePoint mScheduledPresentTime; CompositionCoverageFlags mCompositionCoverage; std::atomic_uint mFrameMissedCount = 0; std::atomic_uint mHwcFrameMissedCount = 0; std::atomic_uint mGpuFrameMissedCount = 0; }; } // namespace android::scheduler