blob: ec27edac6e08cf52bd0c49e1a8d58e56b516942a [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"
Rachel Leeef2e21f2022-02-01 14:51:34 -080031#include "mock/MockVSyncTracker.h"
Ady Abraham50c202a2019-03-14 11:44:38 -070032
33namespace android {
34namespace {
35
36using namespace std::chrono_literals;
Ady Abraham9c53ee72020-07-22 21:16:18 -070037using namespace testing;
38
39class MockVSyncDispatch : public scheduler::VSyncDispatch {
40public:
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080041 MOCK_METHOD(CallbackToken, registerCallback, (Callback, std::string), (override));
42 MOCK_METHOD(void, unregisterCallback, (CallbackToken), (override));
43 MOCK_METHOD(scheduler::ScheduleResult, schedule, (CallbackToken, ScheduleTiming), (override));
44 MOCK_METHOD(scheduler::CancelResult, cancel, (CallbackToken), (override));
45 MOCK_METHOD(void, dump, (std::string&), (const, override));
Ady Abraham9c53ee72020-07-22 21:16:18 -070046
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());
Ady Abrahamb5d3afa2021-05-07 11:22:23 -070069 return scheduler::ScheduleResult{};
Ady Abraham9c53ee72020-07-22 21:16:18 -070070 }
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());
Ady Abrahamb5d3afa2021-05-07 11:22:23 -070078 return scheduler::ScheduleResult{callback.targetWakeupTime};
Ady Abraham9c53ee72020-07-22 21:16:18 -070079 });
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
Rachel Leeef2e21f2022-02-01 14:51:34 -0800129 void SetUp() override;
Ady Abraham50c202a2019-03-14 11:44:38 -0700130 void createDispSyncSource();
131
Rachel Leef16da3c2022-01-20 13:57:18 -0800132 void onVSyncEvent(nsecs_t when, VSyncSource::VSyncData) override;
Ady Abraham50c202a2019-03-14 11:44:38 -0700133
Ady Abraham9c53ee72020-07-22 21:16:18 -0700134 std::unique_ptr<MockVSyncDispatch> mVSyncDispatch;
Rachel Leeef2e21f2022-02-01 14:51:34 -0800135 std::unique_ptr<mock::VSyncTracker> mVSyncTracker;
Ady Abraham9c53ee72020-07-22 21:16:18 -0700136 std::unique_ptr<scheduler::DispSyncSource> mDispSyncSource;
Ady Abraham50c202a2019-03-14 11:44:38 -0700137
Rachel Leef16da3c2022-01-20 13:57:18 -0800138 AsyncCallRecorder<void (*)(nsecs_t, VSyncSource::VSyncData)> 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
Rachel Leeef2e21f2022-02-01 14:51:34 -0800159void DispSyncSourceTest::SetUp() {
160 mVSyncDispatch = std::make_unique<MockVSyncDispatch>();
161 mVSyncTracker = std::make_unique<mock::VSyncTracker>();
162}
163
Rachel Leef16da3c2022-01-20 13:57:18 -0800164void DispSyncSourceTest::onVSyncEvent(nsecs_t when, VSyncSource::VSyncData vsyncData) {
Ady Abraham50c202a2019-03-14 11:44:38 -0700165 ALOGD("onVSyncEvent: %" PRId64, when);
166
Rachel Leef16da3c2022-01-20 13:57:18 -0800167 mVSyncEventCallRecorder.recordCall(when, vsyncData);
Ady Abraham50c202a2019-03-14 11:44:38 -0700168}
169
Ady Abraham50c202a2019-03-14 11:44:38 -0700170void DispSyncSourceTest::createDispSyncSource() {
Rachel Leeef2e21f2022-02-01 14:51:34 -0800171 mDispSyncSource = std::make_unique<scheduler::DispSyncSource>(*mVSyncDispatch, *mVSyncTracker,
172 mWorkDuration, mReadyDuration,
173 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) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700182 EXPECT_TRUE(mVSyncDispatch);
Ady Abraham50c202a2019-03-14 11:44:38 -0700183}
184
185TEST_F(DispSyncSourceTest, createDispSyncSource) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700186 InSequence seq;
187 EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).WillOnce(Return(mFakeToken));
188 EXPECT_CALL(*mVSyncDispatch, cancel(mFakeToken))
189 .WillOnce(Return(scheduler::CancelResult::Cancelled));
190 EXPECT_CALL(*mVSyncDispatch, unregisterCallback(mFakeToken)).WillOnce(Return());
Ady Abraham50c202a2019-03-14 11:44:38 -0700191 createDispSyncSource();
Ady Abraham9c53ee72020-07-22 21:16:18 -0700192
Ady Abraham50c202a2019-03-14 11:44:38 -0700193 EXPECT_TRUE(mDispSyncSource);
194}
195
196TEST_F(DispSyncSourceTest, noCallbackAfterInit) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700197 InSequence seq;
198 EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
199 EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
200 EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
Ady Abraham50c202a2019-03-14 11:44:38 -0700201 createDispSyncSource();
Ady Abraham9c53ee72020-07-22 21:16:18 -0700202
Ady Abraham50c202a2019-03-14 11:44:38 -0700203 EXPECT_TRUE(mDispSyncSource);
204
205 // DispSyncSource starts with Vsync disabled
Ady Abraham9c53ee72020-07-22 21:16:18 -0700206 mVSyncDispatch->triggerCallbacks();
Ady Abraham50c202a2019-03-14 11:44:38 -0700207 EXPECT_FALSE(mVSyncEventCallRecorder.waitForUnexpectedCall().has_value());
208}
209
210TEST_F(DispSyncSourceTest, waitForCallbacks) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700211 InSequence seq;
212 EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
213 EXPECT_CALL(*mVSyncDispatch,
214 schedule(_, Truly([&](auto timings) {
215 return timings.workDuration == mWorkDuration.count() &&
216 timings.readyDuration == mReadyDuration.count();
217 })))
218 .Times(mIterations + 1);
219 EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
220 EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
Ady Abraham50c202a2019-03-14 11:44:38 -0700221 createDispSyncSource();
Ady Abraham9c53ee72020-07-22 21:16:18 -0700222
Ady Abraham50c202a2019-03-14 11:44:38 -0700223 EXPECT_TRUE(mDispSyncSource);
224
225 mDispSyncSource->setVSyncEnabled(true);
Ady Abraham50c202a2019-03-14 11:44:38 -0700226 for (int i = 0; i < mIterations; i++) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700227 mVSyncDispatch->triggerCallbacks();
228 const auto callbackData = mVSyncEventCallRecorder.waitForCall();
229 ASSERT_TRUE(callbackData.has_value());
Rachel Leef16da3c2022-01-20 13:57:18 -0800230 const auto [when, vsyncData] = callbackData.value();
231 EXPECT_EQ(when,
Rachel Leeb9c5a772022-02-04 21:17:37 -0800232 vsyncData.expectedPresentationTime - mWorkDuration.count() -
Rachel Leef16da3c2022-01-20 13:57:18 -0800233 mReadyDuration.count());
Ady Abraham50c202a2019-03-14 11:44:38 -0700234 }
235}
236
Ady Abraham9c53ee72020-07-22 21:16:18 -0700237TEST_F(DispSyncSourceTest, waitForCallbacksWithDurationChange) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700238 InSequence seq;
239 EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
240 EXPECT_CALL(*mVSyncDispatch,
241 schedule(_, Truly([&](auto timings) {
242 return timings.workDuration == mWorkDuration.count() &&
243 timings.readyDuration == mReadyDuration.count();
244 })))
245 .Times(1);
246
Ady Abraham50c202a2019-03-14 11:44:38 -0700247 createDispSyncSource();
Ady Abraham9c53ee72020-07-22 21:16:18 -0700248
Ady Abraham50c202a2019-03-14 11:44:38 -0700249 EXPECT_TRUE(mDispSyncSource);
250
251 mDispSyncSource->setVSyncEnabled(true);
Ady Abraham9c53ee72020-07-22 21:16:18 -0700252 EXPECT_CALL(*mVSyncDispatch,
253 schedule(_, Truly([&](auto timings) {
254 return timings.workDuration == mWorkDuration.count() &&
255 timings.readyDuration == mReadyDuration.count();
256 })))
257 .Times(mIterations);
Ady Abraham50c202a2019-03-14 11:44:38 -0700258 for (int i = 0; i < mIterations; i++) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700259 mVSyncDispatch->triggerCallbacks();
260 const auto callbackData = mVSyncEventCallRecorder.waitForCall();
261 ASSERT_TRUE(callbackData.has_value());
Rachel Leef16da3c2022-01-20 13:57:18 -0800262 const auto [when, vsyncData] = callbackData.value();
263 EXPECT_EQ(when,
Rachel Leeb9c5a772022-02-04 21:17:37 -0800264 vsyncData.expectedPresentationTime - mWorkDuration.count() -
Rachel Leef16da3c2022-01-20 13:57:18 -0800265 mReadyDuration.count());
Ady Abraham50c202a2019-03-14 11:44:38 -0700266 }
267
Ady Abraham9c53ee72020-07-22 21:16:18 -0700268 const auto newDuration = mWorkDuration / 2;
269 EXPECT_CALL(*mVSyncDispatch, schedule(_, Truly([&](auto timings) {
270 return timings.workDuration == newDuration.count() &&
271 timings.readyDuration == 0;
272 })))
273 .Times(1);
274 mDispSyncSource->setDuration(newDuration, 0ns);
Ady Abraham50c202a2019-03-14 11:44:38 -0700275
Ady Abraham9c53ee72020-07-22 21:16:18 -0700276 EXPECT_CALL(*mVSyncDispatch, schedule(_, Truly([&](auto timings) {
277 return timings.workDuration == newDuration.count() &&
278 timings.readyDuration == 0;
279 })))
280 .Times(mIterations);
Ady Abraham50c202a2019-03-14 11:44:38 -0700281 for (int i = 0; i < mIterations; i++) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700282 mVSyncDispatch->triggerCallbacks();
283 const auto callbackData = mVSyncEventCallRecorder.waitForCall();
284 ASSERT_TRUE(callbackData.has_value());
Rachel Leef16da3c2022-01-20 13:57:18 -0800285 const auto [when, vsyncData] = callbackData.value();
Rachel Leeb9c5a772022-02-04 21:17:37 -0800286 EXPECT_EQ(when, vsyncData.expectedPresentationTime - newDuration.count());
Ady Abraham50c202a2019-03-14 11:44:38 -0700287 }
Ady Abraham9c53ee72020-07-22 21:16:18 -0700288
289 EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
290 EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
Ady Abraham50c202a2019-03-14 11:44:38 -0700291}
292
Rachel Leeef2e21f2022-02-01 14:51:34 -0800293TEST_F(DispSyncSourceTest, getLatestVsyncData) {
294 const nsecs_t now = systemTime();
295 const nsecs_t vsyncInternalDuration = mWorkDuration.count() + mReadyDuration.count();
296 EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_))
297 .WillOnce(Return(now + vsyncInternalDuration + 1));
298 {
299 InSequence seq;
300 EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
301 EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
302 EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
303 }
304
305 createDispSyncSource();
306 EXPECT_TRUE(mDispSyncSource);
307
308 const auto vsyncData = mDispSyncSource->getLatestVSyncData();
309 ASSERT_GT(vsyncData.deadlineTimestamp, now);
Rachel Leeb9c5a772022-02-04 21:17:37 -0800310 ASSERT_GT(vsyncData.expectedPresentationTime, vsyncData.deadlineTimestamp);
Rachel Leeef2e21f2022-02-01 14:51:34 -0800311 EXPECT_EQ(vsyncData.deadlineTimestamp,
Rachel Leeb9c5a772022-02-04 21:17:37 -0800312 vsyncData.expectedPresentationTime - vsyncInternalDuration);
Rachel Leeef2e21f2022-02-01 14:51:34 -0800313}
314
Ady Abraham50c202a2019-03-14 11:44:38 -0700315} // namespace
316} // namespace android