1 /*
2  * Copyright 2023 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 
20 #include <gui/SurfaceComposerClient.h>
21 #include "DisplayHardware/Hal.h"
22 #include "DisplayTransactionTestHelpers.h"
23 
24 namespace android {
25 
26 using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
27 using android::hardware::graphics::composer::hal::Error;
28 
29 class NotifyExpectedPresentTest : public DisplayTransactionTest {
30 public:
SetUp()31     void SetUp() override {
32         const auto display = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this).inject();
33         mPhysicalDisplayId = display->getPhysicalId();
34         FakeHwcDisplayInjector(mPhysicalDisplayId, hal::DisplayType::PHYSICAL, /*isPrimary=*/true)
35                 .setPowerMode(hal::PowerMode::ON)
36                 .inject(&mFlinger, mComposer);
37 
38         ASSERT_NO_FATAL_FAILURE(mFlinger.setNotifyExpectedPresentData(mPhysicalDisplayId,
39                                                                       TimePoint::fromNs(0),
40                                                                       kFps60Hz));
41         mCompositor = std::make_unique<Compositor>(mPhysicalDisplayId, mFlinger);
42     }
43 
44 protected:
setTransactionState()45     void setTransactionState() {
46         ASSERT_TRUE(mFlinger.getTransactionQueue().isEmpty());
47         TransactionInfo transaction;
48         mFlinger.setTransactionState(FrameTimelineInfo{}, transaction.states, transaction.displays,
49                                      transaction.flags, transaction.applyToken,
50                                      transaction.inputWindowCommands,
51                                      TimePoint::now().ns() + s2ns(1), transaction.isAutoTimestamp,
52                                      transaction.unCachedBuffers,
53                                      /*HasListenerCallbacks=*/false, transaction.callbacks,
54                                      transaction.id, transaction.mergedTransactionIds);
55     }
56 
57     struct TransactionInfo {
58         Vector<ComposerState> states;
59         Vector<DisplayState> displays;
60         uint32_t flags = 0;
61         sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
62         InputWindowCommands inputWindowCommands;
63         int64_t desiredPresentTime = 0;
64         bool isAutoTimestamp = false;
65         FrameTimelineInfo frameTimelineInfo{};
66         std::vector<client_cache_t> unCachedBuffers;
67         uint64_t id = static_cast<uint64_t>(-1);
68         std::vector<uint64_t> mergedTransactionIds;
69         std::vector<ListenerCallbacks> callbacks;
70     };
71 
72     struct Compositor final : ICompositor {
Compositorandroid::NotifyExpectedPresentTest::Compositor73         explicit Compositor(PhysicalDisplayId displayId, TestableSurfaceFlinger& surfaceFlinger)
74               : displayId(displayId), surfaceFlinger(surfaceFlinger) {}
75 
sendNotifyExpectedPresentHintandroid::NotifyExpectedPresentTest::Compositor76         void sendNotifyExpectedPresentHint(PhysicalDisplayId id) override {
77             surfaceFlinger.sendNotifyExpectedPresentHint(id);
78         }
79 
commitandroid::NotifyExpectedPresentTest::Compositor80         bool commit(PhysicalDisplayId, const scheduler::FrameTargets&) override {
81             return committed;
82         }
83 
compositeandroid::NotifyExpectedPresentTest::Compositor84         CompositeResultsPerDisplay composite(PhysicalDisplayId pacesetterId,
85                                              const scheduler::FrameTargeters& targeters) override {
86             pacesetterIds.composite = pacesetterId;
87             CompositeResultsPerDisplay results;
88 
89             for (const auto& [id, targeter] : targeters) {
90                 vsyncIds.composite.emplace_back(id, targeter->target().vsyncId());
91                 surfaceFlinger.resetNotifyExpectedPresentHintState(pacesetterId);
92                 results.try_emplace(id,
93                                     CompositeResult{.compositionCoverage =
94                                                             CompositionCoverage::Hwc});
95             }
96 
97             return results;
98         }
99 
sampleandroid::NotifyExpectedPresentTest::Compositor100         void sample() override {}
configureandroid::NotifyExpectedPresentTest::Compositor101         void configure() override {}
102 
103         struct {
104             PhysicalDisplayId commit;
105             PhysicalDisplayId composite;
106         } pacesetterIds;
107 
108         using VsyncIds = std::vector<std::pair<PhysicalDisplayId, VsyncId>>;
109         struct {
110             VsyncIds commit;
111             VsyncIds composite;
112         } vsyncIds;
113 
114         bool committed = true;
115         PhysicalDisplayId displayId;
116         TestableSurfaceFlinger& surfaceFlinger;
117     };
118 
119     PhysicalDisplayId mPhysicalDisplayId;
120     std::unique_ptr<Compositor> mCompositor;
121     static constexpr hal::HWDisplayId kHwcDisplayId =
122             FakeHwcDisplayInjector::DEFAULT_HWC_DISPLAY_ID;
123     static constexpr Fps kFps60Hz = 60_Hz;
124     static constexpr int32_t kFrameInterval5HzNs = static_cast<Fps>(5_Hz).getPeriodNsecs();
125     static constexpr int32_t kFrameInterval60HzNs = kFps60Hz.getPeriodNsecs();
126     static constexpr int32_t kFrameInterval120HzNs = static_cast<Fps>(120_Hz).getPeriodNsecs();
127     static constexpr Period kVsyncPeriod =
128             Period::fromNs(static_cast<Fps>(240_Hz).getPeriodNsecs());
129     static constexpr Period kTimeoutNs = Period::fromNs(kFrameInterval5HzNs);
130 };
131 
TEST_F(NotifyExpectedPresentTest,noNotifyExpectedPresentHintCall_absentTimeout)132 TEST_F(NotifyExpectedPresentTest, noNotifyExpectedPresentHintCall_absentTimeout) {
133     auto expectedPresentTime = TimePoint::now().ns() + ms2ns(10);
134     ASSERT_NO_FATAL_FAILURE(
135             mFlinger.setNotifyExpectedPresentData(mPhysicalDisplayId,
136                                                   TimePoint::fromNs(expectedPresentTime),
137                                                   kFps60Hz));
138     EXPECT_CALL(*mComposer, notifyExpectedPresent(kHwcDisplayId, _, _)).Times(0);
139     for (int i = 0; i < 5; i++) {
140         expectedPresentTime += 2 * kFrameInterval5HzNs;
141         mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
142                                                  TimePoint::fromNs(expectedPresentTime), kFps60Hz,
143                                                  /*timeoutOpt*/ std::nullopt);
144         EXPECT_TRUE(
145                 mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
146         ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
147     }
148 }
149 
TEST_F(NotifyExpectedPresentTest,notifyExpectedPresentHint_zeroTimeout)150 TEST_F(NotifyExpectedPresentTest, notifyExpectedPresentHint_zeroTimeout) {
151     auto expectedPresentTime = TimePoint::now().ns() + ms2ns(10);
152     {
153         // Very first ExpectedPresent after idle, no previous timestamp.
154         EXPECT_CALL(*mComposer,
155                     notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs))
156                 .WillOnce(Return(Error::NONE));
157         mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
158                                                  TimePoint::fromNs(expectedPresentTime), kFps60Hz,
159                                                  kTimeoutNs);
160         ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
161 
162         // Present frame
163         mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
164         // Present happens and NotifyExpectedPresentHintStatus is start.
165         ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
166     }
167     {
168         mCompositor->committed = false;
169         expectedPresentTime += kFrameInterval60HzNs;
170         EXPECT_CALL(static_cast<mock::VSyncTracker&>(
171                             mFlinger.scheduler()->getVsyncSchedule()->getTracker()),
172                     nextAnticipatedVSyncTimeFrom(_, _))
173                 .WillRepeatedly(Return(expectedPresentTime));
174         EXPECT_CALL(*mComposer,
175                     notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs))
176                 .WillOnce(Return(Error::NONE));
177         mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
178                                                  TimePoint::fromNs(expectedPresentTime), kFps60Hz,
179                                                  Period::fromNs(0));
180         EXPECT_TRUE(
181                 mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
182         ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
183         mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
184         // Hint sent
185         ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
186     }
187     {
188         expectedPresentTime += kFrameInterval60HzNs;
189         EXPECT_CALL(static_cast<mock::VSyncTracker&>(
190                             mFlinger.scheduler()->getVsyncSchedule()->getTracker()),
191                     nextAnticipatedVSyncTimeFrom(_, _))
192                 .WillRepeatedly(Return(expectedPresentTime));
193         EXPECT_CALL(*mComposer,
194                     notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs))
195                 .WillOnce(Return(Error::NONE));
196         mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
197                                                  TimePoint::fromNs(expectedPresentTime), kFps60Hz,
198                                                  Period::fromNs(0));
199         EXPECT_TRUE(
200                 mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
201         // Hint is executed
202         ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
203         mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
204         ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
205     }
206 }
TEST_F(NotifyExpectedPresentTest,notifyExpectedPresentTimeout)207 TEST_F(NotifyExpectedPresentTest, notifyExpectedPresentTimeout) {
208     auto expectedPresentTime = TimePoint::now().ns() + ms2ns(10);
209     {
210         // Very first ExpectedPresent after idle, no previous timestamp
211         mCompositor->committed = false;
212         EXPECT_CALL(*mComposer,
213                     notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs))
214                 .WillOnce(Return(Error::NONE));
215         mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
216                                                  TimePoint::fromNs(expectedPresentTime), kFps60Hz,
217                                                  kTimeoutNs);
218         ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
219         mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
220         ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
221     }
222     {
223         EXPECT_CALL(*mComposer, notifyExpectedPresent(kHwcDisplayId, _, _)).Times(0);
224         expectedPresentTime += 2 * kFrameInterval5HzNs;
225         mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
226                                                  TimePoint::fromNs(expectedPresentTime), kFps60Hz,
227                                                  kTimeoutNs);
228         EXPECT_TRUE(
229                 mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
230         ASSERT_TRUE(mFlinger.verifyHintStatusIsScheduledOnTx(mPhysicalDisplayId));
231         mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
232         ASSERT_TRUE(mFlinger.verifyHintStatusIsScheduledOnTx(mPhysicalDisplayId));
233         {
234             EXPECT_CALL(*mComposer,
235                         notifyExpectedPresent(kHwcDisplayId, expectedPresentTime,
236                                               kFrameInterval60HzNs))
237                     .WillOnce(Return(Error::NONE));
238             // Hint sent with the setTransactionState
239             setTransactionState();
240             ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
241         }
242     }
243     {
244         // ExpectedPresentTime is after the timeoutNs
245         mCompositor->committed = true;
246         expectedPresentTime += 2 * kFrameInterval5HzNs;
247         EXPECT_CALL(*mComposer, notifyExpectedPresent(kHwcDisplayId, _, _)).Times(0);
248         mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
249                                                  TimePoint::fromNs(expectedPresentTime), kFps60Hz,
250                                                  kTimeoutNs);
251         EXPECT_TRUE(
252                 mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
253         ASSERT_TRUE(mFlinger.verifyHintStatusIsScheduledOnTx(mPhysicalDisplayId));
254         mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
255         // Present happens notifyExpectedPresentHintStatus is Start
256         ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
257 
258         // Another expectedPresent after timeout
259         expectedPresentTime += 2 * kFrameInterval5HzNs;
260         EXPECT_CALL(*mComposer,
261                     notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs))
262                 .WillOnce(Return(Error::NONE));
263         mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
264                                                  TimePoint::fromNs(expectedPresentTime), kFps60Hz,
265                                                  kTimeoutNs);
266         EXPECT_TRUE(
267                 mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
268         ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
269         mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
270         ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
271     }
272     {
273         // ExpectedPresent has not changed
274         EXPECT_CALL(*mComposer, notifyExpectedPresent(kHwcDisplayId, _, _)).Times(0);
275         mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
276                                                  TimePoint::fromNs(expectedPresentTime), kFps60Hz,
277                                                  kTimeoutNs);
278         EXPECT_TRUE(
279                 mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
280         ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
281         mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
282         ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
283     }
284     {
285         // ExpectedPresent is after the last reported ExpectedPresent and within timeout.
286         expectedPresentTime += kFrameInterval60HzNs;
287         EXPECT_CALL(*mComposer, notifyExpectedPresent(kHwcDisplayId, _, _)).Times(0);
288         mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
289                                                  TimePoint::fromNs(expectedPresentTime), kFps60Hz,
290                                                  kTimeoutNs);
291         EXPECT_TRUE(
292                 mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
293         ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
294         mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
295         ASSERT_TRUE(mFlinger.verifyHintStatusIsStart(mPhysicalDisplayId));
296     }
297     {
298         // ExpectedPresent is before the last reported ExpectedPresent but after the timeoutNs,
299         // representing we changed our decision and want to present earlier than previously
300         // reported.
301         mCompositor->committed = false;
302         expectedPresentTime -= kFrameInterval120HzNs;
303         EXPECT_CALL(*mComposer,
304                     notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs))
305                 .WillOnce(Return(Error::NONE));
306         mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
307                                                  TimePoint::fromNs(expectedPresentTime), kFps60Hz,
308                                                  kTimeoutNs);
309         EXPECT_TRUE(
310                 mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime));
311         ASSERT_TRUE(mFlinger.verifyHintIsScheduledOnPresent(mPhysicalDisplayId));
312         mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
313         ASSERT_TRUE(mFlinger.verifyHintIsSent(mPhysicalDisplayId));
314     }
315 }
316 
TEST_F(NotifyExpectedPresentTest,notifyExpectedPresentRenderRateChanged)317 TEST_F(NotifyExpectedPresentTest, notifyExpectedPresentRenderRateChanged) {
318     const auto now = TimePoint::now().ns();
319     auto expectedPresentTime = now;
320     static constexpr Period kTimeoutNs = Period::fromNs(static_cast<Fps>(1_Hz).getPeriodNsecs());
321 
322     ASSERT_NO_FATAL_FAILURE(mFlinger.setNotifyExpectedPresentData(mPhysicalDisplayId,
323                                                                   TimePoint::fromNs(now),
324                                                                   Fps::fromValue(0)));
325     static constexpr int32_t kFrameIntervalNs120Hz = static_cast<Fps>(120_Hz).getPeriodNsecs();
326     static constexpr int32_t kFrameIntervalNs96Hz = static_cast<Fps>(96_Hz).getPeriodNsecs();
327     static constexpr int32_t kFrameIntervalNs80Hz = static_cast<Fps>(80_Hz).getPeriodNsecs();
328     static constexpr int32_t kFrameIntervalNs60Hz = static_cast<Fps>(60_Hz).getPeriodNsecs();
329     static constexpr int32_t kFrameIntervalNs40Hz = static_cast<Fps>(40_Hz).getPeriodNsecs();
330     static constexpr int32_t kFrameIntervalNs30Hz = static_cast<Fps>(30_Hz).getPeriodNsecs();
331     static constexpr int32_t kFrameIntervalNs24Hz = static_cast<Fps>(24_Hz).getPeriodNsecs();
332     static constexpr int32_t kFrameIntervalNs20Hz = static_cast<Fps>(20_Hz).getPeriodNsecs();
333     static constexpr Period kVsyncPeriod =
334             Period::fromNs(static_cast<Fps>(240_Hz).getPeriodNsecs());
335 
336     struct FrameRateIntervalTestData {
337         int32_t frameIntervalNs;
338         bool callNotifyExpectedPresentHint;
339     };
340     const std::vector<FrameRateIntervalTestData> frameIntervals = {
341             {kFrameIntervalNs60Hz, true},  {kFrameIntervalNs96Hz, true},
342             {kFrameIntervalNs80Hz, true},  {kFrameIntervalNs120Hz, true},
343             {kFrameIntervalNs80Hz, true},  {kFrameIntervalNs60Hz, true},
344             {kFrameIntervalNs60Hz, false}, {kFrameIntervalNs30Hz, false},
345             {kFrameIntervalNs24Hz, true},  {kFrameIntervalNs40Hz, true},
346             {kFrameIntervalNs20Hz, false}, {kFrameIntervalNs60Hz, true},
347             {kFrameIntervalNs20Hz, false}, {kFrameIntervalNs120Hz, true},
348     };
349 
350     for (size_t i = 0; i < frameIntervals.size(); i++) {
351         const auto& [frameIntervalNs, callNotifyExpectedPresentHint] = frameIntervals[i];
352         expectedPresentTime += frameIntervalNs;
353         mFlinger.notifyExpectedPresentIfRequired(mPhysicalDisplayId, kVsyncPeriod,
354                                                  TimePoint::fromNs(expectedPresentTime),
355                                                  Fps::fromPeriodNsecs(frameIntervalNs), kTimeoutNs);
356 
357         EXPECT_CALL(static_cast<mock::VSyncTracker&>(
358                             mFlinger.scheduler()->getVsyncSchedule()->getTracker()),
359                     nextAnticipatedVSyncTimeFrom(_, _))
360                 .WillRepeatedly(Return(expectedPresentTime));
361         if (callNotifyExpectedPresentHint) {
362             mCompositor->committed = false;
363             ASSERT_TRUE(mFlinger.verifyHintIsScheduledOnPresent(mPhysicalDisplayId))
364                     << "Hint not scheduled for frameInterval " << frameIntervalNs << " at index "
365                     << i;
366             EXPECT_CALL(*mComposer,
367                         notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, frameIntervalNs))
368                     .WillOnce(Return(Error::NONE));
369         } else {
370             // Only lastExpectedPresentTime is updated
371             EXPECT_TRUE(
372                     mFlinger.verifyLastExpectedPresentTime(mPhysicalDisplayId, expectedPresentTime))
373                     << "LastExpectedPresentTime for frameInterval " << frameIntervalNs
374                     << "at index " << i << " did not match for frameInterval " << frameIntervalNs;
375             EXPECT_CALL(*mComposer, notifyExpectedPresent(kHwcDisplayId, _, _)).Times(0);
376         }
377         mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
378 
379         if (callNotifyExpectedPresentHint) {
380             // Present resumes the calls to the notifyExpectedPresentHint.
381             mCompositor->committed = true;
382             mFlinger.scheduler()->doFrameSignal(*mCompositor, VsyncId{42});
383         }
384     }
385 }
386 } // namespace android