Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8d5227b8 authored by Robert Carr's avatar Robert Carr
Browse files

Include finalCrop in setGeometryAppliesWithResize.

A refresher on this archaic function. Normally window crop and
position apply immediately. This is so the window manager can always
crop surfaces (e.g. while docked resizing) even if the app is lagging
behind. In some cases though the apps position or cropping may depend
on whether the resize has occured or not. For example when an app
gains shadows, we need to move expand the Surface and move it by a
negative offset for the content to remain in the same place. This
movement needs to be synchronized with the buffer latching for the
expansion.

We implemented setGeometryAppliesWithResize to take care of this. At
the time it wasn't clear if it was needed for finalCrop so we let it
be. Now that we are exclusively using final crop in the pinned stack
however it is required. The same way we have an issue with position
and shadows, we have an issue with expanding the crop rect (we may
have actually been cropping out part of a larger surface that is now
supposed to be shadows).

Also includes a test suite for setGeometryAppliesWithResize behavior
which was previously untested.

Bug: 35396882
Test: SurfaceFlinger_test
Change-Id: Ie4d32162eb21154496bb231161692d18341a1e1e
parent 4f4ac845
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -1753,11 +1753,15 @@ bool Layer::setCrop(const Rect& crop, bool immediate) {
    setTransactionFlags(eTransactionNeeded);
    return true;
}
bool Layer::setFinalCrop(const Rect& crop) {

bool Layer::setFinalCrop(const Rect& crop, bool immediate) {
    if (mCurrentState.finalCrop == crop)
        return false;
    mCurrentState.sequence++;
    mCurrentState.requestedFinalCrop = crop;
    if (immediate) {
        mCurrentState.finalCrop = crop;
    }
    mCurrentState.modified = true;
    setTransactionFlags(eTransactionNeeded);
    return true;
+8 −2
Original line number Diff line number Diff line
@@ -135,6 +135,7 @@ public:

        // finalCrop is expressed in display space coordinate.
        Rect finalCrop;
        Rect requestedFinalCrop;

        // If set, defers this state update until the identified Layer
        // receives a frame with the given frameNumber
@@ -163,7 +164,14 @@ public:
    status_t setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);

    // modify current state

    // These members of state (position, crop, and finalCrop)
    // may be updated immediately or have the update delayed
    // until a pending surface resize completes (if applicable).
    bool setPosition(float x, float y, bool immediate);
    bool setCrop(const Rect& crop, bool immediate);
    bool setFinalCrop(const Rect& crop, bool immediate);

    bool setLayer(int32_t z);
    bool setSize(uint32_t w, uint32_t h);
#ifdef USE_HWC2
@@ -174,8 +182,6 @@ public:
    bool setMatrix(const layer_state_t::matrix22_t& matrix);
    bool setTransparentRegionHint(const Region& transparent);
    bool setFlags(uint8_t flags, uint8_t mask);
    bool setCrop(const Rect& crop, bool immediate);
    bool setFinalCrop(const Rect& crop);
    bool setLayerStack(uint32_t layerStack);
    bool setDataSpace(android_dataspace dataSpace);
    uint32_t getLayerStack() const;
+5 −0
Original line number Diff line number Diff line
@@ -120,6 +120,11 @@ bool LayerRejecter::reject(const sp<GraphicBuffer>& buf, const BufferItem& item)
        mCurrent.crop = mFront.requestedCrop;
        mRecomputeVisibleRegions = true;
    }
    if (mFront.finalCrop != mFront.requestedFinalCrop) {
        mFront.finalCrop = mFront.requestedFinalCrop;
        mCurrent.finalCrop = mFront.requestedFinalCrop;
        mRecomputeVisibleRegions = true;
    }
    mFreezePositionUpdates = false;

    return false;
+1 −1
Original line number Diff line number Diff line
@@ -2766,7 +2766,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(
                flags |= eTraversalNeeded;
        }
        if (what & layer_state_t::eFinalCropChanged) {
            if (layer->setFinalCrop(s.finalCrop))
            if (layer->setFinalCrop(s.finalCrop, !geometryAppliesWithResize))
                flags |= eTraversalNeeded;
        }
        if (what & layer_state_t::eLayerStackChanged) {
+137 −2
Original line number Diff line number Diff line
@@ -470,6 +470,141 @@ TEST_F(LayerUpdateTest, LayerSetMatrixWorks) {
    }
}

class GeometryLatchingTest : public LayerUpdateTest {
protected:
    void EXPECT_INITIAL_STATE(const char * trace) {
        SCOPED_TRACE(trace);
        ScreenCapture::captureScreen(&sc);
        // We find the leading edge of the FG surface.
        sc->expectFGColor(127, 127);
        sc->expectBGColor(128, 128);
    }
    void completeFGResize() {
        fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
        waitForPostedBuffers();
    }
    void restoreInitialState() {
        SurfaceComposerClient::openGlobalTransaction();
        mFGSurfaceControl->setSize(64, 64);
        mFGSurfaceControl->setPosition(64, 64);
        mFGSurfaceControl->setCrop(Rect(0, 0, 64, 64));
        mFGSurfaceControl->setFinalCrop(Rect(0, 0, -1, -1));
        SurfaceComposerClient::closeGlobalTransaction(true);

        EXPECT_INITIAL_STATE("After restoring initial state");
    }
    sp<ScreenCapture> sc;
};

