[SF] Send NotifyExpectedPresentHint at the transaction time
BUG: 314199179
BUG: 315989692
BUG: 284845445
Test: atest NotifyExpectedPresentTest
Change-Id: Ief7fff69e8b92f0affd228b2bdcdc5009806f905
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index a145e59..ff88d71 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -17,7 +17,6 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <binder/IPCThreadState.h>
-#include <gui/DisplayEventReceiver.h>
#include <utils/Log.h>
#include <utils/Timers.h>
#include <utils/threads.h>
@@ -66,7 +65,7 @@
{
std::lock_guard lock(mVsync.mutex);
mVsync.lastCallbackTime = expectedVsyncTime;
- mVsync.scheduledFrameTime.reset();
+ mVsync.scheduledFrameTimeOpt.reset();
}
const auto vsyncId = VsyncId{mVsync.tokenManager->generateTokenForPredictions(
@@ -122,7 +121,7 @@
std::placeholders::_3),
"sf");
if (reschedule) {
- mVsync.scheduledFrameTime =
+ mVsync.scheduledFrameTimeOpt =
mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(),
.readyDuration = 0,
.lastVsync = mVsync.lastCallbackTime.ns()});
@@ -140,7 +139,7 @@
ATRACE_CALL();
std::lock_guard lock(mVsync.mutex);
mVsync.workDuration = workDuration;
- mVsync.scheduledFrameTime =
+ mVsync.scheduledFrameTimeOpt =
mVsync.registration->update({.workDuration = mVsync.workDuration.get().count(),
.readyDuration = 0,
.lastVsync = mVsync.lastCallbackTime.ns()});
@@ -193,22 +192,20 @@
ATRACE_CALL();
std::lock_guard lock(mVsync.mutex);
- mVsync.scheduledFrameTime =
+ mVsync.scheduledFrameTimeOpt =
mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(),
.readyDuration = 0,
.lastVsync = mVsync.lastCallbackTime.ns()});
}
-auto MessageQueue::getScheduledFrameTime() const -> std::optional<Clock::time_point> {
+std::optional<scheduler::ScheduleResult> MessageQueue::getScheduledFrameResult() const {
if (mHandler->isFramePending()) {
- return Clock::now();
+ return scheduler::ScheduleResult{TimePoint::now(), mHandler->getExpectedVsyncTime()};
}
-
std::lock_guard lock(mVsync.mutex);
- if (const auto time = mVsync.scheduledFrameTime) {
- return Clock::time_point(std::chrono::nanoseconds(*time));
+ if (const auto scheduledFrameTimeline = mVsync.scheduledFrameTimeOpt) {
+ return scheduledFrameTimeline;
}
-
return std::nullopt;
}
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index edb424b..c5fc371 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -76,8 +76,7 @@
virtual void scheduleConfigure() = 0;
virtual void scheduleFrame() = 0;
- using Clock = std::chrono::steady_clock;
- virtual std::optional<Clock::time_point> getScheduledFrameTime() const = 0;
+ virtual std::optional<scheduler::ScheduleResult> getScheduledFrameResult() const = 0;
};
namespace impl {
@@ -95,7 +94,9 @@
explicit Handler(MessageQueue& queue) : mQueue(queue) {}
void handleMessage(const Message& message) override;
- bool isFramePending() const;
+ virtual TimePoint getExpectedVsyncTime() const { return mExpectedVsyncTime.load(); }
+
+ virtual bool isFramePending() const;
virtual void dispatchFrame(VsyncId, TimePoint expectedVsyncTime);
};
@@ -124,7 +125,7 @@
TracedOrdinal<std::chrono::nanoseconds> workDuration
GUARDED_BY(mutex) = {"VsyncWorkDuration-sf", std::chrono::nanoseconds(0)};
TimePoint lastCallbackTime GUARDED_BY(mutex);
- std::optional<nsecs_t> scheduledFrameTime GUARDED_BY(mutex);
+ std::optional<scheduler::ScheduleResult> scheduledFrameTimeOpt GUARDED_BY(mutex);
TracedOrdinal<int> value = {"VSYNC-sf", 0};
};
@@ -150,7 +151,7 @@
void scheduleConfigure() override;
void scheduleFrame() override;
- std::optional<Clock::time_point> getScheduledFrameTime() const override;
+ std::optional<scheduler::ScheduleResult> getScheduledFrameResult() const override;
};
} // namespace impl
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 9f29e9f..d1934f2 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -133,9 +133,9 @@
void initVsync(frametimeline::TokenManager&, std::chrono::nanoseconds workDuration);
- using Impl::getScheduledFrameTime;
using Impl::setDuration;
+ using Impl::getScheduledFrameResult;
using Impl::scheduleConfigure;
using Impl::scheduleFrame;
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatch.h b/services/surfaceflinger/Scheduler/VSyncDispatch.h
index ed8f8fe..0c43ffb 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatch.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatch.h
@@ -21,11 +21,15 @@
#include <string>
#include <ftl/mixins.h>
+#include <scheduler/Time.h>
#include <utils/Timers.h>
namespace android::scheduler {
-using ScheduleResult = std::optional<nsecs_t>;
+struct ScheduleResult {
+ TimePoint callbackTime;
+ TimePoint vsyncTime;
+};
enum class CancelResult { Cancelled, TooLate, Error };
@@ -124,10 +128,12 @@
*
* \param [in] token The callback to schedule.
* \param [in] scheduleTiming The timing information for this schedule call
- * \return The expected callback time if a callback was scheduled.
+ * \return The expected callback time if a callback was scheduled,
+ * along with VSYNC time for the callback scheduled.
* std::nullopt if the callback is not registered.
*/
- virtual ScheduleResult schedule(CallbackToken token, ScheduleTiming scheduleTiming) = 0;
+ virtual std::optional<ScheduleResult> schedule(CallbackToken token,
+ ScheduleTiming scheduleTiming) = 0;
/*
* Update the timing information for a scheduled callback.
@@ -135,10 +141,12 @@
*
* \param [in] token The callback to schedule.
* \param [in] scheduleTiming The timing information for this schedule call
- * \return The expected callback time if a callback was scheduled.
+ * \return The expected callback time if a callback was scheduled,
+ * along with VSYNC time for the callback scheduled.
* std::nullopt if the callback is not registered.
*/
- virtual ScheduleResult update(CallbackToken token, ScheduleTiming scheduleTiming) = 0;
+ virtual std::optional<ScheduleResult> update(CallbackToken token,
+ ScheduleTiming scheduleTiming) = 0;
/* Cancels a scheduled callback, if possible.
*
@@ -168,10 +176,10 @@
VSyncCallbackRegistration& operator=(VSyncCallbackRegistration&&);
// See documentation for VSyncDispatch::schedule.
- ScheduleResult schedule(VSyncDispatch::ScheduleTiming scheduleTiming);
+ std::optional<ScheduleResult> schedule(VSyncDispatch::ScheduleTiming scheduleTiming);
// See documentation for VSyncDispatch::update.
- ScheduleResult update(VSyncDispatch::ScheduleTiming scheduleTiming);
+ std::optional<ScheduleResult> update(VSyncDispatch::ScheduleTiming scheduleTiming);
// See documentation for VSyncDispatch::cancel.
CancelResult cancel();
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index b92fa24..2a3e5b6 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -38,9 +38,10 @@
namespace {
-nsecs_t getExpectedCallbackTime(nsecs_t nextVsyncTime,
- const VSyncDispatch::ScheduleTiming& timing) {
- return nextVsyncTime - timing.readyDuration - timing.workDuration;
+ScheduleResult getExpectedCallbackTime(nsecs_t nextVsyncTime,
+ const VSyncDispatch::ScheduleTiming& timing) {
+ return {TimePoint::fromNs(nextVsyncTime - timing.readyDuration - timing.workDuration),
+ TimePoint::fromNs(nextVsyncTime)};
}
} // namespace
@@ -84,8 +85,8 @@
return {mArmedInfo->mActualVsyncTime};
}
-ScheduleResult VSyncDispatchTimerQueueEntry::schedule(VSyncDispatch::ScheduleTiming timing,
- VSyncTracker& tracker, nsecs_t now) {
+std::optional<ScheduleResult> VSyncDispatchTimerQueueEntry::schedule(
+ VSyncDispatch::ScheduleTiming timing, VSyncTracker& tracker, nsecs_t now) {
auto nextVsyncTime =
tracker.nextAnticipatedVSyncTimeFrom(std::max(timing.lastVsync,
now + timing.workDuration +
@@ -115,14 +116,15 @@
auto const nextReadyTime = nextVsyncTime - timing.readyDuration;
mScheduleTiming = timing;
mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};
- return nextWakeupTime;
+ return ScheduleResult{TimePoint::fromNs(nextWakeupTime), TimePoint::fromNs(nextVsyncTime)};
}
-nsecs_t VSyncDispatchTimerQueueEntry::addPendingWorkloadUpdate(
+ScheduleResult VSyncDispatchTimerQueueEntry::addPendingWorkloadUpdate(
VSyncTracker& tracker, nsecs_t now, VSyncDispatch::ScheduleTiming timing) {
mWorkloadUpdateInfo = timing;
const auto armedInfo = update(tracker, now, timing, mArmedInfo);
- return armedInfo.mActualWakeupTime;
+ return {TimePoint::fromNs(armedInfo.mActualWakeupTime),
+ TimePoint::fromNs(armedInfo.mActualVsyncTime)};
}
bool VSyncDispatchTimerQueueEntry::hasPendingWorkloadUpdate() const {
@@ -383,14 +385,14 @@
}
}
-ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token,
- ScheduleTiming scheduleTiming) {
+std::optional<ScheduleResult> VSyncDispatchTimerQueue::schedule(CallbackToken token,
+ ScheduleTiming scheduleTiming) {
std::lock_guard lock(mMutex);
return scheduleLocked(token, scheduleTiming);
}
-ScheduleResult VSyncDispatchTimerQueue::scheduleLocked(CallbackToken token,
- ScheduleTiming scheduleTiming) {
+std::optional<ScheduleResult> VSyncDispatchTimerQueue::scheduleLocked(
+ CallbackToken token, ScheduleTiming scheduleTiming) {
auto it = mCallbacks.find(token);
if (it == mCallbacks.end()) {
return {};
@@ -405,19 +407,20 @@
return callback->addPendingWorkloadUpdate(*mTracker, now, scheduleTiming);
}
- const ScheduleResult result = callback->schedule(scheduleTiming, *mTracker, now);
- if (!result.has_value()) {
+ const auto resultOpt = callback->schedule(scheduleTiming, *mTracker, now);
+
+ if (!resultOpt) {
return {};
}
-
if (callback->wakeupTime() < mIntendedWakeupTime - mTimerSlack) {
rearmTimerSkippingUpdateFor(now, it);
}
- return result;
+ return resultOpt;
}
-ScheduleResult VSyncDispatchTimerQueue::update(CallbackToken token, ScheduleTiming scheduleTiming) {
+std::optional<ScheduleResult> VSyncDispatchTimerQueue::update(CallbackToken token,
+ ScheduleTiming scheduleTiming) {
std::lock_guard lock(mMutex);
const auto it = mCallbacks.find(token);
if (it == mCallbacks.end()) {
@@ -494,14 +497,16 @@
if (mToken) mDispatch->unregisterCallback(*mToken);
}
-ScheduleResult VSyncCallbackRegistration::schedule(VSyncDispatch::ScheduleTiming scheduleTiming) {
+std::optional<ScheduleResult> VSyncCallbackRegistration::schedule(
+ VSyncDispatch::ScheduleTiming scheduleTiming) {
if (!mToken) {
return std::nullopt;
}
return mDispatch->schedule(*mToken, scheduleTiming);
}
-ScheduleResult VSyncCallbackRegistration::update(VSyncDispatch::ScheduleTiming scheduleTiming) {
+std::optional<ScheduleResult> VSyncCallbackRegistration::update(
+ VSyncDispatch::ScheduleTiming scheduleTiming) {
if (!mToken) {
return std::nullopt;
}
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
index b5ddd25..afb67ae 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
@@ -48,7 +48,8 @@
std::optional<nsecs_t> lastExecutedVsyncTarget() const;
// This moves the state from disarmed->armed and will calculate the wakeupTime.
- ScheduleResult schedule(VSyncDispatch::ScheduleTiming, VSyncTracker&, nsecs_t now);
+ std::optional<ScheduleResult> schedule(VSyncDispatch::ScheduleTiming, VSyncTracker&,
+ nsecs_t now);
// This will update armed entries with the latest vsync information. Entry remains armed.
void update(VSyncTracker&, nsecs_t now);
@@ -69,7 +70,8 @@
// Adds a pending upload of the earliestVSync and workDuration that will be applied on the next
// call to update()
- nsecs_t addPendingWorkloadUpdate(VSyncTracker&, nsecs_t now, VSyncDispatch::ScheduleTiming);
+ ScheduleResult addPendingWorkloadUpdate(VSyncTracker&, nsecs_t now,
+ VSyncDispatch::ScheduleTiming);
// Checks if there is a pending update to the workload, returning true if so.
bool hasPendingWorkloadUpdate() const;
@@ -128,8 +130,8 @@
CallbackToken registerCallback(Callback, std::string callbackName) final;
void unregisterCallback(CallbackToken) final;
- ScheduleResult schedule(CallbackToken, ScheduleTiming) final;
- ScheduleResult update(CallbackToken, ScheduleTiming) final;
+ std::optional<ScheduleResult> schedule(CallbackToken, ScheduleTiming) final;
+ std::optional<ScheduleResult> update(CallbackToken, ScheduleTiming) final;
CancelResult cancel(CallbackToken) final;
void dump(std::string&) const final;
@@ -147,7 +149,7 @@
void rearmTimerSkippingUpdateFor(nsecs_t now, CallbackMap::const_iterator skipUpdate)
REQUIRES(mMutex);
void cancelTimer() REQUIRES(mMutex);
- ScheduleResult scheduleLocked(CallbackToken, ScheduleTiming) REQUIRES(mMutex);
+ std::optional<ScheduleResult> scheduleLocked(CallbackToken, ScheduleTiming) REQUIRES(mMutex);
std::mutex mutable mMutex;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index edba50b..0436c3c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2759,7 +2759,11 @@
// TODO(b/255601557) Update frameInterval per display
refreshArgs.frameInterval =
mScheduler->getNextFrameInterval(pacesetterId, pacesetterTarget.expectedPresentTime());
- refreshArgs.scheduledFrameTime = mScheduler->getScheduledFrameTime();
+ const auto scheduledFrameResultOpt = mScheduler->getScheduledFrameResult();
+ const auto scheduledFrameTimeOpt = scheduledFrameResultOpt
+ ? std::optional{scheduledFrameResultOpt->callbackTime}
+ : std::nullopt;
+ refreshArgs.scheduledFrameTime = scheduledFrameTimeOpt;
refreshArgs.hasTrustedPresentationListener = mNumTrustedPresentationListeners > 0;
// Store the present time just before calling to the composition engine so we could notify
// the scheduler.
@@ -4258,7 +4262,8 @@
auto hintStatus = data.hintStatus.load();
if (!expectedPresentWithinTimeout) {
- if (hintStatus != NotifyExpectedPresentHintStatus::Sent ||
+ if ((hintStatus != NotifyExpectedPresentHintStatus::Sent &&
+ hintStatus != NotifyExpectedPresentHintStatus::ScheduleOnTx) ||
(timeoutOpt && timeoutOpt->ns() == 0)) {
// Send the hint immediately if timeout, as the hint gets
// delayed otherwise, as the frame is scheduled close
@@ -4267,11 +4272,16 @@
.compare_exchange_strong(hintStatus,
NotifyExpectedPresentHintStatus::ScheduleOnTx)) {
scheduleNotifyExpectedPresentHint(displayId);
+ return;
}
- return;
}
}
+ if (hintStatus == NotifyExpectedPresentHintStatus::Sent &&
+ data.hintStatus.compare_exchange_strong(hintStatus,
+ NotifyExpectedPresentHintStatus::ScheduleOnTx)) {
+ return;
+ }
if (hintStatus != NotifyExpectedPresentHintStatus::Start) {
return;
}
@@ -4279,7 +4289,8 @@
mScheduler->scheduleFrame();
}
-void SurfaceFlinger::scheduleNotifyExpectedPresentHint(PhysicalDisplayId displayId) {
+void SurfaceFlinger::scheduleNotifyExpectedPresentHint(PhysicalDisplayId displayId,
+ VsyncId vsyncId) {
auto itr = mNotifyExpectedPresentMap.find(displayId);
if (itr == mNotifyExpectedPresentMap.end()) {
return;
@@ -4288,10 +4299,30 @@
const char* const whence = __func__;
const auto sendHint = [=, this]() {
auto& data = mNotifyExpectedPresentMap.at(displayId);
- data.hintStatus.store(NotifyExpectedPresentHintStatus::Sent);
- const auto status =
- getHwComposer().notifyExpectedPresent(displayId, data.lastExpectedPresentTimestamp,
- data.lastFrameInterval);
+ TimePoint expectedPresentTime = data.lastExpectedPresentTimestamp;
+ if (ftl::to_underlying(vsyncId) != FrameTimelineInfo::INVALID_VSYNC_ID) {
+ const auto predictionOpt = mFrameTimeline->getTokenManager()->getPredictionsForToken(
+ ftl::to_underlying(vsyncId));
+ const auto expectedPresentTimeOnPredictor = TimePoint::fromNs(
+ predictionOpt ? predictionOpt->presentTime : expectedPresentTime.ns());
+ const auto scheduledFrameResultOpt = mScheduler->getScheduledFrameResult();
+ const auto expectedPresentTimeOnScheduler = scheduledFrameResultOpt.has_value()
+ ? scheduledFrameResultOpt->vsyncTime
+ : TimePoint::fromNs(0);
+ expectedPresentTime =
+ std::max(expectedPresentTimeOnPredictor, expectedPresentTimeOnScheduler);
+ }
+
+ if (expectedPresentTime < TimePoint::now()) {
+ expectedPresentTime =
+ mScheduler->getVsyncSchedule()->vsyncDeadlineAfter(TimePoint::now());
+ if (mScheduler->vsyncModulator().getVsyncConfig().sfWorkDuration >
+ mScheduler->getVsyncSchedule(displayId)->period()) {
+ expectedPresentTime += mScheduler->getVsyncSchedule(displayId)->period();
+ }
+ }
+ const auto status = getHwComposer().notifyExpectedPresent(displayId, expectedPresentTime,
+ data.lastFrameInterval);
if (status != NO_ERROR) {
ALOGE("%s failed to notifyExpectedPresentHint for display %" PRId64, whence,
displayId.value);
@@ -4309,7 +4340,11 @@
}
}));
}
- sendHint();
+ auto scheduleHintOnPresent = NotifyExpectedPresentHintStatus::ScheduleOnPresent;
+ if (itr->second.hintStatus.compare_exchange_strong(scheduleHintOnPresent,
+ NotifyExpectedPresentHintStatus::Sent)) {
+ sendHint();
+ }
}
void SurfaceFlinger::sendNotifyExpectedPresentHint(PhysicalDisplayId displayId) {
@@ -5112,6 +5147,11 @@
const auto frameHint = state.isFrameActive() ? FrameHint::kActive : FrameHint::kNone;
mTransactionHandler.queueTransaction(std::move(state));
+ for (const auto& [displayId, data] : mNotifyExpectedPresentMap) {
+ if (data.hintStatus.load() == NotifyExpectedPresentHintStatus::ScheduleOnTx) {
+ scheduleNotifyExpectedPresentHint(displayId, VsyncId{frameTimelineInfo.vsyncId});
+ }
+ }
setTransactionFlags(eTransactionFlushNeeded, schedule, applyToken, frameHint);
return NO_ERROR;
}
@@ -8820,7 +8860,11 @@
return;
}
- mRegionSamplingThread->onCompositionComplete(mScheduler->getScheduledFrameTime());
+ const auto scheduledFrameResultOpt = mScheduler->getScheduledFrameResult();
+ const auto scheduleFrameTimeOpt = scheduledFrameResultOpt
+ ? std::optional{scheduledFrameResultOpt->callbackTime}
+ : std::nullopt;
+ mRegionSamplingThread->onCompositionComplete(scheduleFrameTimeOpt);
}
void SurfaceFlinger::onActiveDisplaySizeChanged(const DisplayDevice& activeDisplay) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index be05797..ce9fa15 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1500,7 +1500,9 @@
std::unordered_map<PhysicalDisplayId, NotifyExpectedPresentData> mNotifyExpectedPresentMap;
void sendNotifyExpectedPresentHint(PhysicalDisplayId displayId) override
REQUIRES(kMainThreadContext);
- void scheduleNotifyExpectedPresentHint(PhysicalDisplayId displayId);
+ void scheduleNotifyExpectedPresentHint(PhysicalDisplayId displayId,
+ VsyncId vsyncId = VsyncId{
+ FrameTimelineInfo::INVALID_VSYNC_ID});
void notifyExpectedPresentIfRequired(PhysicalDisplayId, Period vsyncPeriod,
TimePoint expectedPresentTime, Fps frameInterval,
std::optional<Period> timeoutOpt);
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index d5ec654..3eabe1f 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -117,14 +117,16 @@
mThread->onVsync(expectedPresentationTime, timestamp, deadlineTimestamp);
}
+ static constexpr scheduler::ScheduleResult kScheduleResult{TimePoint::fromNs(0),
+ TimePoint::fromNs(0)};
AsyncCallRecorderWithCannedReturn<
scheduler::ScheduleResult (*)(scheduler::VSyncDispatch::CallbackToken,
scheduler::VSyncDispatch::ScheduleTiming)>
- mVSyncCallbackScheduleRecorder{0};
+ mVSyncCallbackScheduleRecorder{kScheduleResult};
AsyncCallRecorderWithCannedReturn<
scheduler::ScheduleResult (*)(scheduler::VSyncDispatch::CallbackToken,
scheduler::VSyncDispatch::ScheduleTiming)>
- mVSyncCallbackUpdateRecorder{0};
+ mVSyncCallbackUpdateRecorder{kScheduleResult};
AsyncCallRecorderWithCannedReturn<
scheduler::VSyncDispatch::CallbackToken (*)(scheduler::VSyncDispatch::Callback,
std::string)>
diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
index f5661fc..71f9f88 100644
--- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
@@ -25,6 +25,7 @@
#include "FrameTimeline.h"
#include "Scheduler/MessageQueue.h"
#include "mock/MockVSyncDispatch.h"
+#include "utils/Timers.h"
namespace android {
@@ -49,6 +50,8 @@
using MessageQueue::Handler::Handler;
MOCK_METHOD(void, dispatchFrame, (VsyncId, TimePoint), (override));
+ MOCK_METHOD(bool, isFramePending, (), (const, override));
+ MOCK_METHOD(TimePoint, getExpectedVsyncTime, (), (const override));
};
explicit TestableMessageQueue(sp<MockHandler> handler)
@@ -94,13 +97,17 @@
const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDuration.ns(),
.readyDuration = 0,
.lastVsync = 0};
- EXPECT_FALSE(mEventQueue.getScheduledFrameTime());
+ EXPECT_FALSE(mEventQueue.getScheduledFrameResult());
- EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234));
+ const auto timePoint = TimePoint::fromNs(1234);
+ const auto scheduleResult = scheduler::ScheduleResult{timePoint, timePoint};
+ EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(scheduleResult));
EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame());
- ASSERT_TRUE(mEventQueue.getScheduledFrameTime());
- EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count());
+ const auto scheduledFrameResult = mEventQueue.getScheduledFrameResult();
+ ASSERT_TRUE(scheduledFrameResult);
+ EXPECT_EQ(1234, scheduledFrameResult->callbackTime.ns());
+ EXPECT_EQ(1234, scheduledFrameResult->vsyncTime.ns());
}
TEST_F(MessageQueueTest, commitTwice) {
@@ -109,17 +116,25 @@
.readyDuration = 0,
.lastVsync = 0};
- EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234));
+ auto timePoint = TimePoint::fromNs(1234);
+ auto scheduleResult = scheduler::ScheduleResult{timePoint, timePoint};
+ EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(scheduleResult));
EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame());
- ASSERT_TRUE(mEventQueue.getScheduledFrameTime());
- EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count());
+ auto scheduledFrameResult = mEventQueue.getScheduledFrameResult();
+ ASSERT_TRUE(scheduledFrameResult);
+ EXPECT_EQ(1234, scheduledFrameResult->callbackTime.ns());
+ EXPECT_EQ(1234, scheduledFrameResult->vsyncTime.ns());
- EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(4567));
+ timePoint = TimePoint::fromNs(4567);
+ scheduleResult = scheduler::ScheduleResult{timePoint, timePoint};
+ EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(scheduleResult));
EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame());
- ASSERT_TRUE(mEventQueue.getScheduledFrameTime());
- EXPECT_EQ(4567, mEventQueue.getScheduledFrameTime()->time_since_epoch().count());
+ scheduledFrameResult = mEventQueue.getScheduledFrameResult();
+ ASSERT_TRUE(scheduledFrameResult);
+ EXPECT_EQ(4567, scheduledFrameResult->callbackTime.ns());
+ EXPECT_EQ(4567, scheduledFrameResult->vsyncTime.ns());
}
TEST_F(MessageQueueTest, commitTwiceWithCallback) {
@@ -128,11 +143,15 @@
.readyDuration = 0,
.lastVsync = 0};
- EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234));
+ const auto timePoint = TimePoint::fromNs(1234);
+ auto scheduleResult = scheduler::ScheduleResult{timePoint, timePoint};
+ EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(scheduleResult));
EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame());
- ASSERT_TRUE(mEventQueue.getScheduledFrameTime());
- EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count());
+ auto scheduledFrameResult = mEventQueue.getScheduledFrameResult();
+ ASSERT_TRUE(scheduledFrameResult);
+ EXPECT_EQ(1234, scheduledFrameResult->callbackTime.ns());
+ EXPECT_EQ(1234, scheduledFrameResult->vsyncTime.ns());
constexpr TimePoint kStartTime = TimePoint::fromNs(100);
constexpr TimePoint kEndTime = kStartTime + kDuration;
@@ -148,14 +167,15 @@
EXPECT_NO_FATAL_FAILURE(
mEventQueue.vsyncCallback(kPresentTime.ns(), kStartTime.ns(), kEndTime.ns()));
- EXPECT_FALSE(mEventQueue.getScheduledFrameTime());
+ EXPECT_FALSE(mEventQueue.getScheduledFrameResult());
const auto timingAfterCallback =
scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDuration.ns(),
.readyDuration = 0,
.lastVsync = kPresentTime.ns()};
-
- EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timingAfterCallback)).WillOnce(Return(0));
+ scheduleResult = scheduler::ScheduleResult{TimePoint::fromNs(0), TimePoint::fromNs(0)};
+ EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timingAfterCallback))
+ .WillOnce(Return(scheduleResult));
EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame());
}
@@ -167,9 +187,24 @@
.readyDuration = 0,
.lastVsync = 0};
- EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(0));
+ const auto scheduleResult =
+ scheduler::ScheduleResult{TimePoint::fromNs(0), TimePoint::fromNs(0)};
+ EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(scheduleResult));
EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame());
}
+TEST_F(MessageQueueTest, scheduleResultWhenFrameIsPending) {
+ const auto timePoint = TimePoint::now();
+ EXPECT_CALL(*mEventQueue.mHandler, isFramePending()).WillOnce(Return(true));
+ EXPECT_CALL(*mEventQueue.mHandler, getExpectedVsyncTime()).WillRepeatedly(Return(timePoint));
+
+ const auto scheduledFrameResult = mEventQueue.getScheduledFrameResult();
+
+ ASSERT_TRUE(scheduledFrameResult);
+ EXPECT_NEAR(static_cast<double>(TimePoint::now().ns()),
+ static_cast<double>(scheduledFrameResult->callbackTime.ns()), ms2ns(1));
+ EXPECT_EQ(timePoint, scheduledFrameResult->vsyncTime);
+}
+
} // namespace
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp
index 91b9018..20a3315 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp
@@ -41,6 +41,33 @@
}
protected:
+ void setTransactionState() {
+ ASSERT_TRUE(mFlinger.getTransactionQueue().isEmpty());
+ TransactionInfo transaction;
+ mFlinger.setTransactionState(FrameTimelineInfo{}, transaction.states, transaction.displays,
+ transaction.flags, transaction.applyToken,
+ transaction.inputWindowCommands,
+ TimePoint::now().ns() + s2ns(1), transaction.isAutoTimestamp,
+ transaction.unCachedBuffers,
+ /*HasListenerCallbacks=*/false, transaction.callbacks,
+ transaction.id, transaction.mergedTransactionIds);
+ }
+
+ struct TransactionInfo {
+ Vector<ComposerState> states;
+ Vector<DisplayState> displays;
+ uint32_t flags = 0;
+ sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ InputWindowCommands inputWindowCommands;
+ int64_t desiredPresentTime = 0;
+ bool isAutoTimestamp = false;
+ FrameTimelineInfo frameTimelineInfo{};
+ std::vector<client_cache_t> unCachedBuffers;
+ uint64_t id = static_cast<uint64_t>(-1);
+ std::vector<uint64_t> mergedTransactionIds;
+ std::vector<ListenerCallbacks> callbacks;
+ };
+
struct Compositor final : ICompositor {
explicit Compositor(PhysicalDisplayId displayId, TestableSurfaceFlinger& surfaceFlinger)
: displayId(displayId), surfaceFlinger(surfaceFlinger) {}
@@ -102,7 +129,7 @@
};
TEST_F(NotifyExpectedPresentTest, noNotifyExpectedPresentHintCall_absentTimeout) {
- auto expectedPresentTime = systemTime() + ms2ns(10);
+ auto expectedPresentTime = TimePoint::now().ns() + ms2ns(10);
ASSERT_NO_FATAL_FAILURE(
mFlinger.setNotifyExpectedPresentData(mPhysicalDisplayId,
TimePoint::fromNs(expectedPresentTime),
@@ -120,7 +147,7 @@
}
TEST_F(NotifyExpectedPresentTest, notifyExpectedPresentHint_zeroTimeout) {
- auto expectedPresentTime = systemTime() + ms2ns(10);
+ auto expectedPresentTime = TimePoint::now().ns() + ms2ns(10);
{
// Very first ExpectedPresent after idle, no previous timestamp.
EXPECT_CALL(*mComposer,
@@ -139,6 +166,10 @@
{
mCompositor->committed = false;
expectedPresentTime += kFrameInterval60HzNs;
+ EXPECT_CALL(static_cast<mock::VSyncTracker&>(
+ mFlinger.scheduler()->getVsyncSchedule()->getTracker()),
+ nextAnticipatedVSyncTimeFrom(_, _))
+ .WillRepeatedly(Return(expectedPresentTime));
EXPECT_CALL(*mComposer,
notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs))
.WillOnce(Return(Error::NONE));
@@ -154,6 +185,10 @@
}
{
expectedPresentTime += kFrameInterval60HzNs;
+ EXPECT_CALL(static_cast<mock::VSyncTracker&>(
+ mFlinger.scheduler()->getVsyncSchedule()->getTracker()),
+ nextAnticipatedVSyncTimeFrom(_, _))
+ .WillRepeatedly(Return(expectedPresentTime));
EXPECT_CALL(*mComposer,
notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs))
.WillOnce(Return(Error::NONE));
@@ -168,9 +203,8 @@
ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
}
}
-
TEST_F(NotifyExpectedPresentTest, notifyExpectedPresentTimeout) {
- auto expectedPresentTime = systemTime() + ms2ns(10);
+ auto expectedPresentTime = TimePoint::now().ns() + ms2ns(10);
{
// Very first ExpectedPresent after idle, no previous timestamp
mCompositor->committed = false;
@@ -185,6 +219,27 @@
ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
}
{
+ EXPECT_CALL(*mComposer, notifyExpectedPresent(kHwcDisplayId, _, _)).Times(0);
+ expectedPresentTime += 2 * kFrameInterval5HzNs;
+ mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
+ TimePoint::fromNs(expectedPresentTime), kFps60Hz,
+ kTimeoutNs);
+ EXPECT_TRUE(
+ mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
+ ASSERT_TRUE(mFlinger.verifyHintStatusIsScheduledOnTx(mPhysicalDisplayId));
+ mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
+ ASSERT_TRUE(mFlinger.verifyHintStatusIsScheduledOnTx(mPhysicalDisplayId));
+ {
+ EXPECT_CALL(*mComposer,
+ notifyExpectedPresent(kHwcDisplayId, expectedPresentTime,
+ kFrameInterval60HzNs))
+ .WillOnce(Return(Error::NONE));
+ // Hint sent with the setTransactionState
+ setTransactionState();
+ ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
+ }
+ }
+ {
// ExpectedPresentTime is after the timeoutNs
mCompositor->committed = true;
expectedPresentTime += 2 * kFrameInterval5HzNs;
@@ -194,7 +249,7 @@
kTimeoutNs);
EXPECT_TRUE(
mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
- ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
+ ASSERT_TRUE(mFlinger.verifyHintStatusIsScheduledOnTx(mPhysicalDisplayId));
mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
// Present happens notifyExpectedPresentHintStatus is Start
ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
@@ -259,7 +314,7 @@
}
TEST_F(NotifyExpectedPresentTest, notifyExpectedPresentRenderRateChanged) {
- const auto now = systemTime();
+ const auto now = TimePoint::now().ns();
auto expectedPresentTime = now;
static constexpr Period kTimeoutNs = Period::fromNs(static_cast<Fps>(1_Hz).getPeriodNsecs());
@@ -298,6 +353,10 @@
TimePoint::fromNs(expectedPresentTime),
Fps::fromPeriodNsecs(frameIntervalNs), kTimeoutNs);
+ EXPECT_CALL(static_cast<mock::VSyncTracker&>(
+ mFlinger.scheduler()->getVsyncSchedule()->getTracker()),
+ nextAnticipatedVSyncTimeFrom(_, _))
+ .WillRepeatedly(Return(expectedPresentTime));
if (callNotifyExpectedPresentHint) {
mCompositor->committed = false;
ASSERT_TRUE(mFlinger.verifyHintIsScheduledOnPresent(mPhysicalDisplayId))
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index eb4e84e..951faf6 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -247,7 +247,8 @@
mDispatch->schedule(cb,
{.workDuration = 100, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(900, *result);
+ EXPECT_EQ(900, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
}
}
@@ -260,7 +261,8 @@
mDispatch->schedule(cb,
{.workDuration = 100, .readyDuration = 0, .lastVsync = intended});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(900, *result);
+ EXPECT_EQ(900, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
advanceToNextCallback();
@@ -279,12 +281,14 @@
mDispatch->schedule(cb,
{.workDuration = 100, .readyDuration = 0, .lastVsync = intended});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(900, *result);
+ EXPECT_EQ(900, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
result =
mDispatch->update(cb, {.workDuration = 300, .readyDuration = 0, .lastVsync = intended});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(700, *result);
+ EXPECT_EQ(700, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
advanceToNextCallback();
@@ -332,7 +336,8 @@
.readyDuration = 0,
.lastVsync = mPeriod});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(mPeriod, *result);
+ EXPECT_EQ(mPeriod, result->callbackTime.ns());
+ EXPECT_EQ(workDuration + mPeriod, result->vsyncTime.ns());
}
TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancel) {
@@ -344,7 +349,8 @@
mDispatch->schedule(cb,
{.workDuration = 100, .readyDuration = 0, .lastVsync = mPeriod});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(mPeriod - 100, *result);
+ EXPECT_EQ(mPeriod - 100, result->callbackTime.ns());
+ EXPECT_EQ(mPeriod, result->vsyncTime.ns());
EXPECT_EQ(mDispatch->cancel(cb), CancelResult::Cancelled);
}
@@ -357,7 +363,8 @@
mDispatch->schedule(cb,
{.workDuration = 100, .readyDuration = 0, .lastVsync = mPeriod});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(mPeriod - 100, *result);
+ EXPECT_EQ(mPeriod - 100, result->callbackTime.ns());
+ EXPECT_EQ(mPeriod, result->vsyncTime.ns());
mMockClock.advanceBy(950);
EXPECT_EQ(mDispatch->cancel(cb), CancelResult::TooLate);
}
@@ -371,7 +378,8 @@
mDispatch->schedule(cb,
{.workDuration = 100, .readyDuration = 0, .lastVsync = mPeriod});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(mPeriod - 100, *result);
+ EXPECT_EQ(mPeriod - 100, result->callbackTime.ns());
+ EXPECT_EQ(mPeriod, result->vsyncTime.ns());
std::thread pausingThread([&] { mMockClock.advanceToNextCallback(); });
EXPECT_TRUE(cb.waitForPause());
@@ -392,7 +400,8 @@
mDispatch->schedule(cb,
{.workDuration = 100, .readyDuration = 0, .lastVsync = mPeriod});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(mPeriod - 100, *result);
+ EXPECT_EQ(mPeriod - 100, result->callbackTime.ns());
+ EXPECT_EQ(mPeriod, result->vsyncTime.ns());
std::thread pausingThread([&] { mMockClock.advanceToNextCallback(); });
EXPECT_TRUE(cb.waitForPause());
@@ -625,19 +634,22 @@
.readyDuration = 0,
.lastVsync = timestamp - mVsyncMoveThreshold});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(mPeriod + timestamp - 400, *result);
+ EXPECT_EQ(mPeriod + timestamp - 400, result->callbackTime.ns());
+ EXPECT_EQ(mPeriod + timestamp, result->vsyncTime.ns());
result = mDispatch->schedule(tmp,
{.workDuration = 400,
.readyDuration = 0,
.lastVsync = timestamp});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(mPeriod + timestamp - 400, *result);
+ EXPECT_EQ(mPeriod + timestamp - 400, result->callbackTime.ns());
+ EXPECT_EQ(mPeriod + timestamp, result->vsyncTime.ns());
result = mDispatch->schedule(tmp,
{.workDuration = 400,
.readyDuration = 0,
.lastVsync = timestamp + mVsyncMoveThreshold});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(mPeriod + timestamp - 400, *result);
+ EXPECT_EQ(mPeriod + timestamp - 400, result->callbackTime.ns());
+ EXPECT_EQ(mPeriod + timestamp, result->vsyncTime.ns());
lastTarget = timestamp;
},
"oo");
@@ -726,10 +738,12 @@
auto result =
mDispatch->schedule(cb0, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(500, *result);
+ EXPECT_EQ(500, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
result = mDispatch->schedule(cb0, {.workDuration = 100, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(900, *result);
+ EXPECT_EQ(900, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
}
// b/1450138150
@@ -741,12 +755,14 @@
auto result =
mDispatch->schedule(cb, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(500, *result);
+ EXPECT_EQ(500, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
mMockClock.advanceBy(400);
result = mDispatch->schedule(cb, {.workDuration = 800, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(1200, *result);
+ EXPECT_EQ(1200, result->callbackTime.ns());
+ EXPECT_EQ(2000, result->vsyncTime.ns());
advanceToNextCallback();
ASSERT_THAT(cb.mCalls.size(), Eq(1));
@@ -763,12 +779,14 @@
auto result =
mDispatch->schedule(cb, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(500, *result);
+ EXPECT_EQ(500, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
mMockClock.advanceBy(400);
result = mDispatch->schedule(cb, {.workDuration = 800, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(400, *result);
+ EXPECT_EQ(400, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
advanceToNextCallback();
ASSERT_THAT(cb.mCalls.size(), Eq(1));
@@ -784,11 +802,13 @@
auto result =
mDispatch->schedule(cb, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(500, *result);
+ EXPECT_EQ(500, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
mMockClock.advanceBy(400);
result = mDispatch->schedule(cb, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(602, *result);
+ EXPECT_EQ(602, result->callbackTime.ns());
+ EXPECT_EQ(1002, result->vsyncTime.ns());
}
TEST_F(VSyncDispatchTimerQueueTest, canScheduleNegativeOffsetAgainstDifferentPeriods) {
@@ -796,12 +816,14 @@
auto result =
mDispatch->schedule(cb0, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(500, *result);
+ EXPECT_EQ(500, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
advanceToNextCallback();
result =
mDispatch->schedule(cb0, {.workDuration = 1100, .readyDuration = 0, .lastVsync = 2000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(900, *result);
+ EXPECT_EQ(900, result->callbackTime.ns());
+ EXPECT_EQ(2000, result->vsyncTime.ns());
}
TEST_F(VSyncDispatchTimerQueueTest, canScheduleLargeNegativeOffset) {
@@ -812,12 +834,14 @@
auto result =
mDispatch->schedule(cb0, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(500, *result);
+ EXPECT_EQ(500, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
advanceToNextCallback();
result =
mDispatch->schedule(cb0, {.workDuration = 1900, .readyDuration = 0, .lastVsync = 2000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(1100, *result);
+ EXPECT_EQ(1100, result->callbackTime.ns());
+ EXPECT_EQ(3000, result->vsyncTime.ns());
}
TEST_F(VSyncDispatchTimerQueueTest, scheduleUpdatesDoesNotAffectSchedulingState) {
@@ -829,11 +853,13 @@
auto result =
mDispatch->schedule(cb, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(600, *result);
+ EXPECT_EQ(600, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
result = mDispatch->schedule(cb, {.workDuration = 1400, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(600, *result);
+ EXPECT_EQ(600, result->callbackTime.ns());
+ EXPECT_EQ(2000, result->vsyncTime.ns());
advanceToNextCallback();
}
@@ -849,11 +875,13 @@
auto result =
mDispatch->schedule(cb, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(600, *result);
+ EXPECT_EQ(600, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
result = mDispatch->schedule(cb, {.workDuration = 1400, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(0, *result);
+ EXPECT_EQ(0, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
advanceToNextCallback();
}
@@ -899,14 +927,16 @@
auto result =
mDispatch->schedule(cb1, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(600, *result);
+ EXPECT_EQ(600, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
mMockClock.setLag(100);
mMockClock.advanceBy(620);
result = mDispatch->schedule(cb2, {.workDuration = 100, .readyDuration = 0, .lastVsync = 2000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(1900, *result);
+ EXPECT_EQ(1900, result->callbackTime.ns());
+ EXPECT_EQ(2000, result->vsyncTime.ns());
mMockClock.advanceBy(80);
EXPECT_THAT(cb1.mCalls.size(), Eq(1));
@@ -927,14 +957,16 @@
auto result =
mDispatch->schedule(cb, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(600, *result);
+ EXPECT_EQ(600, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
mMockClock.setLag(100);
mMockClock.advanceBy(620);
result = mDispatch->schedule(cb, {.workDuration = 370, .readyDuration = 0, .lastVsync = 2000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(1630, *result);
+ EXPECT_EQ(1630, result->callbackTime.ns());
+ EXPECT_EQ(2000, result->vsyncTime.ns());
mMockClock.advanceBy(80);
EXPECT_THAT(cb.mCalls.size(), Eq(1));
@@ -954,14 +986,16 @@
auto result =
mDispatch->schedule(cb, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(600, *result);
+ EXPECT_EQ(600, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
mMockClock.setLag(100);
mMockClock.advanceBy(620);
result = mDispatch->schedule(cb, {.workDuration = 370, .readyDuration = 0, .lastVsync = 2000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(600, *result);
+ EXPECT_EQ(600, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
mMockClock.advanceBy(80);
ASSERT_EQ(1, cb.mCalls.size());
@@ -982,10 +1016,12 @@
auto result =
mDispatch->schedule(cb1, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(600, *result);
+ EXPECT_EQ(600, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
result = mDispatch->schedule(cb2, {.workDuration = 100, .readyDuration = 0, .lastVsync = 2000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(1900, *result);
+ EXPECT_EQ(1900, result->callbackTime.ns());
+ EXPECT_EQ(2000, result->vsyncTime.ns());
mMockClock.setLag(100);
mMockClock.advanceBy(620);
@@ -1009,10 +1045,12 @@
auto result =
mDispatch->schedule(cb1, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(600, *result);
+ EXPECT_EQ(600, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
result = mDispatch->schedule(cb2, {.workDuration = 100, .readyDuration = 0, .lastVsync = 2000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(1900, *result);
+ EXPECT_EQ(1900, result->callbackTime.ns());
+ EXPECT_EQ(2000, result->vsyncTime.ns());
mMockClock.setLag(100);
mMockClock.advanceBy(620);
@@ -1045,10 +1083,12 @@
auto result =
mDispatch->schedule(cb1, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(600, *result);
+ EXPECT_EQ(600, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
result = mDispatch->schedule(cb2, {.workDuration = 390, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(610, *result);
+ EXPECT_EQ(610, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
mMockClock.setLag(100);
mMockClock.advanceBy(700);
@@ -1072,7 +1112,8 @@
mDispatch->schedule(cb,
{.workDuration = 70, .readyDuration = 30, .lastVsync = intended});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(900, *result);
+ EXPECT_EQ(900, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
advanceToNextCallback();
ASSERT_THAT(cb.mCalls.size(), Eq(1));
@@ -1138,12 +1179,14 @@
auto result =
mDispatch->schedule(cb, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(500, *result);
+ EXPECT_EQ(500, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
mMockClock.advanceBy(300);
result = mDispatch->schedule(cb, {.workDuration = 800, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(1200, *result);
+ EXPECT_EQ(1200, result->callbackTime.ns());
+ EXPECT_EQ(2000, result->vsyncTime.ns());
advanceToNextCallback();
ASSERT_THAT(cb.mCalls.size(), Eq(1));
@@ -1159,12 +1202,14 @@
auto result =
mDispatch->schedule(cb, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(500, *result);
+ EXPECT_EQ(500, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
mMockClock.advanceBy(300);
result = mDispatch->schedule(cb, {.workDuration = 800, .readyDuration = 0, .lastVsync = 1000});
EXPECT_TRUE(result.has_value());
- EXPECT_EQ(300, *result);
+ EXPECT_EQ(300, result->callbackTime.ns());
+ EXPECT_EQ(1000, result->vsyncTime.ns());
advanceToNextCallback();
ASSERT_THAT(cb.mCalls.size(), Eq(1));
@@ -1197,9 +1242,12 @@
"test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
EXPECT_FALSE(entry.wakeupTime());
- EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500},
- *mStubTracker.get(), 0)
- .has_value());
+ const auto scheduleResultOpt =
+ entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500},
+ *mStubTracker, 0);
+ ASSERT_TRUE(scheduleResultOpt);
+ EXPECT_EQ(900, scheduleResultOpt->callbackTime.ns());
+ EXPECT_EQ(1000, scheduleResultOpt->vsyncTime.ns());
auto const wakeup = entry.wakeupTime();
ASSERT_TRUE(wakeup);
EXPECT_THAT(*wakeup, Eq(900));
@@ -1220,9 +1268,12 @@
"test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
EXPECT_FALSE(entry.wakeupTime());
- EXPECT_TRUE(entry.schedule({.workDuration = 500, .readyDuration = 0, .lastVsync = 994},
- *mStubTracker.get(), now)
- .has_value());
+ const auto scheduleResultOpt =
+ entry.schedule({.workDuration = 500, .readyDuration = 0, .lastVsync = 994},
+ *mStubTracker, now);
+ ASSERT_TRUE(scheduleResultOpt);
+ EXPECT_EQ(9500, scheduleResultOpt->callbackTime.ns());
+ EXPECT_EQ(10000, scheduleResultOpt->vsyncTime.ns());
auto const wakeup = entry.wakeupTime();
ASSERT_TRUE(wakeup);
EXPECT_THAT(*wakeup, Eq(9500));
@@ -1243,9 +1294,12 @@
},
mVsyncMoveThreshold);
- EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500},
- *mStubTracker.get(), 0)
- .has_value());
+ const auto scheduleResultOpt =
+ entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500},
+ *mStubTracker, 0);
+ ASSERT_TRUE(scheduleResultOpt);
+ EXPECT_EQ(900, scheduleResultOpt->callbackTime.ns());
+ EXPECT_EQ(1000, scheduleResultOpt->vsyncTime.ns());
auto const wakeup = entry.wakeupTime();
ASSERT_TRUE(wakeup);
EXPECT_THAT(*wakeup, Eq(900));
@@ -1275,17 +1329,20 @@
"test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
EXPECT_FALSE(entry.wakeupTime());
- entry.update(*mStubTracker.get(), 0);
+ entry.update(*mStubTracker, 0);
EXPECT_FALSE(entry.wakeupTime());
- EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500},
- *mStubTracker.get(), 0)
- .has_value());
+ const auto scheduleResultOpt =
+ entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500},
+ *mStubTracker, 0);
+ ASSERT_TRUE(scheduleResultOpt);
+ EXPECT_EQ(900, scheduleResultOpt->callbackTime.ns());
+ EXPECT_EQ(1000, scheduleResultOpt->vsyncTime.ns());
auto wakeup = entry.wakeupTime();
ASSERT_TRUE(wakeup);
EXPECT_THAT(wakeup, Eq(900));
- entry.update(*mStubTracker.get(), 0);
+ entry.update(*mStubTracker, 0);
wakeup = entry.wakeupTime();
ASSERT_TRUE(wakeup);
EXPECT_THAT(*wakeup, Eq(920));
@@ -1307,26 +1364,35 @@
TEST_F(VSyncDispatchTimerQueueEntryTest, willSnapToNextTargettableVSync) {
VSyncDispatchTimerQueueEntry entry(
"test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
- EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500},
- *mStubTracker.get(), 0)
- .has_value());
+ auto scheduleResultOpt =
+ entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500},
+ *mStubTracker, 0);
+ ASSERT_TRUE(scheduleResultOpt);
+ EXPECT_EQ(900, scheduleResultOpt->callbackTime.ns());
+ EXPECT_EQ(1000, scheduleResultOpt->vsyncTime.ns());
entry.executing(); // 1000 is executing
// had 1000 not been executing, this could have been scheduled for time 800.
- EXPECT_TRUE(entry.schedule({.workDuration = 200, .readyDuration = 0, .lastVsync = 500},
- *mStubTracker.get(), 0)
- .has_value());
+ scheduleResultOpt = entry.schedule({.workDuration = 200, .readyDuration = 0, .lastVsync = 500},
+ *mStubTracker, 0);
+ ASSERT_TRUE(scheduleResultOpt);
+ EXPECT_EQ(1800, scheduleResultOpt->callbackTime.ns());
+ EXPECT_EQ(2000, scheduleResultOpt->vsyncTime.ns());
EXPECT_THAT(*entry.wakeupTime(), Eq(1800));
EXPECT_THAT(*entry.readyTime(), Eq(2000));
- EXPECT_TRUE(entry.schedule({.workDuration = 50, .readyDuration = 0, .lastVsync = 500},
- *mStubTracker.get(), 0)
- .has_value());
+ scheduleResultOpt = entry.schedule({.workDuration = 50, .readyDuration = 0, .lastVsync = 500},
+ *mStubTracker, 0);
+ ASSERT_TRUE(scheduleResultOpt);
+ EXPECT_EQ(1950, scheduleResultOpt->callbackTime.ns());
+ EXPECT_EQ(2000, scheduleResultOpt->vsyncTime.ns());
EXPECT_THAT(*entry.wakeupTime(), Eq(1950));
EXPECT_THAT(*entry.readyTime(), Eq(2000));
- EXPECT_TRUE(entry.schedule({.workDuration = 200, .readyDuration = 0, .lastVsync = 1001},
- *mStubTracker.get(), 0)
- .has_value());
+ scheduleResultOpt = entry.schedule({.workDuration = 200, .readyDuration = 0, .lastVsync = 1001},
+ *mStubTracker, 0);
+ ASSERT_TRUE(scheduleResultOpt);
+ EXPECT_EQ(1800, scheduleResultOpt->callbackTime.ns());
+ EXPECT_EQ(2000, scheduleResultOpt->vsyncTime.ns());
EXPECT_THAT(*entry.wakeupTime(), Eq(1800));
EXPECT_THAT(*entry.readyTime(), Eq(2000));
}
@@ -1349,31 +1415,36 @@
.InSequence(seq)
.WillOnce(Return(2000));
- EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500},
- *mStubTracker.get(), 0)
- .has_value());
+ auto scheduleResultOpt =
+ entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500},
+ *mStubTracker, 0);
+ ASSERT_TRUE(scheduleResultOpt);
+ EXPECT_EQ(900, scheduleResultOpt->callbackTime.ns());
+ EXPECT_EQ(1000, scheduleResultOpt->vsyncTime.ns());
entry.executing(); // 1000 is executing
- EXPECT_TRUE(entry.schedule({.workDuration = 200, .readyDuration = 0, .lastVsync = 500},
- *mStubTracker.get(), 0)
- .has_value());
+ scheduleResultOpt = entry.schedule({.workDuration = 200, .readyDuration = 0, .lastVsync = 500},
+ *mStubTracker, 0);
+ ASSERT_TRUE(scheduleResultOpt);
+ EXPECT_EQ(1800, scheduleResultOpt->callbackTime.ns());
+ EXPECT_EQ(2000, scheduleResultOpt->vsyncTime.ns());
}
TEST_F(VSyncDispatchTimerQueueEntryTest, reportsScheduledIfStillTime) {
VSyncDispatchTimerQueueEntry entry(
"test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500},
- *mStubTracker.get(), 0)
+ *mStubTracker, 0)
.has_value());
EXPECT_TRUE(entry.schedule({.workDuration = 200, .readyDuration = 0, .lastVsync = 500},
- *mStubTracker.get(), 0)
+ *mStubTracker, 0)
.has_value());
EXPECT_TRUE(entry.schedule({.workDuration = 50, .readyDuration = 0, .lastVsync = 500},
- *mStubTracker.get(), 0)
+ *mStubTracker, 0)
.has_value());
EXPECT_TRUE(entry.schedule({.workDuration = 1200, .readyDuration = 0, .lastVsync = 500},
- *mStubTracker.get(), 0)
+ *mStubTracker, 0)
.has_value());
}
@@ -1389,7 +1460,7 @@
.readyDuration = 0,
.lastVsync = 400});
EXPECT_TRUE(entry.hasPendingWorkloadUpdate());
- entry.update(*mStubTracker.get(), 0);
+ entry.update(*mStubTracker, 0);
EXPECT_FALSE(entry.hasPendingWorkloadUpdate());
EXPECT_THAT(*entry.wakeupTime(), Eq(mPeriod - effectualOffset));
}
@@ -1409,9 +1480,12 @@
},
mVsyncMoveThreshold);
- EXPECT_TRUE(entry.schedule({.workDuration = 70, .readyDuration = 30, .lastVsync = 500},
- *mStubTracker.get(), 0)
- .has_value());
+ const auto scheduleResultOpt =
+ entry.schedule({.workDuration = 70, .readyDuration = 30, .lastVsync = 500},
+ *mStubTracker, 0);
+ ASSERT_TRUE(scheduleResultOpt);
+ EXPECT_EQ(900, scheduleResultOpt->callbackTime.ns());
+ EXPECT_EQ(mPeriod, scheduleResultOpt->vsyncTime.ns());
auto const wakeup = entry.wakeupTime();
ASSERT_TRUE(wakeup);
EXPECT_THAT(*wakeup, Eq(900));
diff --git a/services/surfaceflinger/tests/unittests/mock/MockVSyncDispatch.h b/services/surfaceflinger/tests/unittests/mock/MockVSyncDispatch.h
index dc32ff9..1dc2ef4 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockVSyncDispatch.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockVSyncDispatch.h
@@ -29,8 +29,10 @@
MOCK_METHOD(CallbackToken, registerCallback, (Callback, std::string), (override));
MOCK_METHOD(void, unregisterCallback, (CallbackToken), (override));
- MOCK_METHOD(scheduler::ScheduleResult, schedule, (CallbackToken, ScheduleTiming), (override));
- MOCK_METHOD(scheduler::ScheduleResult, update, (CallbackToken, ScheduleTiming), (override));
+ MOCK_METHOD(std::optional<scheduler::ScheduleResult>, schedule, (CallbackToken, ScheduleTiming),
+ (override));
+ MOCK_METHOD(std::optional<scheduler::ScheduleResult>, update, (CallbackToken, ScheduleTiming),
+ (override));
MOCK_METHOD(scheduler::CancelResult, cancel, (CallbackToken token), (override));
MOCK_METHOD(void, dump, (std::string&), (const, override));
};