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

Commit 09c701d9 authored by Ady Abraham's avatar Ady Abraham Committed by Automerger Merge Worker
Browse files

Merge "Add unit tests for...

Merge "Add unit tests for android::compositionengine::impl::planner::CachedSet" into sc-dev am: cc8dc219

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/native/+/13745597

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: Ib4c04117459f2a4576912dc835289d972450e43f
parents 814f1f54 cc8dc219
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -103,6 +103,7 @@ cc_test {
    test_suites: ["device-tests"],
    defaults: ["libcompositionengine_defaults"],
    srcs: [
        "tests/planner/CachedSetTest.cpp",
        "tests/CompositionEngineTest.cpp",
        "tests/DisplayColorProfileTest.cpp",
        "tests/DisplayTest.cpp",
+318 −0
Original line number Diff line number Diff line
/*
 * Copyright 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <compositionengine/impl/planner/CachedSet.h>
#include <compositionengine/impl/planner/LayerState.h>
#include <compositionengine/mock/LayerFE.h>
#include <compositionengine/mock/OutputLayer.h>
#include <gtest/gtest.h>
#include <renderengine/mock/RenderEngine.h>

namespace android::compositionengine {
using namespace std::chrono_literals;

using testing::_;
using testing::DoAll;
using testing::Invoke;
using testing::Return;
using testing::ReturnRef;
using testing::SetArgPointee;

using impl::planner::CachedSet;
using impl::planner::LayerState;
using impl::planner::LayerStateField;

namespace {

class CachedSetTest : public testing::Test {
public:
    CachedSetTest() = default;
    void SetUp() override;
    void TearDown() override;

protected:
    const std::chrono::steady_clock::time_point kStartTime = std::chrono::steady_clock::now();

    struct TestLayer {
        mock::OutputLayer outputLayer;
        impl::OutputLayerCompositionState outputLayerCompositionState;
        // LayerFE inherits from RefBase and must be held by an sp<>
        sp<mock::LayerFE> layerFE;
        LayerFECompositionState layerFECompositionState;

        std::unique_ptr<LayerState> layerState;
        std::unique_ptr<CachedSet::Layer> cachedSetLayer;
    };

    static constexpr size_t kNumLayers = 5;
    std::vector<std::unique_ptr<TestLayer>> mTestLayers;

    android::renderengine::mock::RenderEngine mRenderEngine;
};

void CachedSetTest::SetUp() {
    for (size_t i = 0; i < kNumLayers; i++) {
        auto testLayer = std::make_unique<TestLayer>();
        auto pos = static_cast<int32_t>(i);
        testLayer->outputLayerCompositionState.displayFrame = Rect(pos, pos, pos + 1, pos + 1);

        testLayer->layerFE = sp<mock::LayerFE>::make();

        EXPECT_CALL(*testLayer->layerFE, getSequence)
                .WillRepeatedly(Return(static_cast<int32_t>(i)));
        EXPECT_CALL(*testLayer->layerFE, getDebugName).WillRepeatedly(Return("testLayer"));
        EXPECT_CALL(*testLayer->layerFE, getCompositionState)
                .WillRepeatedly(Return(&testLayer->layerFECompositionState));
        EXPECT_CALL(testLayer->outputLayer, getLayerFE)
                .WillRepeatedly(ReturnRef(*testLayer->layerFE));
        EXPECT_CALL(testLayer->outputLayer, getState)
                .WillRepeatedly(ReturnRef(testLayer->outputLayerCompositionState));

        testLayer->layerState = std::make_unique<LayerState>(&testLayer->outputLayer);
        testLayer->layerState->incrementFramesSinceBufferUpdate();
        testLayer->cachedSetLayer =
                std::make_unique<CachedSet::Layer>(testLayer->layerState.get(), kStartTime);

        mTestLayers.emplace_back(std::move(testLayer));
    }
}

void CachedSetTest::TearDown() {
    mTestLayers.clear();
}

void expectEqual(const CachedSet& cachedSet, const CachedSet::Layer& layer) {
    EXPECT_EQ(layer.getHash(), cachedSet.getFingerprint());
    EXPECT_EQ(layer.getLastUpdate(), cachedSet.getLastUpdate());
    EXPECT_EQ(layer.getDisplayFrame(), cachedSet.getBounds());
    EXPECT_EQ(1u, cachedSet.getLayerCount());
    EXPECT_EQ(layer.getState(), cachedSet.getFirstLayer().getState());
    EXPECT_EQ(0u, cachedSet.getAge());
    EXPECT_EQ(layer.getHash(), cachedSet.getNonBufferHash());
}

void expectEqual(const CachedSet& cachedSet, const LayerState& layerState,
                 std::chrono::steady_clock::time_point lastUpdate) {
    CachedSet::Layer layer(&layerState, lastUpdate);
    expectEqual(cachedSet, layer);
}

void expectNoBuffer(const CachedSet& cachedSet) {
    EXPECT_EQ(nullptr, cachedSet.getBuffer());
    EXPECT_EQ(nullptr, cachedSet.getDrawFence());
    EXPECT_FALSE(cachedSet.hasReadyBuffer());
}

void expectReadyBuffer(const CachedSet& cachedSet) {
    EXPECT_NE(nullptr, cachedSet.getBuffer());
    EXPECT_NE(nullptr, cachedSet.getDrawFence());
    EXPECT_TRUE(cachedSet.hasReadyBuffer());
}

TEST_F(CachedSetTest, createFromLayer) {
    CachedSet::Layer& layer = *mTestLayers[0]->cachedSetLayer.get();
    CachedSet cachedSet(layer);
    expectEqual(cachedSet, layer);
    expectNoBuffer(cachedSet);
}

TEST_F(CachedSetTest, createFromLayerState) {
    LayerState& layerState = *mTestLayers[0]->layerState.get();
    CachedSet cachedSet(&layerState, kStartTime);
    expectEqual(cachedSet, layerState, kStartTime);
    expectNoBuffer(cachedSet);
}

TEST_F(CachedSetTest, addLayer) {
    CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get();
    CachedSet::Layer& layer2 = *mTestLayers[1]->cachedSetLayer.get();

    CachedSet cachedSet(layer1);
    cachedSet.addLayer(layer2.getState(), kStartTime + 10ms);

    EXPECT_EQ(layer1.getHash(), cachedSet.getFingerprint());
    EXPECT_EQ(kStartTime, cachedSet.getLastUpdate());
    EXPECT_EQ(Rect(0, 0, 2, 2), cachedSet.getBounds());
    EXPECT_EQ(2u, cachedSet.getLayerCount());
    EXPECT_EQ(0u, cachedSet.getAge());
    expectNoBuffer(cachedSet);
    // TODO(b/181192080): check that getNonBufferHash returns the correct hash value
    // EXPECT_EQ(android::hashCombine(layer1.getHash(), layer2.getHash()),
    // cachedSet.getNonBufferHash());
}

TEST_F(CachedSetTest, decompose) {
    CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get();
    CachedSet::Layer& layer2 = *mTestLayers[1]->cachedSetLayer.get();
    CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();

    CachedSet cachedSet(layer1);
    cachedSet.addLayer(layer2.getState(), kStartTime + 10ms);
    cachedSet.addLayer(layer3.getState(), kStartTime + 20ms);

    std::vector<CachedSet> decomposed = cachedSet.decompose();
    EXPECT_EQ(3u, decomposed.size());
    expectEqual(decomposed[0], *layer1.getState(), kStartTime);
    expectNoBuffer(decomposed[0]);

    expectEqual(decomposed[1], *layer2.getState(), kStartTime + 10ms);
    expectNoBuffer(decomposed[1]);

    expectEqual(decomposed[2], *layer3.getState(), kStartTime + 20ms);
    expectNoBuffer(decomposed[2]);
}

TEST_F(CachedSetTest, setLastUpdate) {
    LayerState& layerState = *mTestLayers[0]->layerState.get();
    CachedSet cachedSet(&layerState, kStartTime);
    cachedSet.setLastUpdate(kStartTime + 10ms);
    expectEqual(cachedSet, layerState, kStartTime + 10ms);
}

TEST_F(CachedSetTest, incrementAge) {
    CachedSet::Layer& layer = *mTestLayers[0]->cachedSetLayer.get();
    CachedSet cachedSet(layer);
    EXPECT_EQ(0u, cachedSet.getAge());
    cachedSet.incrementAge();
    EXPECT_EQ(1u, cachedSet.getAge());
    cachedSet.incrementAge();
    EXPECT_EQ(2u, cachedSet.getAge());
}

TEST_F(CachedSetTest, hasBufferUpdate_NoUpdate) {
    CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get();
    CachedSet::Layer& layer2 = *mTestLayers[1]->cachedSetLayer.get();
    CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();

    CachedSet cachedSet(layer1);
    cachedSet.addLayer(layer2.getState(), kStartTime + 10ms);
    cachedSet.addLayer(layer3.getState(), kStartTime + 20ms);

    std::vector<const LayerState*> incomingLayers = {
            layer1.getState(),
            layer2.getState(),
            layer3.getState(),
    };

    EXPECT_FALSE(cachedSet.hasBufferUpdate(incomingLayers.begin()));
}

TEST_F(CachedSetTest, hasBufferUpdate_BufferUpdate) {
    CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get();
    CachedSet::Layer& layer2 = *mTestLayers[1]->cachedSetLayer.get();
    CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();

    CachedSet cachedSet(layer1);
    cachedSet.addLayer(layer2.getState(), kStartTime + 10ms);
    cachedSet.addLayer(layer3.getState(), kStartTime + 20ms);

    mTestLayers[1]->layerState->resetFramesSinceBufferUpdate();

    std::vector<const LayerState*> incomingLayers = {
            layer1.getState(),
            layer2.getState(),
            layer3.getState(),
    };

    EXPECT_TRUE(cachedSet.hasBufferUpdate(incomingLayers.begin()));
}

TEST_F(CachedSetTest, append) {
    CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get();
    CachedSet::Layer& layer2 = *mTestLayers[1]->cachedSetLayer.get();
    CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();

    CachedSet cachedSet1(layer1);
    CachedSet cachedSet2(layer2);
    cachedSet1.addLayer(layer3.getState(), kStartTime + 10ms);
    cachedSet1.append(cachedSet2);

    EXPECT_EQ(layer1.getHash(), cachedSet1.getFingerprint());
    EXPECT_EQ(kStartTime, cachedSet1.getLastUpdate());
    EXPECT_EQ(Rect(0, 0, 3, 3), cachedSet1.getBounds());
    EXPECT_EQ(3u, cachedSet1.getLayerCount());
    EXPECT_EQ(0u, cachedSet1.getAge());
    expectNoBuffer(cachedSet1);
    // TODO(b/181192080): check that getNonBufferHash returns the correct hash value
    // EXPECT_EQ(android::hashCombine(layer1.getHash(), layer2.getHash()),
    // cachedSet1.getNonBufferHash());
}

TEST_F(CachedSetTest, updateAge_NoUpdate) {
    CachedSet::Layer& layer = *mTestLayers[0]->cachedSetLayer.get();

    CachedSet cachedSet(layer);
    cachedSet.incrementAge();
    EXPECT_EQ(kStartTime, cachedSet.getLastUpdate());
    EXPECT_EQ(1u, cachedSet.getAge());

    cachedSet.updateAge(kStartTime + 10ms);
    EXPECT_EQ(kStartTime, cachedSet.getLastUpdate());
    EXPECT_EQ(1u, cachedSet.getAge());
}

TEST_F(CachedSetTest, updateAge_BufferUpdate) {
    CachedSet::Layer& layer = *mTestLayers[0]->cachedSetLayer.get();
    mTestLayers[0]->layerState->resetFramesSinceBufferUpdate();

    CachedSet cachedSet(layer);
    cachedSet.incrementAge();
    EXPECT_EQ(kStartTime, cachedSet.getLastUpdate());
    EXPECT_EQ(1u, cachedSet.getAge());

    cachedSet.updateAge(kStartTime + 10ms);
    EXPECT_EQ(kStartTime + 10ms, cachedSet.getLastUpdate());
    EXPECT_EQ(0u, cachedSet.getAge());
}

TEST_F(CachedSetTest, render) {
    CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get();
    sp<mock::LayerFE> layerFE1 = mTestLayers[0]->layerFE;
    CachedSet::Layer& layer2 = *mTestLayers[1]->cachedSetLayer.get();
    sp<mock::LayerFE> layerFE2 = mTestLayers[1]->layerFE;

    CachedSet cachedSet(layer1);
    cachedSet.append(CachedSet(layer2));

    std::vector<compositionengine::LayerFE::LayerSettings> clientCompList1;
    clientCompList1.push_back({});
    clientCompList1[0].alpha = 0.5f;

    std::vector<compositionengine::LayerFE::LayerSettings> clientCompList2;
    clientCompList2.push_back({});
    clientCompList2[0].alpha = 0.75f;

    const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings,
                                const std::vector<const renderengine::LayerSettings*>& layers,
                                const sp<GraphicBuffer>&, const bool, base::unique_fd&&,
                                base::unique_fd*) -> size_t {
        EXPECT_EQ(Rect(0, 0, 2, 2), displaySettings.physicalDisplay);
        EXPECT_EQ(Rect(0, 0, 2, 2), displaySettings.clip);
        EXPECT_EQ(0.5f, layers[0]->alpha);
        EXPECT_EQ(0.75f, layers[1]->alpha);

        return NO_ERROR;
    };

    EXPECT_CALL(*layerFE1, prepareClientCompositionList(_)).WillOnce(Return(clientCompList1));
    EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2));
    EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
    cachedSet.render(mRenderEngine);
    expectReadyBuffer(cachedSet);
}

} // namespace
} // namespace android::compositionengine