blob: 9aa089f90087fb29b97bd8c824de5faf156a25f7 [file] [log] [blame]
/*
* 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 <gmock/gmock.h>
#include <gtest/gtest.h>
#include <scheduler/interface/ICompositor.h>
#include "FrameTimeline.h"
#include "Scheduler/MessageQueue.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(PhysicalDisplayId, const scheduler::FrameTargets&) override { return false; }
CompositeResultsPerDisplay composite(PhysicalDisplayId,
const scheduler::FrameTargeters&) override {
return {};
}
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<MockHandler> handler)
: impl::MessageQueue(gNoOpCompositor, handler), mHandler(std::move(handler)) {}
// impl::MessageQueue overrides:
void onFrameSignal(ICompositor&, VsyncId, TimePoint) override {}
public:
TestableMessageQueue() : TestableMessageQueue(sp<MockHandler>::make(*this)) {}
using impl::MessageQueue::vsyncCallback;
const sp<MockHandler> mHandler;
};
struct MockTokenManager : frametimeline::TokenManager {
MOCK_METHOD1(generateTokenForPredictions, int64_t(frametimeline::TimelineItem&& prediction));
MOCK_CONST_METHOD1(getPredictionsForToken, std::optional<frametimeline::TimelineItem>(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<mock::VSyncDispatch> mVSyncDispatch = std::make_shared<mock::VSyncDispatch>();
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(ftl::to_underlying(vsyncId)));
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