SF: fix a few bugs with FrameTargeter storing N fences
Bug: 267315508
Bug: 354007767
Bug: 308858993
Test: SF unit tests
Flag: com.android.graphics.surfaceflinger.flags.allow_n_vsyncs_in_targeter
Change-Id: Ib603c0fd29a3e4cb2fcd99dca59bbd5bfb55a787
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h
index 38cb446..2185bb0 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h
@@ -55,15 +55,11 @@
std::optional<TimePoint> earliestPresentTime() const { return mEarliestPresentTime; }
- // The time of the VSYNC that preceded this frame. See `presentFenceForPastVsync` for details.
- TimePoint pastVsyncTime(Period minFramePeriod) const;
-
- // Equivalent to `presentFenceForPastVsync` unless running N VSYNCs ahead.
- const FenceTimePtr& presentFenceForPreviousFrame() const {
- return mPresentFences.front().fenceTime;
- }
+ // Equivalent to `expectedSignaledPresentFence` unless running N VSYNCs ahead.
+ const FenceTimePtr& presentFenceForPreviousFrame() const;
bool isFramePending() const { return mFramePending; }
+ bool wouldBackpressureHwc() const { return mWouldBackpressureHwc; }
bool didMissFrame() const { return mFrameMissed; }
bool didMissHwcFrame() const { return mHwcFrameMissed && !mGpuFrameMissed; }
FrameTime lastSignaledFrameTime() const { return mLastSignaledFrameTime; }
@@ -72,7 +68,7 @@
explicit FrameTarget(const std::string& displayLabel);
~FrameTarget() = default;
- bool wouldPresentEarly(Period minFramePeriod) const;
+ bool wouldPresentEarly(Period vsyncPeriod, Period minFramePeriod) const;
// Equivalent to `pastVsyncTime` unless running N VSYNCs ahead.
TimePoint previousFrameVsyncTime(Period minFramePeriod) const {
@@ -81,8 +77,7 @@
void addFence(sp<Fence> presentFence, FenceTimePtr presentFenceTime,
TimePoint expectedPresentTime) {
- mFenceWithFenceTimes.next() = {std::move(presentFence), presentFenceTime,
- expectedPresentTime};
+ mPresentFences.next() = {std::move(presentFence), presentFenceTime, expectedPresentTime};
}
VsyncId mVsyncId;
@@ -94,8 +89,9 @@
TracedOrdinal<bool> mFrameMissed;
TracedOrdinal<bool> mHwcFrameMissed;
TracedOrdinal<bool> mGpuFrameMissed;
+ bool mWouldBackpressureHwc = false;
- struct FenceWithFenceTime {
+ struct PresentFence {
sp<Fence> fence = Fence::NO_FENCE;
FenceTimePtr fenceTime = FenceTime::NO_FENCE;
TimePoint expectedPresentTime = TimePoint();
@@ -106,9 +102,10 @@
// 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).
- FenceWithFenceTime presentFenceForPastVsync(Period minFramePeriod) const;
- std::array<FenceWithFenceTime, 2> mPresentFences;
- utils::RingBuffer<FenceWithFenceTime, 5> mFenceWithFenceTimes;
+ std::pair<bool /* wouldBackpressure */, PresentFence> expectedSignaledPresentFence(
+ Period vsyncPeriod, Period minFramePeriod) const;
+ std::array<PresentFence, 2> mPresentFencesLegacy;
+ utils::RingBuffer<PresentFence, 5> mPresentFences;
FrameTime mLastSignaledFrameTime;
@@ -120,19 +117,6 @@
static_assert(N > 1);
return expectedFrameDuration() > (N - 1) * minFramePeriod;
}
-
- FenceWithFenceTime pastVsyncTimePtr() const {
- FenceWithFenceTime pastFenceWithFenceTime;
- for (size_t i = 0; i < mFenceWithFenceTimes.size(); i++) {
- const auto& fenceWithFenceTime = mFenceWithFenceTimes[i];
- // TODO(b/354007767) Fix the below condition to avoid frame drop
- if (fenceWithFenceTime.expectedPresentTime > mFrameBeginTime) {
- return pastFenceWithFenceTime;
- }
- pastFenceWithFenceTime = fenceWithFenceTime;
- }
- return pastFenceWithFenceTime;
- }
};
// Computes a display's per-frame metrics about past/upcoming targeting of present deadlines.
@@ -155,7 +139,7 @@
void beginFrame(const BeginFrameArgs&, const IVsyncSource&);
- std::optional<TimePoint> computeEarliestPresentTime(Period minFramePeriod,
+ std::optional<TimePoint> computeEarliestPresentTime(Period vsyncPeriod, Period minFramePeriod,
Duration hwcMinWorkDuration);
// TODO(b/241285191): Merge with FrameTargeter::endFrame.
diff --git a/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp b/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp
index 1d248fb..21f5949 100644
--- a/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp
+++ b/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp
@@ -18,8 +18,10 @@
#include <common/trace.h>
#include <scheduler/FrameTargeter.h>
#include <scheduler/IVsyncSource.h>
+#include <utils/Log.h>
namespace android::scheduler {
+using namespace std::chrono_literals;
FrameTarget::FrameTarget(const std::string& displayLabel)
: mFramePending("PrevFramePending " + displayLabel, false),
@@ -27,32 +29,48 @@
mHwcFrameMissed("PrevHwcFrameMissed " + displayLabel, false),
mGpuFrameMissed("PrevGpuFrameMissed " + displayLabel, false) {}
-TimePoint FrameTarget::pastVsyncTime(Period minFramePeriod) const {
- // TODO(b/267315508): Generalize to N VSYNCs.
- const int shift = static_cast<int>(targetsVsyncsAhead<2>(minFramePeriod));
- return mExpectedPresentTime - Period::fromNs(minFramePeriod.ns() << shift);
-}
-
-FrameTarget::FenceWithFenceTime FrameTarget::presentFenceForPastVsync(Period minFramePeriod) const {
- if (FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
- return pastVsyncTimePtr();
+std::pair<bool /* wouldBackpressure */, FrameTarget::PresentFence>
+FrameTarget::expectedSignaledPresentFence(Period vsyncPeriod, Period minFramePeriod) const {
+ if (!FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
+ const size_t i = static_cast<size_t>(targetsVsyncsAhead<2>(minFramePeriod));
+ return {true, mPresentFencesLegacy[i]};
}
- const size_t i = static_cast<size_t>(targetsVsyncsAhead<2>(minFramePeriod));
- return mPresentFences[i];
+
+ bool wouldBackpressure = true;
+ auto expectedPresentTime = mExpectedPresentTime;
+ for (size_t i = mPresentFences.size(); i != 0; --i) {
+ const auto& fence = mPresentFences[i - 1];
+
+ if (fence.expectedPresentTime + minFramePeriod < expectedPresentTime - vsyncPeriod / 2) {
+ wouldBackpressure = false;
+ }
+
+ if (fence.expectedPresentTime <= mFrameBeginTime) {
+ return {wouldBackpressure, fence};
+ }
+
+ expectedPresentTime = fence.expectedPresentTime;
+ }
+ return {wouldBackpressure, PresentFence{}};
}
-bool FrameTarget::wouldPresentEarly(Period minFramePeriod) 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.
- const bool allowNVsyncs = FlagManager::getInstance().allow_n_vsyncs_in_targeter();
- if (!allowNVsyncs && targetsVsyncsAhead<3>(minFramePeriod)) {
+bool FrameTarget::wouldPresentEarly(Period vsyncPeriod, Period minFramePeriod) const {
+ if (targetsVsyncsAhead<3>(minFramePeriod)) {
return true;
}
- const auto fence = presentFenceForPastVsync(minFramePeriod).fenceTime;
- return fence->isValid() && fence->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
+ const auto [wouldBackpressure, fence] =
+ expectedSignaledPresentFence(vsyncPeriod, minFramePeriod);
+ return wouldBackpressure && fence.fenceTime->isValid() &&
+ fence.fenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
+}
+
+const FenceTimePtr& FrameTarget::presentFenceForPreviousFrame() const {
+ if (FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
+ return mPresentFences.back().fenceTime;
+ }
+
+ return mPresentFencesLegacy.front().fenceTime;
}
void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& vsyncSource) {
@@ -86,27 +104,39 @@
}
if (!mSupportsExpectedPresentTime) {
- mEarliestPresentTime = computeEarliestPresentTime(minFramePeriod, args.hwcMinWorkDuration);
+ mEarliestPresentTime =
+ computeEarliestPresentTime(vsyncPeriod, minFramePeriod, args.hwcMinWorkDuration);
}
SFTRACE_FORMAT("%s %" PRId64 " vsyncIn %.2fms%s", __func__, ftl::to_underlying(args.vsyncId),
ticks<std::milli, float>(mExpectedPresentTime - TimePoint::now()),
mExpectedPresentTime == args.expectedVsyncTime ? "" : " (adjusted)");
- FenceWithFenceTime pastPresentFence = presentFenceForPastVsync(minFramePeriod);
+ const auto [wouldBackpressure, fence] =
+ expectedSignaledPresentFence(vsyncPeriod, minFramePeriod);
// 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));
+ const int graceTimeForPresentFenceMs = [&] {
+ const bool considerBackpressure =
+ mBackpressureGpuComposition || !mCompositionCoverage.test(CompositionCoverage::Gpu);
+
+ if (!FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
+ return static_cast<int>(considerBackpressure);
+ }
+
+ if (!wouldBackpressure || !considerBackpressure) {
+ return 0;
+ }
+
+ return static_cast<int>((std::abs(fence.expectedPresentTime.ns() - mFrameBeginTime.ns()) <=
+ Duration(1ms).ns()));
+ }();
// Pending frames may trigger backpressure propagation.
const auto& isFencePending = *isFencePendingFuncPtr;
- mFramePending = pastPresentFence.fenceTime != FenceTime::NO_FENCE &&
- isFencePending(pastPresentFence.fenceTime, graceTimeForPresentFenceMs);
+ mFramePending = fence.fenceTime != FenceTime::NO_FENCE &&
+ isFencePending(fence.fenceTime, 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
@@ -114,10 +144,10 @@
// 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.fenceTime->getSignalTime();
+ const nsecs_t pastPresentTime = fence.fenceTime->getSignalTime();
if (pastPresentTime < 0) return false;
mLastSignaledFrameTime = {.signalTime = TimePoint::fromNs(pastPresentTime),
- .expectedPresentTime = pastPresentFence.expectedPresentTime};
+ .expectedPresentTime = fence.expectedPresentTime};
const nsecs_t frameMissedSlop = vsyncPeriod.ns() / 2;
return lastScheduledPresentTime.ns() < pastPresentTime - frameMissedSlop;
}();
@@ -128,11 +158,14 @@
if (mFrameMissed) mFrameMissedCount++;
if (mHwcFrameMissed) mHwcFrameMissedCount++;
if (mGpuFrameMissed) mGpuFrameMissedCount++;
+
+ mWouldBackpressureHwc = mFramePending && wouldBackpressure;
}
-std::optional<TimePoint> FrameTargeter::computeEarliestPresentTime(Period minFramePeriod,
+std::optional<TimePoint> FrameTargeter::computeEarliestPresentTime(Period vsyncPeriod,
+ Period minFramePeriod,
Duration hwcMinWorkDuration) {
- if (wouldPresentEarly(minFramePeriod)) {
+ if (wouldPresentEarly(vsyncPeriod, minFramePeriod)) {
return previousFrameVsyncTime(minFramePeriod) - hwcMinWorkDuration;
}
return {};
@@ -151,8 +184,8 @@
if (FlagManager::getInstance().allow_n_vsyncs_in_targeter()) {
addFence(std::move(presentFence), presentFenceTime, mExpectedPresentTime);
} else {
- mPresentFences[1] = mPresentFences[0];
- mPresentFences[0] = {std::move(presentFence), presentFenceTime, mExpectedPresentTime};
+ mPresentFencesLegacy[1] = mPresentFencesLegacy[0];
+ mPresentFencesLegacy[0] = {std::move(presentFence), presentFenceTime, mExpectedPresentTime};
}
return presentFenceTime;
}
diff --git a/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp b/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp
index 190d062..bc73cbb 100644
--- a/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp
+++ b/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp
@@ -53,12 +53,13 @@
const auto& target() const { return mTargeter.target(); }
- bool wouldPresentEarly(Period minFramePeriod) const {
- return target().wouldPresentEarly(minFramePeriod);
+ bool wouldPresentEarly(Period vsyncPeriod, Period minFramePeriod) const {
+ return target().wouldPresentEarly(vsyncPeriod, minFramePeriod);
}
- FrameTarget::FenceWithFenceTime presentFenceForPastVsync(Period minFramePeriod) const {
- return target().presentFenceForPastVsync(minFramePeriod);
+ std::pair<bool /*wouldBackpressure*/, FrameTarget::PresentFence> expectedSignaledPresentFence(
+ Period vsyncPeriod, Period minFramePeriod) const {
+ return target().expectedSignaledPresentFence(vsyncPeriod, minFramePeriod);
}
struct Frame {
@@ -173,7 +174,6 @@
}
TEST_F(FrameTargeterTest, recallsPastVsync) {
- SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
VsyncId vsyncId{111};
TimePoint frameBeginTime(1000ms);
constexpr Fps kRefreshRate = 60_Hz;
@@ -181,16 +181,72 @@
constexpr Duration kFrameDuration = 13ms;
for (int n = 5; n-- > 0;) {
- Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
- const auto fence = frame.end();
+ FenceTimePtr fence;
+ {
+ Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate,
+ kRefreshRate);
+ fence = frame.end();
+ }
- EXPECT_EQ(target().pastVsyncTime(kPeriod), frameBeginTime + kFrameDuration - kPeriod);
- EXPECT_EQ(presentFenceForPastVsync(kPeriod).fenceTime, fence);
+ Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
+ const auto [wouldBackpressure, presentFence] =
+ expectedSignaledPresentFence(kPeriod, kPeriod);
+ ASSERT_TRUE(wouldBackpressure);
+ EXPECT_EQ(presentFence.fenceTime, fence);
+ }
+}
+
+TEST_F(FrameTargeterTest, wouldBackpressureAfterTime) {
+ SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, true);
+ VsyncId vsyncId{111};
+ TimePoint frameBeginTime(1000ms);
+ constexpr Fps kRefreshRate = 60_Hz;
+ constexpr Period kPeriod = kRefreshRate.getPeriod();
+ constexpr Duration kFrameDuration = 13ms;
+
+ { Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate); }
+ {
+ Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
+
+ const auto [wouldBackpressure, presentFence] =
+ expectedSignaledPresentFence(kPeriod, kPeriod);
+ EXPECT_TRUE(wouldBackpressure);
+ }
+ {
+ frameBeginTime += kPeriod;
+ Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
+ const auto [wouldBackpressure, presentFence] =
+ expectedSignaledPresentFence(kPeriod, kPeriod);
+ EXPECT_FALSE(wouldBackpressure);
+ }
+}
+
+TEST_F(FrameTargeterTest, wouldBackpressureAfterTimeLegacy) {
+ SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
+ VsyncId vsyncId{111};
+ TimePoint frameBeginTime(1000ms);
+ constexpr Fps kRefreshRate = 60_Hz;
+ constexpr Period kPeriod = kRefreshRate.getPeriod();
+ constexpr Duration kFrameDuration = 13ms;
+
+ { Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate); }
+ {
+ Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
+
+ const auto [wouldBackpressure, presentFence] =
+ expectedSignaledPresentFence(kPeriod, kPeriod);
+ EXPECT_TRUE(wouldBackpressure);
+ }
+ {
+ frameBeginTime += kPeriod;
+ Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
+ const auto [wouldBackpressure, presentFence] =
+ expectedSignaledPresentFence(kPeriod, kPeriod);
+ EXPECT_TRUE(wouldBackpressure);
}
}
TEST_F(FrameTargeterTest, recallsPastVsyncTwoVsyncsAhead) {
- SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
VsyncId vsyncId{222};
TimePoint frameBeginTime(2000ms);
constexpr Fps kRefreshRate = 120_Hz;
@@ -198,101 +254,66 @@
constexpr Duration kFrameDuration = 10ms;
FenceTimePtr previousFence = FenceTime::NO_FENCE;
-
+ FenceTimePtr currentFence = FenceTime::NO_FENCE;
for (int n = 5; n-- > 0;) {
Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
- const auto fence = frame.end();
-
- EXPECT_EQ(target().pastVsyncTime(kPeriod), frameBeginTime + kFrameDuration - 2 * kPeriod);
- EXPECT_EQ(presentFenceForPastVsync(kPeriod).fenceTime, previousFence);
-
- previousFence = fence;
+ EXPECT_EQ(expectedSignaledPresentFence(kPeriod, kPeriod).second.fenceTime, previousFence);
+ previousFence = currentFence;
+ currentFence = frame.end();
}
}
-TEST_F(FrameTargeterTest, recallsPastNVsyncTwoVsyncsAhead) {
+TEST_F(FrameTargeterTest, recallsPastVsyncFiveVsyncsAhead) {
SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, true);
+
VsyncId vsyncId{222};
TimePoint frameBeginTime(2000ms);
constexpr Fps kRefreshRate = 120_Hz;
constexpr Period kPeriod = kRefreshRate.getPeriod();
- constexpr Duration kFrameDuration = 10ms;
+ constexpr Duration kFrameDuration = 40ms;
- FenceTimePtr previousFence = FenceTime::NO_FENCE;
-
+ FenceTimePtr firstFence = FenceTime::NO_FENCE;
for (int n = 5; n-- > 0;) {
Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
const auto fence = frame.end();
-
- const auto pastVsyncTime = frameBeginTime + kFrameDuration - 2 * kPeriod;
- EXPECT_EQ(target().pastVsyncTime(kPeriod), pastVsyncTime);
- EXPECT_EQ(presentFenceForPastVsync(kFrameDuration).fenceTime, previousFence);
-
- frameBeginTime += kPeriod;
- previousFence = fence;
+ if (firstFence == FenceTime::NO_FENCE) {
+ firstFence = fence;
+ }
}
+
+ Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
+ EXPECT_EQ(expectedSignaledPresentFence(kPeriod, kPeriod).second.fenceTime, firstFence);
}
TEST_F(FrameTargeterTest, recallsPastVsyncTwoVsyncsAheadVrr) {
SET_FLAG_FOR_TEST(flags::vrr_config, true);
- SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
VsyncId vsyncId{222};
TimePoint frameBeginTime(2000ms);
constexpr Fps kRefreshRate = 120_Hz;
- constexpr Fps kPeakRefreshRate = 240_Hz;
+ constexpr Fps kVsyncRate = 240_Hz;
constexpr Period kPeriod = kRefreshRate.getPeriod();
+ constexpr Period kVsyncPeriod = kVsyncRate.getPeriod();
constexpr Duration kFrameDuration = 10ms;
FenceTimePtr previousFence = FenceTime::NO_FENCE;
-
+ FenceTimePtr currentFence = FenceTime::NO_FENCE;
for (int n = 5; n-- > 0;) {
- Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate,
- kPeakRefreshRate);
- const auto fence = frame.end();
-
- EXPECT_EQ(target().pastVsyncTime(kPeriod), frameBeginTime + kFrameDuration - 2 * kPeriod);
- EXPECT_EQ(presentFenceForPastVsync(kPeriod).fenceTime, previousFence);
-
- previousFence = fence;
- }
-}
-
-TEST_F(FrameTargeterTest, recallsPastNVsyncTwoVsyncsAheadVrr) {
- SET_FLAG_FOR_TEST(flags::vrr_config, true);
- SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, true);
-
- VsyncId vsyncId{222};
- TimePoint frameBeginTime(2000ms);
- constexpr Fps kRefreshRate = 120_Hz;
- constexpr Fps kPeakRefreshRate = 240_Hz;
- constexpr Period kPeriod = kRefreshRate.getPeriod();
- constexpr Duration kFrameDuration = 10ms;
-
- FenceTimePtr previousFence = FenceTime::NO_FENCE;
-
- for (int n = 5; n-- > 0;) {
- Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate,
- kPeakRefreshRate);
- const auto fence = frame.end();
-
- const auto pastVsyncTime = frameBeginTime + kFrameDuration - 2 * kPeriod;
- EXPECT_EQ(target().pastVsyncTime(kPeriod), pastVsyncTime);
- EXPECT_EQ(presentFenceForPastVsync(kFrameDuration).fenceTime, previousFence);
-
- frameBeginTime += kPeriod;
- previousFence = fence;
+ Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate, kRefreshRate);
+ EXPECT_EQ(expectedSignaledPresentFence(kVsyncPeriod, kPeriod).second.fenceTime,
+ previousFence);
+ previousFence = currentFence;
+ currentFence = frame.end();
}
}
TEST_F(FrameTargeterTest, doesNotDetectEarlyPresentIfNoFence) {
constexpr Period kPeriod = (60_Hz).getPeriod();
- EXPECT_EQ(presentFenceForPastVsync(kPeriod).fenceTime, FenceTime::NO_FENCE);
- EXPECT_FALSE(wouldPresentEarly(kPeriod));
+ EXPECT_EQ(expectedSignaledPresentFence(kPeriod, kPeriod).second.fenceTime, FenceTime::NO_FENCE);
+ EXPECT_FALSE(wouldPresentEarly(kPeriod, kPeriod));
}
TEST_F(FrameTargeterTest, detectsEarlyPresent) {
- SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
VsyncId vsyncId{333};
TimePoint frameBeginTime(3000ms);
constexpr Fps kRefreshRate = 60_Hz;
@@ -300,20 +321,24 @@
// The target is not early while past present fences are pending.
for (int n = 3; n-- > 0;) {
- const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
- EXPECT_FALSE(wouldPresentEarly(kPeriod));
+ {
+ const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
+ }
+ EXPECT_FALSE(wouldPresentEarly(kPeriod, kPeriod));
EXPECT_FALSE(target().earliestPresentTime());
}
// The target is early if the past present fence was signaled.
- Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
- const auto fence = frame.end();
- fence->signalForTest(frameBeginTime.ns());
+ {
+ Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
+ const auto fence = frame.end();
+ fence->signalForTest(frameBeginTime.ns());
+ }
Frame finalFrame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
// `finalFrame` would present early, so it has an earliest present time.
- EXPECT_TRUE(wouldPresentEarly(kPeriod));
+ EXPECT_TRUE(wouldPresentEarly(kPeriod, kPeriod));
ASSERT_NE(std::nullopt, target().earliestPresentTime());
EXPECT_EQ(*target().earliestPresentTime(),
target().expectedPresentTime() - kPeriod - kHwcMinWorkDuration);
@@ -322,7 +347,6 @@
// Same as `detectsEarlyPresent`, above, but verifies that we do not set an earliest present time
// when there is expected present time support.
TEST_F(FrameTargeterWithExpectedPresentSupportTest, detectsEarlyPresent) {
- SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
VsyncId vsyncId{333};
TimePoint frameBeginTime(3000ms);
constexpr Fps kRefreshRate = 60_Hz;
@@ -330,26 +354,30 @@
// The target is not early while past present fences are pending.
for (int n = 3; n-- > 0;) {
- const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
- EXPECT_FALSE(wouldPresentEarly(kPeriod));
+ {
+ const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
+ }
+ EXPECT_FALSE(wouldPresentEarly(kPeriod, kPeriod));
EXPECT_FALSE(target().earliestPresentTime());
}
// The target is early if the past present fence was signaled.
- Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
- const auto fence = frame.end();
- fence->signalForTest(frameBeginTime.ns());
+ {
+ Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
+
+ const auto fence = frame.end();
+ fence->signalForTest(frameBeginTime.ns());
+ }
Frame finalFrame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
// `finalFrame` would present early, but we have expected present time support, so it has no
// earliest present time.
- EXPECT_TRUE(wouldPresentEarly(kPeriod));
+ EXPECT_TRUE(wouldPresentEarly(kPeriod, kPeriod));
ASSERT_EQ(std::nullopt, target().earliestPresentTime());
}
TEST_F(FrameTargeterTest, detectsEarlyPresentTwoVsyncsAhead) {
- SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
VsyncId vsyncId{444};
TimePoint frameBeginTime(4000ms);
constexpr Fps kRefreshRate = 120_Hz;
@@ -357,17 +385,21 @@
// The target is not early while past present fences are pending.
for (int n = 3; n-- > 0;) {
- const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
- EXPECT_FALSE(wouldPresentEarly(kPeriod));
+ {
+ const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
+ }
+ EXPECT_FALSE(wouldPresentEarly(kPeriod, kPeriod));
EXPECT_FALSE(target().earliestPresentTime());
}
+ {
+ Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
- Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
- const auto fence = frame.end();
- fence->signalForTest(frameBeginTime.ns());
+ const auto fence = frame.end();
+ fence->signalForTest(frameBeginTime.ns());
+ }
// The target is two VSYNCs ahead, so the past present fence is still pending.
- EXPECT_FALSE(wouldPresentEarly(kPeriod));
+ EXPECT_FALSE(wouldPresentEarly(kPeriod, kPeriod));
EXPECT_FALSE(target().earliestPresentTime());
{ const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate); }
@@ -375,66 +407,21 @@
Frame finalFrame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, kRefreshRate);
// The target is early if the past present fence was signaled.
- EXPECT_TRUE(wouldPresentEarly(kPeriod));
+ EXPECT_TRUE(wouldPresentEarly(kPeriod, kPeriod));
ASSERT_NE(std::nullopt, target().earliestPresentTime());
EXPECT_EQ(*target().earliestPresentTime(),
target().expectedPresentTime() - kPeriod - kHwcMinWorkDuration);
}
-TEST_F(FrameTargeterTest, detectsEarlyPresentNVsyncsAhead) {
- SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, true);
- VsyncId vsyncId{444};
- TimePoint frameBeginTime(4000ms);
- Fps refreshRate = 120_Hz;
- Period period = refreshRate.getPeriod();
-
- // The target is not early while past present fences are pending.
- for (int n = 5; n-- > 0;) {
- const Frame frame(this, vsyncId++, frameBeginTime, 10ms, refreshRate, refreshRate);
- EXPECT_FALSE(wouldPresentEarly(period));
- EXPECT_FALSE(target().earliestPresentTime());
- }
-
- Frame frame(this, vsyncId++, frameBeginTime, 10ms, refreshRate, refreshRate);
- auto fence = frame.end();
- frameBeginTime += period;
- fence->signalForTest(frameBeginTime.ns());
-
- // The target is two VSYNCs ahead, so the past present fence is still pending.
- EXPECT_FALSE(wouldPresentEarly(period));
- EXPECT_FALSE(target().earliestPresentTime());
-
- { const Frame frame(this, vsyncId++, frameBeginTime, 10ms, refreshRate, refreshRate); }
-
- Frame oneEarlyPresentFrame(this, vsyncId++, frameBeginTime, 10ms, refreshRate, refreshRate);
- // The target is early if the past present fence was signaled.
- EXPECT_TRUE(wouldPresentEarly(period));
- ASSERT_NE(std::nullopt, target().earliestPresentTime());
- EXPECT_EQ(*target().earliestPresentTime(),
- target().expectedPresentTime() - period - kHwcMinWorkDuration);
-
- fence = oneEarlyPresentFrame.end();
- frameBeginTime += period;
- fence->signalForTest(frameBeginTime.ns());
-
- // Change rate to track frame more than 2 vsyncs ahead
- refreshRate = 144_Hz;
- period = refreshRate.getPeriod();
- Frame onePresentEarlyFrame(this, vsyncId++, frameBeginTime, 16ms, refreshRate, refreshRate);
- // The target is not early as last frame as the past frame is tracked for pending.
- EXPECT_FALSE(wouldPresentEarly(period));
-}
-
TEST_F(FrameTargeterTest, detectsEarlyPresentThreeVsyncsAhead) {
- SET_FLAG_FOR_TEST(flags::allow_n_vsyncs_in_targeter, false);
TimePoint frameBeginTime(5000ms);
constexpr Fps kRefreshRate = 144_Hz;
constexpr Period kPeriod = kRefreshRate.getPeriod();
- const Frame frame(this, VsyncId{555}, frameBeginTime, 16ms, kRefreshRate, kRefreshRate);
+ { const Frame frame(this, VsyncId{555}, frameBeginTime, 16ms, kRefreshRate, kRefreshRate); }
// The target is more than two VSYNCs ahead, but present fences are not tracked that far back.
- EXPECT_TRUE(wouldPresentEarly(kPeriod));
+ EXPECT_TRUE(wouldPresentEarly(kPeriod, kPeriod));
EXPECT_TRUE(target().earliestPresentTime());
EXPECT_EQ(*target().earliestPresentTime(),
target().expectedPresentTime() - kPeriod - kHwcMinWorkDuration);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 1d35730..e32202f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2623,7 +2623,7 @@
}
}
- if (pacesetterFrameTarget.isFramePending()) {
+ if (pacesetterFrameTarget.wouldBackpressureHwc()) {
if (mBackpressureGpuComposition || pacesetterFrameTarget.didMissHwcFrame()) {
if (FlagManager::getInstance().vrr_config()) {
mScheduler->getVsyncSchedule()->getTracker().onFrameMissed(
@@ -2921,6 +2921,9 @@
// Now that the current frame has been presented above, PowerAdvisor needs the present time
// of the previous frame (whose fence is signaled by now) to determine how long the HWC had
// waited on that fence to retire before presenting.
+ // TODO(b/355238809) `presentFenceForPreviousFrame` might not always be signaled (e.g. on
+ // devices
+ // where HWC does not block on the previous present fence). Revise this assumtion.
const auto& previousPresentFence = pacesetterTarget.presentFenceForPreviousFrame();
mPowerAdvisor->setSfPresentTiming(TimePoint::fromNs(previousPresentFence->getSignalTime()),
diff --git a/services/surfaceflinger/Utils/RingBuffer.h b/services/surfaceflinger/Utils/RingBuffer.h
index 198e7b2..215472b 100644
--- a/services/surfaceflinger/Utils/RingBuffer.h
+++ b/services/surfaceflinger/Utils/RingBuffer.h
@@ -43,8 +43,10 @@
}
T& front() { return (*this)[0]; }
+ const T& front() const { return (*this)[0]; }
T& back() { return (*this)[size() - 1]; }
+ const T& back() const { return (*this)[size() - 1]; }
T& operator[](size_t index) {
return mBuffer[(static_cast<size_t>(mHead + 1) + index) % mCount];