diff options
-rw-r--r-- | services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp | 589 | ||||
-rw-r--r-- | services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h | 23 |
2 files changed, 607 insertions, 5 deletions
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index 2b8a22c122..bb6ca39023 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -386,6 +386,11 @@ struct PhysicalDisplayVariant DisplayVariant<type, type, width, height, critical, Async::FALSE, Secure::TRUE, GRALLOC_USAGE_PHYSICAL_DISPLAY>> {}; +// An invalid display +using InvalidDisplayVariant = + DisplayVariant<DisplayDevice::DISPLAY_ID_INVALID, DisplayDevice::DISPLAY_ID_INVALID, 0, 0, + Critical::FALSE, Async::FALSE, Secure::FALSE, 0>; + // A primary display is a physical display that is critical using PrimaryDisplayVariant = PhysicalDisplayVariant<1001, DisplayDevice::DISPLAY_PRIMARY, 3840, 2160, Critical::TRUE>; @@ -645,6 +650,8 @@ using HdrHlgDisplayCase = using HdrDolbyVisionDisplayCase = Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>, HdrDolbyVisionSupportedVariant<PrimaryDisplayVariant>>; +using InvalidDisplayCase = Case<InvalidDisplayVariant, WideColorSupportNotConfiguredVariant, + NonHwcDisplayHdrSupportVariant>; /* ------------------------------------------------------------------------ * @@ -1560,7 +1567,7 @@ TEST_F(HandleTransactionLockedTest, processesDisplayLayerStackChanges) { // -------------------------------------------------------------------- // Postconditions - EXPECT_EQ(newLayerStack, getDisplayDevice(display.token())->getLayerStack()); + EXPECT_EQ(newLayerStack, display.mutableDisplayDevice()->getLayerStack()); } TEST_F(HandleTransactionLockedTest, processesDisplayTransformChanges) { @@ -1588,7 +1595,7 @@ TEST_F(HandleTransactionLockedTest, processesDisplayTransformChanges) { // -------------------------------------------------------------------- // Postconditions - EXPECT_EQ(newTransform, getDisplayDevice(display.token())->getOrientation()); + EXPECT_EQ(newTransform, display.mutableDisplayDevice()->getOrientation()); } TEST_F(HandleTransactionLockedTest, processesDisplayViewportChanges) { @@ -1616,7 +1623,7 @@ TEST_F(HandleTransactionLockedTest, processesDisplayViewportChanges) { // -------------------------------------------------------------------- // Postconditions - EXPECT_EQ(newViewport, getDisplayDevice(display.token())->getViewport()); + EXPECT_EQ(newViewport, display.mutableDisplayDevice()->getViewport()); } TEST_F(HandleTransactionLockedTest, processesDisplayFrameChanges) { @@ -1644,7 +1651,7 @@ TEST_F(HandleTransactionLockedTest, processesDisplayFrameChanges) { // -------------------------------------------------------------------- // Postconditions - EXPECT_EQ(newFrame, getDisplayDevice(display.token())->getFrame()); + EXPECT_EQ(newFrame, display.mutableDisplayDevice()->getFrame()); } TEST_F(HandleTransactionLockedTest, processesDisplayWidthChanges) { @@ -1729,5 +1736,579 @@ TEST_F(HandleTransactionLockedTest, processesDisplayHeightChanges) { mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); } +/* ------------------------------------------------------------------------ + * SurfaceFlinger::setDisplayStateLocked + */ + +TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingWithUnknownDisplay) { + // -------------------------------------------------------------------- + // Preconditions + + // We have an unknown display token not associated with a known display + sp<BBinder> displayToken = new BBinder(); + + // The requested display state references the unknown display. + DisplayState state; + state.what = DisplayState::eLayerStackChanged; + state.token = displayToken; + state.layerStack = 456; + + // -------------------------------------------------------------------- + // Invocation + + uint32_t flags = mFlinger.setDisplayStateLocked(state); + + // -------------------------------------------------------------------- + // Postconditions + + // The returned flags are empty + EXPECT_EQ(0u, flags); + + // The display token still doesn't match anything known. + EXPECT_FALSE(hasCurrentDisplayState(displayToken)); +} + +TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingWithInvalidDisplay) { + using Case = InvalidDisplayCase; + + // -------------------------------------------------------------------- + // Preconditions + + // An invalid display is set up + auto display = Case::Display::makeFakeExistingDisplayInjector(this); + display.inject(); + + // The invalid display has some state + display.mutableCurrentDisplayState().layerStack = 654u; + + // The requested display state tries to change the display state. + DisplayState state; + state.what = DisplayState::eLayerStackChanged; + state.token = display.token(); + state.layerStack = 456; + + // -------------------------------------------------------------------- + // Invocation + + uint32_t flags = mFlinger.setDisplayStateLocked(state); + + // -------------------------------------------------------------------- + // Postconditions + + // The returned flags are empty + EXPECT_EQ(0u, flags); + + // The current display layer stack value is unchanged. + EXPECT_EQ(654u, getCurrentDisplayState(display.token()).layerStack); +} + +TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingWhenNoChanges) { + using Case = SimplePrimaryDisplayCase; + + // -------------------------------------------------------------------- + // Preconditions + + // A display is already set up + auto display = Case::Display::makeFakeExistingDisplayInjector(this); + display.inject(); + + // No changes are made to the display + DisplayState state; + state.what = 0; + state.token = display.token(); + + // -------------------------------------------------------------------- + // Invocation + + uint32_t flags = mFlinger.setDisplayStateLocked(state); + + // -------------------------------------------------------------------- + // Postconditions + + // The returned flags are empty + EXPECT_EQ(0u, flags); +} + +TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingIfSurfaceDidNotChange) { + using Case = SimplePrimaryDisplayCase; + + // -------------------------------------------------------------------- + // Preconditions + + // A display is already set up + auto display = Case::Display::makeFakeExistingDisplayInjector(this); + display.inject(); + + // There is a surface that can be set. + sp<mock::GraphicBufferProducer> surface = new mock::GraphicBufferProducer(); + + // The current display state has the surface set + display.mutableCurrentDisplayState().surface = surface; + + // The incoming request sets the same surface + DisplayState state; + state.what = DisplayState::eSurfaceChanged; + state.token = display.token(); + state.surface = surface; + + // -------------------------------------------------------------------- + // Invocation + + uint32_t flags = mFlinger.setDisplayStateLocked(state); + + // -------------------------------------------------------------------- + // Postconditions + + // The returned flags are empty + EXPECT_EQ(0u, flags); + + // The current display state is unchanged. + EXPECT_EQ(surface.get(), display.getCurrentDisplayState().surface.get()); +} + +TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfSurfaceChanged) { + using Case = SimplePrimaryDisplayCase; + + // -------------------------------------------------------------------- + // Preconditions + + // A display is already set up + auto display = Case::Display::makeFakeExistingDisplayInjector(this); + display.inject(); + + // There is a surface that can be set. + sp<mock::GraphicBufferProducer> surface = new mock::GraphicBufferProducer(); + + // The current display state does not have a surface + display.mutableCurrentDisplayState().surface = nullptr; + + // The incoming request sets a surface + DisplayState state; + state.what = DisplayState::eSurfaceChanged; + state.token = display.token(); + state.surface = surface; + + // -------------------------------------------------------------------- + // Invocation + + uint32_t flags = mFlinger.setDisplayStateLocked(state); + + // -------------------------------------------------------------------- + // Postconditions + + // The returned flags indicate a transaction is needed + EXPECT_EQ(eDisplayTransactionNeeded, flags); + + // The current display layer stack state is set to the new value + EXPECT_EQ(surface.get(), display.getCurrentDisplayState().surface.get()); +} + +TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingIfLayerStackDidNotChange) { + using Case = SimplePrimaryDisplayCase; + + // -------------------------------------------------------------------- + // Preconditions + + // A display is already set up + auto display = Case::Display::makeFakeExistingDisplayInjector(this); + display.inject(); + + // The display has a layer stack set + display.mutableCurrentDisplayState().layerStack = 456u; + + // The incoming request sets the same layer stack + DisplayState state; + state.what = DisplayState::eLayerStackChanged; + state.token = display.token(); + state.layerStack = 456u; + + // -------------------------------------------------------------------- + // Invocation + + uint32_t flags = mFlinger.setDisplayStateLocked(state); + + // -------------------------------------------------------------------- + // Postconditions + + // The returned flags are empty + EXPECT_EQ(0u, flags); + + // The current display state is unchanged + EXPECT_EQ(456u, display.getCurrentDisplayState().layerStack); +} + +TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfLayerStackChanged) { + using Case = SimplePrimaryDisplayCase; + + // -------------------------------------------------------------------- + // Preconditions + + // A display is set up + auto display = Case::Display::makeFakeExistingDisplayInjector(this); + display.inject(); + + // The display has a layer stack set + display.mutableCurrentDisplayState().layerStack = 654u; + + // The incoming request sets a different layer stack + DisplayState state; + state.what = DisplayState::eLayerStackChanged; + state.token = display.token(); + state.layerStack = 456u; + + // -------------------------------------------------------------------- + // Invocation + + uint32_t flags = mFlinger.setDisplayStateLocked(state); + + // -------------------------------------------------------------------- + // Postconditions + + // The returned flags indicate a transaction is needed + EXPECT_EQ(eDisplayTransactionNeeded, flags); + + // The desired display state has been set to the new value. + EXPECT_EQ(456u, display.getCurrentDisplayState().layerStack); +} + +TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingIfProjectionDidNotChange) { + using Case = SimplePrimaryDisplayCase; + constexpr int initialOrientation = 180; + const Rect initialFrame = {1, 2, 3, 4}; + const Rect initialViewport = {5, 6, 7, 8}; + + // -------------------------------------------------------------------- + // Preconditions + + // A display is set up + auto display = Case::Display::makeFakeExistingDisplayInjector(this); + display.inject(); + + // The current display state projection state is all set + display.mutableCurrentDisplayState().orientation = initialOrientation; + display.mutableCurrentDisplayState().frame = initialFrame; + display.mutableCurrentDisplayState().viewport = initialViewport; + + // The incoming request sets the same projection state + DisplayState state; + state.what = DisplayState::eDisplayProjectionChanged; + state.token = display.token(); + state.orientation = initialOrientation; + state.frame = initialFrame; + state.viewport = initialViewport; + + // -------------------------------------------------------------------- + // Invocation + + uint32_t flags = mFlinger.setDisplayStateLocked(state); + + // -------------------------------------------------------------------- + // Postconditions + + // The returned flags are empty + EXPECT_EQ(0u, flags); + + // The current display state is unchanged + EXPECT_EQ(initialOrientation, display.getCurrentDisplayState().orientation); + + EXPECT_EQ(initialFrame, display.getCurrentDisplayState().frame); + EXPECT_EQ(initialViewport, display.getCurrentDisplayState().viewport); +} + +TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfOrientationChanged) { + using Case = SimplePrimaryDisplayCase; + constexpr int initialOrientation = 90; + constexpr int desiredOrientation = 180; + + // -------------------------------------------------------------------- + // Preconditions + + // A display is set up + auto display = Case::Display::makeFakeExistingDisplayInjector(this); + display.inject(); + + // The current display state has an orientation set + display.mutableCurrentDisplayState().orientation = initialOrientation; + + // The incoming request sets a different orientation + DisplayState state; + state.what = DisplayState::eDisplayProjectionChanged; + state.token = display.token(); + state.orientation = desiredOrientation; + + // -------------------------------------------------------------------- + // Invocation + + uint32_t flags = mFlinger.setDisplayStateLocked(state); + + // -------------------------------------------------------------------- + // Postconditions + + // The returned flags indicate a transaction is needed + EXPECT_EQ(eDisplayTransactionNeeded, flags); + + // The current display state has the new value. + EXPECT_EQ(desiredOrientation, display.getCurrentDisplayState().orientation); +} + +TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfFrameChanged) { + using Case = SimplePrimaryDisplayCase; + const Rect initialFrame = {0, 0, 0, 0}; + const Rect desiredFrame = {5, 6, 7, 8}; + + // -------------------------------------------------------------------- + // Preconditions + + // A display is set up + auto display = Case::Display::makeFakeExistingDisplayInjector(this); + display.inject(); + + // The current display state does not have a frame + display.mutableCurrentDisplayState().frame = initialFrame; + + // The incoming request sets a frame + DisplayState state; + state.what = DisplayState::eDisplayProjectionChanged; + state.token = display.token(); + state.frame = desiredFrame; + + // -------------------------------------------------------------------- + // Invocation + + uint32_t flags = mFlinger.setDisplayStateLocked(state); + + // -------------------------------------------------------------------- + // Postconditions + + // The returned flags indicate a transaction is needed + EXPECT_EQ(eDisplayTransactionNeeded, flags); + + // The current display state has the new value. + EXPECT_EQ(desiredFrame, display.getCurrentDisplayState().frame); +} + +TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfViewportChanged) { + using Case = SimplePrimaryDisplayCase; + const Rect initialViewport = {0, 0, 0, 0}; + const Rect desiredViewport = {5, 6, 7, 8}; + + // -------------------------------------------------------------------- + // Preconditions + + // A display is set up + auto display = Case::Display::makeFakeExistingDisplayInjector(this); + display.inject(); + + // The current display state does not have a viewport + display.mutableCurrentDisplayState().viewport = initialViewport; + + // The incoming request sets a viewport + DisplayState state; + state.what = DisplayState::eDisplayProjectionChanged; + state.token = display.token(); + state.viewport = desiredViewport; + + // -------------------------------------------------------------------- + // Invocation + + uint32_t flags = mFlinger.setDisplayStateLocked(state); + + // -------------------------------------------------------------------- + // Postconditions + + // The returned flags indicate a transaction is needed + EXPECT_EQ(eDisplayTransactionNeeded, flags); + + // The current display state has the new value. + EXPECT_EQ(desiredViewport, display.getCurrentDisplayState().viewport); +} + +TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingIfSizeDidNotChange) { + using Case = SimplePrimaryDisplayCase; + constexpr uint32_t initialWidth = 1024; + constexpr uint32_t initialHeight = 768; + + // -------------------------------------------------------------------- + // Preconditions + + // A display is set up + auto display = Case::Display::makeFakeExistingDisplayInjector(this); + display.inject(); + + // The current display state has a size set + display.mutableCurrentDisplayState().width = initialWidth; + display.mutableCurrentDisplayState().height = initialHeight; + + // The incoming request sets the same display size + DisplayState state; + state.what = DisplayState::eDisplaySizeChanged; + state.token = display.token(); + state.width = initialWidth; + state.height = initialHeight; + + // -------------------------------------------------------------------- + // Invocation + + uint32_t flags = mFlinger.setDisplayStateLocked(state); + + // -------------------------------------------------------------------- + // Postconditions + + // The returned flags are empty + EXPECT_EQ(0u, flags); + + // The current display state is unchanged + EXPECT_EQ(initialWidth, display.getCurrentDisplayState().width); + EXPECT_EQ(initialHeight, display.getCurrentDisplayState().height); +} + +TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfWidthChanged) { + using Case = SimplePrimaryDisplayCase; + constexpr uint32_t initialWidth = 0; + constexpr uint32_t desiredWidth = 1024; + + // -------------------------------------------------------------------- + // Preconditions + + // A display is set up + auto display = Case::Display::makeFakeExistingDisplayInjector(this); + display.inject(); + + // The display does not yet have a width + display.mutableCurrentDisplayState().width = initialWidth; + + // The incoming request sets a display width + DisplayState state; + state.what = DisplayState::eDisplaySizeChanged; + state.token = display.token(); + state.width = desiredWidth; + + // -------------------------------------------------------------------- + // Invocation + + uint32_t flags = mFlinger.setDisplayStateLocked(state); + + // -------------------------------------------------------------------- + // Postconditions + + // The returned flags indicate a transaction is needed + EXPECT_EQ(eDisplayTransactionNeeded, flags); + + // The current display state has the new value. + EXPECT_EQ(desiredWidth, display.getCurrentDisplayState().width); +} + +TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfHeightChanged) { + using Case = SimplePrimaryDisplayCase; + constexpr uint32_t initialHeight = 0; + constexpr uint32_t desiredHeight = 768; + + // -------------------------------------------------------------------- + // Preconditions + + // A display is set up + auto display = Case::Display::makeFakeExistingDisplayInjector(this); + display.inject(); + + // The display does not yet have a height + display.mutableCurrentDisplayState().height = initialHeight; + + // The incoming request sets a display height + DisplayState state; + state.what = DisplayState::eDisplaySizeChanged; + state.token = display.token(); + state.height = desiredHeight; + + // -------------------------------------------------------------------- + // Invocation + + uint32_t flags = mFlinger.setDisplayStateLocked(state); + + // -------------------------------------------------------------------- + // Postconditions + + // The returned flags indicate a transaction is needed + EXPECT_EQ(eDisplayTransactionNeeded, flags); + + // The current display state has the new value. + EXPECT_EQ(desiredHeight, display.getCurrentDisplayState().height); +} + +/* ------------------------------------------------------------------------ + * SurfaceFlinger::onInitializeDisplays + */ + +TEST_F(DisplayTransactionTest, onInitializeDisplaysSetsUpPrimaryDisplay) { + using Case = SimplePrimaryDisplayCase; + + // -------------------------------------------------------------------- + // Preconditions + + // A primary display is set up + Case::Display::injectHwcDisplay(this); + auto primaryDisplay = Case::Display::makeFakeExistingDisplayInjector(this); + primaryDisplay.inject(); + + // -------------------------------------------------------------------- + // Call Expectations + + // We expect the surface interceptor to possibly be used, but we treat it as + // disabled since it is called as a side effect rather than directly by this + // function. + EXPECT_CALL(*mSurfaceInterceptor, isEnabled()).WillOnce(Return(false)); + + // We expect a call to get the active display config. + Case::Display::setupHwcGetActiveConfigCallExpectations(this); + + // We expect invalidate() to be invoked once to trigger display transaction + // processing. + EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + + // -------------------------------------------------------------------- + // Invocation + + mFlinger.onInitializeDisplays(); + + // -------------------------------------------------------------------- + // Postconditions + + // The primary display should have a current state + ASSERT_TRUE(hasCurrentDisplayState(primaryDisplay.token())); + const auto& primaryDisplayState = getCurrentDisplayState(primaryDisplay.token()); + // The layer stack state should be set to zero + EXPECT_EQ(0u, primaryDisplayState.layerStack); + // The orientation state should be set to zero + EXPECT_EQ(0, primaryDisplayState.orientation); + + // The frame state should be set to INVALID + EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.frame); + + // The viewport state should be set to INVALID + EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.viewport); + + // The width and height should both be zero + EXPECT_EQ(0u, primaryDisplayState.width); + EXPECT_EQ(0u, primaryDisplayState.height); + + // The display should be set to HWC_POWER_MODE_NORMAL + ASSERT_TRUE(hasDisplayDevice(primaryDisplay.token())); + auto displayDevice = primaryDisplay.mutableDisplayDevice(); + EXPECT_EQ(HWC_POWER_MODE_NORMAL, displayDevice->getPowerMode()); + + // The display refresh period should be set in the frame tracker. + FrameStats stats; + mFlinger.getAnimFrameTracker().getStats(&stats); + EXPECT_EQ(DEFAULT_REFRESH_RATE, stats.refreshPeriodNano); + + // The display transaction needed flag should be set. + EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded)); + + // The compositor timing should be set to default values + const auto& compositorTiming = mFlinger.getCompositorTiming(); + EXPECT_EQ(-DEFAULT_REFRESH_RATE, compositorTiming.deadline); + EXPECT_EQ(DEFAULT_REFRESH_RATE, compositorTiming.interval); + EXPECT_EQ(DEFAULT_REFRESH_RATE, compositorTiming.presentLatency); +} + } // namespace } // namespace android diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index b8a3baf604..f6895371f6 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -85,6 +85,17 @@ public: return mFlinger->onHotplugReceived(sequenceId, display, connection); } + auto setDisplayStateLocked(const DisplayState& s) { return mFlinger->setDisplayStateLocked(s); } + + auto onInitializeDisplays() { return mFlinger->onInitializeDisplays(); } + + /* ------------------------------------------------------------------------ + * Read-only access to private data to assert post-conditions. + */ + + const auto& getAnimFrameTracker() const { return mFlinger->mAnimFrameTracker; } + const auto& getCompositorTiming() const { return mFlinger->getBE().mCompositorTiming; } + /* ------------------------------------------------------------------------ * Read-write access to private data to set up preconditions and assert * post-conditions. @@ -247,6 +258,16 @@ public: return mFlinger.mutableCurrentState().displays.editValueFor(mDisplayToken); } + const auto& getDrawingDisplayState() { + return mFlinger.mutableDrawingState().displays.valueFor(mDisplayToken); + } + + const auto& getCurrentDisplayState() { + return mFlinger.mutableCurrentState().displays.valueFor(mDisplayToken); + } + + auto& mutableDisplayDevice() { return mFlinger.mutableDisplays().valueFor(mDisplayToken); } + auto& setNativeWindow(const sp<ANativeWindow>& nativeWindow) { mNativeWindow = nativeWindow; return *this; @@ -278,7 +299,7 @@ public: mFlinger.mutableCurrentState().displays.add(mDisplayToken, state); mFlinger.mutableDrawingState().displays.add(mDisplayToken, state); - if (mType < DisplayDevice::DISPLAY_VIRTUAL) { + if (mType >= DisplayDevice::DISPLAY_PRIMARY && mType < DisplayDevice::DISPLAY_VIRTUAL) { mFlinger.mutableBuiltinDisplays()[mType] = mDisplayToken; } |