Valerie Hau | e9137b7 | 2019-08-27 13:22:18 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 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 | #pragma once |
| 17 | |
| 18 | #include <gtest/gtest.h> |
| 19 | #include <gui/SurfaceComposerClient.h> |
| 20 | #include <gui/SurfaceControl.h> |
| 21 | #include <ui/Fence.h> |
| 22 | #include <utils/Timers.h> |
| 23 | #include <thread> |
| 24 | |
| 25 | namespace android { |
| 26 | |
| 27 | namespace { |
| 28 | |
| 29 | struct CallbackData { |
| 30 | CallbackData() = default; |
| 31 | CallbackData(nsecs_t time, const sp<Fence>& fence, |
| 32 | const std::vector<SurfaceControlStats>& stats) |
| 33 | : latchTime(time), presentFence(fence), surfaceControlStats(stats) {} |
| 34 | |
| 35 | nsecs_t latchTime; |
| 36 | sp<Fence> presentFence; |
| 37 | std::vector<SurfaceControlStats> surfaceControlStats; |
| 38 | }; |
| 39 | |
| 40 | class ExpectedResult { |
| 41 | public: |
| 42 | enum Transaction { |
| 43 | NOT_PRESENTED = 0, |
| 44 | PRESENTED, |
| 45 | }; |
| 46 | |
| 47 | enum Buffer { |
| 48 | NOT_ACQUIRED = 0, |
| 49 | ACQUIRED, |
| 50 | }; |
| 51 | |
| 52 | enum PreviousBuffer { |
| 53 | NOT_RELEASED = 0, |
| 54 | RELEASED, |
| 55 | UNKNOWN, |
| 56 | }; |
| 57 | |
| 58 | void reset() { |
| 59 | mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED; |
| 60 | mExpectedSurfaceResults.clear(); |
| 61 | } |
| 62 | |
| 63 | void addSurface(ExpectedResult::Transaction transactionResult, const sp<SurfaceControl>& layer, |
| 64 | ExpectedResult::Buffer bufferResult = ACQUIRED, |
| 65 | ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) { |
| 66 | mTransactionResult = transactionResult; |
| 67 | mExpectedSurfaceResults.emplace(std::piecewise_construct, std::forward_as_tuple(layer), |
| 68 | std::forward_as_tuple(bufferResult, previousBufferResult)); |
| 69 | } |
| 70 | |
| 71 | void addSurfaces(ExpectedResult::Transaction transactionResult, |
| 72 | const std::vector<sp<SurfaceControl>>& layers, |
| 73 | ExpectedResult::Buffer bufferResult = ACQUIRED, |
| 74 | ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) { |
| 75 | for (const auto& layer : layers) { |
| 76 | addSurface(transactionResult, layer, bufferResult, previousBufferResult); |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | void addExpectedPresentTime(nsecs_t expectedPresentTime) { |
| 81 | mExpectedPresentTime = expectedPresentTime; |
| 82 | } |
| 83 | |
| 84 | void verifyCallbackData(const CallbackData& callbackData) const { |
| 85 | const auto& [latchTime, presentFence, surfaceControlStats] = callbackData; |
| 86 | if (mTransactionResult == ExpectedResult::Transaction::PRESENTED) { |
| 87 | ASSERT_GE(latchTime, 0) << "bad latch time"; |
| 88 | ASSERT_NE(presentFence, nullptr); |
| 89 | if (mExpectedPresentTime >= 0) { |
| 90 | ASSERT_EQ(presentFence->wait(3000), NO_ERROR); |
| 91 | ASSERT_GE(presentFence->getSignalTime(), mExpectedPresentTime - nsecs_t(5 * 1e6)); |
| 92 | // if the panel is running at 30 hz, at the worst case, our expected time just |
| 93 | // misses vsync and we have to wait another 33.3ms |
| 94 | ASSERT_LE(presentFence->getSignalTime(), |
| 95 | mExpectedPresentTime + nsecs_t(66.666666 * 1e6)); |
| 96 | } |
| 97 | } else { |
| 98 | ASSERT_EQ(presentFence, nullptr) << "transaction shouldn't have been presented"; |
| 99 | ASSERT_EQ(latchTime, -1) << "unpresented transactions shouldn't be latched"; |
| 100 | } |
| 101 | |
| 102 | ASSERT_EQ(surfaceControlStats.size(), mExpectedSurfaceResults.size()) |
| 103 | << "wrong number of surfaces"; |
| 104 | |
| 105 | for (const auto& stats : surfaceControlStats) { |
| 106 | ASSERT_NE(stats.surfaceControl, nullptr) << "returned null surface control"; |
| 107 | |
| 108 | const auto& expectedSurfaceResult = mExpectedSurfaceResults.find(stats.surfaceControl); |
| 109 | ASSERT_NE(expectedSurfaceResult, mExpectedSurfaceResults.end()) |
| 110 | << "unexpected surface control"; |
| 111 | expectedSurfaceResult->second.verifySurfaceControlStats(stats, latchTime); |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | private: |
| 116 | class ExpectedSurfaceResult { |
| 117 | public: |
| 118 | ExpectedSurfaceResult(ExpectedResult::Buffer bufferResult, |
| 119 | ExpectedResult::PreviousBuffer previousBufferResult) |
| 120 | : mBufferResult(bufferResult), mPreviousBufferResult(previousBufferResult) {} |
| 121 | |
| 122 | void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats, |
| 123 | nsecs_t latchTime) const { |
Valerie Hau | 32cdc1f | 2019-10-21 14:45:54 -0700 | [diff] [blame^] | 124 | const auto& [surfaceControl, acquireTime, previousReleaseFence, transformHint] = |
| 125 | surfaceControlStats; |
Valerie Hau | e9137b7 | 2019-08-27 13:22:18 -0700 | [diff] [blame] | 126 | |
| 127 | ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED) |
| 128 | << "bad acquire time"; |
| 129 | ASSERT_LE(acquireTime, latchTime) << "acquire time should be <= latch time"; |
| 130 | |
| 131 | if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED) { |
| 132 | ASSERT_NE(previousReleaseFence, nullptr) |
| 133 | << "failed to set release prev buffer fence"; |
| 134 | } else if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::NOT_RELEASED) { |
| 135 | ASSERT_EQ(previousReleaseFence, nullptr) |
| 136 | << "should not have set released prev buffer fence"; |
| 137 | } |
| 138 | } |
| 139 | |
| 140 | private: |
| 141 | ExpectedResult::Buffer mBufferResult; |
| 142 | ExpectedResult::PreviousBuffer mPreviousBufferResult; |
| 143 | }; |
| 144 | |
| 145 | struct SCHash { |
| 146 | std::size_t operator()(const sp<SurfaceControl>& sc) const { |
| 147 | return std::hash<IBinder*>{}(sc->getHandle().get()); |
| 148 | } |
| 149 | }; |
| 150 | ExpectedResult::Transaction mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED; |
| 151 | nsecs_t mExpectedPresentTime = -1; |
| 152 | std::unordered_map<sp<SurfaceControl>, ExpectedSurfaceResult, SCHash> mExpectedSurfaceResults; |
| 153 | }; |
| 154 | |
| 155 | class CallbackHelper { |
| 156 | public: |
| 157 | static void function(void* callbackContext, nsecs_t latchTime, const sp<Fence>& presentFence, |
| 158 | const std::vector<SurfaceControlStats>& stats) { |
| 159 | if (!callbackContext) { |
| 160 | ALOGE("failed to get callback context"); |
| 161 | } |
| 162 | CallbackHelper* helper = static_cast<CallbackHelper*>(callbackContext); |
| 163 | std::lock_guard lock(helper->mMutex); |
| 164 | helper->mCallbackDataQueue.emplace(latchTime, presentFence, stats); |
| 165 | helper->mConditionVariable.notify_all(); |
| 166 | } |
| 167 | |
| 168 | void getCallbackData(CallbackData* outData) { |
| 169 | std::unique_lock lock(mMutex); |
| 170 | |
| 171 | if (mCallbackDataQueue.empty()) { |
| 172 | ASSERT_NE(mConditionVariable.wait_for(lock, std::chrono::seconds(3)), |
| 173 | std::cv_status::timeout) |
| 174 | << "did not receive callback"; |
| 175 | } |
| 176 | |
| 177 | *outData = std::move(mCallbackDataQueue.front()); |
| 178 | mCallbackDataQueue.pop(); |
| 179 | } |
| 180 | |
| 181 | void verifyFinalState() { |
| 182 | // Wait to see if there are extra callbacks |
| 183 | std::this_thread::sleep_for(500ms); |
| 184 | |
| 185 | std::lock_guard lock(mMutex); |
| 186 | EXPECT_EQ(mCallbackDataQueue.size(), 0) << "extra callbacks received"; |
| 187 | mCallbackDataQueue = {}; |
| 188 | } |
| 189 | |
| 190 | void* getContext() { return static_cast<void*>(this); } |
| 191 | |
| 192 | std::mutex mMutex; |
| 193 | std::condition_variable mConditionVariable; |
| 194 | std::queue<CallbackData> mCallbackDataQueue; |
| 195 | }; |
| 196 | } |
| 197 | } // namespace android |