Loading services/surfaceflinger/CompositionEngine/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -104,6 +104,7 @@ cc_test { defaults: ["libcompositionengine_defaults"], srcs: [ "tests/planner/CachedSetTest.cpp", "tests/planner/FlattenerTest.cpp", "tests/CompositionEngineTest.cpp", "tests/DisplayColorProfileTest.cpp", "tests/DisplayTest.cpp", Loading services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h +2 −1 Original line number Diff line number Diff line Loading @@ -39,7 +39,8 @@ public: void setDisplaySize(ui::Size size) { mDisplaySize = size; } NonBufferHash flattenLayers(const std::vector<const LayerState*>& layers, NonBufferHash); NonBufferHash flattenLayers(const std::vector<const LayerState*>& layers, NonBufferHash, std::chrono::steady_clock::time_point now); void renderCachedSets(renderengine::RenderEngine&); Loading services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp +1 −3 Original line number Diff line number Diff line Loading @@ -28,9 +28,7 @@ using namespace std::chrono_literals; namespace android::compositionengine::impl::planner { NonBufferHash Flattener::flattenLayers(const std::vector<const LayerState*>& layers, NonBufferHash hash) { const auto now = std::chrono::steady_clock::now(); NonBufferHash hash, time_point now) { const size_t unflattenedDisplayCost = calculateDisplayCost(layers); mUnflattenedDisplayCost += unflattenedDisplayCost; Loading services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp +2 −1 Original line number Diff line number Diff line Loading @@ -89,7 +89,8 @@ void Planner::plan( }); const NonBufferHash hash = getNonBufferHash(mCurrentLayers); mFlattenedHash = mFlattener.flattenLayers(mCurrentLayers, hash); mFlattenedHash = mFlattener.flattenLayers(mCurrentLayers, hash, std::chrono::steady_clock::now()); const bool layersWereFlattened = hash != mFlattenedHash; ALOGV("[%s] Initial hash %zx flattened hash %zx", __func__, hash, mFlattenedHash); Loading services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp 0 → 100644 +448 −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/Flattener.h> #include <compositionengine/impl/planner/LayerState.h> #include <compositionengine/impl/planner/Predictor.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 impl::planner::Flattener; using impl::planner::LayerState; using impl::planner::NonBufferHash; using impl::planner::Predictor; using testing::_; using testing::ByMove; using testing::ByRef; using testing::DoAll; using testing::Invoke; using testing::Return; using testing::ReturnRef; using testing::Sequence; using testing::SetArgPointee; namespace { class FlattenerTest : public testing::Test { public: FlattenerTest() : mFlattener(std::make_unique<Flattener>(mPredictor)) {} void SetUp() override; protected: void initializeOverrideBuffer(const std::vector<const LayerState*>& layers); void initializeFlattener(const std::vector<const LayerState*>& layers); void expectAllLayersFlattened(const std::vector<const LayerState*>& layers); // TODO(b/181192467): Once Flattener starts to do something useful with Predictor, // mPredictor should be mocked and checked for expectations. Predictor mPredictor; std::unique_ptr<Flattener> mFlattener; renderengine::mock::RenderEngine mRenderEngine; const std::chrono::steady_clock::time_point kStartTime = std::chrono::steady_clock::now(); std::chrono::steady_clock::time_point mTime = kStartTime; struct TestLayer { std::string name; 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; }; static constexpr size_t kNumLayers = 5; std::vector<std::unique_ptr<TestLayer>> mTestLayers; }; void FlattenerTest::SetUp() { for (size_t i = 0; i < kNumLayers; i++) { auto testLayer = std::make_unique<TestLayer>(); auto pos = static_cast<int32_t>(i); std::stringstream ss; ss << "testLayer" << i; testLayer->name = ss.str(); testLayer->outputLayerCompositionState.displayFrame = Rect(pos, pos, pos + 1, pos + 1); testLayer->layerFECompositionState.buffer = new GraphicBuffer(100, 100, HAL_PIXEL_FORMAT_RGBA_8888, 1, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE, "output"); 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->name.c_str())); EXPECT_CALL(*testLayer->layerFE, getCompositionState) .WillRepeatedly(Return(&testLayer->layerFECompositionState)); std::vector<LayerFE::LayerSettings> clientCompositionList = { LayerFE::LayerSettings{}, }; EXPECT_CALL(*testLayer->layerFE, prepareClientCompositionList) .WillRepeatedly(Return(clientCompositionList)); EXPECT_CALL(testLayer->outputLayer, getLayerFE) .WillRepeatedly(ReturnRef(*testLayer->layerFE)); EXPECT_CALL(testLayer->outputLayer, getState) .WillRepeatedly(ReturnRef(testLayer->outputLayerCompositionState)); EXPECT_CALL(testLayer->outputLayer, editState) .WillRepeatedly(ReturnRef(testLayer->outputLayerCompositionState)); testLayer->layerState = std::make_unique<LayerState>(&testLayer->outputLayer); testLayer->layerState->incrementFramesSinceBufferUpdate(); mTestLayers.emplace_back(std::move(testLayer)); } } void FlattenerTest::initializeOverrideBuffer(const std::vector<const LayerState*>& layers) { for (const auto layer : layers) { layer->getOutputLayer()->editState().overrideInfo = {}; } } void FlattenerTest::initializeFlattener(const std::vector<const LayerState*>& layers) { // layer stack is unknown, reset current geomentry initializeOverrideBuffer(layers); EXPECT_EQ(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); // same geometry, update the internal layer stack initializeOverrideBuffer(layers); EXPECT_EQ(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); } void FlattenerTest::expectAllLayersFlattened(const std::vector<const LayerState*>& layers) { // layers would be flattened but the buffer would not be overridden EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR)); initializeOverrideBuffer(layers); EXPECT_EQ(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); for (const auto layer : layers) { EXPECT_EQ(nullptr, layer->getOutputLayer()->getState().overrideInfo.buffer); } // the new flattened layer is replaced initializeOverrideBuffer(layers); EXPECT_NE(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); const auto buffer = layers[0]->getOutputLayer()->getState().overrideInfo.buffer; EXPECT_NE(nullptr, buffer); for (const auto layer : layers) { EXPECT_EQ(buffer, layer->getOutputLayer()->getState().overrideInfo.buffer); } } TEST_F(FlattenerTest, flattenLayers_NewLayerStack) { auto& layerState1 = mTestLayers[0]->layerState; auto& layerState2 = mTestLayers[1]->layerState; const std::vector<const LayerState*> layers = { layerState1.get(), layerState2.get(), }; initializeFlattener(layers); } TEST_F(FlattenerTest, flattenLayers_ActiveLayersAreNotFlattened) { auto& layerState1 = mTestLayers[0]->layerState; auto& layerState2 = mTestLayers[1]->layerState; const std::vector<const LayerState*> layers = { layerState1.get(), layerState2.get(), }; initializeFlattener(layers); // layers cannot be flattened yet, since they are still active initializeOverrideBuffer(layers); EXPECT_EQ(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); } TEST_F(FlattenerTest, flattenLayers_basicFlatten) { auto& layerState1 = mTestLayers[0]->layerState; auto& layerState2 = mTestLayers[1]->layerState; auto& layerState3 = mTestLayers[2]->layerState; const std::vector<const LayerState*> layers = { layerState1.get(), layerState2.get(), layerState3.get(), }; initializeFlattener(layers); // make all layers inactive mTime += 200ms; expectAllLayersFlattened(layers); } TEST_F(FlattenerTest, flattenLayers_FlattenedLayersStayFlattenWhenNoUpdate) { auto& layerState1 = mTestLayers[0]->layerState; const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer; auto& layerState2 = mTestLayers[1]->layerState; const auto& overrideBuffer2 = layerState2->getOutputLayer()->getState().overrideInfo.buffer; auto& layerState3 = mTestLayers[2]->layerState; const auto& overrideBuffer3 = layerState3->getOutputLayer()->getState().overrideInfo.buffer; const std::vector<const LayerState*> layers = { layerState1.get(), layerState2.get(), layerState3.get(), }; initializeFlattener(layers); // make all layers inactive mTime += 200ms; expectAllLayersFlattened(layers); initializeOverrideBuffer(layers); EXPECT_NE(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); EXPECT_NE(nullptr, overrideBuffer1); EXPECT_EQ(overrideBuffer1, overrideBuffer2); EXPECT_EQ(overrideBuffer2, overrideBuffer3); } TEST_F(FlattenerTest, flattenLayers_addLayerToFlattenedCauseReset) { auto& layerState1 = mTestLayers[0]->layerState; const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer; auto& layerState2 = mTestLayers[1]->layerState; const auto& overrideBuffer2 = layerState2->getOutputLayer()->getState().overrideInfo.buffer; auto& layerState3 = mTestLayers[2]->layerState; const auto& overrideBuffer3 = layerState3->getOutputLayer()->getState().overrideInfo.buffer; std::vector<const LayerState*> layers = { layerState1.get(), layerState2.get(), }; initializeFlattener(layers); // make all layers inactive mTime += 200ms; initializeOverrideBuffer(layers); expectAllLayersFlattened(layers); // add a new layer to the stack, this will cause all the flatenner to reset layers.push_back(layerState3.get()); initializeOverrideBuffer(layers); EXPECT_EQ(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); EXPECT_EQ(nullptr, overrideBuffer1); EXPECT_EQ(nullptr, overrideBuffer2); EXPECT_EQ(nullptr, overrideBuffer3); } TEST_F(FlattenerTest, flattenLayers_BufferUpdateToFlatten) { auto& layerState1 = mTestLayers[0]->layerState; const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer; auto& layerState2 = mTestLayers[1]->layerState; const auto& overrideBuffer2 = layerState2->getOutputLayer()->getState().overrideInfo.buffer; auto& layerState3 = mTestLayers[2]->layerState; const auto& overrideBuffer3 = layerState3->getOutputLayer()->getState().overrideInfo.buffer; const std::vector<const LayerState*> layers = { layerState1.get(), layerState2.get(), layerState3.get(), }; initializeFlattener(layers); // make all layers inactive mTime += 200ms; expectAllLayersFlattened(layers); // Layer 1 posted a buffer update, layers would be decomposed, and a new drawFrame would be // caleed for Layer2 and Layer3 layerState1->resetFramesSinceBufferUpdate(); EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR)); initializeOverrideBuffer(layers); EXPECT_EQ(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); EXPECT_EQ(nullptr, overrideBuffer1); EXPECT_EQ(nullptr, overrideBuffer2); EXPECT_EQ(nullptr, overrideBuffer3); initializeOverrideBuffer(layers); EXPECT_NE(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); EXPECT_EQ(nullptr, overrideBuffer1); EXPECT_NE(nullptr, overrideBuffer2); EXPECT_EQ(overrideBuffer2, overrideBuffer3); layerState1->incrementFramesSinceBufferUpdate(); mTime += 200ms; EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR)); initializeOverrideBuffer(layers); EXPECT_NE(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); EXPECT_EQ(nullptr, overrideBuffer1); EXPECT_NE(nullptr, overrideBuffer2); EXPECT_EQ(overrideBuffer2, overrideBuffer3); initializeOverrideBuffer(layers); EXPECT_NE(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); EXPECT_NE(nullptr, overrideBuffer1); EXPECT_EQ(overrideBuffer1, overrideBuffer2); EXPECT_EQ(overrideBuffer2, overrideBuffer3); } TEST_F(FlattenerTest, flattenLayers_BufferUpdateForMiddleLayer) { auto& layerState1 = mTestLayers[0]->layerState; const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer; auto& layerState2 = mTestLayers[1]->layerState; const auto& overrideBuffer2 = layerState2->getOutputLayer()->getState().overrideInfo.buffer; auto& layerState3 = mTestLayers[2]->layerState; const auto& overrideBuffer3 = layerState3->getOutputLayer()->getState().overrideInfo.buffer; auto& layerState4 = mTestLayers[3]->layerState; const auto& overrideBuffer4 = layerState4->getOutputLayer()->getState().overrideInfo.buffer; auto& layerState5 = mTestLayers[4]->layerState; const auto& overrideBuffer5 = layerState5->getOutputLayer()->getState().overrideInfo.buffer; const std::vector<const LayerState*> layers = { layerState1.get(), layerState2.get(), layerState3.get(), layerState4.get(), layerState5.get(), }; initializeFlattener(layers); // make all layers inactive mTime += 200ms; expectAllLayersFlattened(layers); // Layer 3 posted a buffer update, layers would be decomposed, and a new drawFrame would be // called for Layer1 and Layer2 layerState3->resetFramesSinceBufferUpdate(); EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR)); initializeOverrideBuffer(layers); EXPECT_EQ(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); EXPECT_EQ(nullptr, overrideBuffer1); EXPECT_EQ(nullptr, overrideBuffer2); EXPECT_EQ(nullptr, overrideBuffer3); EXPECT_EQ(nullptr, overrideBuffer4); EXPECT_EQ(nullptr, overrideBuffer5); // Layers 1 and 2 will be flattened a new drawFrame would be called for Layer4 and Layer5 EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR)); initializeOverrideBuffer(layers); EXPECT_NE(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); EXPECT_NE(nullptr, overrideBuffer1); EXPECT_EQ(overrideBuffer1, overrideBuffer2); EXPECT_EQ(nullptr, overrideBuffer3); EXPECT_EQ(nullptr, overrideBuffer4); EXPECT_EQ(nullptr, overrideBuffer5); // Layers 4 and 5 will be flattened initializeOverrideBuffer(layers); EXPECT_NE(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); EXPECT_NE(nullptr, overrideBuffer1); EXPECT_EQ(overrideBuffer1, overrideBuffer2); EXPECT_EQ(nullptr, overrideBuffer3); EXPECT_NE(nullptr, overrideBuffer4); EXPECT_EQ(overrideBuffer4, overrideBuffer5); layerState3->incrementFramesSinceBufferUpdate(); mTime += 200ms; EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR)); initializeOverrideBuffer(layers); EXPECT_NE(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); EXPECT_NE(nullptr, overrideBuffer1); EXPECT_EQ(overrideBuffer1, overrideBuffer2); EXPECT_EQ(nullptr, overrideBuffer3); EXPECT_NE(nullptr, overrideBuffer4); EXPECT_EQ(overrideBuffer4, overrideBuffer5); initializeOverrideBuffer(layers); EXPECT_NE(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); EXPECT_NE(nullptr, overrideBuffer1); EXPECT_EQ(overrideBuffer1, overrideBuffer2); EXPECT_EQ(overrideBuffer2, overrideBuffer3); EXPECT_EQ(overrideBuffer3, overrideBuffer4); EXPECT_EQ(overrideBuffer4, overrideBuffer5); } } // namespace } // namespace android::compositionengine Loading
services/surfaceflinger/CompositionEngine/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -104,6 +104,7 @@ cc_test { defaults: ["libcompositionengine_defaults"], srcs: [ "tests/planner/CachedSetTest.cpp", "tests/planner/FlattenerTest.cpp", "tests/CompositionEngineTest.cpp", "tests/DisplayColorProfileTest.cpp", "tests/DisplayTest.cpp", Loading
services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h +2 −1 Original line number Diff line number Diff line Loading @@ -39,7 +39,8 @@ public: void setDisplaySize(ui::Size size) { mDisplaySize = size; } NonBufferHash flattenLayers(const std::vector<const LayerState*>& layers, NonBufferHash); NonBufferHash flattenLayers(const std::vector<const LayerState*>& layers, NonBufferHash, std::chrono::steady_clock::time_point now); void renderCachedSets(renderengine::RenderEngine&); Loading
services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp +1 −3 Original line number Diff line number Diff line Loading @@ -28,9 +28,7 @@ using namespace std::chrono_literals; namespace android::compositionengine::impl::planner { NonBufferHash Flattener::flattenLayers(const std::vector<const LayerState*>& layers, NonBufferHash hash) { const auto now = std::chrono::steady_clock::now(); NonBufferHash hash, time_point now) { const size_t unflattenedDisplayCost = calculateDisplayCost(layers); mUnflattenedDisplayCost += unflattenedDisplayCost; Loading
services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp +2 −1 Original line number Diff line number Diff line Loading @@ -89,7 +89,8 @@ void Planner::plan( }); const NonBufferHash hash = getNonBufferHash(mCurrentLayers); mFlattenedHash = mFlattener.flattenLayers(mCurrentLayers, hash); mFlattenedHash = mFlattener.flattenLayers(mCurrentLayers, hash, std::chrono::steady_clock::now()); const bool layersWereFlattened = hash != mFlattenedHash; ALOGV("[%s] Initial hash %zx flattened hash %zx", __func__, hash, mFlattenedHash); Loading
services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp 0 → 100644 +448 −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/Flattener.h> #include <compositionengine/impl/planner/LayerState.h> #include <compositionengine/impl/planner/Predictor.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 impl::planner::Flattener; using impl::planner::LayerState; using impl::planner::NonBufferHash; using impl::planner::Predictor; using testing::_; using testing::ByMove; using testing::ByRef; using testing::DoAll; using testing::Invoke; using testing::Return; using testing::ReturnRef; using testing::Sequence; using testing::SetArgPointee; namespace { class FlattenerTest : public testing::Test { public: FlattenerTest() : mFlattener(std::make_unique<Flattener>(mPredictor)) {} void SetUp() override; protected: void initializeOverrideBuffer(const std::vector<const LayerState*>& layers); void initializeFlattener(const std::vector<const LayerState*>& layers); void expectAllLayersFlattened(const std::vector<const LayerState*>& layers); // TODO(b/181192467): Once Flattener starts to do something useful with Predictor, // mPredictor should be mocked and checked for expectations. Predictor mPredictor; std::unique_ptr<Flattener> mFlattener; renderengine::mock::RenderEngine mRenderEngine; const std::chrono::steady_clock::time_point kStartTime = std::chrono::steady_clock::now(); std::chrono::steady_clock::time_point mTime = kStartTime; struct TestLayer { std::string name; 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; }; static constexpr size_t kNumLayers = 5; std::vector<std::unique_ptr<TestLayer>> mTestLayers; }; void FlattenerTest::SetUp() { for (size_t i = 0; i < kNumLayers; i++) { auto testLayer = std::make_unique<TestLayer>(); auto pos = static_cast<int32_t>(i); std::stringstream ss; ss << "testLayer" << i; testLayer->name = ss.str(); testLayer->outputLayerCompositionState.displayFrame = Rect(pos, pos, pos + 1, pos + 1); testLayer->layerFECompositionState.buffer = new GraphicBuffer(100, 100, HAL_PIXEL_FORMAT_RGBA_8888, 1, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE, "output"); 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->name.c_str())); EXPECT_CALL(*testLayer->layerFE, getCompositionState) .WillRepeatedly(Return(&testLayer->layerFECompositionState)); std::vector<LayerFE::LayerSettings> clientCompositionList = { LayerFE::LayerSettings{}, }; EXPECT_CALL(*testLayer->layerFE, prepareClientCompositionList) .WillRepeatedly(Return(clientCompositionList)); EXPECT_CALL(testLayer->outputLayer, getLayerFE) .WillRepeatedly(ReturnRef(*testLayer->layerFE)); EXPECT_CALL(testLayer->outputLayer, getState) .WillRepeatedly(ReturnRef(testLayer->outputLayerCompositionState)); EXPECT_CALL(testLayer->outputLayer, editState) .WillRepeatedly(ReturnRef(testLayer->outputLayerCompositionState)); testLayer->layerState = std::make_unique<LayerState>(&testLayer->outputLayer); testLayer->layerState->incrementFramesSinceBufferUpdate(); mTestLayers.emplace_back(std::move(testLayer)); } } void FlattenerTest::initializeOverrideBuffer(const std::vector<const LayerState*>& layers) { for (const auto layer : layers) { layer->getOutputLayer()->editState().overrideInfo = {}; } } void FlattenerTest::initializeFlattener(const std::vector<const LayerState*>& layers) { // layer stack is unknown, reset current geomentry initializeOverrideBuffer(layers); EXPECT_EQ(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); // same geometry, update the internal layer stack initializeOverrideBuffer(layers); EXPECT_EQ(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); } void FlattenerTest::expectAllLayersFlattened(const std::vector<const LayerState*>& layers) { // layers would be flattened but the buffer would not be overridden EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR)); initializeOverrideBuffer(layers); EXPECT_EQ(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); for (const auto layer : layers) { EXPECT_EQ(nullptr, layer->getOutputLayer()->getState().overrideInfo.buffer); } // the new flattened layer is replaced initializeOverrideBuffer(layers); EXPECT_NE(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); const auto buffer = layers[0]->getOutputLayer()->getState().overrideInfo.buffer; EXPECT_NE(nullptr, buffer); for (const auto layer : layers) { EXPECT_EQ(buffer, layer->getOutputLayer()->getState().overrideInfo.buffer); } } TEST_F(FlattenerTest, flattenLayers_NewLayerStack) { auto& layerState1 = mTestLayers[0]->layerState; auto& layerState2 = mTestLayers[1]->layerState; const std::vector<const LayerState*> layers = { layerState1.get(), layerState2.get(), }; initializeFlattener(layers); } TEST_F(FlattenerTest, flattenLayers_ActiveLayersAreNotFlattened) { auto& layerState1 = mTestLayers[0]->layerState; auto& layerState2 = mTestLayers[1]->layerState; const std::vector<const LayerState*> layers = { layerState1.get(), layerState2.get(), }; initializeFlattener(layers); // layers cannot be flattened yet, since they are still active initializeOverrideBuffer(layers); EXPECT_EQ(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); } TEST_F(FlattenerTest, flattenLayers_basicFlatten) { auto& layerState1 = mTestLayers[0]->layerState; auto& layerState2 = mTestLayers[1]->layerState; auto& layerState3 = mTestLayers[2]->layerState; const std::vector<const LayerState*> layers = { layerState1.get(), layerState2.get(), layerState3.get(), }; initializeFlattener(layers); // make all layers inactive mTime += 200ms; expectAllLayersFlattened(layers); } TEST_F(FlattenerTest, flattenLayers_FlattenedLayersStayFlattenWhenNoUpdate) { auto& layerState1 = mTestLayers[0]->layerState; const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer; auto& layerState2 = mTestLayers[1]->layerState; const auto& overrideBuffer2 = layerState2->getOutputLayer()->getState().overrideInfo.buffer; auto& layerState3 = mTestLayers[2]->layerState; const auto& overrideBuffer3 = layerState3->getOutputLayer()->getState().overrideInfo.buffer; const std::vector<const LayerState*> layers = { layerState1.get(), layerState2.get(), layerState3.get(), }; initializeFlattener(layers); // make all layers inactive mTime += 200ms; expectAllLayersFlattened(layers); initializeOverrideBuffer(layers); EXPECT_NE(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); EXPECT_NE(nullptr, overrideBuffer1); EXPECT_EQ(overrideBuffer1, overrideBuffer2); EXPECT_EQ(overrideBuffer2, overrideBuffer3); } TEST_F(FlattenerTest, flattenLayers_addLayerToFlattenedCauseReset) { auto& layerState1 = mTestLayers[0]->layerState; const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer; auto& layerState2 = mTestLayers[1]->layerState; const auto& overrideBuffer2 = layerState2->getOutputLayer()->getState().overrideInfo.buffer; auto& layerState3 = mTestLayers[2]->layerState; const auto& overrideBuffer3 = layerState3->getOutputLayer()->getState().overrideInfo.buffer; std::vector<const LayerState*> layers = { layerState1.get(), layerState2.get(), }; initializeFlattener(layers); // make all layers inactive mTime += 200ms; initializeOverrideBuffer(layers); expectAllLayersFlattened(layers); // add a new layer to the stack, this will cause all the flatenner to reset layers.push_back(layerState3.get()); initializeOverrideBuffer(layers); EXPECT_EQ(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); EXPECT_EQ(nullptr, overrideBuffer1); EXPECT_EQ(nullptr, overrideBuffer2); EXPECT_EQ(nullptr, overrideBuffer3); } TEST_F(FlattenerTest, flattenLayers_BufferUpdateToFlatten) { auto& layerState1 = mTestLayers[0]->layerState; const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer; auto& layerState2 = mTestLayers[1]->layerState; const auto& overrideBuffer2 = layerState2->getOutputLayer()->getState().overrideInfo.buffer; auto& layerState3 = mTestLayers[2]->layerState; const auto& overrideBuffer3 = layerState3->getOutputLayer()->getState().overrideInfo.buffer; const std::vector<const LayerState*> layers = { layerState1.get(), layerState2.get(), layerState3.get(), }; initializeFlattener(layers); // make all layers inactive mTime += 200ms; expectAllLayersFlattened(layers); // Layer 1 posted a buffer update, layers would be decomposed, and a new drawFrame would be // caleed for Layer2 and Layer3 layerState1->resetFramesSinceBufferUpdate(); EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR)); initializeOverrideBuffer(layers); EXPECT_EQ(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); EXPECT_EQ(nullptr, overrideBuffer1); EXPECT_EQ(nullptr, overrideBuffer2); EXPECT_EQ(nullptr, overrideBuffer3); initializeOverrideBuffer(layers); EXPECT_NE(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); EXPECT_EQ(nullptr, overrideBuffer1); EXPECT_NE(nullptr, overrideBuffer2); EXPECT_EQ(overrideBuffer2, overrideBuffer3); layerState1->incrementFramesSinceBufferUpdate(); mTime += 200ms; EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR)); initializeOverrideBuffer(layers); EXPECT_NE(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); EXPECT_EQ(nullptr, overrideBuffer1); EXPECT_NE(nullptr, overrideBuffer2); EXPECT_EQ(overrideBuffer2, overrideBuffer3); initializeOverrideBuffer(layers); EXPECT_NE(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); EXPECT_NE(nullptr, overrideBuffer1); EXPECT_EQ(overrideBuffer1, overrideBuffer2); EXPECT_EQ(overrideBuffer2, overrideBuffer3); } TEST_F(FlattenerTest, flattenLayers_BufferUpdateForMiddleLayer) { auto& layerState1 = mTestLayers[0]->layerState; const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer; auto& layerState2 = mTestLayers[1]->layerState; const auto& overrideBuffer2 = layerState2->getOutputLayer()->getState().overrideInfo.buffer; auto& layerState3 = mTestLayers[2]->layerState; const auto& overrideBuffer3 = layerState3->getOutputLayer()->getState().overrideInfo.buffer; auto& layerState4 = mTestLayers[3]->layerState; const auto& overrideBuffer4 = layerState4->getOutputLayer()->getState().overrideInfo.buffer; auto& layerState5 = mTestLayers[4]->layerState; const auto& overrideBuffer5 = layerState5->getOutputLayer()->getState().overrideInfo.buffer; const std::vector<const LayerState*> layers = { layerState1.get(), layerState2.get(), layerState3.get(), layerState4.get(), layerState5.get(), }; initializeFlattener(layers); // make all layers inactive mTime += 200ms; expectAllLayersFlattened(layers); // Layer 3 posted a buffer update, layers would be decomposed, and a new drawFrame would be // called for Layer1 and Layer2 layerState3->resetFramesSinceBufferUpdate(); EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR)); initializeOverrideBuffer(layers); EXPECT_EQ(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); EXPECT_EQ(nullptr, overrideBuffer1); EXPECT_EQ(nullptr, overrideBuffer2); EXPECT_EQ(nullptr, overrideBuffer3); EXPECT_EQ(nullptr, overrideBuffer4); EXPECT_EQ(nullptr, overrideBuffer5); // Layers 1 and 2 will be flattened a new drawFrame would be called for Layer4 and Layer5 EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR)); initializeOverrideBuffer(layers); EXPECT_NE(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); EXPECT_NE(nullptr, overrideBuffer1); EXPECT_EQ(overrideBuffer1, overrideBuffer2); EXPECT_EQ(nullptr, overrideBuffer3); EXPECT_EQ(nullptr, overrideBuffer4); EXPECT_EQ(nullptr, overrideBuffer5); // Layers 4 and 5 will be flattened initializeOverrideBuffer(layers); EXPECT_NE(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); EXPECT_NE(nullptr, overrideBuffer1); EXPECT_EQ(overrideBuffer1, overrideBuffer2); EXPECT_EQ(nullptr, overrideBuffer3); EXPECT_NE(nullptr, overrideBuffer4); EXPECT_EQ(overrideBuffer4, overrideBuffer5); layerState3->incrementFramesSinceBufferUpdate(); mTime += 200ms; EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR)); initializeOverrideBuffer(layers); EXPECT_NE(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); EXPECT_NE(nullptr, overrideBuffer1); EXPECT_EQ(overrideBuffer1, overrideBuffer2); EXPECT_EQ(nullptr, overrideBuffer3); EXPECT_NE(nullptr, overrideBuffer4); EXPECT_EQ(overrideBuffer4, overrideBuffer5); initializeOverrideBuffer(layers); EXPECT_NE(getNonBufferHash(layers), mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); mFlattener->renderCachedSets(mRenderEngine); EXPECT_NE(nullptr, overrideBuffer1); EXPECT_EQ(overrideBuffer1, overrideBuffer2); EXPECT_EQ(overrideBuffer2, overrideBuffer3); EXPECT_EQ(overrideBuffer3, overrideBuffer4); EXPECT_EQ(overrideBuffer4, overrideBuffer5); } } // namespace } // namespace android::compositionengine