Marin Shalamanov | 07b1ff3 | 2020-10-07 16:57:22 +0200 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2020 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 | #pragma once |
| 18 | |
| 19 | // TODO(b/129481165): remove the #pragma below and fix conversion issues |
| 20 | #pragma clang diagnostic push |
| 21 | #pragma clang diagnostic ignored "-Wconversion" |
| 22 | |
| 23 | #include <type_traits> |
| 24 | #include "DisplayIdentificationTest.h" |
| 25 | |
| 26 | #include <binder/IPCThreadState.h> |
| 27 | #include <compositionengine/Display.h> |
| 28 | #include <compositionengine/DisplayColorProfile.h> |
| 29 | #include <compositionengine/impl/Display.h> |
| 30 | #include <compositionengine/impl/OutputCompositionState.h> |
| 31 | #include <compositionengine/mock/Display.h> |
| 32 | #include <compositionengine/mock/DisplayColorProfile.h> |
| 33 | #include <compositionengine/mock/DisplaySurface.h> |
| 34 | #include <compositionengine/mock/RenderSurface.h> |
| 35 | #include <gmock/gmock.h> |
| 36 | #include <gtest/gtest.h> |
| 37 | #include <gui/mock/GraphicBufferConsumer.h> |
| 38 | #include <gui/mock/GraphicBufferProducer.h> |
| 39 | #include <log/log.h> |
| 40 | #include <private/android_filesystem_config.h> |
| 41 | #include <renderengine/mock/RenderEngine.h> |
| 42 | #include <ui/DebugUtils.h> |
| 43 | |
| 44 | #include "TestableScheduler.h" |
| 45 | #include "TestableSurfaceFlinger.h" |
| 46 | #include "mock/DisplayHardware/MockComposer.h" |
| 47 | #include "mock/DisplayHardware/MockPowerAdvisor.h" |
| 48 | #include "mock/MockEventThread.h" |
| 49 | #include "mock/MockMessageQueue.h" |
| 50 | #include "mock/MockNativeWindowSurface.h" |
| 51 | #include "mock/MockSchedulerCallback.h" |
| 52 | #include "mock/MockSurfaceInterceptor.h" |
| 53 | #include "mock/MockVsyncController.h" |
| 54 | #include "mock/system/window/MockNativeWindow.h" |
| 55 | |
| 56 | namespace android { |
| 57 | |
| 58 | // TODO: Do not polute the android namespace |
| 59 | namespace hal = android::hardware::graphics::composer::hal; |
| 60 | |
| 61 | using testing::_; |
| 62 | using testing::AnyNumber; |
| 63 | using testing::DoAll; |
| 64 | using testing::Mock; |
| 65 | using testing::ResultOf; |
| 66 | using testing::Return; |
| 67 | using testing::SetArgPointee; |
| 68 | |
| 69 | using hal::ColorMode; |
| 70 | using hal::Connection; |
| 71 | using hal::DisplayCapability; |
| 72 | using hal::DisplayType; |
| 73 | using hal::Error; |
| 74 | using hal::Hdr; |
| 75 | using hal::HWDisplayId; |
| 76 | using hal::IComposer; |
| 77 | using hal::IComposerClient; |
| 78 | using hal::PerFrameMetadataKey; |
| 79 | using hal::PowerMode; |
| 80 | |
| 81 | class DisplayTransactionTest : public testing::Test { |
| 82 | public: |
| 83 | ~DisplayTransactionTest() override; |
| 84 | |
| 85 | // -------------------------------------------------------------------- |
| 86 | // Mock/Fake injection |
| 87 | |
| 88 | void injectMockScheduler(); |
| 89 | void injectMockComposer(int virtualDisplayCount); |
| 90 | void injectFakeBufferQueueFactory(); |
| 91 | void injectFakeNativeWindowSurfaceFactory(); |
| 92 | sp<DisplayDevice> injectDefaultInternalDisplay( |
| 93 | std::function<void(TestableSurfaceFlinger::FakeDisplayDeviceInjector&)>); |
| 94 | |
| 95 | // -------------------------------------------------------------------- |
| 96 | // Postcondition helpers |
| 97 | |
| 98 | bool hasPhysicalHwcDisplay(hal::HWDisplayId hwcDisplayId); |
| 99 | bool hasTransactionFlagSet(int flag); |
| 100 | bool hasDisplayDevice(sp<IBinder> displayToken); |
| 101 | sp<DisplayDevice> getDisplayDevice(sp<IBinder> displayToken); |
| 102 | bool hasCurrentDisplayState(sp<IBinder> displayToken); |
| 103 | const DisplayDeviceState& getCurrentDisplayState(sp<IBinder> displayToken); |
| 104 | bool hasDrawingDisplayState(sp<IBinder> displayToken); |
| 105 | const DisplayDeviceState& getDrawingDisplayState(sp<IBinder> displayToken); |
| 106 | |
| 107 | // -------------------------------------------------------------------- |
| 108 | // Test instances |
| 109 | |
| 110 | TestableSurfaceFlinger mFlinger; |
| 111 | sp<mock::NativeWindow> mNativeWindow = new mock::NativeWindow(); |
| 112 | sp<GraphicBuffer> mBuffer = new GraphicBuffer(); |
| 113 | Hwc2::mock::PowerAdvisor mPowerAdvisor; |
| 114 | |
| 115 | // These mocks are created by the test, but are destroyed by SurfaceFlinger |
| 116 | // by virtue of being stored into a std::unique_ptr. However we still need |
| 117 | // to keep a reference to them for use in setting up call expectations. |
| 118 | renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine(); |
| 119 | Hwc2::mock::Composer* mComposer = nullptr; |
| 120 | mock::MessageQueue* mMessageQueue = new mock::MessageQueue(); |
| 121 | sp<mock::SurfaceInterceptor> mSurfaceInterceptor = new mock::SurfaceInterceptor; |
| 122 | |
| 123 | mock::VsyncController* mVsyncController = new mock::VsyncController; |
| 124 | mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker; |
| 125 | mock::SchedulerCallback mSchedulerCallback; |
| 126 | mock::EventThread* mEventThread = new mock::EventThread; |
| 127 | mock::EventThread* mSFEventThread = new mock::EventThread; |
| 128 | |
| 129 | // These mocks are created only when expected to be created via a factory. |
| 130 | sp<mock::GraphicBufferConsumer> mConsumer; |
| 131 | sp<mock::GraphicBufferProducer> mProducer; |
| 132 | surfaceflinger::mock::NativeWindowSurface* mNativeWindowSurface = nullptr; |
| 133 | |
| 134 | protected: |
| 135 | DisplayTransactionTest(); |
| 136 | }; |
| 137 | |
| 138 | constexpr int32_t DEFAULT_REFRESH_RATE = 16'666'667; |
| 139 | constexpr int32_t DEFAULT_DPI = 320; |
| 140 | constexpr int DEFAULT_VIRTUAL_DISPLAY_SURFACE_FORMAT = HAL_PIXEL_FORMAT_RGB_565; |
| 141 | |
| 142 | constexpr int POWER_MODE_LEET = 1337; // An out of range power mode value |
| 143 | |
| 144 | /* ------------------------------------------------------------------------ |
| 145 | * Boolean avoidance |
| 146 | * |
| 147 | * To make calls and template instantiations more readable, we define some |
| 148 | * local enums along with an implicit bool conversion. |
| 149 | */ |
| 150 | |
| 151 | #define BOOL_SUBSTITUTE(TYPENAME) enum class TYPENAME : bool { FALSE = false, TRUE = true }; |
| 152 | |
| 153 | BOOL_SUBSTITUTE(Async); |
| 154 | BOOL_SUBSTITUTE(Critical); |
| 155 | BOOL_SUBSTITUTE(Primary); |
| 156 | BOOL_SUBSTITUTE(Secure); |
| 157 | BOOL_SUBSTITUTE(Virtual); |
| 158 | |
| 159 | template <typename PhysicalDisplay> |
| 160 | struct PhysicalDisplayIdType {}; |
| 161 | |
| 162 | template <uint64_t displayId> |
| 163 | using HalVirtualDisplayIdType = std::integral_constant<uint64_t, displayId>; |
| 164 | |
| 165 | struct GpuVirtualDisplayIdType {}; |
| 166 | |
| 167 | template <typename> |
| 168 | struct IsPhysicalDisplayId : std::bool_constant<false> {}; |
| 169 | |
| 170 | template <typename PhysicalDisplay> |
| 171 | struct IsPhysicalDisplayId<PhysicalDisplayIdType<PhysicalDisplay>> : std::bool_constant<true> {}; |
| 172 | |
| 173 | template <typename> |
| 174 | struct DisplayIdGetter; |
| 175 | |
| 176 | template <typename PhysicalDisplay> |
| 177 | struct DisplayIdGetter<PhysicalDisplayIdType<PhysicalDisplay>> { |
| 178 | static PhysicalDisplayId get() { |
| 179 | if (!PhysicalDisplay::HAS_IDENTIFICATION_DATA) { |
| 180 | return PhysicalDisplayId::fromPort(static_cast<bool>(PhysicalDisplay::PRIMARY) |
| 181 | ? LEGACY_DISPLAY_TYPE_PRIMARY |
| 182 | : LEGACY_DISPLAY_TYPE_EXTERNAL); |
| 183 | } |
| 184 | |
| 185 | const auto info = |
| 186 | parseDisplayIdentificationData(PhysicalDisplay::PORT, |
| 187 | PhysicalDisplay::GET_IDENTIFICATION_DATA()); |
| 188 | return info ? info->id : PhysicalDisplayId::fromPort(PhysicalDisplay::PORT); |
| 189 | } |
| 190 | }; |
| 191 | |
| 192 | template <uint64_t displayId> |
| 193 | struct DisplayIdGetter<HalVirtualDisplayIdType<displayId>> { |
| 194 | static HalVirtualDisplayId get() { return HalVirtualDisplayId(displayId); } |
| 195 | }; |
| 196 | |
| 197 | template <> |
| 198 | struct DisplayIdGetter<GpuVirtualDisplayIdType> { |
| 199 | static GpuVirtualDisplayId get() { return GpuVirtualDisplayId(0); } |
| 200 | }; |
| 201 | |
| 202 | template <typename> |
| 203 | struct DisplayConnectionTypeGetter { |
| 204 | static constexpr std::optional<DisplayConnectionType> value; |
| 205 | }; |
| 206 | |
| 207 | template <typename PhysicalDisplay> |
| 208 | struct DisplayConnectionTypeGetter<PhysicalDisplayIdType<PhysicalDisplay>> { |
| 209 | static constexpr std::optional<DisplayConnectionType> value = PhysicalDisplay::CONNECTION_TYPE; |
| 210 | }; |
| 211 | |
| 212 | template <typename> |
| 213 | struct HwcDisplayIdGetter { |
| 214 | static constexpr std::optional<HWDisplayId> value; |
| 215 | }; |
| 216 | |
| 217 | constexpr HWDisplayId HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID = 1010; |
| 218 | |
| 219 | template <uint64_t displayId> |
| 220 | struct HwcDisplayIdGetter<HalVirtualDisplayIdType<displayId>> { |
| 221 | static constexpr std::optional<HWDisplayId> value = HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID; |
| 222 | }; |
| 223 | |
| 224 | template <typename PhysicalDisplay> |
| 225 | struct HwcDisplayIdGetter<PhysicalDisplayIdType<PhysicalDisplay>> { |
| 226 | static constexpr std::optional<HWDisplayId> value = PhysicalDisplay::HWC_DISPLAY_ID; |
| 227 | }; |
| 228 | |
| 229 | // DisplayIdType can be: |
| 230 | // 1) PhysicalDisplayIdType<...> for generated ID of physical display backed by HWC. |
| 231 | // 2) HalVirtualDisplayIdType<...> for hard-coded ID of virtual display backed by HWC. |
| 232 | // 3) GpuVirtualDisplayIdType for virtual display without HWC backing. |
| 233 | template <typename DisplayIdType, int width, int height, Critical critical, Async async, |
| 234 | Secure secure, Primary primary, int grallocUsage> |
| 235 | struct DisplayVariant { |
| 236 | using DISPLAY_ID = DisplayIdGetter<DisplayIdType>; |
| 237 | using CONNECTION_TYPE = DisplayConnectionTypeGetter<DisplayIdType>; |
| 238 | using HWC_DISPLAY_ID_OPT = HwcDisplayIdGetter<DisplayIdType>; |
| 239 | |
| 240 | // The display width and height |
| 241 | static constexpr int WIDTH = width; |
| 242 | static constexpr int HEIGHT = height; |
| 243 | |
| 244 | static constexpr int GRALLOC_USAGE = grallocUsage; |
| 245 | |
| 246 | // Whether the display is virtual or physical |
| 247 | static constexpr Virtual VIRTUAL = |
| 248 | IsPhysicalDisplayId<DisplayIdType>{} ? Virtual::FALSE : Virtual::TRUE; |
| 249 | |
| 250 | // When creating native window surfaces for the framebuffer, whether those should be critical |
| 251 | static constexpr Critical CRITICAL = critical; |
| 252 | |
| 253 | // When creating native window surfaces for the framebuffer, whether those should be async |
| 254 | static constexpr Async ASYNC = async; |
| 255 | |
| 256 | // Whether the display should be treated as secure |
| 257 | static constexpr Secure SECURE = secure; |
| 258 | |
| 259 | // Whether the display is primary |
| 260 | static constexpr Primary PRIMARY = primary; |
| 261 | |
| 262 | static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) { |
| 263 | auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder(); |
| 264 | if (auto displayId = PhysicalDisplayId::tryCast(DISPLAY_ID::get())) { |
| 265 | ceDisplayArgs.setPhysical({*displayId, DisplayConnectionType::Internal}); |
| 266 | } else { |
| 267 | // We turn off the use of HwcVirtualDisplays, to prevent Composition Engine |
| 268 | // from calling into HWComposer. This way all virtual displays will get |
| 269 | // a GpuVirtualDisplayId, even if we are in the HwcVirtualDisplayVariant. |
| 270 | // In this case we later override it by calling display.setDisplayIdForTesting(). |
| 271 | ceDisplayArgs.setUseHwcVirtualDisplays(false); |
| 272 | |
| 273 | GpuVirtualDisplayId desiredDisplayId = GpuVirtualDisplayId::tryCast(DISPLAY_ID::get()) |
| 274 | .value_or(GpuVirtualDisplayId(0)); |
| 275 | |
| 276 | ON_CALL(test->mFlinger.gpuVirtualDisplayIdGenerator(), nextId()) |
| 277 | .WillByDefault(Return(desiredDisplayId)); |
| 278 | |
| 279 | auto& generator = test->mFlinger.gpuVirtualDisplayIdGenerator(); |
| 280 | ceDisplayArgs.setGpuVirtualDisplayIdGenerator(generator); |
| 281 | } |
| 282 | ceDisplayArgs.setPixels({WIDTH, HEIGHT}).setPowerAdvisor(&test->mPowerAdvisor); |
| 283 | |
| 284 | auto compositionDisplay = |
| 285 | compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(), |
| 286 | ceDisplayArgs.build()); |
| 287 | |
| 288 | if (HalVirtualDisplayId::tryCast(DISPLAY_ID::get())) { |
| 289 | // CompositionEngine has assigned a placeholder GpuVirtualDisplayId and we need to |
| 290 | // override it with the correct HalVirtualDisplayId. |
| 291 | compositionDisplay->setDisplayIdForTesting(DISPLAY_ID::get()); |
| 292 | } |
| 293 | |
| 294 | auto injector = |
| 295 | TestableSurfaceFlinger::FakeDisplayDeviceInjector(test->mFlinger, |
| 296 | compositionDisplay, |
| 297 | CONNECTION_TYPE::value, |
| 298 | HWC_DISPLAY_ID_OPT::value, |
| 299 | static_cast<bool>(PRIMARY)); |
| 300 | |
| 301 | injector.setSecure(static_cast<bool>(SECURE)); |
| 302 | injector.setNativeWindow(test->mNativeWindow); |
| 303 | |
| 304 | // Creating a DisplayDevice requires getting default dimensions from the |
| 305 | // native window along with some other initial setup. |
| 306 | EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _)) |
| 307 | .WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0))); |
| 308 | EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _)) |
| 309 | .WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0))); |
| 310 | EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)) |
| 311 | .WillRepeatedly(Return(0)); |
| 312 | EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT)) |
| 313 | .WillRepeatedly(Return(0)); |
| 314 | EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)) |
| 315 | .WillRepeatedly(Return(0)); |
| 316 | EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)) |
| 317 | .WillRepeatedly(Return(0)); |
| 318 | |
| 319 | return injector; |
| 320 | } |
| 321 | |
| 322 | // Called by tests to set up any native window creation call expectations. |
| 323 | static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) { |
| 324 | EXPECT_CALL(*test->mNativeWindowSurface, getNativeWindow()) |
| 325 | .WillOnce(Return(test->mNativeWindow)); |
| 326 | |
| 327 | EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _)) |
| 328 | .WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0))); |
| 329 | EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _)) |
| 330 | .WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0))); |
| 331 | EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)) |
| 332 | .WillRepeatedly(Return(0)); |
| 333 | EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT)) |
| 334 | .WillRepeatedly(Return(0)); |
| 335 | EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)) |
| 336 | .WillRepeatedly(Return(0)); |
| 337 | EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)) |
| 338 | .WillRepeatedly(Return(0)); |
| 339 | } |
| 340 | |
| 341 | static void setupFramebufferConsumerBufferQueueCallExpectations(DisplayTransactionTest* test) { |
| 342 | EXPECT_CALL(*test->mConsumer, consumerConnect(_, false)).WillOnce(Return(NO_ERROR)); |
| 343 | EXPECT_CALL(*test->mConsumer, setConsumerName(_)).WillRepeatedly(Return(NO_ERROR)); |
| 344 | EXPECT_CALL(*test->mConsumer, setConsumerUsageBits(GRALLOC_USAGE)) |
| 345 | .WillRepeatedly(Return(NO_ERROR)); |
| 346 | EXPECT_CALL(*test->mConsumer, setDefaultBufferSize(WIDTH, HEIGHT)) |
| 347 | .WillRepeatedly(Return(NO_ERROR)); |
| 348 | EXPECT_CALL(*test->mConsumer, setMaxAcquiredBufferCount(_)) |
| 349 | .WillRepeatedly(Return(NO_ERROR)); |
| 350 | } |
| 351 | |
| 352 | static void setupFramebufferProducerBufferQueueCallExpectations(DisplayTransactionTest* test) { |
| 353 | EXPECT_CALL(*test->mProducer, allocateBuffers(0, 0, 0, 0)).WillRepeatedly(Return()); |
| 354 | } |
| 355 | }; |
| 356 | |
| 357 | template <HWDisplayId hwcDisplayId, DisplayType hwcDisplayType, typename DisplayVariant, |
| 358 | typename PhysicalDisplay = void> |
| 359 | struct HwcDisplayVariant { |
| 360 | // The display id supplied by the HWC |
| 361 | static constexpr HWDisplayId HWC_DISPLAY_ID = hwcDisplayId; |
| 362 | |
| 363 | // The HWC display type |
| 364 | static constexpr DisplayType HWC_DISPLAY_TYPE = hwcDisplayType; |
| 365 | |
| 366 | // The HWC active configuration id |
| 367 | static constexpr int HWC_ACTIVE_CONFIG_ID = 2001; |
| 368 | static constexpr PowerMode INIT_POWER_MODE = hal::PowerMode::ON; |
| 369 | |
| 370 | static void injectPendingHotplugEvent(DisplayTransactionTest* test, Connection connection) { |
| 371 | test->mFlinger.mutablePendingHotplugEvents().emplace_back( |
| 372 | TestableSurfaceFlinger::HotplugEvent{HWC_DISPLAY_ID, connection}); |
| 373 | } |
| 374 | |
| 375 | // Called by tests to inject a HWC display setup |
| 376 | static void injectHwcDisplayWithNoDefaultCapabilities(DisplayTransactionTest* test) { |
| 377 | const auto displayId = DisplayVariant::DISPLAY_ID::get(); |
| 378 | ASSERT_FALSE(GpuVirtualDisplayId::tryCast(displayId)); |
| 379 | TestableSurfaceFlinger::FakeHwcDisplayInjector(displayId, HWC_DISPLAY_TYPE, |
| 380 | static_cast<bool>(DisplayVariant::PRIMARY)) |
| 381 | .setHwcDisplayId(HWC_DISPLAY_ID) |
| 382 | .setWidth(DisplayVariant::WIDTH) |
| 383 | .setHeight(DisplayVariant::HEIGHT) |
| 384 | .setActiveConfig(HWC_ACTIVE_CONFIG_ID) |
| 385 | .setPowerMode(INIT_POWER_MODE) |
| 386 | .inject(&test->mFlinger, test->mComposer); |
| 387 | } |
| 388 | |
| 389 | // Called by tests to inject a HWC display setup |
| 390 | static void injectHwcDisplay(DisplayTransactionTest* test) { |
| 391 | EXPECT_CALL(*test->mComposer, getDisplayCapabilities(HWC_DISPLAY_ID, _)) |
| 392 | .WillOnce(DoAll(SetArgPointee<1>(std::vector<DisplayCapability>({})), |
| 393 | Return(Error::NONE))); |
| 394 | EXPECT_CALL(*test->mComposer, setPowerMode(HWC_DISPLAY_ID, INIT_POWER_MODE)) |
| 395 | .WillOnce(Return(Error::NONE)); |
| 396 | injectHwcDisplayWithNoDefaultCapabilities(test); |
| 397 | } |
| 398 | |
| 399 | static std::shared_ptr<compositionengine::Display> injectCompositionDisplay( |
| 400 | DisplayTransactionTest* test) { |
| 401 | const ::testing::TestInfo* const test_info = |
| 402 | ::testing::UnitTest::GetInstance()->current_test_info(); |
| 403 | |
| 404 | auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder() |
| 405 | .setPhysical({DisplayVariant::DISPLAY_ID::get(), |
| 406 | PhysicalDisplay::CONNECTION_TYPE}) |
| 407 | .setPixels({DisplayVariant::WIDTH, DisplayVariant::HEIGHT}) |
| 408 | .setIsSecure(static_cast<bool>(DisplayVariant::SECURE)) |
| 409 | .setPowerAdvisor(&test->mPowerAdvisor) |
| 410 | .setName(std::string("Injected display for ") + |
| 411 | test_info->test_case_name() + "." + test_info->name()) |
| 412 | .build(); |
| 413 | |
| 414 | return compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(), |
| 415 | ceDisplayArgs); |
| 416 | } |
| 417 | |
| 418 | static void setupHwcHotplugCallExpectations(DisplayTransactionTest* test) { |
| 419 | constexpr auto CONNECTION_TYPE = |
| 420 | PhysicalDisplay::CONNECTION_TYPE == DisplayConnectionType::Internal |
| 421 | ? IComposerClient::DisplayConnectionType::INTERNAL |
| 422 | : IComposerClient::DisplayConnectionType::EXTERNAL; |
| 423 | |
| 424 | EXPECT_CALL(*test->mComposer, getDisplayConnectionType(HWC_DISPLAY_ID, _)) |
| 425 | .WillOnce(DoAll(SetArgPointee<1>(CONNECTION_TYPE), Return(hal::V2_4::Error::NONE))); |
| 426 | |
| 427 | EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_)) |
| 428 | .WillOnce(Return(hal::Error::NONE)); |
| 429 | EXPECT_CALL(*test->mComposer, getDisplayConfigs(HWC_DISPLAY_ID, _)) |
| 430 | .WillOnce(DoAll(SetArgPointee<1>(std::vector<unsigned>{HWC_ACTIVE_CONFIG_ID}), |
| 431 | Return(Error::NONE))); |
| 432 | EXPECT_CALL(*test->mComposer, |
| 433 | getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID, |
| 434 | IComposerClient::Attribute::WIDTH, _)) |
| 435 | .WillOnce(DoAll(SetArgPointee<3>(DisplayVariant::WIDTH), Return(Error::NONE))); |
| 436 | EXPECT_CALL(*test->mComposer, |
| 437 | getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID, |
| 438 | IComposerClient::Attribute::HEIGHT, _)) |
| 439 | .WillOnce(DoAll(SetArgPointee<3>(DisplayVariant::HEIGHT), Return(Error::NONE))); |
| 440 | EXPECT_CALL(*test->mComposer, |
| 441 | getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID, |
| 442 | IComposerClient::Attribute::VSYNC_PERIOD, _)) |
| 443 | .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_REFRESH_RATE), Return(Error::NONE))); |
| 444 | EXPECT_CALL(*test->mComposer, |
| 445 | getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID, |
| 446 | IComposerClient::Attribute::DPI_X, _)) |
| 447 | .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE))); |
| 448 | EXPECT_CALL(*test->mComposer, |
| 449 | getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID, |
| 450 | IComposerClient::Attribute::DPI_Y, _)) |
| 451 | .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE))); |
| 452 | EXPECT_CALL(*test->mComposer, |
| 453 | getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID, |
| 454 | IComposerClient::Attribute::CONFIG_GROUP, _)) |
| 455 | .WillOnce(DoAll(SetArgPointee<3>(-1), Return(Error::NONE))); |
| 456 | |
| 457 | if (PhysicalDisplay::HAS_IDENTIFICATION_DATA) { |
| 458 | EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _)) |
| 459 | .WillOnce(DoAll(SetArgPointee<1>(PhysicalDisplay::PORT), |
| 460 | SetArgPointee<2>(PhysicalDisplay::GET_IDENTIFICATION_DATA()), |
| 461 | Return(Error::NONE))); |
| 462 | } else { |
| 463 | EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _)) |
| 464 | .WillOnce(Return(Error::UNSUPPORTED)); |
| 465 | } |
| 466 | } |
| 467 | |
| 468 | // Called by tests to set up HWC call expectations |
| 469 | static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) { |
| 470 | EXPECT_CALL(*test->mComposer, getActiveConfig(HWC_DISPLAY_ID, _)) |
| 471 | .WillRepeatedly(DoAll(SetArgPointee<1>(HWC_ACTIVE_CONFIG_ID), Return(Error::NONE))); |
| 472 | } |
| 473 | }; |
| 474 | |
| 475 | // Physical displays are expected to be synchronous, secure, and have a HWC display for output. |
| 476 | constexpr uint32_t GRALLOC_USAGE_PHYSICAL_DISPLAY = |
| 477 | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_FB; |
| 478 | |
| 479 | template <typename PhysicalDisplay, int width, int height, Critical critical> |
| 480 | struct PhysicalDisplayVariant |
| 481 | : DisplayVariant<PhysicalDisplayIdType<PhysicalDisplay>, width, height, critical, |
| 482 | Async::FALSE, Secure::TRUE, PhysicalDisplay::PRIMARY, |
| 483 | GRALLOC_USAGE_PHYSICAL_DISPLAY>, |
| 484 | HwcDisplayVariant<PhysicalDisplay::HWC_DISPLAY_ID, DisplayType::PHYSICAL, |
| 485 | DisplayVariant<PhysicalDisplayIdType<PhysicalDisplay>, width, height, |
| 486 | critical, Async::FALSE, Secure::TRUE, |
| 487 | PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY>, |
| 488 | PhysicalDisplay> {}; |
| 489 | |
| 490 | template <bool hasIdentificationData> |
| 491 | struct PrimaryDisplay { |
| 492 | static constexpr auto CONNECTION_TYPE = DisplayConnectionType::Internal; |
| 493 | static constexpr Primary PRIMARY = Primary::TRUE; |
| 494 | static constexpr uint8_t PORT = 255; |
| 495 | static constexpr HWDisplayId HWC_DISPLAY_ID = 1001; |
| 496 | static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData; |
| 497 | static constexpr auto GET_IDENTIFICATION_DATA = getInternalEdid; |
| 498 | }; |
| 499 | |
| 500 | template <bool hasIdentificationData> |
| 501 | struct ExternalDisplay { |
| 502 | static constexpr auto CONNECTION_TYPE = DisplayConnectionType::External; |
| 503 | static constexpr Primary PRIMARY = Primary::FALSE; |
| 504 | static constexpr uint8_t PORT = 254; |
| 505 | static constexpr HWDisplayId HWC_DISPLAY_ID = 1002; |
| 506 | static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData; |
| 507 | static constexpr auto GET_IDENTIFICATION_DATA = getExternalEdid; |
| 508 | }; |
| 509 | |
| 510 | struct TertiaryDisplay { |
| 511 | static constexpr Primary PRIMARY = Primary::FALSE; |
| 512 | static constexpr uint8_t PORT = 253; |
| 513 | static constexpr HWDisplayId HWC_DISPLAY_ID = 1003; |
| 514 | static constexpr auto GET_IDENTIFICATION_DATA = getExternalEdid; |
| 515 | }; |
| 516 | |
| 517 | // A primary display is a physical display that is critical |
| 518 | using PrimaryDisplayVariant = |
| 519 | PhysicalDisplayVariant<PrimaryDisplay<false>, 3840, 2160, Critical::TRUE>; |
| 520 | |
| 521 | // An external display is physical display that is not critical. |
| 522 | using ExternalDisplayVariant = |
| 523 | PhysicalDisplayVariant<ExternalDisplay<false>, 1920, 1280, Critical::FALSE>; |
| 524 | |
| 525 | using TertiaryDisplayVariant = PhysicalDisplayVariant<TertiaryDisplay, 1600, 1200, Critical::FALSE>; |
| 526 | |
| 527 | // A virtual display not supported by the HWC. |
| 528 | constexpr uint32_t GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY = 0; |
| 529 | |
| 530 | template <int width, int height, Secure secure> |
| 531 | struct NonHwcVirtualDisplayVariant |
| 532 | : DisplayVariant<GpuVirtualDisplayIdType, width, height, Critical::FALSE, Async::TRUE, secure, |
| 533 | Primary::FALSE, GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY> { |
| 534 | using Base = |
| 535 | DisplayVariant<GpuVirtualDisplayIdType, width, height, Critical::FALSE, Async::TRUE, |
| 536 | secure, Primary::FALSE, GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY>; |
| 537 | |
| 538 | static void injectHwcDisplay(DisplayTransactionTest*) {} |
| 539 | |
| 540 | static std::shared_ptr<compositionengine::Display> injectCompositionDisplay( |
| 541 | DisplayTransactionTest* test) { |
| 542 | const ::testing::TestInfo* const test_info = |
| 543 | ::testing::UnitTest::GetInstance()->current_test_info(); |
| 544 | |
| 545 | ON_CALL(test->mFlinger.gpuVirtualDisplayIdGenerator(), nextId()) |
| 546 | .WillByDefault(Return(Base::DISPLAY_ID::get())); |
| 547 | |
| 548 | auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder() |
| 549 | .setPixels({Base::WIDTH, Base::HEIGHT}) |
| 550 | .setIsSecure(static_cast<bool>(Base::SECURE)) |
| 551 | .setPowerAdvisor(&test->mPowerAdvisor) |
| 552 | .setName(std::string("Injected display for ") + |
| 553 | test_info->test_case_name() + "." + test_info->name()) |
| 554 | .setGpuVirtualDisplayIdGenerator( |
| 555 | test->mFlinger.gpuVirtualDisplayIdGenerator()) |
| 556 | .build(); |
| 557 | |
| 558 | return compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(), |
| 559 | ceDisplayArgs); |
| 560 | } |
| 561 | |
| 562 | static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) { |
| 563 | EXPECT_CALL(*test->mComposer, getActiveConfig(_, _)).Times(0); |
| 564 | } |
| 565 | |
| 566 | static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) { |
| 567 | Base::setupNativeWindowSurfaceCreationCallExpectations(test); |
| 568 | EXPECT_CALL(*test->mNativeWindow, setSwapInterval(0)).Times(1); |
| 569 | } |
| 570 | }; |
| 571 | |
| 572 | // A virtual display supported by the HWC. |
| 573 | constexpr uint32_t GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY = GRALLOC_USAGE_HW_COMPOSER; |
| 574 | |
| 575 | template <int width, int height, Secure secure> |
| 576 | struct HwcVirtualDisplayVariant |
| 577 | : DisplayVariant<HalVirtualDisplayIdType<42>, width, height, Critical::FALSE, Async::TRUE, |
| 578 | secure, Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>, |
| 579 | HwcDisplayVariant<HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID, DisplayType::VIRTUAL, |
| 580 | DisplayVariant<HalVirtualDisplayIdType<42>, width, height, |
| 581 | Critical::FALSE, Async::TRUE, secure, Primary::FALSE, |
| 582 | GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>> { |
| 583 | using Base = DisplayVariant<HalVirtualDisplayIdType<42>, width, height, Critical::FALSE, |
| 584 | Async::TRUE, secure, Primary::FALSE, GRALLOC_USAGE_HW_COMPOSER>; |
| 585 | using Self = HwcVirtualDisplayVariant<width, height, secure>; |
| 586 | |
| 587 | static std::shared_ptr<compositionengine::Display> injectCompositionDisplay( |
| 588 | DisplayTransactionTest* test) { |
| 589 | const ::testing::TestInfo* const test_info = |
| 590 | ::testing::UnitTest::GetInstance()->current_test_info(); |
| 591 | |
| 592 | // In order to prevent compostition engine calling into HWComposer, we |
| 593 | // 1. turn off the use of HWC virtual displays, |
| 594 | // 2. provide a GpuVirtualDisplayIdGenerator which always returns some fake ID |
| 595 | // 3. override the ID by calling setDisplayIdForTesting() |
| 596 | |
| 597 | ON_CALL(test->mFlinger.gpuVirtualDisplayIdGenerator(), nextId()) |
| 598 | .WillByDefault(Return(GpuVirtualDisplayId(0))); |
| 599 | |
| 600 | auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder() |
| 601 | .setUseHwcVirtualDisplays(false) |
| 602 | .setPixels({Base::WIDTH, Base::HEIGHT}) |
| 603 | .setIsSecure(static_cast<bool>(Base::SECURE)) |
| 604 | .setPowerAdvisor(&test->mPowerAdvisor) |
| 605 | .setName(std::string("Injected display for ") + |
| 606 | test_info->test_case_name() + "." + test_info->name()) |
| 607 | .setGpuVirtualDisplayIdGenerator( |
| 608 | test->mFlinger.gpuVirtualDisplayIdGenerator()) |
| 609 | .build(); |
| 610 | |
| 611 | auto compositionDisplay = |
| 612 | compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(), |
| 613 | ceDisplayArgs); |
| 614 | compositionDisplay->setDisplayIdForTesting(Base::DISPLAY_ID::get()); |
| 615 | |
| 616 | // Insert display data so that the HWC thinks it created the virtual display. |
| 617 | if (const auto displayId = Base::DISPLAY_ID::get(); |
| 618 | HalVirtualDisplayId::tryCast(displayId)) { |
| 619 | test->mFlinger.mutableHwcDisplayData().try_emplace(displayId); |
| 620 | } |
| 621 | |
| 622 | return compositionDisplay; |
| 623 | } |
| 624 | |
| 625 | static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) { |
| 626 | Base::setupNativeWindowSurfaceCreationCallExpectations(test); |
| 627 | EXPECT_CALL(*test->mNativeWindow, setSwapInterval(0)).Times(1); |
| 628 | } |
| 629 | |
| 630 | static void setupHwcVirtualDisplayCreationCallExpectations(DisplayTransactionTest* test) { |
| 631 | EXPECT_CALL(*test->mComposer, createVirtualDisplay(Base::WIDTH, Base::HEIGHT, _, _)) |
| 632 | .WillOnce(DoAll(SetArgPointee<3>(Self::HWC_DISPLAY_ID), Return(Error::NONE))); |
| 633 | EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE)); |
| 634 | } |
| 635 | }; |
| 636 | |
| 637 | // For this variant, the display is not a HWC display, so no HDR support should |
| 638 | // be configured. |
| 639 | struct NonHwcDisplayHdrSupportVariant { |
| 640 | static constexpr bool HDR10_PLUS_SUPPORTED = false; |
| 641 | static constexpr bool HDR10_SUPPORTED = false; |
| 642 | static constexpr bool HDR_HLG_SUPPORTED = false; |
| 643 | static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false; |
| 644 | static void setupComposerCallExpectations(DisplayTransactionTest* test) { |
| 645 | EXPECT_CALL(*test->mComposer, getHdrCapabilities(_, _, _, _, _)).Times(0); |
| 646 | } |
| 647 | }; |
| 648 | |
| 649 | // For this variant, the composer should respond with am empty list of HDR |
| 650 | // modes, so no HDR support should be configured. |
| 651 | template <typename Display> |
| 652 | struct HdrNotSupportedVariant { |
| 653 | static constexpr bool HDR10_PLUS_SUPPORTED = false; |
| 654 | static constexpr bool HDR10_SUPPORTED = false; |
| 655 | static constexpr bool HDR_HLG_SUPPORTED = false; |
| 656 | static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false; |
| 657 | static void setupComposerCallExpectations(DisplayTransactionTest* test) { |
| 658 | EXPECT_CALL(*test->mComposer, getHdrCapabilities(Display::HWC_DISPLAY_ID, _, _, _, _)) |
| 659 | .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hdr>()), Return(Error::NONE))); |
| 660 | } |
| 661 | }; |
| 662 | |
| 663 | struct NonHwcPerFrameMetadataSupportVariant { |
| 664 | static constexpr int PER_FRAME_METADATA_KEYS = 0; |
| 665 | static void setupComposerCallExpectations(DisplayTransactionTest* test) { |
| 666 | EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(_)).Times(0); |
| 667 | } |
| 668 | }; |
| 669 | |
| 670 | template <typename Display> |
| 671 | struct NoPerFrameMetadataSupportVariant { |
| 672 | static constexpr int PER_FRAME_METADATA_KEYS = 0; |
| 673 | static void setupComposerCallExpectations(DisplayTransactionTest* test) { |
| 674 | EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID)) |
| 675 | .WillOnce(Return(std::vector<PerFrameMetadataKey>())); |
| 676 | } |
| 677 | }; |
| 678 | |
| 679 | // For this variant, SurfaceFlinger should configure itself with wide display |
| 680 | // support, but the display should respond with an empty list of supported color |
| 681 | // modes. Wide-color support for the display should not be configured. |
| 682 | template <typename Display> |
| 683 | struct WideColorNotSupportedVariant { |
| 684 | static constexpr bool WIDE_COLOR_SUPPORTED = false; |
| 685 | |
| 686 | static void injectConfigChange(DisplayTransactionTest* test) { |
| 687 | test->mFlinger.mutableUseColorManagement() = true; |
| 688 | test->mFlinger.mutableHasWideColorDisplay() = true; |
| 689 | } |
| 690 | |
| 691 | static void setupComposerCallExpectations(DisplayTransactionTest* test) { |
| 692 | EXPECT_CALL(*test->mComposer, getColorModes(Display::HWC_DISPLAY_ID, _)) |
| 693 | .WillOnce(DoAll(SetArgPointee<1>(std::vector<ColorMode>()), Return(Error::NONE))); |
| 694 | EXPECT_CALL(*test->mComposer, setColorMode(_, _, _)).Times(0); |
| 695 | } |
| 696 | }; |
| 697 | |
| 698 | // For this variant, SurfaceFlinger should not configure itself with wide |
| 699 | // display support, so the display should not be configured for wide-color |
| 700 | // support. |
| 701 | struct WideColorSupportNotConfiguredVariant { |
| 702 | static constexpr bool WIDE_COLOR_SUPPORTED = false; |
| 703 | |
| 704 | static void injectConfigChange(DisplayTransactionTest* test) { |
| 705 | test->mFlinger.mutableHasWideColorDisplay() = false; |
| 706 | test->mFlinger.mutableUseColorManagement() = false; |
| 707 | test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged; |
| 708 | } |
| 709 | |
| 710 | static void setupComposerCallExpectations(DisplayTransactionTest* test) { |
| 711 | EXPECT_CALL(*test->mComposer, getColorModes(_, _)).Times(0); |
| 712 | EXPECT_CALL(*test->mComposer, getRenderIntents(_, _, _)).Times(0); |
| 713 | EXPECT_CALL(*test->mComposer, setColorMode(_, _, _)).Times(0); |
| 714 | } |
| 715 | }; |
| 716 | |
| 717 | /* ------------------------------------------------------------------------ |
| 718 | * Typical display configurations to test |
| 719 | */ |
| 720 | |
| 721 | template <typename DisplayPolicy, typename WideColorSupportPolicy, typename HdrSupportPolicy, |
| 722 | typename PerFrameMetadataSupportPolicy> |
| 723 | struct Case { |
| 724 | using Display = DisplayPolicy; |
| 725 | using WideColorSupport = WideColorSupportPolicy; |
| 726 | using HdrSupport = HdrSupportPolicy; |
| 727 | using PerFrameMetadataSupport = PerFrameMetadataSupportPolicy; |
| 728 | }; |
| 729 | |
| 730 | using SimplePrimaryDisplayCase = |
| 731 | Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>, |
| 732 | HdrNotSupportedVariant<PrimaryDisplayVariant>, |
| 733 | NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>; |
| 734 | using SimpleExternalDisplayCase = |
| 735 | Case<ExternalDisplayVariant, WideColorNotSupportedVariant<ExternalDisplayVariant>, |
| 736 | HdrNotSupportedVariant<ExternalDisplayVariant>, |
| 737 | NoPerFrameMetadataSupportVariant<ExternalDisplayVariant>>; |
| 738 | using SimpleTertiaryDisplayCase = |
| 739 | Case<TertiaryDisplayVariant, WideColorNotSupportedVariant<TertiaryDisplayVariant>, |
| 740 | HdrNotSupportedVariant<TertiaryDisplayVariant>, |
| 741 | NoPerFrameMetadataSupportVariant<TertiaryDisplayVariant>>; |
| 742 | |
| 743 | using NonHwcVirtualDisplayCase = |
| 744 | Case<NonHwcVirtualDisplayVariant<1024, 768, Secure::FALSE>, |
| 745 | WideColorSupportNotConfiguredVariant, NonHwcDisplayHdrSupportVariant, |
| 746 | NonHwcPerFrameMetadataSupportVariant>; |
| 747 | using SimpleHwcVirtualDisplayVariant = HwcVirtualDisplayVariant<1024, 768, Secure::TRUE>; |
| 748 | using HwcVirtualDisplayCase = |
| 749 | Case<SimpleHwcVirtualDisplayVariant, WideColorSupportNotConfiguredVariant, |
| 750 | HdrNotSupportedVariant<SimpleHwcVirtualDisplayVariant>, |
| 751 | NoPerFrameMetadataSupportVariant<SimpleHwcVirtualDisplayVariant>>; |
| 752 | |
| 753 | } // namespace android |
| 754 | |
| 755 | // TODO(b/129481165): remove the #pragma below and fix conversion issues |
| 756 | #pragma clang diagnostic pop // ignored "-Wconversion" |