diff options
Diffstat (limited to 'services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp')
-rw-r--r-- | services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp | 215 |
1 files changed, 184 insertions, 31 deletions
diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp index afebc40aa9..a9ad249383 100644 --- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp +++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp @@ -27,13 +27,99 @@ #include "AsyncCallRecorder.h" #include "Scheduler/DispSyncSource.h" -#include "mock/MockDispSync.h" +#include "Scheduler/VSyncDispatch.h" namespace android { namespace { using namespace std::chrono_literals; -using testing::Return; +using namespace testing; + +class MockVSyncDispatch : public scheduler::VSyncDispatch { +public: + MOCK_METHOD2(registerCallback, + CallbackToken(std::function<void(nsecs_t, nsecs_t, nsecs_t)> const&, std::string)); + MOCK_METHOD1(unregisterCallback, void(CallbackToken)); + MOCK_METHOD2(schedule, scheduler::ScheduleResult(CallbackToken, ScheduleTiming)); + MOCK_METHOD1(cancel, scheduler::CancelResult(CallbackToken token)); + MOCK_CONST_METHOD1(dump, void(std::string&)); + + MockVSyncDispatch() { + ON_CALL(*this, registerCallback) + .WillByDefault( + [this](std::function<void(nsecs_t, nsecs_t, nsecs_t)> const& callback, + std::string) { + CallbackToken token(mNextToken); + mNextToken++; + + mCallbacks.emplace(token, CallbackData(callback)); + ALOGD("registerCallback: %zu", token.value()); + return token; + }); + + ON_CALL(*this, unregisterCallback).WillByDefault([this](CallbackToken token) { + ALOGD("unregisterCallback: %zu", token.value()); + mCallbacks.erase(token); + }); + + ON_CALL(*this, schedule).WillByDefault([this](CallbackToken token, ScheduleTiming timing) { + ALOGD("schedule: %zu", token.value()); + if (mCallbacks.count(token) == 0) { + ALOGD("schedule: callback %zu not registered", token.value()); + return scheduler::ScheduleResult{}; + } + + auto& callback = mCallbacks.at(token); + callback.scheduled = true; + callback.vsyncTime = timing.earliestVsync; + callback.targetWakeupTime = + timing.earliestVsync - timing.workDuration - timing.readyDuration; + ALOGD("schedule: callback %zu scheduled", token.value()); + return scheduler::ScheduleResult{callback.targetWakeupTime}; + }); + + ON_CALL(*this, cancel).WillByDefault([this](CallbackToken token) { + ALOGD("cancel: %zu", token.value()); + if (mCallbacks.count(token) == 0) { + ALOGD("cancel: callback %zu is not registered", token.value()); + return scheduler::CancelResult::Error; + } + + auto& callback = mCallbacks.at(token); + callback.scheduled = false; + ALOGD("cancel: callback %zu cancelled", token.value()); + return scheduler::CancelResult::Cancelled; + }); + } + + void triggerCallbacks() { + ALOGD("triggerCallbacks"); + for (auto& [token, callback] : mCallbacks) { + if (callback.scheduled) { + ALOGD("triggerCallbacks: callback %zu", token.value()); + callback.scheduled = false; + callback.func(callback.vsyncTime, callback.targetWakeupTime, callback.readyTime); + } else { + ALOGD("triggerCallbacks: callback %zu is not scheduled", token.value()); + } + } + } + +private: + struct CallbackData { + explicit CallbackData(std::function<void(nsecs_t, nsecs_t, nsecs_t)> func) + : func(std::move(func)) {} + + std::function<void(nsecs_t, nsecs_t, nsecs_t)> func; + bool scheduled = false; + nsecs_t vsyncTime = 0; + nsecs_t targetWakeupTime = 0; + nsecs_t readyTime = 0; + }; + + std::unordered_map<CallbackToken, CallbackData> mCallbacks; + size_t mNextToken; +}; class DispSyncSourceTest : public testing::Test, private VSyncSource::Callback { protected: @@ -43,15 +129,19 @@ protected: void createDispSync(); void createDispSyncSource(); - void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) override; + void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp, + nsecs_t deadlineTimestamp) override; - std::unique_ptr<mock::DispSync> mDispSync; - std::unique_ptr<DispSyncSource> mDispSyncSource; + std::unique_ptr<MockVSyncDispatch> mVSyncDispatch; + std::unique_ptr<scheduler::DispSyncSource> mDispSyncSource; - AsyncCallRecorder<void (*)(nsecs_t)> mVSyncEventCallRecorder; + AsyncCallRecorder<void (*)(nsecs_t, nsecs_t, nsecs_t)> mVSyncEventCallRecorder; - static constexpr std::chrono::nanoseconds mPhaseOffset = 6ms; + static constexpr std::chrono::nanoseconds mWorkDuration = 20ms; + static constexpr std::chrono::nanoseconds mReadyDuration = 10ms; static constexpr int mIterations = 100; + const scheduler::VSyncDispatch::CallbackToken mFakeToken{2398}; + const std::string mName = "DispSyncSourceTest"; }; DispSyncSourceTest::DispSyncSourceTest() { @@ -66,20 +156,21 @@ DispSyncSourceTest::~DispSyncSourceTest() { ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); } -void DispSyncSourceTest::onVSyncEvent(nsecs_t when, nsecs_t /*expectedVSyncTimestamp*/) { +void DispSyncSourceTest::onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp, + nsecs_t deadlineTimestamp) { ALOGD("onVSyncEvent: %" PRId64, when); - mVSyncEventCallRecorder.recordCall(when); + mVSyncEventCallRecorder.recordCall(when, expectedVSyncTimestamp, deadlineTimestamp); } void DispSyncSourceTest::createDispSync() { - mDispSync = std::make_unique<mock::DispSync>(); + mVSyncDispatch = std::make_unique<MockVSyncDispatch>(); } void DispSyncSourceTest::createDispSyncSource() { - createDispSync(); - mDispSyncSource = std::make_unique<DispSyncSource>(mDispSync.get(), mPhaseOffset.count(), true, - "DispSyncSourceTest"); + mDispSyncSource = + std::make_unique<scheduler::DispSyncSource>(*mVSyncDispatch, mWorkDuration, + mReadyDuration, true, mName.c_str()); mDispSyncSource->setCallback(this); } @@ -89,57 +180,119 @@ void DispSyncSourceTest::createDispSyncSource() { TEST_F(DispSyncSourceTest, createDispSync) { createDispSync(); - EXPECT_TRUE(mDispSync); + EXPECT_TRUE(mVSyncDispatch); } TEST_F(DispSyncSourceTest, createDispSyncSource) { + createDispSync(); + + InSequence seq; + EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).WillOnce(Return(mFakeToken)); + EXPECT_CALL(*mVSyncDispatch, cancel(mFakeToken)) + .WillOnce(Return(scheduler::CancelResult::Cancelled)); + EXPECT_CALL(*mVSyncDispatch, unregisterCallback(mFakeToken)).WillOnce(Return()); createDispSyncSource(); + EXPECT_TRUE(mDispSyncSource); } TEST_F(DispSyncSourceTest, noCallbackAfterInit) { + createDispSync(); + + InSequence seq; + EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1); + EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1); + EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1); createDispSyncSource(); + EXPECT_TRUE(mDispSyncSource); // DispSyncSource starts with Vsync disabled - mDispSync->triggerCallback(); + mVSyncDispatch->triggerCallbacks(); EXPECT_FALSE(mVSyncEventCallRecorder.waitForUnexpectedCall().has_value()); } TEST_F(DispSyncSourceTest, waitForCallbacks) { + createDispSync(); + + InSequence seq; + EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1); + EXPECT_CALL(*mVSyncDispatch, + schedule(_, Truly([&](auto timings) { + return timings.workDuration == mWorkDuration.count() && + timings.readyDuration == mReadyDuration.count(); + }))) + .Times(mIterations + 1); + EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1); + EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1); createDispSyncSource(); + EXPECT_TRUE(mDispSyncSource); mDispSyncSource->setVSyncEnabled(true); - EXPECT_EQ(mDispSync->getCallbackPhase(), mPhaseOffset.count()); - for (int i = 0; i < mIterations; i++) { - mDispSync->triggerCallback(); - EXPECT_TRUE(mVSyncEventCallRecorder.waitForCall().has_value()); + mVSyncDispatch->triggerCallbacks(); + const auto callbackData = mVSyncEventCallRecorder.waitForCall(); + ASSERT_TRUE(callbackData.has_value()); + const auto [when, expectedVSyncTimestamp, deadlineTimestamp] = callbackData.value(); + EXPECT_EQ(when, expectedVSyncTimestamp - mWorkDuration.count() - mReadyDuration.count()); } } -TEST_F(DispSyncSourceTest, waitForCallbacksWithPhaseChange) { +TEST_F(DispSyncSourceTest, waitForCallbacksWithDurationChange) { + createDispSync(); + + InSequence seq; + EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1); + EXPECT_CALL(*mVSyncDispatch, + schedule(_, Truly([&](auto timings) { + return timings.workDuration == mWorkDuration.count() && + timings.readyDuration == mReadyDuration.count(); + }))) + .Times(1); + createDispSyncSource(); + EXPECT_TRUE(mDispSyncSource); mDispSyncSource->setVSyncEnabled(true); - EXPECT_EQ(mDispSync->getCallbackPhase(), mPhaseOffset.count()); - + EXPECT_CALL(*mVSyncDispatch, + schedule(_, Truly([&](auto timings) { + return timings.workDuration == mWorkDuration.count() && + timings.readyDuration == mReadyDuration.count(); + }))) + .Times(mIterations); for (int i = 0; i < mIterations; i++) { - mDispSync->triggerCallback(); - EXPECT_TRUE(mVSyncEventCallRecorder.waitForCall().has_value()); + mVSyncDispatch->triggerCallbacks(); + const auto callbackData = mVSyncEventCallRecorder.waitForCall(); + ASSERT_TRUE(callbackData.has_value()); + const auto [when, expectedVSyncTimestamp, deadlineTimestamp] = callbackData.value(); + EXPECT_EQ(when, expectedVSyncTimestamp - mWorkDuration.count() - mReadyDuration.count()); } - EXPECT_CALL(*mDispSync, getPeriod()).Times(1).WillOnce(Return(16666666)); - mDispSyncSource->setPhaseOffset((mPhaseOffset / 2).count()); - - EXPECT_EQ(mDispSync->getCallbackPhase(), (mPhaseOffset / 2).count()); - + const auto newDuration = mWorkDuration / 2; + EXPECT_CALL(*mVSyncDispatch, schedule(_, Truly([&](auto timings) { + return timings.workDuration == newDuration.count() && + timings.readyDuration == 0; + }))) + .Times(1); + mDispSyncSource->setDuration(newDuration, 0ns); + + EXPECT_CALL(*mVSyncDispatch, schedule(_, Truly([&](auto timings) { + return timings.workDuration == newDuration.count() && + timings.readyDuration == 0; + }))) + .Times(mIterations); for (int i = 0; i < mIterations; i++) { - mDispSync->triggerCallback(); - EXPECT_TRUE(mVSyncEventCallRecorder.waitForCall().has_value()); + mVSyncDispatch->triggerCallbacks(); + const auto callbackData = mVSyncEventCallRecorder.waitForCall(); + ASSERT_TRUE(callbackData.has_value()); + const auto [when, expectedVSyncTimestamp, deadlineTimestamp] = callbackData.value(); + EXPECT_EQ(when, expectedVSyncTimestamp - newDuration.count()); } + + EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1); + EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1); } } // namespace |