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

Commit 1e69253c authored by Nathaniel Nifong's avatar Nathaniel Nifong
Browse files

Allow single inactive layers to be cached if they would be used for a hole punch.

Test: atest libcompositionengine_test

Bug: b/195448126

Change-Id: I2eb19397990d76a835fd842b33c627be91135e2f
parent 9cf612f1
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -98,8 +98,8 @@ private:
                             std::chrono::steady_clock::time_point now);

    // A Run is a sequence of CachedSets, which is a candidate for flattening into a single
    // CachedSet. Because it is wasteful to flatten 1 CachedSet, a Run must contain more than 1
    // CachedSet
    // CachedSet. Because it is wasteful to flatten 1 CachedSet, a run must contain more than
    // 1 CachedSet or be used for a hole punch.
    class Run {
    public:
        // A builder for a Run, to aid in construction
@@ -133,7 +133,13 @@ private:

            // Builds a Run instance, if a valid Run may be built.
            std::optional<Run> validateAndBuild() {
                if (mLengths.size() <= 1) {
                if (mLengths.size() == 0) {
                    return std::nullopt;
                }
                // Runs of length 1 which are hole punch candidates are allowed if the candidate is
                // going to be used.
                if (mLengths.size() == 1 &&
                    (!mHolePunchCandidate || !(mHolePunchCandidate->requiresHolePunch()))) {
                    return std::nullopt;
                }

+67 −0
Original line number Diff line number Diff line
@@ -659,6 +659,73 @@ TEST_F(FlattenerTest, flattenLayers_pip) {
    EXPECT_EQ(peekThroughLayer1, peekThroughLayer2);
}

// A test that verifies the hole puch optimization can be done on a single layer.
TEST_F(FlattenerTest, flattenLayers_holePunchSingleLayer) {
    mTestLayers[0]->outputLayerCompositionState.displayFrame = Rect(0, 0, 5, 5);

    // An opaque static background
    auto& layerState0 = mTestLayers[0]->layerState;
    const auto& overrideBuffer0 = layerState0->getOutputLayer()->getState().overrideInfo.buffer;

    // a rounded updating layer
    auto& layerState1 = mTestLayers[1]->layerState;
    const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer;

    EXPECT_CALL(*mTestLayers[1]->layerFE, hasRoundedCorners()).WillRepeatedly(Return(true));

    std::vector<LayerFE::LayerSettings> clientCompositionList = {
            LayerFE::LayerSettings{},
    };
    clientCompositionList[0].source.buffer.buffer = std::make_shared<
            renderengine::ExternalTexture>(mTestLayers[1]->layerFECompositionState.buffer,
                                           mRenderEngine,
                                           renderengine::ExternalTexture::Usage::READABLE);
    EXPECT_CALL(*mTestLayers[1]->layerFE, prepareClientCompositionList(_))
            .WillOnce(Return(clientCompositionList));

    const std::vector<const LayerState*> layers = {
            layerState0.get(),
            layerState1.get(),
    };

    initializeFlattener(layers);

    // layer 1 satisfies every condition in CachedSet::requiresHolePunch()
    mTime += 200ms;
    layerState1->resetFramesSinceBufferUpdate(); // it is updating

    initializeOverrideBuffer(layers);
    // Expect no cache invalidation the first time (there's no cache yet)
    EXPECT_EQ(getNonBufferHash(layers),
              mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));

    // This will render a CachedSet of layer 0. Though it is just one layer, it satisfies the
    // exception that there would be a hole punch above it.
    EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
    mFlattener->renderCachedSets(mOutputState, std::nullopt);

    // We've rendered a CachedSet, but we haven't merged it in.
    EXPECT_EQ(nullptr, overrideBuffer0);

    // This time we merge the CachedSet in and we should still have only two sets.
    EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).Times(0);
    initializeOverrideBuffer(layers);
    EXPECT_EQ(getNonBufferHash(layers),
              mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
    mFlattener->renderCachedSets(mOutputState, std::nullopt);

    EXPECT_NE(nullptr, overrideBuffer0); // got overridden
    EXPECT_EQ(nullptr, overrideBuffer1); // did not

    // expect 0's peek though layer to be 1's output layer
    const auto* peekThroughLayer0 =
            layerState0->getOutputLayer()->getState().overrideInfo.peekThroughLayer;
    const auto* peekThroughLayer1 =
            layerState1->getOutputLayer()->getState().overrideInfo.peekThroughLayer;
    EXPECT_EQ(&mTestLayers[1]->outputLayer, peekThroughLayer0);
    EXPECT_EQ(nullptr, peekThroughLayer1);
}

TEST_F(FlattenerTest, flattenLayers_flattensBlurBehindRunIfFirstRun) {
    auto& layerState1 = mTestLayers[0]->layerState;