[SF] Updates to not send hints without a present being followed
Updates the hint to be sent through a frame scheduling.
Reduce the number of callbacks to notifyExpectedPresentIfRequired
by making calls only through EventThread.
Timeout hint is sent directly without scheduling a frame
to avoid delay in sending the hint.
A hint through setTransactionState for ScheduleOnTx will
be in a follow up CL
BUG: 316615878
Test: atest NotifyExpectedPresentTest
Change-Id: I60f555d69626656901951808353f4a632e9b5e71
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index c80c8fd..ccd1c0f 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -404,6 +404,9 @@
}();
generateFrameTimeline(vsyncEventData, frameInterval.ns(), systemTime(SYSTEM_TIME_MONOTONIC),
presentTime, deadline);
+ if (FlagManager::getInstance().vrr_config()) {
+ mCallback.onExpectedPresentTimePosted(TimePoint::fromNs(presentTime));
+ }
return vsyncEventData;
}
@@ -721,6 +724,11 @@
removeDisplayEventConnectionLocked(consumer);
}
}
+ if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC &&
+ FlagManager::getInstance().vrr_config()) {
+ mCallback.onExpectedPresentTimePosted(
+ TimePoint::fromNs(event.vsync.vsyncData.preferredExpectedPresentationTime()));
+ }
}
void EventThread::dump(std::string& result) const {
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 8970103..90e61a9 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -142,6 +142,7 @@
virtual bool throttleVsync(TimePoint, uid_t) = 0;
virtual Period getVsyncPeriod(uid_t) = 0;
virtual void resync() = 0;
+ virtual void onExpectedPresentTimePosted(TimePoint) = 0;
};
namespace impl {
diff --git a/services/surfaceflinger/Scheduler/ISchedulerCallback.h b/services/surfaceflinger/Scheduler/ISchedulerCallback.h
index 3b61de7..9f4f5b6 100644
--- a/services/surfaceflinger/Scheduler/ISchedulerCallback.h
+++ b/services/surfaceflinger/Scheduler/ISchedulerCallback.h
@@ -30,6 +30,8 @@
virtual void kernelTimerChanged(bool expired) = 0;
virtual void triggerOnFrameRateOverridesChanged() = 0;
virtual void onChoreographerAttached() = 0;
+ virtual void onExpectedPresentTimePosted(TimePoint, ftl::NonNull<DisplayModePtr>,
+ Fps renderRate) = 0;
protected:
~ISchedulerCallback() = default;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index fff97f7..ce47c8d 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -71,15 +71,13 @@
namespace android::scheduler {
Scheduler::Scheduler(ICompositor& compositor, ISchedulerCallback& callback, FeatureFlags features,
- surfaceflinger::Factory& factory, Fps activeRefreshRate, TimeStats& timeStats,
- IVsyncTrackerCallback& vsyncTrackerCallback)
+ surfaceflinger::Factory& factory, Fps activeRefreshRate, TimeStats& timeStats)
: android::impl::MessageQueue(compositor),
mFeatures(features),
mVsyncConfiguration(factory.createVsyncConfiguration(activeRefreshRate)),
mVsyncModulator(sp<VsyncModulator>::make(mVsyncConfiguration->getCurrentConfigs())),
mRefreshRateStats(std::make_unique<RefreshRateStats>(timeStats, activeRefreshRate)),
- mSchedulerCallback(callback),
- mVsyncTrackerCallback(vsyncTrackerCallback) {}
+ mSchedulerCallback(callback) {}
Scheduler::~Scheduler() {
// MessageQueue depends on VsyncSchedule, so first destroy it.
@@ -134,10 +132,11 @@
}
void Scheduler::registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr) {
- auto schedulePtr = std::make_shared<VsyncSchedule>(
- selectorPtr->getActiveMode().modePtr, mFeatures,
- [this](PhysicalDisplayId id, bool enable) { onHardwareVsyncRequest(id, enable); },
- mVsyncTrackerCallback);
+ auto schedulePtr =
+ std::make_shared<VsyncSchedule>(selectorPtr->getActiveMode().modePtr, mFeatures,
+ [this](PhysicalDisplayId id, bool enable) {
+ onHardwareVsyncRequest(id, enable);
+ });
registerDisplayInternal(displayId, std::move(selectorPtr), std::move(schedulePtr));
}
@@ -222,7 +221,12 @@
targets.try_emplace(id, &targeter.target());
}
- if (!compositor.commit(pacesetterPtr->displayId, targets)) return;
+ if (!compositor.commit(pacesetterPtr->displayId, targets)) {
+ if (FlagManager::getInstance().vrr_config()) {
+ compositor.sendNotifyExpectedPresentHint(pacesetterPtr->displayId);
+ }
+ return;
+ }
}
// The pacesetter may have changed or been registered anew during commit.
@@ -263,6 +267,9 @@
}
const auto resultsPerDisplay = compositor.composite(pacesetterPtr->displayId, targeters);
+ if (FlagManager::getInstance().vrr_config()) {
+ compositor.sendNotifyExpectedPresentHint(pacesetterPtr->displayId);
+ }
compositor.sample();
for (const auto& [id, targeter] : targeters) {
@@ -323,6 +330,19 @@
// behaviour.
return Period::fromNs(currentPeriod.ns() * divisor);
}
+void Scheduler::onExpectedPresentTimePosted(TimePoint expectedPresentTime) {
+ const auto frameRateMode = [this] {
+ std::scoped_lock lock(mDisplayLock);
+ const auto pacesetterOpt = pacesetterDisplayLocked();
+ const Display& pacesetter = *pacesetterOpt;
+ return pacesetter.selectorPtr->getActiveMode();
+ }();
+
+ if (frameRateMode.modePtr->getVrrConfig()) {
+ mSchedulerCallback.onExpectedPresentTimePosted(expectedPresentTime, frameRateMode.modePtr,
+ frameRateMode.fps);
+ }
+}
ConnectionHandle Scheduler::createEventThread(Cycle cycle,
frametimeline::TokenManager* tokenManager,
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 9912622..9f29e9f 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -111,7 +111,7 @@
public:
Scheduler(ICompositor&, ISchedulerCallback&, FeatureFlags, surfaceflinger::Factory&,
- Fps activeRefreshRate, TimeStats&, IVsyncTrackerCallback&);
+ Fps activeRefreshRate, TimeStats&);
virtual ~Scheduler();
void startTimers();
@@ -458,6 +458,7 @@
bool throttleVsync(TimePoint, uid_t) override;
Period getVsyncPeriod(uid_t) override EXCLUDES(mDisplayLock);
void resync() override EXCLUDES(mDisplayLock);
+ void onExpectedPresentTimePosted(TimePoint expectedPresentTime) override EXCLUDES(mDisplayLock);
// Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection.
struct Connection {
@@ -497,8 +498,6 @@
ISchedulerCallback& mSchedulerCallback;
- IVsyncTrackerCallback& mVsyncTrackerCallback;
-
// mDisplayLock may be locked while under mPolicyLock.
mutable std::mutex mPolicyLock;
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 6e12b33..8697696 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -48,14 +48,12 @@
VSyncPredictor::~VSyncPredictor() = default;
VSyncPredictor::VSyncPredictor(ftl::NonNull<DisplayModePtr> modePtr, size_t historySize,
- size_t minimumSamplesForPrediction, uint32_t outlierTolerancePercent,
- IVsyncTrackerCallback& callback)
+ size_t minimumSamplesForPrediction, uint32_t outlierTolerancePercent)
: mId(modePtr->getPhysicalDisplayId()),
mTraceOn(property_get_bool("debug.sf.vsp_trace", false)),
kHistorySize(historySize),
kMinimumSamplesForPrediction(minimumSamplesForPrediction),
kOutlierTolerancePercent(std::min(outlierTolerancePercent, kMaxPercent)),
- mVsyncTrackerCallback(callback),
mDisplayModePtr(modePtr) {
resetModel();
}
@@ -312,13 +310,7 @@
FlagManager::getInstance().vrr_config() && !lastFrameMissed && lastVsyncOpt
? std::max(timePoint, *lastVsyncOpt + minFramePeriod - threshold)
: timePoint;
- const auto vsyncTime = snapToVsyncAlignedWithRenderRate(baseTime);
- if (FlagManager::getInstance().vrr_config() && mDisplayModePtr->getVrrConfig()) {
- const auto vsyncTimePoint = TimePoint::fromNs(vsyncTime);
- const Fps renderRate = mRenderRateOpt ? *mRenderRateOpt : mDisplayModePtr->getPeakFps();
- mVsyncTrackerCallback.onVsyncGenerated(vsyncTimePoint, mDisplayModePtr, renderRate);
- }
- return vsyncTime;
+ return snapToVsyncAlignedWithRenderRate(baseTime);
}
nsecs_t VSyncPredictor::snapToVsyncAlignedWithRenderRate(nsecs_t timePoint) const {
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h
index 9191003..8fd7e60 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.h
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h
@@ -37,11 +37,9 @@
* \param [in] minimumSamplesForPrediction The minimum number of samples to collect before
* predicting. \param [in] outlierTolerancePercent a number 0 to 100 that will be used to filter
* samples that fall outlierTolerancePercent from an anticipated vsync event.
- * \param [in] IVsyncTrackerCallback The callback for the VSyncTracker.
*/
VSyncPredictor(ftl::NonNull<DisplayModePtr> modePtr, size_t historySize,
- size_t minimumSamplesForPrediction, uint32_t outlierTolerancePercent,
- IVsyncTrackerCallback&);
+ size_t minimumSamplesForPrediction, uint32_t outlierTolerancePercent);
~VSyncPredictor();
bool addVsyncTimestamp(nsecs_t timestamp) final EXCLUDES(mMutex);
@@ -106,7 +104,6 @@
size_t const kHistorySize;
size_t const kMinimumSamplesForPrediction;
size_t const kOutlierTolerancePercent;
- IVsyncTrackerCallback& mVsyncTrackerCallback;
std::mutex mutable mMutex;
std::optional<nsecs_t> mKnownTimestamp GUARDED_BY(mMutex);
diff --git a/services/surfaceflinger/Scheduler/VSyncTracker.h b/services/surfaceflinger/Scheduler/VSyncTracker.h
index 417163f..37bd4b4 100644
--- a/services/surfaceflinger/Scheduler/VSyncTracker.h
+++ b/services/surfaceflinger/Scheduler/VSyncTracker.h
@@ -26,12 +26,6 @@
namespace android::scheduler {
-struct IVsyncTrackerCallback {
- virtual ~IVsyncTrackerCallback() = default;
- virtual void onVsyncGenerated(TimePoint expectedPresentTime, ftl::NonNull<DisplayModePtr>,
- Fps renderRate) = 0;
-};
-
/*
* VSyncTracker is an interface for providing estimates on future Vsync signal times based on
* historical vsync timing data.
diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp
index db6a187..1eeccd3 100644
--- a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp
+++ b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp
@@ -57,11 +57,10 @@
};
VsyncSchedule::VsyncSchedule(ftl::NonNull<DisplayModePtr> modePtr, FeatureFlags features,
- RequestHardwareVsync requestHardwareVsync,
- IVsyncTrackerCallback& callback)
+ RequestHardwareVsync requestHardwareVsync)
: mId(modePtr->getPhysicalDisplayId()),
mRequestHardwareVsync(std::move(requestHardwareVsync)),
- mTracker(createTracker(modePtr, callback)),
+ mTracker(createTracker(modePtr)),
mDispatch(createDispatch(mTracker)),
mController(createController(modePtr->getPhysicalDisplayId(), *mTracker, features)),
mTracer(features.test(Feature::kTracePredictedVsync)
@@ -111,15 +110,14 @@
mDispatch->dump(out);
}
-VsyncSchedule::TrackerPtr VsyncSchedule::createTracker(ftl::NonNull<DisplayModePtr> modePtr,
- IVsyncTrackerCallback& callback) {
+VsyncSchedule::TrackerPtr VsyncSchedule::createTracker(ftl::NonNull<DisplayModePtr> modePtr) {
// TODO(b/144707443): Tune constants.
constexpr size_t kHistorySize = 20;
constexpr size_t kMinSamplesForPrediction = 6;
constexpr uint32_t kDiscardOutlierPercent = 20;
return std::make_unique<VSyncPredictor>(modePtr, kHistorySize, kMinSamplesForPrediction,
- kDiscardOutlierPercent, callback);
+ kDiscardOutlierPercent);
}
VsyncSchedule::DispatchPtr VsyncSchedule::createDispatch(TrackerPtr tracker) {
diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.h b/services/surfaceflinger/Scheduler/VsyncSchedule.h
index 722ea0b..4ff4cdf 100644
--- a/services/surfaceflinger/Scheduler/VsyncSchedule.h
+++ b/services/surfaceflinger/Scheduler/VsyncSchedule.h
@@ -57,8 +57,7 @@
public:
using RequestHardwareVsync = std::function<void(PhysicalDisplayId, bool enabled)>;
- VsyncSchedule(ftl::NonNull<DisplayModePtr> modePtr, FeatureFlags, RequestHardwareVsync,
- IVsyncTrackerCallback&);
+ VsyncSchedule(ftl::NonNull<DisplayModePtr> modePtr, FeatureFlags, RequestHardwareVsync);
~VsyncSchedule();
// IVsyncSource overrides:
@@ -127,7 +126,7 @@
friend class android::VsyncScheduleTest;
friend class android::fuzz::SchedulerFuzzer;
- static TrackerPtr createTracker(ftl::NonNull<DisplayModePtr> modePtr, IVsyncTrackerCallback&);
+ static TrackerPtr createTracker(ftl::NonNull<DisplayModePtr> modePtr);
static DispatchPtr createDispatch(TrackerPtr);
static ControllerPtr createController(PhysicalDisplayId, VsyncTracker&, FeatureFlags);
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h b/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h
index 12ee36e..8673a22 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h
@@ -47,6 +47,9 @@
virtual CompositeResultsPerDisplay composite(PhysicalDisplayId pacesetterId,
const scheduler::FrameTargeters&) = 0;
+ // Sends a hint about the expected present time
+ virtual void sendNotifyExpectedPresentHint(PhysicalDisplayId) = 0;
+
// Samples the composited frame via RegionSamplingThread.
virtual void sample() = 0;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 0c640aa..02f8309 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2750,23 +2750,11 @@
refreshArgs.devOptFlashDirtyRegionsDelay = std::chrono::milliseconds(mDebugFlashDelay);
}
- const TimePoint expectedPresentTime = pacesetterTarget.expectedPresentTime();
// TODO(b/255601557) Update frameInterval per display
- refreshArgs.frameInterval = mScheduler->getNextFrameInterval(pacesetterId, expectedPresentTime);
+ refreshArgs.frameInterval =
+ mScheduler->getNextFrameInterval(pacesetterId, pacesetterTarget.expectedPresentTime());
refreshArgs.scheduledFrameTime = mScheduler->getScheduledFrameTime();
refreshArgs.hasTrustedPresentationListener = mNumTrustedPresentationListeners > 0;
- {
- auto& notifyExpectedPresentData = mNotifyExpectedPresentMap[pacesetterId];
- auto lastExpectedPresentTimestamp = TimePoint::fromNs(
- notifyExpectedPresentData.lastExpectedPresentTimestamp.load().ns());
- if (expectedPresentTime > lastExpectedPresentTimestamp) {
- // If the values are not same, then hint is sent with newer value.
- // And because composition always follows the notifyExpectedPresentIfRequired, we can
- // skip updating the lastExpectedPresentTimestamp in this case.
- notifyExpectedPresentData.lastExpectedPresentTimestamp
- .compare_exchange_weak(lastExpectedPresentTimestamp, expectedPresentTime);
- }
- }
// Store the present time just before calling to the composition engine so we could notify
// the scheduler.
const auto presentTime = systemTime();
@@ -2830,6 +2818,7 @@
scheduleComposite(FrameHint::kNone);
}
+ mNotifyExpectedPresentMap[pacesetterId].hintStatus = NotifyExpectedPresentHintStatus::Start;
onCompositionPresented(pacesetterId, frameTargeters, presentTime);
const bool hadGpuComposited =
@@ -4110,8 +4099,9 @@
}
}
-void SurfaceFlinger::onVsyncGenerated(TimePoint expectedPresentTime,
- ftl::NonNull<DisplayModePtr> modePtr, Fps renderRate) {
+void SurfaceFlinger::onExpectedPresentTimePosted(TimePoint expectedPresentTime,
+ ftl::NonNull<DisplayModePtr> modePtr,
+ Fps renderRate) {
const auto vsyncPeriod = modePtr->getVsyncRate().getPeriod();
const auto timeoutOpt = [&]() -> std::optional<Period> {
const auto vrrConfig = modePtr->getVrrConfig();
@@ -4132,45 +4122,91 @@
TimePoint expectedPresentTime,
Fps frameInterval,
std::optional<Period> timeoutOpt) {
- {
- auto& data = mNotifyExpectedPresentMap[displayId];
- const auto lastExpectedPresentTimestamp = data.lastExpectedPresentTimestamp.load();
- const auto lastFrameInterval = data.lastFrameInterval;
- data.lastFrameInterval = frameInterval;
- const auto threshold = Duration::fromNs(vsyncPeriod.ns() / 2);
+ auto& data = mNotifyExpectedPresentMap[displayId];
+ const auto lastExpectedPresentTimestamp = data.lastExpectedPresentTimestamp;
+ const auto lastFrameInterval = data.lastFrameInterval;
+ data.lastFrameInterval = frameInterval;
+ data.lastExpectedPresentTimestamp = expectedPresentTime;
+ const auto threshold = Duration::fromNs(vsyncPeriod.ns() / 2);
- const constexpr nsecs_t kOneSecondNs =
- std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count();
- const auto timeout = Period::fromNs(timeoutOpt && timeoutOpt->ns() > 0 ? timeoutOpt->ns()
- : kOneSecondNs);
- const bool frameIntervalIsOnCadence =
- isFrameIntervalOnCadence(expectedPresentTime, lastExpectedPresentTimestamp,
- lastFrameInterval, timeout, threshold);
+ const constexpr nsecs_t kOneSecondNs =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count();
+ const auto timeout =
+ Period::fromNs(timeoutOpt && timeoutOpt->ns() > 0 ? timeoutOpt->ns() : kOneSecondNs);
+ const bool frameIntervalIsOnCadence =
+ isFrameIntervalOnCadence(expectedPresentTime, lastExpectedPresentTimestamp,
+ lastFrameInterval, timeout, threshold);
- const bool expectedPresentWithinTimeout =
- isExpectedPresentWithinTimeout(expectedPresentTime, lastExpectedPresentTimestamp,
- timeoutOpt, threshold);
+ const bool expectedPresentWithinTimeout =
+ isExpectedPresentWithinTimeout(expectedPresentTime, lastExpectedPresentTimestamp,
+ timeoutOpt, threshold);
+ if (expectedPresentWithinTimeout && frameIntervalIsOnCadence) {
+ return;
+ }
- using fps_approx_ops::operator!=;
- if (frameIntervalIsOnCadence && frameInterval != lastFrameInterval) {
- data.lastExpectedPresentTimestamp = expectedPresentTime;
- }
-
- if (expectedPresentWithinTimeout && frameIntervalIsOnCadence) {
+ auto hintStatus = data.hintStatus.load();
+ if (!expectedPresentWithinTimeout) {
+ if (hintStatus != NotifyExpectedPresentHintStatus::Sent ||
+ (timeoutOpt && timeoutOpt->ns() == 0)) {
+ // Send the hint immediately if timeout, as the hint gets
+ // delayed otherwise, as the frame is scheduled close
+ // to the actual present.
+ if (data.hintStatus
+ .compare_exchange_strong(hintStatus,
+ NotifyExpectedPresentHintStatus::ScheduleOnTx)) {
+ scheduleNotifyExpectedPresentHint(displayId);
+ }
return;
}
- data.lastExpectedPresentTimestamp = expectedPresentTime;
+ }
+
+ if (hintStatus != NotifyExpectedPresentHintStatus::Start) {
+ return;
+ }
+ data.hintStatus.store(NotifyExpectedPresentHintStatus::ScheduleOnPresent);
+ mScheduler->scheduleFrame();
+}
+
+void SurfaceFlinger::scheduleNotifyExpectedPresentHint(PhysicalDisplayId displayId) {
+ auto itr = mNotifyExpectedPresentMap.find(displayId);
+ if (itr == mNotifyExpectedPresentMap.end()) {
+ return;
}
const char* const whence = __func__;
- static_cast<void>(mScheduler->schedule([=, this]() FTL_FAKE_GUARD(kMainThreadContext) {
- const auto status = getHwComposer().notifyExpectedPresent(displayId, expectedPresentTime,
- frameInterval);
+ const auto sendHint = [=, this]() {
+ auto& data = mNotifyExpectedPresentMap.at(displayId);
+ data.hintStatus.store(NotifyExpectedPresentHintStatus::Sent);
+ const auto status =
+ getHwComposer().notifyExpectedPresent(displayId, data.lastExpectedPresentTimestamp,
+ data.lastFrameInterval);
if (status != NO_ERROR) {
ALOGE("%s failed to notifyExpectedPresentHint for display %" PRId64, whence,
displayId.value);
}
- }));
+ };
+
+ if (itr->second.hintStatus == NotifyExpectedPresentHintStatus::ScheduleOnTx) {
+ return static_cast<void>(mScheduler->schedule([=,
+ this]() FTL_FAKE_GUARD(kMainThreadContext) {
+ auto& data = mNotifyExpectedPresentMap.at(displayId);
+ auto scheduleHintOnTx = NotifyExpectedPresentHintStatus::ScheduleOnTx;
+ if (data.hintStatus.compare_exchange_strong(scheduleHintOnTx,
+ NotifyExpectedPresentHintStatus::Sent)) {
+ sendHint();
+ }
+ }));
+ }
+ sendHint();
+}
+
+void SurfaceFlinger::sendNotifyExpectedPresentHint(PhysicalDisplayId displayId) {
+ if (auto itr = mNotifyExpectedPresentMap.find(displayId);
+ itr == mNotifyExpectedPresentMap.end() ||
+ itr->second.hintStatus != NotifyExpectedPresentHintStatus::ScheduleOnPresent) {
+ return;
+ }
+ scheduleNotifyExpectedPresentHint(displayId);
}
void SurfaceFlinger::initScheduler(const sp<const DisplayDevice>& display) {
@@ -4212,8 +4248,7 @@
mScheduler = std::make_unique<Scheduler>(static_cast<ICompositor&>(*this),
static_cast<ISchedulerCallback&>(*this), features,
- getFactory(), activeRefreshRate, *mTimeStats,
- static_cast<IVsyncTrackerCallback&>(*this));
+ getFactory(), activeRefreshRate, *mTimeStats);
mScheduler->registerDisplay(display->getPhysicalId(), display->holdRefreshRateSelector());
if (FlagManager::getInstance().vrr_config()) {
mScheduler->setRenderRate(display->getPhysicalId(), activeMode.fps);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 6e12172..d536597 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -199,8 +199,7 @@
private HWC2::ComposerCallback,
private ICompositor,
private scheduler::ISchedulerCallback,
- private compositionengine::ICEPowerCallback,
- private scheduler::IVsyncTrackerCallback {
+ private compositionengine::ICEPowerCallback {
public:
struct SkipInitializationTag {};
@@ -685,14 +684,12 @@
void kernelTimerChanged(bool expired) override;
void triggerOnFrameRateOverridesChanged() override;
void onChoreographerAttached() override;
+ void onExpectedPresentTimePosted(TimePoint expectedPresentTime, ftl::NonNull<DisplayModePtr>,
+ Fps renderRate) override;
// ICEPowerCallback overrides:
void notifyCpuLoadUp() override;
- // IVsyncTrackerCallback overrides
- void onVsyncGenerated(TimePoint expectedPresentTime, ftl::NonNull<DisplayModePtr>,
- Fps renderRate) override;
-
// Toggles the kernel idle timer on or off depending the policy decisions around refresh rates.
void toggleKernelIdleTimer() REQUIRES(mStateLock);
@@ -1480,14 +1477,28 @@
ftl::SmallMap<int64_t, sp<SurfaceControl>, 3> mMirrorMapForDebug;
// NotifyExpectedPresentHint
+ enum class NotifyExpectedPresentHintStatus {
+ // Represents that framework can start sending hint if required.
+ Start,
+ // Represents that the hint is already sent.
+ Sent,
+ // Represents that the hint will be scheduled with a new frame.
+ ScheduleOnPresent,
+ // Represents that a hint will be sent instantly by scheduling on the main thread.
+ ScheduleOnTx
+ };
struct NotifyExpectedPresentData {
- // lastExpectedPresentTimestamp is read and write from multiple threads such as
- // main thread, EventThread, MessageQueue. And is atomic for that reason.
- std::atomic<TimePoint> lastExpectedPresentTimestamp{};
+ TimePoint lastExpectedPresentTimestamp{};
Fps lastFrameInterval{};
+ // hintStatus is read and write from multiple threads such as
+ // main thread, EventThread. And is atomic for that reason.
+ std::atomic<NotifyExpectedPresentHintStatus> hintStatus =
+ NotifyExpectedPresentHintStatus::Start;
};
std::unordered_map<PhysicalDisplayId, NotifyExpectedPresentData> mNotifyExpectedPresentMap;
-
+ void sendNotifyExpectedPresentHint(PhysicalDisplayId displayId) override
+ REQUIRES(kMainThreadContext);
+ void scheduleNotifyExpectedPresentHint(PhysicalDisplayId displayId);
void notifyExpectedPresentIfRequired(PhysicalDisplayId, Period vsyncPeriod,
TimePoint expectedPresentTime, Fps frameInterval,
std::optional<Period> timeoutOpt);
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index fa79956..0d15f62 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -228,9 +228,9 @@
VsyncSchedule::TrackerPtr tracker,
std::shared_ptr<RefreshRateSelector> selectorPtr,
surfaceflinger::Factory& factory, TimeStats& timeStats,
- ISchedulerCallback& callback, IVsyncTrackerCallback& vsyncTrackerCallback)
+ ISchedulerCallback& callback)
: Scheduler(*this, callback, Feature::kContentDetection, factory,
- selectorPtr->getActiveMode().fps, timeStats, vsyncTrackerCallback) {
+ selectorPtr->getActiveMode().fps, timeStats) {
const auto displayId = selectorPtr->getActiveMode().modePtr->getPhysicalDisplayId();
registerDisplayInternal(displayId, std::move(selectorPtr),
std::shared_ptr<VsyncSchedule>(
@@ -289,6 +289,8 @@
}
void sample() override {}
+ void sendNotifyExpectedPresentHint(PhysicalDisplayId) override {}
+
// MessageQueue overrides:
void scheduleFrame() override {}
void postMessage(sp<MessageHandler>&& handler) override { handler->handleMessage(Message()); }
@@ -396,8 +398,7 @@
} // namespace surfaceflinger::test
// TODO(b/189053744) : Create a common test/mock library for surfaceflinger
-class TestableSurfaceFlinger final : private scheduler::ISchedulerCallback,
- private scheduler::IVsyncTrackerCallback {
+class TestableSurfaceFlinger final : private scheduler::ISchedulerCallback {
public:
using HotplugEvent = SurfaceFlinger::HotplugEvent;
@@ -660,7 +661,6 @@
std::unique_ptr<EventThread> appEventThread,
std::unique_ptr<EventThread> sfEventThread,
scheduler::ISchedulerCallback* callback = nullptr,
- scheduler::IVsyncTrackerCallback* vsyncTrackerCallback = nullptr,
bool hasMultipleModes = false) {
constexpr DisplayModeId kModeId60{0};
DisplayModes modes = makeModes(mock::createDisplayMode(kModeId60, 60_Hz));
@@ -675,8 +675,7 @@
mScheduler = new scheduler::TestableScheduler(std::move(vsyncController),
std::move(vsyncTracker), mRefreshRateSelector,
mFactory, *mFlinger->mTimeStats,
- *(callback ?: this),
- *(vsyncTrackerCallback ?: this));
+ *(callback ?: this));
mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread));
mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread));
@@ -796,9 +795,7 @@
void kernelTimerChanged(bool) override {}
void triggerOnFrameRateOverridesChanged() override {}
void onChoreographerAttached() override {}
-
- // IVsyncTrackerCallback overrides
- void onVsyncGenerated(TimePoint, ftl::NonNull<DisplayModePtr>, Fps) override {}
+ void onExpectedPresentTimePosted(TimePoint, ftl::NonNull<DisplayModePtr>, Fps) override {}
surfaceflinger::test::Factory mFactory;
sp<SurfaceFlinger> mFlinger =
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index c098dda..76d4207 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -103,6 +103,7 @@
bool throttleVsync(TimePoint, uid_t) override { return false; }
Period getVsyncPeriod(uid_t) override { return kSyncPeriod; }
void resync() override {}
+ void onExpectedPresentTimePosted(TimePoint) override {}
};
void SchedulerFuzzer::fuzzEventThread() {
@@ -180,21 +181,15 @@
dump<scheduler::VSyncDispatchTimerQueueEntry>(&entry, &mFdp);
}
-struct VsyncTrackerCallback : public scheduler::IVsyncTrackerCallback {
- void onVsyncGenerated(TimePoint, ftl::NonNull<DisplayModePtr>, Fps) override {}
-};
-
void SchedulerFuzzer::fuzzVSyncPredictor() {
uint16_t now = mFdp.ConsumeIntegral<uint16_t>();
uint16_t historySize = mFdp.ConsumeIntegralInRange<uint16_t>(1, UINT16_MAX);
uint16_t minimumSamplesForPrediction = mFdp.ConsumeIntegralInRange<uint16_t>(1, UINT16_MAX);
nsecs_t idealPeriod = mFdp.ConsumeIntegralInRange<nsecs_t>(1, UINT32_MAX);
- VsyncTrackerCallback callback;
const auto mode = ftl::as_non_null(
mock::createDisplayMode(DisplayModeId(0), Fps::fromPeriodNsecs(idealPeriod)));
scheduler::VSyncPredictor tracker{mode, historySize, minimumSamplesForPrediction,
- mFdp.ConsumeIntegral<uint32_t>() /*outlierTolerancePercent*/,
- callback};
+ mFdp.ConsumeIntegral<uint32_t>() /*outlierTolerancePercent*/};
uint16_t period = mFdp.ConsumeIntegral<uint16_t>();
tracker.setDisplayModePtr(ftl::as_non_null(
mock::createDisplayMode(DisplayModeId(0), Fps::fromPeriodNsecs(period))));
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 1379665..fa31643 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -80,8 +80,7 @@
std::unique_ptr<EventThread>(mEventThread),
std::unique_ptr<EventThread>(mSFEventThread),
TestableSurfaceFlinger::DefaultDisplayMode{displayId},
- TestableSurfaceFlinger::SchedulerCallbackImpl::kMock,
- TestableSurfaceFlinger::VsyncTrackerCallbackImpl::kMock);
+ TestableSurfaceFlinger::SchedulerCallbackImpl::kMock);
}
void DisplayTransactionTest::injectMockComposer(int virtualDisplayCount) {
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 45db0c5..d5ec654 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -85,6 +85,7 @@
bool throttleVsync(TimePoint, uid_t) override;
Period getVsyncPeriod(uid_t) override;
void resync() override;
+ void onExpectedPresentTimePosted(TimePoint) override;
void setupEventThread();
sp<MockEventThreadConnection> createConnection(ConnectionEventRecorder& recorder,
@@ -107,6 +108,7 @@
int32_t expectedConfigId,
nsecs_t expectedVsyncPeriod);
void expectThrottleVsyncReceived(nsecs_t expectedTimestamp, uid_t);
+ void expectOnExpectedPresentTimePosted(nsecs_t expectedPresentTime);
void expectUidFrameRateMappingEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
std::vector<FrameRateOverride>);
@@ -131,6 +133,7 @@
mVSyncCallbackUnregisterRecorder;
AsyncCallRecorder<void (*)()> mResyncCallRecorder;
AsyncCallRecorder<void (*)(nsecs_t, uid_t)> mThrottleVsyncCallRecorder;
+ AsyncCallRecorder<void (*)(nsecs_t)> mOnExpectedPresentTimePostedRecorder;
ConnectionEventRecorder mConnectionEventCallRecorder{0};
ConnectionEventRecorder mThrottledConnectionEventCallRecorder{0};
@@ -190,6 +193,10 @@
mResyncCallRecorder.recordCall();
}
+void EventThreadTest::onExpectedPresentTimePosted(TimePoint expectedPresentTime) {
+ mOnExpectedPresentTimePostedRecorder.recordCall(expectedPresentTime.ns());
+}
+
void EventThreadTest::setupEventThread() {
mTokenManager = std::make_unique<frametimeline::impl::TokenManager>();
mThread = std::make_unique<impl::EventThread>("EventThreadTest", mVsyncSchedule,
@@ -244,6 +251,12 @@
EXPECT_EQ(uid, std::get<1>(args.value()));
}
+void EventThreadTest::expectOnExpectedPresentTimePosted(nsecs_t expectedPresentTime) {
+ auto args = mOnExpectedPresentTimePostedRecorder.waitForCall();
+ ASSERT_TRUE(args.has_value());
+ EXPECT_EQ(expectedPresentTime, std::get<0>(args.value()));
+}
+
void EventThreadTest::expectVsyncEventReceivedByConnection(
const char* name, ConnectionEventRecorder& connectionEventRecorder,
nsecs_t expectedTimestamp, unsigned expectedCount) {
@@ -410,6 +423,7 @@
onVSyncEvent(123, 456, 789);
expectThrottleVsyncReceived(456, mConnectionUid);
expectVsyncEventReceivedByConnection(123, 1u);
+ expectOnExpectedPresentTimePosted(456);
// EventThread is requesting one more callback due to VsyncRequest::SingleSuppressCallback
expectVSyncCallbackScheduleReceived(true);
@@ -562,16 +576,19 @@
onVSyncEvent(123, 456, 789);
expectThrottleVsyncReceived(456, mConnectionUid);
expectVsyncEventReceivedByConnection(123, 1u);
+ expectOnExpectedPresentTimePosted(456);
// A second event should go to the same places.
onVSyncEvent(456, 123, 0);
expectThrottleVsyncReceived(123, mConnectionUid);
expectVsyncEventReceivedByConnection(456, 2u);
+ expectOnExpectedPresentTimePosted(123);
// A third event should go to the same places.
onVSyncEvent(789, 777, 111);
expectThrottleVsyncReceived(777, mConnectionUid);
expectVsyncEventReceivedByConnection(789, 3u);
+ expectOnExpectedPresentTimePosted(777);
}
TEST_F(EventThreadTest, setVsyncRateTwoPostsEveryOtherEventToThatConnection) {
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
index 734fddb..01762c1 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
@@ -165,12 +165,8 @@
DisplayModeId(0));
mock::SchedulerCallback mSchedulerCallback;
- mock::VsyncTrackerCallback mVsyncTrackerCallback;
-
TestableSurfaceFlinger mFlinger;
-
- TestableScheduler* mScheduler =
- new TestableScheduler(mSelector, mFlinger, mSchedulerCallback, mVsyncTrackerCallback);
+ TestableScheduler* mScheduler = new TestableScheduler(mSelector, mFlinger, mSchedulerCallback);
};
namespace {
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index 9456e37..bc06a31 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -146,11 +146,8 @@
DisplayModeId(0));
mock::SchedulerCallback mSchedulerCallback;
-
- mock::VsyncTrackerCallback mVsyncTrackerCallback;
TestableSurfaceFlinger mFlinger;
- TestableScheduler* mScheduler =
- new TestableScheduler(mSelector, mFlinger, mSchedulerCallback, mVsyncTrackerCallback);
+ TestableScheduler* mScheduler = new TestableScheduler(mSelector, mFlinger, mSchedulerCallback);
};
namespace {
diff --git a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
index 22cfbd8..9fe9ee8 100644
--- a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
@@ -64,10 +64,8 @@
HI_FPS)),
DisplayModeId(0));
mock::SchedulerCallback mSchedulerCallback;
- mock::VsyncTrackerCallback mVsyncTrackerCallback;
TestableSurfaceFlinger mFlinger;
- TestableScheduler* mScheduler =
- new TestableScheduler(mSelector, mFlinger, mSchedulerCallback, mVsyncTrackerCallback);
+ TestableScheduler* mScheduler = new TestableScheduler(mSelector, mFlinger, mSchedulerCallback);
};
namespace {
diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
index 249ed40..f5661fc 100644
--- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
@@ -41,6 +41,7 @@
return {};
}
void sample() override {}
+ void sendNotifyExpectedPresentHint(PhysicalDisplayId) {}
} gNoOpCompositor;
class TestableMessageQueue : public impl::MessageQueue {
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 6986689..10c5848 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -95,10 +95,8 @@
kDisplay1Mode60->getId());
mock::SchedulerCallback mSchedulerCallback;
- mock::VsyncTrackerCallback mVsyncTrackerCallback;
TestableSurfaceFlinger mFlinger;
- TestableScheduler* mScheduler =
- new TestableScheduler{mSelector, mFlinger, mSchedulerCallback, mVsyncTrackerCallback};
+ TestableScheduler* mScheduler = new TestableScheduler{mSelector, mFlinger, mSchedulerCallback};
surfaceflinger::frontend::LayerHierarchyBuilder mLayerHierarchyBuilder;
ConnectionHandle mConnectionHandle;
@@ -516,6 +514,7 @@
}
void sample() override {}
+ void sendNotifyExpectedPresentHint(PhysicalDisplayId) override {}
} compositor(*mScheduler);
mScheduler->doFrameSignal(compositor, VsyncId(42));
@@ -568,7 +567,7 @@
frameRate.getPeriodNsecs())}));
std::shared_ptr<VSyncPredictor> vrrTracker =
std::make_shared<VSyncPredictor>(kMode, kHistorySize, kMinimumSamplesForPrediction,
- kOutlierTolerancePercent, mVsyncTrackerCallback);
+ kOutlierTolerancePercent);
std::shared_ptr<RefreshRateSelector> vrrSelectorPtr =
std::make_shared<RefreshRateSelector>(makeModes(kMode), kMode->getId());
TestableScheduler scheduler{std::make_unique<android::mock::VsyncController>(),
@@ -576,8 +575,7 @@
vrrSelectorPtr,
mFlinger.getFactory(),
mFlinger.getTimeStats(),
- mSchedulerCallback,
- mVsyncTrackerCallback};
+ mSchedulerCallback};
scheduler.registerDisplay(kMode->getPhysicalDisplayId(), vrrSelectorPtr, vrrTracker);
vrrSelectorPtr->setActiveMode(kMode->getId(), frameRate);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp
index 7206e29..91b9018 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp
@@ -17,31 +17,81 @@
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
+#include <gui/SurfaceComposerClient.h>
#include "DisplayTransactionTestHelpers.h"
namespace android {
using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+using android::hardware::graphics::composer::V2_1::Error;
class NotifyExpectedPresentTest : public DisplayTransactionTest {
public:
void SetUp() override {
- mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this).inject();
- FakeHwcDisplayInjector(mDisplay->getPhysicalId(), hal::DisplayType::PHYSICAL, kIsPrimary)
+ const auto display = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this).inject();
+ mPhysicalDisplayId = display->getPhysicalId();
+ FakeHwcDisplayInjector(mPhysicalDisplayId, hal::DisplayType::PHYSICAL, /*isPrimary=*/true)
.setPowerMode(hal::PowerMode::ON)
.inject(&mFlinger, mComposer);
+
+ ASSERT_NO_FATAL_FAILURE(mFlinger.setNotifyExpectedPresentData(mPhysicalDisplayId,
+ TimePoint::fromNs(0),
+ kFps60Hz));
+ mCompositor = std::make_unique<Compositor>(mPhysicalDisplayId, mFlinger);
}
protected:
- sp<DisplayDevice> mDisplay;
- static constexpr bool kIsPrimary = true;
- static constexpr hal::HWDisplayId HWC_DISPLAY_ID =
- FakeHwcDisplayInjector::DEFAULT_HWC_DISPLAY_ID;
-};
+ struct Compositor final : ICompositor {
+ explicit Compositor(PhysicalDisplayId displayId, TestableSurfaceFlinger& surfaceFlinger)
+ : displayId(displayId), surfaceFlinger(surfaceFlinger) {}
-TEST_F(NotifyExpectedPresentTest, notifyExpectedPresentTimeout) {
- const auto physicDisplayId = mDisplay->getPhysicalId();
- auto expectedPresentTime = systemTime() + ms2ns(10);
+ void sendNotifyExpectedPresentHint(PhysicalDisplayId id) override {
+ surfaceFlinger.sendNotifyExpectedPresentHint(id);
+ }
+
+ bool commit(PhysicalDisplayId, const scheduler::FrameTargets&) override {
+ return committed;
+ }
+
+ CompositeResultsPerDisplay composite(PhysicalDisplayId pacesetterId,
+ const scheduler::FrameTargeters& targeters) override {
+ pacesetterIds.composite = pacesetterId;
+ CompositeResultsPerDisplay results;
+
+ for (const auto& [id, targeter] : targeters) {
+ vsyncIds.composite.emplace_back(id, targeter->target().vsyncId());
+ surfaceFlinger.resetNotifyExpectedPresentHintState(pacesetterId);
+ results.try_emplace(id,
+ CompositeResult{.compositionCoverage =
+ CompositionCoverage::Hwc});
+ }
+
+ return results;
+ }
+
+ void sample() override {}
+ void configure() override {}
+
+ struct {
+ PhysicalDisplayId commit;
+ PhysicalDisplayId composite;
+ } pacesetterIds;
+
+ using VsyncIds = std::vector<std::pair<PhysicalDisplayId, VsyncId>>;
+ struct {
+ VsyncIds commit;
+ VsyncIds composite;
+ } vsyncIds;
+
+ bool committed = true;
+ PhysicalDisplayId displayId;
+ TestableSurfaceFlinger& surfaceFlinger;
+ };
+
+ PhysicalDisplayId mPhysicalDisplayId;
+ std::unique_ptr<Compositor> mCompositor;
+ static constexpr hal::HWDisplayId kHwcDisplayId =
+ FakeHwcDisplayInjector::DEFAULT_HWC_DISPLAY_ID;
static constexpr Fps kFps60Hz = 60_Hz;
static constexpr int32_t kFrameInterval5HzNs = static_cast<Fps>(5_Hz).getPeriodNsecs();
static constexpr int32_t kFrameInterval60HzNs = kFps60Hz.getPeriodNsecs();
@@ -49,89 +99,171 @@
static constexpr Period kVsyncPeriod =
Period::fromNs(static_cast<Fps>(240_Hz).getPeriodNsecs());
static constexpr Period kTimeoutNs = Period::fromNs(kFrameInterval5HzNs);
- static constexpr auto kLastExpectedPresentTimestamp = TimePoint::fromNs(0);
+};
- ASSERT_NO_FATAL_FAILURE(mFlinger.setNotifyExpectedPresentData(physicDisplayId,
- kLastExpectedPresentTimestamp,
- kFps60Hz));
-
- {
- // Very first ExpectedPresent after idle, no previous timestamp
- EXPECT_CALL(*mComposer,
- notifyExpectedPresent(HWC_DISPLAY_ID, expectedPresentTime,
- kFrameInterval60HzNs))
- .WillOnce(Return(Error::NONE));
- mFlinger.notifyExpectedPresentIfRequired(physicDisplayId, kVsyncPeriod,
- TimePoint::fromNs(expectedPresentTime), kFps60Hz,
- kTimeoutNs);
- }
- {
- // Absent timeoutNs
+TEST_F(NotifyExpectedPresentTest, noNotifyExpectedPresentHintCall_absentTimeout) {
+ auto expectedPresentTime = systemTime() + ms2ns(10);
+ ASSERT_NO_FATAL_FAILURE(
+ mFlinger.setNotifyExpectedPresentData(mPhysicalDisplayId,
+ TimePoint::fromNs(expectedPresentTime),
+ kFps60Hz));
+ EXPECT_CALL(*mComposer, notifyExpectedPresent(kHwcDisplayId, _, _)).Times(0);
+ for (int i = 0; i < 5; i++) {
expectedPresentTime += 2 * kFrameInterval5HzNs;
- EXPECT_CALL(*mComposer, notifyExpectedPresent(HWC_DISPLAY_ID, _, _)).Times(0);
- mFlinger.notifyExpectedPresentIfRequired(physicDisplayId, kVsyncPeriod,
+ mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
TimePoint::fromNs(expectedPresentTime), kFps60Hz,
/*timeoutOpt*/ std::nullopt);
+ EXPECT_TRUE(
+ mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
+ ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
}
+}
+
+TEST_F(NotifyExpectedPresentTest, notifyExpectedPresentHint_zeroTimeout) {
+ auto expectedPresentTime = systemTime() + ms2ns(10);
{
- // Timeout is 0
- expectedPresentTime += kFrameInterval60HzNs;
+ // Very first ExpectedPresent after idle, no previous timestamp.
EXPECT_CALL(*mComposer,
- notifyExpectedPresent(HWC_DISPLAY_ID, expectedPresentTime,
- kFrameInterval60HzNs))
+ notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs))
.WillOnce(Return(Error::NONE));
- mFlinger.notifyExpectedPresentIfRequired(physicDisplayId, kVsyncPeriod,
- TimePoint::fromNs(expectedPresentTime), kFps60Hz,
- Period::fromNs(0));
- }
- {
- // ExpectedPresent is after the timeoutNs
- expectedPresentTime += 2 * kFrameInterval5HzNs;
- EXPECT_CALL(*mComposer,
- notifyExpectedPresent(HWC_DISPLAY_ID, expectedPresentTime,
- kFrameInterval60HzNs))
- .WillOnce(Return(Error::NONE));
- mFlinger.notifyExpectedPresentIfRequired(physicDisplayId, kVsyncPeriod,
+ mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
TimePoint::fromNs(expectedPresentTime), kFps60Hz,
kTimeoutNs);
+ ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
+
+ // Present frame
+ mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
+ // Present happens and NotifyExpectedPresentHintStatus is start.
+ ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
+ }
+ {
+ mCompositor->committed = false;
+ expectedPresentTime += kFrameInterval60HzNs;
+ EXPECT_CALL(*mComposer,
+ notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs))
+ .WillOnce(Return(Error::NONE));
+ mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
+ TimePoint::fromNs(expectedPresentTime), kFps60Hz,
+ Period::fromNs(0));
+ EXPECT_TRUE(
+ mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
+ ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
+ mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
+ // Hint sent
+ ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
+ }
+ {
+ expectedPresentTime += kFrameInterval60HzNs;
+ EXPECT_CALL(*mComposer,
+ notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs))
+ .WillOnce(Return(Error::NONE));
+ mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
+ TimePoint::fromNs(expectedPresentTime), kFps60Hz,
+ Period::fromNs(0));
+ EXPECT_TRUE(
+ mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
+ // Hint is executed
+ ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
+ mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
+ ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
+ }
+}
+
+TEST_F(NotifyExpectedPresentTest, notifyExpectedPresentTimeout) {
+ auto expectedPresentTime = systemTime() + ms2ns(10);
+ {
+ // Very first ExpectedPresent after idle, no previous timestamp
+ mCompositor->committed = false;
+ EXPECT_CALL(*mComposer,
+ notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs))
+ .WillOnce(Return(Error::NONE));
+ mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
+ TimePoint::fromNs(expectedPresentTime), kFps60Hz,
+ kTimeoutNs);
+ ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
+ mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
+ ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
+ }
+ {
+ // ExpectedPresentTime is after the timeoutNs
+ mCompositor->committed = true;
+ expectedPresentTime += 2 * kFrameInterval5HzNs;
+ EXPECT_CALL(*mComposer, notifyExpectedPresent(kHwcDisplayId, _, _)).Times(0);
+ mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
+ TimePoint::fromNs(expectedPresentTime), kFps60Hz,
+ kTimeoutNs);
+ EXPECT_TRUE(
+ mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
+ ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
+ mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
+ // Present happens notifyExpectedPresentHintStatus is Start
+ ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
+
+ // Another expectedPresent after timeout
+ expectedPresentTime += 2 * kFrameInterval5HzNs;
+ EXPECT_CALL(*mComposer,
+ notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs))
+ .WillOnce(Return(Error::NONE));
+ mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
+ TimePoint::fromNs(expectedPresentTime), kFps60Hz,
+ kTimeoutNs);
+ EXPECT_TRUE(
+ mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
+ ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
+ mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
+ ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
}
{
// ExpectedPresent has not changed
- EXPECT_CALL(*mComposer, notifyExpectedPresent(HWC_DISPLAY_ID, _, _)).Times(0);
- mFlinger.notifyExpectedPresentIfRequired(physicDisplayId, kVsyncPeriod,
+ EXPECT_CALL(*mComposer, notifyExpectedPresent(kHwcDisplayId, _, _)).Times(0);
+ mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
TimePoint::fromNs(expectedPresentTime), kFps60Hz,
kTimeoutNs);
+ EXPECT_TRUE(
+ mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
+ ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
+ mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
+ ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
}
{
- // ExpectedPresent is after the last reported ExpectedPresent.
+ // ExpectedPresent is after the last reported ExpectedPresent and within timeout.
expectedPresentTime += kFrameInterval60HzNs;
- EXPECT_CALL(*mComposer, notifyExpectedPresent(HWC_DISPLAY_ID, _, _)).Times(0);
- mFlinger.notifyExpectedPresentIfRequired(physicDisplayId, kVsyncPeriod,
+ EXPECT_CALL(*mComposer, notifyExpectedPresent(kHwcDisplayId, _, _)).Times(0);
+ mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
TimePoint::fromNs(expectedPresentTime), kFps60Hz,
kTimeoutNs);
+ EXPECT_TRUE(
+ mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
+ ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
+ mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
+ ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
}
{
// ExpectedPresent is before the last reported ExpectedPresent but after the timeoutNs,
// representing we changed our decision and want to present earlier than previously
// reported.
+ mCompositor->committed = false;
expectedPresentTime -= kFrameInterval120HzNs;
EXPECT_CALL(*mComposer,
- notifyExpectedPresent(HWC_DISPLAY_ID, expectedPresentTime,
- kFrameInterval60HzNs))
+ notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs))
.WillOnce(Return(Error::NONE));
- mFlinger.notifyExpectedPresentIfRequired(physicDisplayId, kVsyncPeriod,
+ mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
TimePoint::fromNs(expectedPresentTime), kFps60Hz,
kTimeoutNs);
+ EXPECT_TRUE(
+ mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
+ ASSERT_TRUE(mFlinger.verifyHintIsScheduledOnPresent(mPhysicalDisplayId));
+ mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
+ ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
}
}
TEST_F(NotifyExpectedPresentTest, notifyExpectedPresentRenderRateChanged) {
- const auto physicDisplayId = mDisplay->getPhysicalId();
const auto now = systemTime();
auto expectedPresentTime = now;
static constexpr Period kTimeoutNs = Period::fromNs(static_cast<Fps>(1_Hz).getPeriodNsecs());
- ASSERT_NO_FATAL_FAILURE(mFlinger.setNotifyExpectedPresentData(physicDisplayId,
+ ASSERT_NO_FATAL_FAILURE(mFlinger.setNotifyExpectedPresentData(mPhysicalDisplayId,
TimePoint::fromNs(now),
Fps::fromValue(0)));
static constexpr int32_t kFrameIntervalNs120Hz = static_cast<Fps>(120_Hz).getPeriodNsecs();
@@ -147,7 +279,7 @@
struct FrameRateIntervalTestData {
int32_t frameIntervalNs;
- bool callExpectedPresent;
+ bool callNotifyExpectedPresentHint;
};
const std::vector<FrameRateIntervalTestData> frameIntervals = {
{kFrameIntervalNs60Hz, true}, {kFrameIntervalNs96Hz, true},
@@ -159,21 +291,35 @@
{kFrameIntervalNs20Hz, false}, {kFrameIntervalNs120Hz, true},
};
- for (const auto& [frameIntervalNs, callExpectedPresent] : frameIntervals) {
- {
- expectedPresentTime += frameIntervalNs;
- if (callExpectedPresent) {
- EXPECT_CALL(*mComposer,
- notifyExpectedPresent(HWC_DISPLAY_ID, expectedPresentTime,
- frameIntervalNs))
- .WillOnce(Return(Error::NONE));
- } else {
- EXPECT_CALL(*mComposer, notifyExpectedPresent(HWC_DISPLAY_ID, _, _)).Times(0);
- }
- mFlinger.notifyExpectedPresentIfRequired(physicDisplayId, kVsyncPeriod,
- TimePoint::fromNs(expectedPresentTime),
- Fps::fromPeriodNsecs(frameIntervalNs),
- kTimeoutNs);
+ for (size_t i = 0; i < frameIntervals.size(); i++) {
+ const auto& [frameIntervalNs, callNotifyExpectedPresentHint] = frameIntervals[i];
+ expectedPresentTime += frameIntervalNs;
+ mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
+ TimePoint::fromNs(expectedPresentTime),
+ Fps::fromPeriodNsecs(frameIntervalNs), kTimeoutNs);
+
+ if (callNotifyExpectedPresentHint) {
+ mCompositor->committed = false;
+ ASSERT_TRUE(mFlinger.verifyHintIsScheduledOnPresent(mPhysicalDisplayId))
+ << "Hint not scheduled for frameInterval " << frameIntervalNs << " at index "
+ << i;
+ EXPECT_CALL(*mComposer,
+ notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, frameIntervalNs))
+ .WillOnce(Return(Error::NONE));
+ } else {
+ // Only lastExpectedPresentTime is updated
+ EXPECT_TRUE(
+ mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime))
+ << "LastExpectedPresentTime for frameInterval " << frameIntervalNs
+ << "at index " << i << " did not match for frameInterval " << frameIntervalNs;
+ EXPECT_CALL(*mComposer, notifyExpectedPresent(kHwcDisplayId, _, _)).Times(0);
+ }
+ mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
+
+ if (callNotifyExpectedPresentHint) {
+ // Present resumes the calls to the notifyExpectedPresentHint.
+ mCompositor->committed = true;
+ mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
}
}
}
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.cpp b/services/surfaceflinger/tests/unittests/TestableScheduler.cpp
index e0b7366..7b92a5b 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.cpp
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.cpp
@@ -21,11 +21,10 @@
TestableScheduler::TestableScheduler(RefreshRateSelectorPtr selectorPtr,
TestableSurfaceFlinger& testableSurfaceFlinger,
- ISchedulerCallback& callback,
- IVsyncTrackerCallback& vsyncTrackerCallback)
+ ISchedulerCallback& callback)
: TestableScheduler(std::make_unique<android::mock::VsyncController>(),
std::make_shared<android::mock::VSyncTracker>(), std::move(selectorPtr),
testableSurfaceFlinger.getFactory(),
- testableSurfaceFlinger.getTimeStats(), callback, vsyncTrackerCallback) {}
+ testableSurfaceFlinger.getTimeStats(), callback) {}
} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index 6213713..25a85df 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -41,18 +41,16 @@
class TestableScheduler : public Scheduler, private ICompositor {
public:
TestableScheduler(RefreshRateSelectorPtr selectorPtr,
- TestableSurfaceFlinger& testableSurfaceFlinger, ISchedulerCallback& callback,
- IVsyncTrackerCallback& vsyncTrackerCallback);
+ TestableSurfaceFlinger& testableSurfaceFlinger, ISchedulerCallback& callback);
TestableScheduler(std::unique_ptr<VsyncController> controller,
std::shared_ptr<VSyncTracker> tracker, RefreshRateSelectorPtr selectorPtr,
surfaceflinger::Factory& factory, TimeStats& timeStats,
- ISchedulerCallback& schedulerCallback,
- IVsyncTrackerCallback& vsyncTrackerCallback)
+ ISchedulerCallback& schedulerCallback)
: Scheduler(*this, schedulerCallback,
(FeatureFlags)Feature::kContentDetection |
Feature::kSmallDirtyContentDetection,
- factory, selectorPtr->getActiveMode().fps, timeStats, vsyncTrackerCallback) {
+ factory, selectorPtr->getActiveMode().fps, timeStats) {
const auto displayId = selectorPtr->getActiveMode().modePtr->getPhysicalDisplayId();
registerDisplay(displayId, std::move(selectorPtr), std::move(controller),
std::move(tracker));
@@ -210,6 +208,7 @@
return {};
}
void sample() override {}
+ void sendNotifyExpectedPresentHint(PhysicalDisplayId) override {}
};
} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 4e0b5af..6a916a4 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -53,7 +53,6 @@
#include "mock/MockFrameTimeline.h"
#include "mock/MockFrameTracer.h"
#include "mock/MockSchedulerCallback.h"
-#include "mock/MockVsyncTrackerCallback.h"
#include "mock/system/window/MockNativeWindow.h"
#include "Scheduler/VSyncTracker.h"
@@ -205,8 +204,6 @@
enum class SchedulerCallbackImpl { kNoOp, kMock };
- enum class VsyncTrackerCallbackImpl { kNoOp, kMock };
-
struct DefaultDisplayMode {
// The ID of the injected RefreshRateSelector and its default display mode.
PhysicalDisplayId displayId;
@@ -220,14 +217,13 @@
TimeStats& getTimeStats() { return *mFlinger->mTimeStats; }
- void setupScheduler(
- std::unique_ptr<scheduler::VsyncController> vsyncController,
- std::shared_ptr<scheduler::VSyncTracker> vsyncTracker,
- std::unique_ptr<EventThread> appEventThread, std::unique_ptr<EventThread> sfEventThread,
- DisplayModesVariant modesVariant,
- SchedulerCallbackImpl callbackImpl = SchedulerCallbackImpl::kNoOp,
- VsyncTrackerCallbackImpl vsyncTrackerCallbackImpl = VsyncTrackerCallbackImpl::kNoOp,
- bool useNiceMock = false) {
+ void setupScheduler(std::unique_ptr<scheduler::VsyncController> vsyncController,
+ std::shared_ptr<scheduler::VSyncTracker> vsyncTracker,
+ std::unique_ptr<EventThread> appEventThread,
+ std::unique_ptr<EventThread> sfEventThread,
+ DisplayModesVariant modesVariant,
+ SchedulerCallbackImpl callbackImpl = SchedulerCallbackImpl::kNoOp,
+ bool useNiceMock = false) {
RefreshRateSelectorPtr selectorPtr = ftl::match(
modesVariant,
[](DefaultDisplayMode arg) {
@@ -245,12 +241,6 @@
? static_cast<ISchedulerCallback&>(mNoOpSchedulerCallback)
: static_cast<ISchedulerCallback&>(mSchedulerCallback);
- using VsyncTrackerCallback = scheduler::IVsyncTrackerCallback;
- VsyncTrackerCallback& vsyncTrackerCallback =
- vsyncTrackerCallbackImpl == VsyncTrackerCallbackImpl::kNoOp
- ? static_cast<VsyncTrackerCallback&>(mNoOpVsyncTrackerCallback)
- : static_cast<VsyncTrackerCallback&>(mVsyncTrackerCallback);
-
if (useNiceMock) {
mScheduler =
new testing::NiceMock<scheduler::TestableScheduler>(std::move(vsyncController),
@@ -258,14 +248,12 @@
std::move(selectorPtr),
mFactory,
*mFlinger->mTimeStats,
- schedulerCallback,
- vsyncTrackerCallback);
+ schedulerCallback);
} else {
mScheduler = new scheduler::TestableScheduler(std::move(vsyncController),
std::move(vsyncTracker),
std::move(selectorPtr), mFactory,
- *mFlinger->mTimeStats, schedulerCallback,
- vsyncTrackerCallback);
+ *mFlinger->mTimeStats, schedulerCallback);
}
mScheduler->initVsync(*mTokenManager, 0ms);
@@ -307,8 +295,7 @@
EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_, _)).WillRepeatedly(Return(0));
setupScheduler(std::move(vsyncController), std::move(vsyncTracker), std::move(eventThread),
std::move(sfEventThread), DefaultDisplayMode{options.displayId},
- SchedulerCallbackImpl::kNoOp, VsyncTrackerCallbackImpl::kNoOp,
- options.useNiceMock);
+ SchedulerCallbackImpl::kNoOp, options.useNiceMock);
}
void resetScheduler(scheduler::Scheduler* scheduler) { mFlinger->mScheduler.reset(scheduler); }
@@ -698,6 +685,36 @@
frameInterval, timeoutOpt);
}
+ void sendNotifyExpectedPresentHint(PhysicalDisplayId displayId) {
+ ftl::FakeGuard guard(kMainThreadContext);
+ mFlinger->sendNotifyExpectedPresentHint(displayId);
+ }
+
+ bool verifyHintIsScheduledOnPresent(PhysicalDisplayId displayId) {
+ return mFlinger->mNotifyExpectedPresentMap.at(displayId).hintStatus ==
+ SurfaceFlinger::NotifyExpectedPresentHintStatus::ScheduleOnPresent;
+ }
+
+ bool verifyHintIsSent(PhysicalDisplayId displayId) {
+ return mFlinger->mNotifyExpectedPresentMap.at(displayId).hintStatus ==
+ SurfaceFlinger::NotifyExpectedPresentHintStatus::Sent;
+ }
+
+ bool verifyHintStatusIsStart(PhysicalDisplayId displayId) {
+ return mFlinger->mNotifyExpectedPresentMap.at(displayId).hintStatus ==
+ SurfaceFlinger::NotifyExpectedPresentHintStatus::Start;
+ }
+
+ bool verifyHintStatusIsScheduledOnTx(PhysicalDisplayId displayId) {
+ return mFlinger->mNotifyExpectedPresentMap.at(displayId).hintStatus ==
+ SurfaceFlinger::NotifyExpectedPresentHintStatus::ScheduleOnTx;
+ }
+
+ bool verifyLastExpectedPresentTime(PhysicalDisplayId displayId, nsecs_t expectedPresentTime) {
+ return mFlinger->mNotifyExpectedPresentMap.at(displayId)
+ .lastExpectedPresentTimestamp.ns() == expectedPresentTime;
+ }
+
void setNotifyExpectedPresentData(PhysicalDisplayId displayId,
TimePoint lastExpectedPresentTimestamp,
Fps lastFrameInterval) {
@@ -706,6 +723,11 @@
displayData.lastFrameInterval = lastFrameInterval;
}
+ void resetNotifyExpectedPresentHintState(PhysicalDisplayId displayId) {
+ mFlinger->mNotifyExpectedPresentMap.at(displayId).hintStatus =
+ SurfaceFlinger::NotifyExpectedPresentHintStatus::Start;
+ }
+
~TestableSurfaceFlinger() {
// All these pointer and container clears help ensure that GMock does
// not report a leaked object, since the SurfaceFlinger instance may
@@ -1102,8 +1124,6 @@
sp<SurfaceFlinger> mFlinger;
scheduler::mock::SchedulerCallback mSchedulerCallback;
scheduler::mock::NoOpSchedulerCallback mNoOpSchedulerCallback;
- scheduler::mock::VsyncTrackerCallback mVsyncTrackerCallback;
- scheduler::mock::NoOpVsyncTrackerCallback mNoOpVsyncTrackerCallback;
std::unique_ptr<frametimeline::impl::TokenManager> mTokenManager;
scheduler::TestableScheduler* mScheduler = nullptr;
Hwc2::mock::PowerAdvisor mPowerAdvisor;
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index d952b70..b9f3d70 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -26,7 +26,6 @@
#include <common/test/FlagUtils.h>
#include "Scheduler/VSyncPredictor.h"
#include "mock/DisplayHardware/MockDisplayMode.h"
-#include "mock/MockVsyncTrackerCallback.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -82,14 +81,13 @@
nsecs_t mNow = 0;
nsecs_t mPeriod = 1000;
ftl::NonNull<DisplayModePtr> mMode = displayMode(mPeriod);
- scheduler::mock::VsyncTrackerCallback mVsyncTrackerCallback;
static constexpr size_t kHistorySize = 10;
static constexpr size_t kMinimumSamplesForPrediction = 6;
static constexpr size_t kOutlierTolerancePercent = 25;
static constexpr nsecs_t mMaxRoundingError = 100;
VSyncPredictor tracker{mMode, kHistorySize, kMinimumSamplesForPrediction,
- kOutlierTolerancePercent, mVsyncTrackerCallback};
+ kOutlierTolerancePercent};
};
TEST_F(VSyncPredictorTest, reportsAnticipatedPeriod) {
@@ -410,8 +408,7 @@
// See b/151146131
TEST_F(VSyncPredictorTest, hasEnoughPrecision) {
const auto mode = displayMode(mPeriod);
- VSyncPredictor tracker{mode, 20, kMinimumSamplesForPrediction, kOutlierTolerancePercent,
- mVsyncTrackerCallback};
+ VSyncPredictor tracker{mode, 20, kMinimumSamplesForPrediction, kOutlierTolerancePercent};
std::vector<nsecs_t> const simulatedVsyncs{840873348817, 840890049444, 840906762675,
840923581635, 840940161584, 840956868096,
840973702473, 840990256277, 841007116851,
@@ -658,48 +655,6 @@
EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 5100), Eq(mNow + 6 * mPeriod));
}
-TEST_F(VSyncPredictorTest, vsyncTrackerCallback) {
- SET_FLAG_FOR_TEST(flags::vrr_config, true);
-
- const auto refreshRate = Fps::fromPeriodNsecs(mPeriod);
- NotifyExpectedPresentConfig notifyExpectedPresentConfig;
- notifyExpectedPresentConfig.timeoutNs = Period::fromNs(30).ns();
-
- hal::VrrConfig vrrConfig;
- vrrConfig.notifyExpectedPresentConfig = notifyExpectedPresentConfig;
- vrrConfig.minFrameIntervalNs = refreshRate.getPeriodNsecs();
-
- const int32_t kGroup = 0;
- const auto kResolution = ui::Size(1920, 1080);
- const auto mode =
- ftl::as_non_null(createVrrDisplayMode(DisplayModeId(0), refreshRate, vrrConfig, kGroup,
- kResolution, DEFAULT_DISPLAY_ID));
-
- tracker.setDisplayModePtr(mode);
- auto last = mNow;
- for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
- EXPECT_CALL(mVsyncTrackerCallback,
- onVsyncGenerated(TimePoint::fromNs(last + mPeriod), mode,
- FpsMatcher(refreshRate)))
- .Times(1);
- EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod));
- mNow += mPeriod;
- last = mNow;
- tracker.addVsyncTimestamp(mNow);
- }
-
- tracker.setRenderRate(refreshRate / 2);
- {
- // out of render rate phase
- EXPECT_CALL(mVsyncTrackerCallback,
- onVsyncGenerated(TimePoint::fromNs(mNow + 3 * mPeriod), mode,
- FpsMatcher(refreshRate / 2)))
- .Times(1);
- EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 1 * mPeriod),
- Eq(mNow + 3 * mPeriod));
- }
-}
-
TEST_F(VSyncPredictorTest, adjustsVrrTimeline) {
SET_FLAG_FOR_TEST(flags::vrr_config, true);
@@ -716,7 +671,7 @@
.build());
VSyncPredictor vrrTracker{kMode, kHistorySize, kMinimumSamplesForPrediction,
- kOutlierTolerancePercent, mVsyncTrackerCallback};
+ kOutlierTolerancePercent};
vrrTracker.setRenderRate(minFrameRate);
vrrTracker.addVsyncTimestamp(0);
@@ -733,28 +688,6 @@
EXPECT_EQ(5000, vrrTracker.nextAnticipatedVSyncTimeFrom(4500, 4500));
EXPECT_EQ(6000, vrrTracker.nextAnticipatedVSyncTimeFrom(5000, 5000));
}
-
-TEST_F(VSyncPredictorTest, absentVrrConfigNoVsyncTrackerCallback) {
- SET_FLAG_FOR_TEST(flags::vrr_config, true);
- const auto refreshRate = Fps::fromPeriodNsecs(mPeriod);
- const std::optional<hal::VrrConfig> vrrConfigOpt = std::nullopt;
- constexpr int32_t kGroup = 0;
- constexpr auto kResolution = ui::Size(1920, 1080);
- const auto mode =
- ftl::as_non_null(createVrrDisplayMode(DisplayModeId(0), refreshRate, vrrConfigOpt,
- kGroup, kResolution, DEFAULT_DISPLAY_ID));
- tracker.setDisplayModePtr(mode);
-
- auto last = mNow;
- for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
- EXPECT_CALL(mVsyncTrackerCallback, onVsyncGenerated(_, _, _)).Times(0);
- EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod));
- mNow += mPeriod;
- last = mNow;
- tracker.addVsyncTimestamp(mNow);
- }
-}
-
} // namespace android::scheduler
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
index 22b2ccc..4ca0542 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
@@ -28,6 +28,8 @@
MOCK_METHOD(void, kernelTimerChanged, (bool), (override));
MOCK_METHOD(void, triggerOnFrameRateOverridesChanged, (), (override));
MOCK_METHOD(void, onChoreographerAttached, (), (override));
+ MOCK_METHOD(void, onExpectedPresentTimePosted, (TimePoint, ftl::NonNull<DisplayModePtr>, Fps),
+ (override));
};
struct NoOpSchedulerCallback final : ISchedulerCallback {
@@ -36,6 +38,7 @@
void kernelTimerChanged(bool) override {}
void triggerOnFrameRateOverridesChanged() override {}
void onChoreographerAttached() override {}
+ void onExpectedPresentTimePosted(TimePoint, ftl::NonNull<DisplayModePtr>, Fps) override {}
};
} // namespace android::scheduler::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockVsyncTrackerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockVsyncTrackerCallback.h
deleted file mode 100644
index b48529f..0000000
--- a/services/surfaceflinger/tests/unittests/mock/MockVsyncTrackerCallback.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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 <gmock/gmock.h>
-
-#include "Scheduler/VSyncTracker.h"
-
-namespace android::scheduler::mock {
-
-struct VsyncTrackerCallback final : IVsyncTrackerCallback {
- MOCK_METHOD(void, onVsyncGenerated, (TimePoint, ftl::NonNull<DisplayModePtr>, Fps), (override));
-};
-
-struct NoOpVsyncTrackerCallback final : IVsyncTrackerCallback {
- void onVsyncGenerated(TimePoint, ftl::NonNull<DisplayModePtr>, Fps) override{};
-};
-} // namespace android::scheduler::mock