xref: /aosp_15_r20/frameworks/native/include/gui/test/CallbackUtils.h (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright (C) 2019 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  *
4*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  *
8*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  *
10*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker #pragma once
17*38e8c45fSAndroid Build Coastguard Worker 
18*38e8c45fSAndroid Build Coastguard Worker #include <gtest/gtest.h>
19*38e8c45fSAndroid Build Coastguard Worker #include <gui/SurfaceComposerClient.h>
20*38e8c45fSAndroid Build Coastguard Worker #include <gui/SurfaceControl.h>
21*38e8c45fSAndroid Build Coastguard Worker #include <ui/Fence.h>
22*38e8c45fSAndroid Build Coastguard Worker #include <utils/Timers.h>
23*38e8c45fSAndroid Build Coastguard Worker #include <chrono>
24*38e8c45fSAndroid Build Coastguard Worker #include <thread>
25*38e8c45fSAndroid Build Coastguard Worker 
26*38e8c45fSAndroid Build Coastguard Worker using ::std::literals::chrono_literals::operator""ms;
27*38e8c45fSAndroid Build Coastguard Worker using ::std::literals::chrono_literals::operator""s;
28*38e8c45fSAndroid Build Coastguard Worker 
29*38e8c45fSAndroid Build Coastguard Worker namespace android {
30*38e8c45fSAndroid Build Coastguard Worker 
31*38e8c45fSAndroid Build Coastguard Worker namespace {
32*38e8c45fSAndroid Build Coastguard Worker 
33*38e8c45fSAndroid Build Coastguard Worker struct CallbackData {
34*38e8c45fSAndroid Build Coastguard Worker     CallbackData() = default;
CallbackDataCallbackData35*38e8c45fSAndroid Build Coastguard Worker     CallbackData(nsecs_t time, const sp<Fence>& fence,
36*38e8c45fSAndroid Build Coastguard Worker                  const std::vector<SurfaceControlStats>& stats)
37*38e8c45fSAndroid Build Coastguard Worker           : latchTime(time), presentFence(fence), surfaceControlStats(stats) {}
38*38e8c45fSAndroid Build Coastguard Worker 
39*38e8c45fSAndroid Build Coastguard Worker     nsecs_t latchTime;
40*38e8c45fSAndroid Build Coastguard Worker     sp<Fence> presentFence;
41*38e8c45fSAndroid Build Coastguard Worker     std::vector<SurfaceControlStats> surfaceControlStats;
42*38e8c45fSAndroid Build Coastguard Worker };
43*38e8c45fSAndroid Build Coastguard Worker 
44*38e8c45fSAndroid Build Coastguard Worker class ExpectedResult {
45*38e8c45fSAndroid Build Coastguard Worker public:
46*38e8c45fSAndroid Build Coastguard Worker     enum Transaction {
47*38e8c45fSAndroid Build Coastguard Worker         NOT_PRESENTED = 0,
48*38e8c45fSAndroid Build Coastguard Worker         PRESENTED,
49*38e8c45fSAndroid Build Coastguard Worker     };
50*38e8c45fSAndroid Build Coastguard Worker 
51*38e8c45fSAndroid Build Coastguard Worker     enum Buffer {
52*38e8c45fSAndroid Build Coastguard Worker         NOT_ACQUIRED = 0,
53*38e8c45fSAndroid Build Coastguard Worker         ACQUIRED,
54*38e8c45fSAndroid Build Coastguard Worker         ACQUIRED_NULL,
55*38e8c45fSAndroid Build Coastguard Worker     };
56*38e8c45fSAndroid Build Coastguard Worker 
57*38e8c45fSAndroid Build Coastguard Worker     enum PreviousBuffer {
58*38e8c45fSAndroid Build Coastguard Worker         NOT_RELEASED = 0,
59*38e8c45fSAndroid Build Coastguard Worker         RELEASED,
60*38e8c45fSAndroid Build Coastguard Worker         UNKNOWN,
61*38e8c45fSAndroid Build Coastguard Worker     };
62*38e8c45fSAndroid Build Coastguard Worker 
reset()63*38e8c45fSAndroid Build Coastguard Worker     void reset() {
64*38e8c45fSAndroid Build Coastguard Worker         mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
65*38e8c45fSAndroid Build Coastguard Worker         mExpectedSurfaceResults.clear();
66*38e8c45fSAndroid Build Coastguard Worker     }
67*38e8c45fSAndroid Build Coastguard Worker 
68*38e8c45fSAndroid Build Coastguard Worker     void addSurface(ExpectedResult::Transaction transactionResult, const sp<SurfaceControl>& layer,
69*38e8c45fSAndroid Build Coastguard Worker                     ExpectedResult::Buffer bufferResult = ACQUIRED,
70*38e8c45fSAndroid Build Coastguard Worker                     ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) {
71*38e8c45fSAndroid Build Coastguard Worker         mTransactionResult = transactionResult;
72*38e8c45fSAndroid Build Coastguard Worker         mExpectedSurfaceResults.emplace(std::piecewise_construct, std::forward_as_tuple(layer),
73*38e8c45fSAndroid Build Coastguard Worker                                         std::forward_as_tuple(bufferResult, previousBufferResult));
74*38e8c45fSAndroid Build Coastguard Worker     }
75*38e8c45fSAndroid Build Coastguard Worker 
76*38e8c45fSAndroid Build Coastguard Worker     void addSurfaces(ExpectedResult::Transaction transactionResult,
77*38e8c45fSAndroid Build Coastguard Worker                      const std::vector<sp<SurfaceControl>>& layers,
78*38e8c45fSAndroid Build Coastguard Worker                      ExpectedResult::Buffer bufferResult = ACQUIRED,
79*38e8c45fSAndroid Build Coastguard Worker                      ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) {
80*38e8c45fSAndroid Build Coastguard Worker         for (const auto& layer : layers) {
81*38e8c45fSAndroid Build Coastguard Worker             addSurface(transactionResult, layer, bufferResult, previousBufferResult);
82*38e8c45fSAndroid Build Coastguard Worker         }
83*38e8c45fSAndroid Build Coastguard Worker     }
84*38e8c45fSAndroid Build Coastguard Worker 
addExpectedPresentTime(nsecs_t expectedPresentTime)85*38e8c45fSAndroid Build Coastguard Worker     void addExpectedPresentTime(nsecs_t expectedPresentTime) {
86*38e8c45fSAndroid Build Coastguard Worker         mExpectedPresentTime = expectedPresentTime;
87*38e8c45fSAndroid Build Coastguard Worker     }
88*38e8c45fSAndroid Build Coastguard Worker 
addExpectedPresentTimeForVsyncId(nsecs_t expectedPresentTime)89*38e8c45fSAndroid Build Coastguard Worker     void addExpectedPresentTimeForVsyncId(nsecs_t expectedPresentTime) {
90*38e8c45fSAndroid Build Coastguard Worker         mExpectedPresentTimeForVsyncId = expectedPresentTime;
91*38e8c45fSAndroid Build Coastguard Worker     }
92*38e8c45fSAndroid Build Coastguard Worker 
verifyCallbackData(const CallbackData & callbackData)93*38e8c45fSAndroid Build Coastguard Worker     void verifyCallbackData(const CallbackData& callbackData) const {
94*38e8c45fSAndroid Build Coastguard Worker         const auto& [latchTime, presentFence, surfaceControlStats] = callbackData;
95*38e8c45fSAndroid Build Coastguard Worker         if (mTransactionResult == ExpectedResult::Transaction::PRESENTED) {
96*38e8c45fSAndroid Build Coastguard Worker             ASSERT_GE(latchTime, 0) << "bad latch time";
97*38e8c45fSAndroid Build Coastguard Worker             ASSERT_NE(presentFence, nullptr);
98*38e8c45fSAndroid Build Coastguard Worker             if (mExpectedPresentTime >= 0) {
99*38e8c45fSAndroid Build Coastguard Worker                 ASSERT_EQ(presentFence->wait(3000), NO_ERROR);
100*38e8c45fSAndroid Build Coastguard Worker                 ASSERT_GE(presentFence->getSignalTime(), mExpectedPresentTime - nsecs_t(5 * 1e6));
101*38e8c45fSAndroid Build Coastguard Worker                 // if the panel is running at 30 hz, at the worst case, our expected time just
102*38e8c45fSAndroid Build Coastguard Worker                 // misses vsync and we have to wait another 33.3ms
103*38e8c45fSAndroid Build Coastguard Worker                 ASSERT_LE(presentFence->getSignalTime(),
104*38e8c45fSAndroid Build Coastguard Worker                           mExpectedPresentTime + nsecs_t(66.666666 * 1e6));
105*38e8c45fSAndroid Build Coastguard Worker             } else if (mExpectedPresentTimeForVsyncId >= 0) {
106*38e8c45fSAndroid Build Coastguard Worker                 ASSERT_EQ(presentFence->wait(3000), NO_ERROR);
107*38e8c45fSAndroid Build Coastguard Worker                 // We give 4ms for prediction error
108*38e8c45fSAndroid Build Coastguard Worker                 ASSERT_GE(presentFence->getSignalTime(),
109*38e8c45fSAndroid Build Coastguard Worker                           mExpectedPresentTimeForVsyncId - 4'000'000);
110*38e8c45fSAndroid Build Coastguard Worker             }
111*38e8c45fSAndroid Build Coastguard Worker         } else {
112*38e8c45fSAndroid Build Coastguard Worker             ASSERT_EQ(presentFence, nullptr) << "transaction shouldn't have been presented";
113*38e8c45fSAndroid Build Coastguard Worker             ASSERT_EQ(latchTime, -1) << "unpresented transactions shouldn't be latched";
114*38e8c45fSAndroid Build Coastguard Worker         }
115*38e8c45fSAndroid Build Coastguard Worker 
116*38e8c45fSAndroid Build Coastguard Worker         ASSERT_EQ(surfaceControlStats.size(), mExpectedSurfaceResults.size())
117*38e8c45fSAndroid Build Coastguard Worker                 << "wrong number of surfaces";
118*38e8c45fSAndroid Build Coastguard Worker 
119*38e8c45fSAndroid Build Coastguard Worker         for (const auto& stats : surfaceControlStats) {
120*38e8c45fSAndroid Build Coastguard Worker             ASSERT_NE(stats.surfaceControl, nullptr) << "returned null surface control";
121*38e8c45fSAndroid Build Coastguard Worker 
122*38e8c45fSAndroid Build Coastguard Worker             const auto& expectedSurfaceResult = mExpectedSurfaceResults.find(stats.surfaceControl);
123*38e8c45fSAndroid Build Coastguard Worker             ASSERT_NE(expectedSurfaceResult, mExpectedSurfaceResults.end())
124*38e8c45fSAndroid Build Coastguard Worker                     << "unexpected surface control";
125*38e8c45fSAndroid Build Coastguard Worker             expectedSurfaceResult->second.verifySurfaceControlStats(stats, latchTime);
126*38e8c45fSAndroid Build Coastguard Worker         }
127*38e8c45fSAndroid Build Coastguard Worker     }
128*38e8c45fSAndroid Build Coastguard Worker 
129*38e8c45fSAndroid Build Coastguard Worker private:
130*38e8c45fSAndroid Build Coastguard Worker     class ExpectedSurfaceResult {
131*38e8c45fSAndroid Build Coastguard Worker     public:
ExpectedSurfaceResult(ExpectedResult::Buffer bufferResult,ExpectedResult::PreviousBuffer previousBufferResult)132*38e8c45fSAndroid Build Coastguard Worker         ExpectedSurfaceResult(ExpectedResult::Buffer bufferResult,
133*38e8c45fSAndroid Build Coastguard Worker                               ExpectedResult::PreviousBuffer previousBufferResult)
134*38e8c45fSAndroid Build Coastguard Worker               : mBufferResult(bufferResult), mPreviousBufferResult(previousBufferResult) {}
135*38e8c45fSAndroid Build Coastguard Worker 
verifySurfaceControlStats(const SurfaceControlStats & surfaceControlStats,nsecs_t)136*38e8c45fSAndroid Build Coastguard Worker         void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats,
137*38e8c45fSAndroid Build Coastguard Worker                                        nsecs_t /* latchTime */) const {
138*38e8c45fSAndroid Build Coastguard Worker             const auto& [surfaceControl, latch, acquireTimeOrFence, presentFence,
139*38e8c45fSAndroid Build Coastguard Worker                          previousReleaseFence, transformHint, frameEvents, ignore] =
140*38e8c45fSAndroid Build Coastguard Worker                     surfaceControlStats;
141*38e8c45fSAndroid Build Coastguard Worker 
142*38e8c45fSAndroid Build Coastguard Worker             nsecs_t acquireTime = -1;
143*38e8c45fSAndroid Build Coastguard Worker             if (std::holds_alternative<nsecs_t>(acquireTimeOrFence)) {
144*38e8c45fSAndroid Build Coastguard Worker                 acquireTime = std::get<nsecs_t>(acquireTimeOrFence);
145*38e8c45fSAndroid Build Coastguard Worker             } else {
146*38e8c45fSAndroid Build Coastguard Worker                 auto fence = std::get<sp<Fence>>(acquireTimeOrFence);
147*38e8c45fSAndroid Build Coastguard Worker                 if (fence) {
148*38e8c45fSAndroid Build Coastguard Worker                     ASSERT_EQ(fence->wait(3000), NO_ERROR);
149*38e8c45fSAndroid Build Coastguard Worker                     acquireTime = fence->getSignalTime();
150*38e8c45fSAndroid Build Coastguard Worker                 }
151*38e8c45fSAndroid Build Coastguard Worker             }
152*38e8c45fSAndroid Build Coastguard Worker 
153*38e8c45fSAndroid Build Coastguard Worker             if (mBufferResult == ExpectedResult::Buffer::ACQUIRED) {
154*38e8c45fSAndroid Build Coastguard Worker                 ASSERT_GT(acquireTime, 0) << "acquire time should be valid";
155*38e8c45fSAndroid Build Coastguard Worker             } else {
156*38e8c45fSAndroid Build Coastguard Worker                 ASSERT_LE(acquireTime, 0) << "acquire time should not be valid";
157*38e8c45fSAndroid Build Coastguard Worker             }
158*38e8c45fSAndroid Build Coastguard Worker             ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED);
159*38e8c45fSAndroid Build Coastguard Worker 
160*38e8c45fSAndroid Build Coastguard Worker             if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED) {
161*38e8c45fSAndroid Build Coastguard Worker                 ASSERT_NE(previousReleaseFence, nullptr)
162*38e8c45fSAndroid Build Coastguard Worker                         << "failed to set release prev buffer fence";
163*38e8c45fSAndroid Build Coastguard Worker             } else if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::NOT_RELEASED) {
164*38e8c45fSAndroid Build Coastguard Worker                 ASSERT_EQ(previousReleaseFence, nullptr)
165*38e8c45fSAndroid Build Coastguard Worker                         << "should not have set released prev buffer fence";
166*38e8c45fSAndroid Build Coastguard Worker             }
167*38e8c45fSAndroid Build Coastguard Worker         }
168*38e8c45fSAndroid Build Coastguard Worker 
169*38e8c45fSAndroid Build Coastguard Worker     private:
170*38e8c45fSAndroid Build Coastguard Worker         ExpectedResult::Buffer mBufferResult;
171*38e8c45fSAndroid Build Coastguard Worker         ExpectedResult::PreviousBuffer mPreviousBufferResult;
172*38e8c45fSAndroid Build Coastguard Worker     };
173*38e8c45fSAndroid Build Coastguard Worker 
174*38e8c45fSAndroid Build Coastguard Worker     struct SCHash {
operatorSCHash175*38e8c45fSAndroid Build Coastguard Worker         std::size_t operator()(const sp<SurfaceControl>& sc) const {
176*38e8c45fSAndroid Build Coastguard Worker             return std::hash<IBinder*>{}(sc->getHandle().get());
177*38e8c45fSAndroid Build Coastguard Worker         }
178*38e8c45fSAndroid Build Coastguard Worker     };
179*38e8c45fSAndroid Build Coastguard Worker     ExpectedResult::Transaction mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
180*38e8c45fSAndroid Build Coastguard Worker     nsecs_t mExpectedPresentTime = -1;
181*38e8c45fSAndroid Build Coastguard Worker     nsecs_t mExpectedPresentTimeForVsyncId = -1;
182*38e8c45fSAndroid Build Coastguard Worker     std::unordered_map<sp<SurfaceControl>, ExpectedSurfaceResult, SCHash> mExpectedSurfaceResults;
183*38e8c45fSAndroid Build Coastguard Worker };
184*38e8c45fSAndroid Build Coastguard Worker 
185*38e8c45fSAndroid Build Coastguard Worker class CallbackHelper {
186*38e8c45fSAndroid Build Coastguard Worker public:
function(void * callbackContext,nsecs_t latchTime,const sp<Fence> & presentFence,const std::vector<SurfaceControlStats> & stats)187*38e8c45fSAndroid Build Coastguard Worker     static void function(void* callbackContext, nsecs_t latchTime, const sp<Fence>& presentFence,
188*38e8c45fSAndroid Build Coastguard Worker                          const std::vector<SurfaceControlStats>& stats) {
189*38e8c45fSAndroid Build Coastguard Worker         if (!callbackContext) {
190*38e8c45fSAndroid Build Coastguard Worker             ALOGE("failed to get callback context");
191*38e8c45fSAndroid Build Coastguard Worker         }
192*38e8c45fSAndroid Build Coastguard Worker         CallbackHelper* helper = static_cast<CallbackHelper*>(callbackContext);
193*38e8c45fSAndroid Build Coastguard Worker         std::lock_guard lock(helper->mMutex);
194*38e8c45fSAndroid Build Coastguard Worker         helper->mCallbackDataQueue.emplace(latchTime, presentFence, stats);
195*38e8c45fSAndroid Build Coastguard Worker         helper->mConditionVariable.notify_all();
196*38e8c45fSAndroid Build Coastguard Worker     }
197*38e8c45fSAndroid Build Coastguard Worker 
getCallbackData(CallbackData * outData)198*38e8c45fSAndroid Build Coastguard Worker     void getCallbackData(CallbackData* outData) {
199*38e8c45fSAndroid Build Coastguard Worker         std::unique_lock lock(mMutex);
200*38e8c45fSAndroid Build Coastguard Worker 
201*38e8c45fSAndroid Build Coastguard Worker         if (mCallbackDataQueue.empty()) {
202*38e8c45fSAndroid Build Coastguard Worker             ASSERT_NE(mConditionVariable.wait_for(lock, std::chrono::seconds(3)),
203*38e8c45fSAndroid Build Coastguard Worker                       std::cv_status::timeout)
204*38e8c45fSAndroid Build Coastguard Worker                     << "did not receive callback";
205*38e8c45fSAndroid Build Coastguard Worker         }
206*38e8c45fSAndroid Build Coastguard Worker 
207*38e8c45fSAndroid Build Coastguard Worker         *outData = std::move(mCallbackDataQueue.front());
208*38e8c45fSAndroid Build Coastguard Worker         mCallbackDataQueue.pop();
209*38e8c45fSAndroid Build Coastguard Worker     }
210*38e8c45fSAndroid Build Coastguard Worker 
verifyFinalState()211*38e8c45fSAndroid Build Coastguard Worker     void verifyFinalState() {
212*38e8c45fSAndroid Build Coastguard Worker         // Wait to see if there are extra callbacks
213*38e8c45fSAndroid Build Coastguard Worker         std::this_thread::sleep_for(500ms);
214*38e8c45fSAndroid Build Coastguard Worker 
215*38e8c45fSAndroid Build Coastguard Worker         std::lock_guard lock(mMutex);
216*38e8c45fSAndroid Build Coastguard Worker         EXPECT_EQ(mCallbackDataQueue.size(), 0U) << "extra callbacks received";
217*38e8c45fSAndroid Build Coastguard Worker         mCallbackDataQueue = {};
218*38e8c45fSAndroid Build Coastguard Worker     }
219*38e8c45fSAndroid Build Coastguard Worker 
getContext()220*38e8c45fSAndroid Build Coastguard Worker     void* getContext() { return static_cast<void*>(this); }
221*38e8c45fSAndroid Build Coastguard Worker 
222*38e8c45fSAndroid Build Coastguard Worker     std::mutex mMutex;
223*38e8c45fSAndroid Build Coastguard Worker     std::condition_variable mConditionVariable;
224*38e8c45fSAndroid Build Coastguard Worker     std::queue<CallbackData> mCallbackDataQueue;
225*38e8c45fSAndroid Build Coastguard Worker };
226*38e8c45fSAndroid Build Coastguard Worker } // namespace
227*38e8c45fSAndroid Build Coastguard Worker } // namespace android
228