From 802ac4f6e84a830077963db7299ae9184b56e12e Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Wed, 10 May 2023 13:55:22 -0700 Subject: [sf] avoid traversals for cursor updates and buffer udpates In U, we have a unified way to traverse the layer hierarchy from both new FrontEnd and legacy logic to generate the snapshots to provide to CE. We update CE twice, once to draw the cursor and once for the remaining layers. In T we relied on the previous frame's composition state to update cursor state. This extra traversal increases the cpu usage for buffer updates. Fix this by keeping track of the previous composition state and expand on this to avoid all traversals when there are only buffer updates. Bug: 278634536 Test: simple perf and check the instruction count between T and U Change-Id: I26989bf42aa00650ee97c3c60e7f34171c385c5c --- services/surfaceflinger/SurfaceFlinger.cpp | 19 +++++++++++++++++-- services/surfaceflinger/SurfaceFlinger.h | 5 +++++ .../tests/unittests/CompositionTest.cpp | 5 +++++ .../tests/unittests/TestableSurfaceFlinger.h | 2 ++ 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index dfe8c72bca..9476c45452 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -8144,7 +8144,7 @@ std::vector> SurfaceFlinger::moveSnapshotsToComposit }); } if (mLegacyFrontEndEnabled && !mLayerLifecycleManagerEnabled) { - mDrawingState.traverseInZOrder([&refreshArgs, cursorOnly, &layers](Layer* layer) { + auto moveSnapshots = [&layers, &refreshArgs, cursorOnly](Layer* layer) { if (const auto& layerFE = layer->getCompositionEngineLayerFE()) { if (cursorOnly && layer->getLayerSnapshot()->compositionType != @@ -8155,7 +8155,22 @@ std::vector> SurfaceFlinger::moveSnapshotsToComposit refreshArgs.layers.push_back(layerFE); layers.emplace_back(layer, layerFE.get()); } - }); + }; + + if (cursorOnly || !mVisibleRegionsDirty) { + // for hot path avoid traversals by walking though the previous composition list + for (sp layer : mPreviouslyComposedLayers) { + moveSnapshots(layer.get()); + } + } else { + mPreviouslyComposedLayers.clear(); + mDrawingState.traverseInZOrder( + [&moveSnapshots](Layer* layer) { moveSnapshots(layer); }); + mPreviouslyComposedLayers.reserve(layers.size()); + for (auto [layer, _] : layers) { + mPreviouslyComposedLayers.push_back(sp::fromExisting(layer)); + } + } } return layers; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index d92ec7a3b6..adf52cba75 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1199,6 +1199,11 @@ private: std::unordered_set, SpHash> mLayersWithBuffersRemoved; // Tracks layers that need to update a display's dirty region. std::vector> mLayersPendingRefresh; + // Sorted list of layers that were composed during previous frame. This is used to + // avoid an expensive traversal of the layer hierarchy when there are no + // visible region changes. Because this is a list of strong pointers, this will + // extend the life of the layer but this list is only updated in the main thread. + std::vector> mPreviouslyComposedLayers; BootStage mBootStage = BootStage::BOOTLOADER; diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 6ca21bd458..e8a9cfe9d7 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -680,6 +680,9 @@ struct SidebandLayerProperties : public BaseLayerProperties(DEFAULT_SIDEBAND_STREAM), false); test->mFlinger.setLayerSidebandStream(layer, stream); + auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer); + layerDrawingState.crop = + Rect(0, 0, SidebandLayerProperties::HEIGHT, SidebandLayerProperties::WIDTH); } static void setupHwcSetSourceCropBufferCallExpectations(CompositionTest* test) { @@ -814,6 +817,7 @@ struct BaseLayerVariant { Mock::VerifyAndClear(test->mComposer); test->mFlinger.mutableDrawingState().layersSortedByZ.add(layer); + test->mFlinger.mutableVisibleRegionsDirty() = true; } static void cleanupInjectedLayers(CompositionTest* test) { @@ -822,6 +826,7 @@ struct BaseLayerVariant { test->mDisplay->getCompositionDisplay()->clearOutputLayers(); test->mFlinger.mutableDrawingState().layersSortedByZ.clear(); + test->mFlinger.mutablePreviouslyComposedLayers().clear(); // Layer should be unregistered with scheduler. test->mFlinger.commit(); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index a189c002c9..f135c2cfa9 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -588,6 +588,7 @@ public: auto& mutablePhysicalDisplays() { return mFlinger->mPhysicalDisplays; } auto& mutableDrawingState() { return mFlinger->mDrawingState; } auto& mutableGeometryDirty() { return mFlinger->mGeometryDirty; } + auto& mutableVisibleRegionsDirty() { return mFlinger->mVisibleRegionsDirty; } auto& mutableMainThreadId() { return mFlinger->mMainThreadId; } auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; } auto& mutableTexturePool() { return mFlinger->mTexturePool; } @@ -599,6 +600,7 @@ public: auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; } auto& mutablePrimaryHwcDisplayId() { return getHwComposer().mPrimaryHwcDisplayId; } auto& mutableActiveDisplayId() { return mFlinger->mActiveDisplayId; } + auto& mutablePreviouslyComposedLayers() { return mFlinger->mPreviouslyComposedLayers; } auto fromHandle(const sp& handle) { return LayerHandle::getLayer(handle); } -- cgit v1.2.3-59-g8ed1b