/* * Copyright 2020 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. */ #undef LOG_TAG #define LOG_TAG "LibSurfaceFlingerUnittests" #include #include #include "FrameTimeline.h" #include "Scheduler/MessageQueue.h" #include "SurfaceFlinger.h" #include "mock/MockVSyncDispatch.h" namespace android { using namespace std::chrono_literals; using namespace testing; using CallbackToken = scheduler::VSyncDispatch::CallbackToken; struct NoOpCompositor final : ICompositor { void configure() override {} bool commit(TimePoint, VsyncId, TimePoint) override { return false; } void composite(TimePoint, VsyncId) override {} void sample() override {} } gNoOpCompositor; class TestableMessageQueue : public impl::MessageQueue { struct MockHandler : MessageQueue::Handler { using MessageQueue::Handler::Handler; MOCK_METHOD(void, dispatchFrame, (VsyncId, TimePoint), (override)); }; explicit TestableMessageQueue(sp handler) : impl::MessageQueue(gNoOpCompositor, handler), mHandler(std::move(handler)) {} // impl::MessageQueue overrides: void onFrameSignal(ICompositor&, VsyncId, TimePoint) override {} public: TestableMessageQueue() : TestableMessageQueue(sp::make(*this)) {} using impl::MessageQueue::vsyncCallback; const sp mHandler; }; struct MockTokenManager : frametimeline::TokenManager { MOCK_METHOD1(generateTokenForPredictions, int64_t(frametimeline::TimelineItem&& prediction)); MOCK_CONST_METHOD1(getPredictionsForToken, std::optional(int64_t)); }; struct MessageQueueTest : testing::Test { void SetUp() override { EXPECT_CALL(*mVSyncDispatch, registerCallback(_, "sf")).WillOnce(Return(mCallbackToken)); EXPECT_NO_FATAL_FAILURE(mEventQueue.initVsync(mVSyncDispatch, mTokenManager, kDuration)); EXPECT_CALL(*mVSyncDispatch, unregisterCallback(mCallbackToken)).Times(1); } std::shared_ptr mVSyncDispatch = std::make_shared(); MockTokenManager mTokenManager; TestableMessageQueue mEventQueue; const CallbackToken mCallbackToken{5}; static constexpr Duration kDuration = 100ms; static constexpr Duration kDifferentDuration = 250ms; }; namespace { TEST_F(MessageQueueTest, commit) { const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDuration.ns(), .readyDuration = 0, .earliestVsync = 0}; EXPECT_FALSE(mEventQueue.getScheduledFrameTime()); EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234)); EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame()); ASSERT_TRUE(mEventQueue.getScheduledFrameTime()); EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count()); } TEST_F(MessageQueueTest, commitTwice) { InSequence s; const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDuration.ns(), .readyDuration = 0, .earliestVsync = 0}; EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234)); EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame()); ASSERT_TRUE(mEventQueue.getScheduledFrameTime()); EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count()); EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(4567)); EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame()); ASSERT_TRUE(mEventQueue.getScheduledFrameTime()); EXPECT_EQ(4567, mEventQueue.getScheduledFrameTime()->time_since_epoch().count()); } TEST_F(MessageQueueTest, commitTwiceWithCallback) { InSequence s; const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDuration.ns(), .readyDuration = 0, .earliestVsync = 0}; EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234)); EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame()); ASSERT_TRUE(mEventQueue.getScheduledFrameTime()); EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count()); constexpr TimePoint kStartTime = TimePoint::fromNs(100); constexpr TimePoint kEndTime = kStartTime + kDuration; constexpr TimePoint kPresentTime = TimePoint::fromNs(500); constexpr VsyncId vsyncId{42}; EXPECT_CALL(mTokenManager, generateTokenForPredictions(frametimeline::TimelineItem(kStartTime.ns(), kEndTime.ns(), kPresentTime.ns()))) .WillOnce(Return(vsyncId.value)); EXPECT_CALL(*mEventQueue.mHandler, dispatchFrame(vsyncId, kPresentTime)).Times(1); EXPECT_NO_FATAL_FAILURE( mEventQueue.vsyncCallback(kPresentTime.ns(), kStartTime.ns(), kEndTime.ns())); EXPECT_FALSE(mEventQueue.getScheduledFrameTime()); const auto timingAfterCallback = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDuration.ns(), .readyDuration = 0, .earliestVsync = kPresentTime.ns()}; EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timingAfterCallback)).WillOnce(Return(0)); EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame()); } TEST_F(MessageQueueTest, commitWithDurationChange) { EXPECT_NO_FATAL_FAILURE(mEventQueue.setDuration(kDifferentDuration)); const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDifferentDuration.ns(), .readyDuration = 0, .earliestVsync = 0}; EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(0)); EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame()); } } // namespace } // namespace android