blob: 54f4c7c018601c8907632843a0de20a5839212bc [file] [log] [blame]
Ady Abraham50c202a2019-03-14 11:44:38 -07001/*
2 * Copyright 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#undef LOG_TAG
18#define LOG_TAG "LibSurfaceFlingerUnittests"
19#define LOG_NDEBUG 0
20
21#include <inttypes.h>
22
23#include <gmock/gmock.h>
24#include <gtest/gtest.h>
25
26#include <log/log.h>
27
28#include "AsyncCallRecorder.h"
29#include "Scheduler/DispSyncSource.h"
Ady Abraham9c53ee72020-07-22 21:16:18 -070030#include "Scheduler/VSyncDispatch.h"
Ady Abraham50c202a2019-03-14 11:44:38 -070031
32namespace android {
33namespace {
34
35using namespace std::chrono_literals;
Ady Abraham9c53ee72020-07-22 21:16:18 -070036using namespace testing;
37
38class MockVSyncDispatch : public scheduler::VSyncDispatch {
39public:
40 MOCK_METHOD2(registerCallback,
41 CallbackToken(std::function<void(nsecs_t, nsecs_t, nsecs_t)> const&, std::string));
42 MOCK_METHOD1(unregisterCallback, void(CallbackToken));
43 MOCK_METHOD2(schedule, scheduler::ScheduleResult(CallbackToken, ScheduleTiming));
44 MOCK_METHOD1(cancel, scheduler::CancelResult(CallbackToken token));
45 MOCK_CONST_METHOD1(dump, void(std::string&));
46
47 MockVSyncDispatch() {
48 ON_CALL(*this, registerCallback)
49 .WillByDefault(
50 [this](std::function<void(nsecs_t, nsecs_t, nsecs_t)> const& callback,
51 std::string) {
52 CallbackToken token(mNextToken);
53 mNextToken++;
54
55 mCallbacks.emplace(token, CallbackData(callback));
56 ALOGD("registerCallback: %zu", token.value());
57 return token;
58 });
59
60 ON_CALL(*this, unregisterCallback).WillByDefault([this](CallbackToken token) {
61 ALOGD("unregisterCallback: %zu", token.value());
62 mCallbacks.erase(token);
63 });
64
65 ON_CALL(*this, schedule).WillByDefault([this](CallbackToken token, ScheduleTiming timing) {
66 ALOGD("schedule: %zu", token.value());
67 if (mCallbacks.count(token) == 0) {
68 ALOGD("schedule: callback %zu not registered", token.value());
69 return scheduler::ScheduleResult::Error;
70 }
71
72 auto& callback = mCallbacks.at(token);
73 callback.scheduled = true;
74 callback.vsyncTime = timing.earliestVsync;
75 callback.targetWakeupTime =
76 timing.earliestVsync - timing.workDuration - timing.readyDuration;
77 ALOGD("schedule: callback %zu scheduled", token.value());
78 return scheduler::ScheduleResult::Scheduled;
79 });
80
81 ON_CALL(*this, cancel).WillByDefault([this](CallbackToken token) {
82 ALOGD("cancel: %zu", token.value());
83 if (mCallbacks.count(token) == 0) {
84 ALOGD("cancel: callback %zu is not registered", token.value());
85 return scheduler::CancelResult::Error;
86 }
87
88 auto& callback = mCallbacks.at(token);
89 callback.scheduled = false;
90 ALOGD("cancel: callback %zu cancelled", token.value());
91 return scheduler::CancelResult::Cancelled;
92 });
93 }
94
95 void triggerCallbacks() {
96 ALOGD("triggerCallbacks");
97 for (auto& [token, callback] : mCallbacks) {
98 if (callback.scheduled) {
99 ALOGD("triggerCallbacks: callback %zu", token.value());
100 callback.scheduled = false;
101 callback.func(callback.vsyncTime, callback.targetWakeupTime, callback.readyTime);
102 } else {
103 ALOGD("triggerCallbacks: callback %zu is not scheduled", token.value());
104 }
105 }
106 }
107
108private:
109 struct CallbackData {
110 explicit CallbackData(std::function<void(nsecs_t, nsecs_t, nsecs_t)> func)
111 : func(std::move(func)) {}
112
113 std::function<void(nsecs_t, nsecs_t, nsecs_t)> func;
114 bool scheduled = false;
115 nsecs_t vsyncTime = 0;
116 nsecs_t targetWakeupTime = 0;
117 nsecs_t readyTime = 0;
118 };
119
120 std::unordered_map<CallbackToken, CallbackData> mCallbacks;
121 size_t mNextToken;
122};
Ady Abraham50c202a2019-03-14 11:44:38 -0700123
124class DispSyncSourceTest : public testing::Test, private VSyncSource::Callback {
125protected:
126 DispSyncSourceTest();
127 ~DispSyncSourceTest() override;
128
129 void createDispSync();
130 void createDispSyncSource();
131
Ady Abraham9c53ee72020-07-22 21:16:18 -0700132 void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp,
133 nsecs_t deadlineTimestamp) override;
Ady Abraham50c202a2019-03-14 11:44:38 -0700134
Ady Abraham9c53ee72020-07-22 21:16:18 -0700135 std::unique_ptr<MockVSyncDispatch> mVSyncDispatch;
136 std::unique_ptr<scheduler::DispSyncSource> mDispSyncSource;
Ady Abraham50c202a2019-03-14 11:44:38 -0700137
Ady Abraham9c53ee72020-07-22 21:16:18 -0700138 AsyncCallRecorder<void (*)(nsecs_t, nsecs_t, nsecs_t)> mVSyncEventCallRecorder;
Ady Abraham50c202a2019-03-14 11:44:38 -0700139
Ady Abraham9c53ee72020-07-22 21:16:18 -0700140 static constexpr std::chrono::nanoseconds mWorkDuration = 20ms;
141 static constexpr std::chrono::nanoseconds mReadyDuration = 10ms;
Ady Abraham50c202a2019-03-14 11:44:38 -0700142 static constexpr int mIterations = 100;
Ady Abraham9c53ee72020-07-22 21:16:18 -0700143 const scheduler::VSyncDispatch::CallbackToken mFakeToken{2398};
144 const std::string mName = "DispSyncSourceTest";
Ady Abraham50c202a2019-03-14 11:44:38 -0700145};
146
147DispSyncSourceTest::DispSyncSourceTest() {
148 const ::testing::TestInfo* const test_info =
149 ::testing::UnitTest::GetInstance()->current_test_info();
150 ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
151}
152
153DispSyncSourceTest::~DispSyncSourceTest() {
154 const ::testing::TestInfo* const test_info =
155 ::testing::UnitTest::GetInstance()->current_test_info();
156 ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
157}
158
Ady Abraham9c53ee72020-07-22 21:16:18 -0700159void DispSyncSourceTest::onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp,
160 nsecs_t deadlineTimestamp) {
Ady Abraham50c202a2019-03-14 11:44:38 -0700161 ALOGD("onVSyncEvent: %" PRId64, when);
162
Ady Abraham9c53ee72020-07-22 21:16:18 -0700163 mVSyncEventCallRecorder.recordCall(when, expectedVSyncTimestamp, deadlineTimestamp);
Ady Abraham50c202a2019-03-14 11:44:38 -0700164}
165
166void DispSyncSourceTest::createDispSync() {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700167 mVSyncDispatch = std::make_unique<MockVSyncDispatch>();
Ady Abraham50c202a2019-03-14 11:44:38 -0700168}
169
170void DispSyncSourceTest::createDispSyncSource() {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700171 mDispSyncSource =
172 std::make_unique<scheduler::DispSyncSource>(*mVSyncDispatch, mWorkDuration,
173 mReadyDuration, true, mName.c_str());
Ady Abraham50c202a2019-03-14 11:44:38 -0700174 mDispSyncSource->setCallback(this);
175}
176
177/* ------------------------------------------------------------------------
178 * Test cases
179 */
180
181TEST_F(DispSyncSourceTest, createDispSync) {
182 createDispSync();
Ady Abraham9c53ee72020-07-22 21:16:18 -0700183 EXPECT_TRUE(mVSyncDispatch);
Ady Abraham50c202a2019-03-14 11:44:38 -0700184}
185
186TEST_F(DispSyncSourceTest, createDispSyncSource) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700187 createDispSync();
188
189 InSequence seq;
190 EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).WillOnce(Return(mFakeToken));
191 EXPECT_CALL(*mVSyncDispatch, cancel(mFakeToken))
192 .WillOnce(Return(scheduler::CancelResult::Cancelled));
193 EXPECT_CALL(*mVSyncDispatch, unregisterCallback(mFakeToken)).WillOnce(Return());
Ady Abraham50c202a2019-03-14 11:44:38 -0700194 createDispSyncSource();
Ady Abraham9c53ee72020-07-22 21:16:18 -0700195
Ady Abraham50c202a2019-03-14 11:44:38 -0700196 EXPECT_TRUE(mDispSyncSource);
197}
198
199TEST_F(DispSyncSourceTest, noCallbackAfterInit) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700200 createDispSync();
201
202 InSequence seq;
203 EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
204 EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
205 EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
Ady Abraham50c202a2019-03-14 11:44:38 -0700206 createDispSyncSource();
Ady Abraham9c53ee72020-07-22 21:16:18 -0700207
Ady Abraham50c202a2019-03-14 11:44:38 -0700208 EXPECT_TRUE(mDispSyncSource);
209
210 // DispSyncSource starts with Vsync disabled
Ady Abraham9c53ee72020-07-22 21:16:18 -0700211 mVSyncDispatch->triggerCallbacks();
Ady Abraham50c202a2019-03-14 11:44:38 -0700212 EXPECT_FALSE(mVSyncEventCallRecorder.waitForUnexpectedCall().has_value());
213}
214
215TEST_F(DispSyncSourceTest, waitForCallbacks) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700216 createDispSync();
217
218 InSequence seq;
219 EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
220 EXPECT_CALL(*mVSyncDispatch,
221 schedule(_, Truly([&](auto timings) {
222 return timings.workDuration == mWorkDuration.count() &&
223 timings.readyDuration == mReadyDuration.count();
224 })))
225 .Times(mIterations + 1);
226 EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
227 EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
Ady Abraham50c202a2019-03-14 11:44:38 -0700228 createDispSyncSource();
Ady Abraham9c53ee72020-07-22 21:16:18 -0700229
Ady Abraham50c202a2019-03-14 11:44:38 -0700230 EXPECT_TRUE(mDispSyncSource);
231
232 mDispSyncSource->setVSyncEnabled(true);
Ady Abraham50c202a2019-03-14 11:44:38 -0700233 for (int i = 0; i < mIterations; i++) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700234 mVSyncDispatch->triggerCallbacks();
235 const auto callbackData = mVSyncEventCallRecorder.waitForCall();
236 ASSERT_TRUE(callbackData.has_value());
237 const auto [when, expectedVSyncTimestamp, deadlineTimestamp] = callbackData.value();
238 EXPECT_EQ(when, expectedVSyncTimestamp - mWorkDuration.count() - mReadyDuration.count());
Ady Abraham50c202a2019-03-14 11:44:38 -0700239 }
240}
241
Ady Abraham9c53ee72020-07-22 21:16:18 -0700242TEST_F(DispSyncSourceTest, waitForCallbacksWithDurationChange) {
243 createDispSync();
244
245 InSequence seq;
246 EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
247 EXPECT_CALL(*mVSyncDispatch,
248 schedule(_, Truly([&](auto timings) {
249 return timings.workDuration == mWorkDuration.count() &&
250 timings.readyDuration == mReadyDuration.count();
251 })))
252 .Times(1);
253
Ady Abraham50c202a2019-03-14 11:44:38 -0700254 createDispSyncSource();
Ady Abraham9c53ee72020-07-22 21:16:18 -0700255
Ady Abraham50c202a2019-03-14 11:44:38 -0700256 EXPECT_TRUE(mDispSyncSource);
257
258 mDispSyncSource->setVSyncEnabled(true);
Ady Abraham9c53ee72020-07-22 21:16:18 -0700259 EXPECT_CALL(*mVSyncDispatch,
260 schedule(_, Truly([&](auto timings) {
261 return timings.workDuration == mWorkDuration.count() &&
262 timings.readyDuration == mReadyDuration.count();
263 })))
264 .Times(mIterations);
Ady Abraham50c202a2019-03-14 11:44:38 -0700265 for (int i = 0; i < mIterations; i++) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700266 mVSyncDispatch->triggerCallbacks();
267 const auto callbackData = mVSyncEventCallRecorder.waitForCall();
268 ASSERT_TRUE(callbackData.has_value());
269 const auto [when, expectedVSyncTimestamp, deadlineTimestamp] = callbackData.value();
270 EXPECT_EQ(when, expectedVSyncTimestamp - mWorkDuration.count() - mReadyDuration.count());
Ady Abraham50c202a2019-03-14 11:44:38 -0700271 }
272
Ady Abraham9c53ee72020-07-22 21:16:18 -0700273 const auto newDuration = mWorkDuration / 2;
274 EXPECT_CALL(*mVSyncDispatch, schedule(_, Truly([&](auto timings) {
275 return timings.workDuration == newDuration.count() &&
276 timings.readyDuration == 0;
277 })))
278 .Times(1);
279 mDispSyncSource->setDuration(newDuration, 0ns);
Ady Abraham50c202a2019-03-14 11:44:38 -0700280
Ady Abraham9c53ee72020-07-22 21:16:18 -0700281 EXPECT_CALL(*mVSyncDispatch, schedule(_, Truly([&](auto timings) {
282 return timings.workDuration == newDuration.count() &&
283 timings.readyDuration == 0;
284 })))
285 .Times(mIterations);
Ady Abraham50c202a2019-03-14 11:44:38 -0700286 for (int i = 0; i < mIterations; i++) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700287 mVSyncDispatch->triggerCallbacks();
288 const auto callbackData = mVSyncEventCallRecorder.waitForCall();
289 ASSERT_TRUE(callbackData.has_value());
290 const auto [when, expectedVSyncTimestamp, deadlineTimestamp] = callbackData.value();
291 EXPECT_EQ(when, expectedVSyncTimestamp - newDuration.count());
Ady Abraham50c202a2019-03-14 11:44:38 -0700292 }
Ady Abraham9c53ee72020-07-22 21:16:18 -0700293
294 EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
295 EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
Ady Abraham50c202a2019-03-14 11:44:38 -0700296}
297
Ady Abraham50c202a2019-03-14 11:44:38 -0700298} // namespace
299} // namespace android