TEST_F(GeometryLatchingTest, SurfacePositionLatching) {
    EXPECT_INITIAL_STATE("before anything");

    // By default position can be updated even while
    // a resize is pending.
    SurfaceComposerClient::openGlobalTransaction();
    mFGSurfaceControl->setSize(32, 32);
    mFGSurfaceControl->setPosition(100, 100);
    SurfaceComposerClient::closeGlobalTransaction(true);

    {
        SCOPED_TRACE("After moving surface");
        ScreenCapture::captureScreen(&sc);
        // If we moved, the FG Surface should cover up what was previously BG
        // however if we didn't move the FG wouldn't be large enough now.
        sc->expectFGColor(163, 163);
    }

    restoreInitialState();

    // Now we repeat with setGeometryAppliesWithResize
    // and verify the position DOESN'T latch.
    SurfaceComposerClient::openGlobalTransaction();
    mFGSurfaceControl->setGeometryAppliesWithResize();
    mFGSurfaceControl->setSize(32, 32);
    mFGSurfaceControl->setPosition(100, 100);
    SurfaceComposerClient::closeGlobalTransaction(true);

    {
        SCOPED_TRACE("While resize is pending");
        ScreenCapture::captureScreen(&sc);
        // This time we shouldn't have moved, so the BG color
        // should still be visible.
        sc->expectBGColor(128, 128);
    }

    completeFGResize();

    {
        SCOPED_TRACE("After the resize");
        ScreenCapture::captureScreen(&sc);
        // But after the resize completes, we should move
        // and the FG should be visible here.
        sc->expectFGColor(128, 128);
    }
}

class CropLatchingTest : public GeometryLatchingTest {
protected:
    void EXPECT_CROPPED_STATE(const char* trace) {
        SCOPED_TRACE(trace);
        ScreenCapture::captureScreen(&sc);
        // The edge should be moved back one pixel by our crop.
        sc->expectFGColor(126, 126);
        sc->expectBGColor(127, 127);
        sc->expectBGColor(128, 128);
    }
};

TEST_F(CropLatchingTest, CropLatching) {
    EXPECT_INITIAL_STATE("before anything");
    // Normally the crop applies immediately even while a resize is pending.
    SurfaceComposerClient::openGlobalTransaction();
    mFGSurfaceControl->setSize(128, 128);
    mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63));
    SurfaceComposerClient::closeGlobalTransaction(true);

    EXPECT_CROPPED_STATE("after setting crop (without geometryAppliesWithResize)");

    restoreInitialState();

    SurfaceComposerClient::openGlobalTransaction();
    mFGSurfaceControl->setSize(128, 128);
    mFGSurfaceControl->setGeometryAppliesWithResize();
    mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63));
    SurfaceComposerClient::closeGlobalTransaction(true);

    EXPECT_INITIAL_STATE("after setting crop (with geometryAppliesWithResize)");

    completeFGResize();

    EXPECT_CROPPED_STATE("after the resize finishes");
}

TEST_F(CropLatchingTest, FinalCropLatching) {
    EXPECT_INITIAL_STATE("before anything");
    // Normally the crop applies immediately even while a resize is pending.
    SurfaceComposerClient::openGlobalTransaction();
    mFGSurfaceControl->setSize(128, 128);
    mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
    SurfaceComposerClient::closeGlobalTransaction(true);

    EXPECT_CROPPED_STATE("after setting crop (without geometryAppliesWithResize)");

    restoreInitialState();

    SurfaceComposerClient::openGlobalTransaction();
    mFGSurfaceControl->setSize(128, 128);
    mFGSurfaceControl->setGeometryAppliesWithResize();
    mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
    SurfaceComposerClient::closeGlobalTransaction(true);

    EXPECT_INITIAL_STATE("after setting crop (with geometryAppliesWithResize)");

    completeFGResize();

    EXPECT_CROPPED_STATE("after the resize finishes");
}

TEST_F(LayerUpdateTest, DeferredTransactionTest) {
    sp<ScreenCapture> sc;
    {
@@ -677,11 +812,11 @@ TEST_F(ChildLayerTest, DetachChildren) {

    SurfaceComposerClient::openGlobalTransaction();
    mFGSurfaceControl->detachChildren();
    SurfaceComposerClient::closeGlobalTransaction();
    SurfaceComposerClient::closeGlobalTransaction(true);

    SurfaceComposerClient::openGlobalTransaction();
    mChild->hide();
    SurfaceComposerClient::closeGlobalTransaction();
    SurfaceComposerClient::closeGlobalTransaction(true);

    // Nothing should have changed.
    {